/**
* @file
* @brief Misc function related to player transformations.
**/
#include "AppHdr.h"
#include "transform.h"
#include <cstdio>
#include <cstring>
#include "artefact.h"
#include "art-enum.h"
#include "delay.h"
#include "english.h"
#include "env.h"
#include "god-item.h"
#include "god-passive.h" // passive_t::resist_polymorph
#include "invent.h" // check_old_item_warning
#include "item-use.h"
#include "item-name.h"
#include "item-prop.h"
#include "items.h"
#include "message.h"
#include "mon-death.h"
#include "mutation.h"
#include "output.h"
#include "player-equip.h"
#include "player-stats.h"
#include "prompt.h"
#include "religion.h"
#include "spl-cast.h"
#include "state.h"
#include "stringutil.h"
#include "terrain.h"
#include "traps.h"
#include "xom.h"
// transform slot enums into flags
#define SLOTF(s) (1 << s)
static const int EQF_NONE = 0;
// "hand" slots (not rings)
static const int EQF_HANDS = SLOTF(EQ_WEAPON) | SLOTF(EQ_SHIELD)
| SLOTF(EQ_GLOVES);
// core body slots (statue form)
static const int EQF_STATUE = SLOTF(EQ_GLOVES) | SLOTF(EQ_BOOTS)
| SLOTF(EQ_BODY_ARMOUR);
// more core body slots (Lear's Hauberk)
static const int EQF_LEAR = EQF_STATUE | SLOTF(EQ_HELMET);
// everything you can (W)ear
static const int EQF_WEAR = EQF_LEAR | SLOTF(EQ_CLOAK) | SLOTF(EQ_SHIELD);
// everything but jewellery
static const int EQF_PHYSICAL = EQF_HANDS | EQF_WEAR;
// all rings (except for the macabre finger amulet's)
static const int EQF_RINGS = SLOTF(EQ_LEFT_RING) | SLOTF(EQ_RIGHT_RING)
| SLOTF(EQ_RING_ONE) | SLOTF(EQ_RING_TWO)
| SLOTF(EQ_RING_THREE) | SLOTF(EQ_RING_FOUR)
| SLOTF(EQ_RING_FIVE) | SLOTF(EQ_RING_SIX)
| SLOTF(EQ_RING_SEVEN) | SLOTF(EQ_RING_EIGHT);
// amulet & pal
static const int EQF_AMULETS = SLOTF(EQ_AMULET) | SLOTF(EQ_RING_AMULET);
// everything
static const int EQF_ALL = EQF_PHYSICAL | EQF_RINGS | EQF_AMULETS;
static const FormAttackVerbs DEFAULT_VERBS = FormAttackVerbs(nullptr, nullptr,
nullptr, nullptr);
static const FormAttackVerbs ANIMAL_VERBS = FormAttackVerbs("hit", "bite",
"maul", "maul");
static const FormDuration DEFAULT_DURATION = FormDuration(20, PS_DOUBLE, 100);
static const FormDuration BAD_DURATION = FormDuration(15, PS_ONE_AND_A_HALF,
100);
// Class form_entry and the formdata array
#include "form-data.h"
static const form_entry &_find_form_entry(transformation form)
{
for (const form_entry &entry : formdata)
if (entry.tran == form)
return entry;
die("No formdata entry found for form %d", (int)form);
}
Form::Form(const form_entry &fe)
: short_name(fe.short_name), wiz_name(fe.wiz_name),
duration(fe.duration),
str_mod(fe.str_mod), dex_mod(fe.dex_mod),
blocked_slots(fe.blocked_slots), size(fe.size), hp_mod(fe.hp_mod),
can_cast(fe.can_cast), spellcasting_penalty(fe.spellcasting_penalty),
unarmed_hit_bonus(fe.unarmed_hit_bonus), uc_colour(fe.uc_colour),
uc_attack_verbs(fe.uc_attack_verbs),
can_bleed(fe.can_bleed), breathes(fe.breathes),
keeps_mutations(fe.keeps_mutations),
shout_verb(fe.shout_verb),
shout_volume_modifier(fe.shout_volume_modifier),
hand_name(fe.hand_name), foot_name(fe.foot_name),
flesh_equivalent(fe.flesh_equivalent),
long_name(fe.long_name), description(fe.description),
resists(fe.resists),
base_unarmed_damage(fe.base_unarmed_damage),
can_fly(fe.can_fly), can_swim(fe.can_swim),
flat_ac(fe.flat_ac), power_ac(fe.power_ac), xl_ac(fe.xl_ac),
uc_brand(fe.uc_brand), uc_attack(fe.uc_attack),
prayer_action(fe.prayer_action), equivalent_mons(fe.equivalent_mons)
{ }
Form::Form(transformation tran)
: Form(_find_form_entry(tran))
{ }
/**
* Is the given equipment slot available for use in this form?
*
* @param slot The equipment slot in question. (May be a weird fake
* slot - EQ_STAFF or EQ_ALL_ARMOUR.)
* @return Whether at least some items can be worn in this slot in
* this form.
* (The player's race, or mutations, may still block the
* slot, or it may be restricted to subtypes.)
*/
bool Form::slot_available(int slot) const
{
if (slot == EQ_ALL_ARMOUR)
return !all_blocked(EQF_WEAR);
if (slot == EQ_RINGS || slot == EQ_RINGS_PLUS)
return !all_blocked(EQF_RINGS);
if (slot == EQ_STAFF)
slot = EQ_WEAPON;
return !(blocked_slots & SLOTF(slot));
}
/**
* Can the player wear the given item while in this form?
*
* Does not take mutations into account.
*
* @param item The item in question
* @return Whether this form prevents the player from wearing the
* item. (Other things may also prevent it, of course)
*/
bool Form::can_wear_item(const item_def& item) const
{
if (item.base_type == OBJ_JEWELLERY)
{
if (jewellery_is_amulet(item))
return slot_available(EQ_AMULET);
return !all_blocked(EQF_RINGS);
}
if (is_unrandom_artefact(item, UNRAND_LEAR))
return !(blocked_slots & EQF_LEAR); // ok if no body slots blocked
return slot_available(get_armour_slot(item));
}
/**
* Get the bonus to form duration granted for a given (spell)power.
*
* @param pow The spellpower/equivalent of the form.
* @return A bonus to form duration.
*/
int FormDuration::power_bonus(int pow) const
{
switch (scaling_type)
{
case PS_NONE:
return 0;
case PS_SINGLE:
return random2(pow);
case PS_ONE_AND_A_HALF:
return random2(pow) + random2(pow/2);
case PS_DOUBLE:
return random2(pow) + random2(pow);
default:
die("Unknown scaling type!");
return -1;
}
}
/**
* Get the duration for this form, when newly entered.
*
* @param pow The power of the effect creating this form. (Spellpower, etc.)
* @return The duration of the form. (XXX: in turns...?)
*/
int Form::get_duration(int pow) const
{
return min(duration.base + duration.power_bonus(pow), duration.max);
}
/**
* Get a verbose description for the form.
*
* @param past_tense Whether the description should be in past or present
* tense.
* @return A description for the form.
*/
string Form::get_description(bool past_tense) const
{
return make_stringf("You %s %s",
past_tense ? "were" : "are",
description.c_str());
}
/**
* Get a message for transforming into this form, based on your current
* situation (e.g. in water...)
*
* @return The message for turning into this form.
*/
string Form::transform_message(transformation previous_trans) const
{
// XXX: refactor this into a second function (and also rethink the logic)
string start = "Buggily, y";
if (you.in_water() && player_can_fly())
start = "You fly out of the water as y";
else if (get_form(previous_trans)->player_can_fly()
&& player_can_swim()
&& feat_is_water(grd(you.pos())))
start = "As you dive into the water, y";
else
start = "Y";
return make_stringf("%sou turn into %s", start.c_str(),
get_transform_description().c_str());
}
/**
* Get a message for untransforming from this form.
*
* @return "Your transform has ended."
*/
string Form::get_untransform_message() const
{
return "Your transformation has ended.";
}
/**
* What AC bonus does the player get while in this form?
*
* Many forms are power-dependent, so the answer given may be strange if the
* player isn't currently in the form in question.
*
* @return The AC bonus currently granted by the form, multiplied by 100 to
* allow for pseudo-decimal flexibility (& to match
* player::armour_class())
*/
int Form::get_ac_bonus() const
{
return flat_ac * 100
+ power_ac * you.props[TRANSFORM_POW_KEY].get_int()
+ xl_ac * you.experience_level;
}
/**
* (freeze)
*/
static string _brand_suffix(brand_type brand)
{
if (brand == SPWPN_NORMAL)
return "";
return make_stringf(" (%s)", brand_type_name(brand, true));
}
/**
* What name should be used for the player's means of unarmed attack while
* in this form?
*
* (E.g. for display in the top-right of the UI.)
*
* @param The player's UC weapon when not in a form (claws, etc)
* @return A string describing the form's UC attack 'weapon'.
*/
string Form::get_uc_attack_name(string default_name) const
{
const string brand_suffix = _brand_suffix(get_uc_brand());
if (uc_attack.empty())
return default_name + brand_suffix;
return uc_attack + brand_suffix;
}
/**
* How many levels of resistance against fire does this form provide?
*/
int Form::res_fire() const
{
return get_resist(resists, MR_RES_FIRE);
}
/**
* How many levels of resistance against cold does this form provide?
*/
int Form::res_cold() const
{
return get_resist(resists, MR_RES_COLD);
}
/**
* How many levels of resistance against negative energy does this form give?
*/
int Form::res_neg() const
{
return get_resist(resists, MR_RES_NEG);
}
/**
* Does this form provide resistance to electricity?
*/
bool Form::res_elec() const
{
return get_resist(resists, MR_RES_ELEC);
}
/**
* How many levels of resistance against poison does this form give?
*/
int Form::res_pois() const
{
return get_resist(resists, MR_RES_POISON);
}
/**
* Does this form provide resistance to rotting?
*/
bool Form::res_rot() const
{
return get_resist(resists, MR_RES_ROTTING);
}
/**
* Does this form provide resistance against acid?
*/
bool Form::res_acid() const
{
return get_resist(resists, MR_RES_ACID);
}
/**
* Does this form provide resistance to sticky flame?
*/
bool Form::res_sticky_flame() const
{
return get_resist(resists, MR_RES_STICKY_FLAME);
}
/**
* Does this form provide resistance to petrification?
*/
bool Form::res_petrify() const
{
return get_resist(resists, MR_RES_PETRIFY);
}
/**
* Does this form enable flight?
*
* @return Whether this form allows flight for characters which don't already
* have access to it.
*/
bool Form::enables_flight() const
{
return can_fly == FC_ENABLE;
}
/**
* Does this form disable flight?
*
* @return Whether flight is always impossible while in this form.
*/
bool Form::forbids_flight() const
{
return can_fly == FC_FORBID;
}
/**
* Does this form disable swimming?
*
* @return Whether swimming is always impossible while in this form.
*/
bool Form::forbids_swimming() const
{
return can_swim == FC_FORBID;
}
/**
* Can the player fly, if in this form?
*
* DOES consider player state besides form.
* @return Whether the player will be able to fly in this form.
*/
bool Form::player_can_fly() const
{
return !forbids_flight()
&& (enables_flight()
|| you.racial_permanent_flight() && you.permanent_flight());
}
/**
* Can the player swim, if in this form?
*
* DOES consider player state besides form.
* @return Whether the player will be able to swim in this form.
*/
bool Form::player_can_swim() const
{
const size_type player_size = size == SIZE_CHARACTER ?
you.body_size(PSIZE_BODY, true) :
size;
return can_swim == FC_ENABLE
|| species_can_swim(you.species) && can_swim != FC_FORBID
|| player_size >= SIZE_GIANT;
}
/**
* Are all of the given equipment slots blocked while in this form?
*
* @param slotflags A set of flags, corresponding to the union of
(1 << the slot enum) for each slot in question.
* @return Whether all of the given slots are blocked.
*/
bool Form::all_blocked(int slotflags) const
{
return slotflags == (blocked_slots & slotflags);
}
/**
* What message should be printed when the player prays at an altar?
* To be inserted into "You %s the altar of foo."
*
* If the form has a valid custom action, print that; otherwise, default to the
* 'flying' or species-specific actions, as appropriate.
*
* @return An action to be printed when the player prays at an altar.
* E.g., "perch on", "crawl onto", "sway towards", etc.
*/
string Form::player_prayer_action() const
{
// If the form is naturally flying & specifies an action, use that.
if (can_fly == FC_ENABLE && !prayer_action.empty())
return prayer_action;
// Otherwise, if you're flying, use the generic flying action.
// XXX: if we ever get a default-permaflying species again that wants to
// have a separate verb, we'll want to check for that right here.
if (you.airborne())
return "hover solemnly before";
// Otherwise, if you have a verb, use that...
if (!prayer_action.empty())
return prayer_action;
// Finally, default to your species' verb.
return species_prayer_action(you.species);
}
class FormNone : public Form
{
private:
FormNone() : Form(transformation::none) { }
DISALLOW_COPY_AND_ASSIGN(FormNone);
public:
static const FormNone &instance() { static FormNone inst; return inst; }
/**
* Get a string describing the form you're turning into. (If not the same
* as the one used to describe this form in @.
*/
string get_transform_description() const override { return "your old self."; }
};
class FormSpider : public Form
{
private:
FormSpider() : Form(transformation::spider) { }
DISALLOW_COPY_AND_ASSIGN(FormSpider);
public:
static const FormSpider &instance() { static FormSpider inst; return inst; }
};
class FormBlade : public Form
{
private:
FormBlade() : Form(transformation::blade_hands) { }
DISALLOW_COPY_AND_ASSIGN(FormBlade);
public:
static const FormBlade &instance() { static FormBlade inst; return inst; }
/**
* % screen description
*/
string get_long_name() const override
{
return "blade " + blade_parts(true);
}
/**
* @ description
*/
string get_description(bool past_tense) const override
{
return make_stringf("You %s blades for %s.",
past_tense ? "had" : "have",
blade_parts().c_str());
}
/**
* Get a message for transforming into this form.
*/
string transform_message(transformation /*previous_trans*/) const override
{
const bool singular = you.get_mutation_level(MUT_MISSING_HAND);
// XXX: a little ugly
return make_stringf("Your %s turn%s into%s razor-sharp scythe blade%s.",
blade_parts().c_str(), singular ? "s" : "",
singular ? " a" : "", singular ? "" : "s");
}
/**
* Get a message for untransforming from this form.
*/
string get_untransform_message() const override
{
const bool singular = you.get_mutation_level(MUT_MISSING_HAND);
// XXX: a little ugly
return make_stringf("Your %s revert%s to %s normal proportions.",
blade_parts().c_str(), singular ? "s" : "",
singular ? "its" : "their");
}
bool can_offhand_punch() const override { return true; }
/**
* Get the name displayed in the UI for the form's unarmed-combat 'weapon'.
*/
string get_uc_attack_name(string /*default_name*/) const override
{
return "Blade " + blade_parts(true);
}
};
class FormStatue : public Form
{
private:
FormStatue() : Form(transformation::statue) { }
DISALLOW_COPY_AND_ASSIGN(FormStatue);
public:
static const FormStatue &instance() { static FormStatue inst; return inst; }
/**
* Get a message for transforming into this form.
*/
string transform_message(transformation previous_trans) const override
{
if (you.species == SP_DEEP_DWARF && one_chance_in(10))
return "You inwardly fear your resemblance to a lawn ornament.";
else if (you.species == SP_GARGOYLE)
return "Your body stiffens and grows slower.";
else
return Form::transform_message(previous_trans);
}
/**
* Get a string describing the form you're turning into. (If not the same
* as the one used to describe this form in @.
*/
string get_transform_description() const override
{
return "a living statue of rough stone.";
}
/**
* Get a message for untransforming from this form.
*/
string get_untransform_message() const override
{
// This only handles lava orcs going statue -> stoneskin.
if (you.species == SP_GARGOYLE)
return "You revert to a slightly less stony form.";
return "You revert to your normal fleshy form.";
}
/**
* Get the name displayed in the UI for the form's unarmed-combat 'weapon'.
*/
string get_uc_attack_name(string /*default_name*/) const override
{
if (you.has_usable_claws(true))
return "Stone claws";
if (you.has_usable_tentacles(true))
return "Stone tentacles";
const bool singular = you.get_mutation_level(MUT_MISSING_HAND);
return make_stringf("Stone fist%s", singular ? "" : "s");
}
};
class FormIce : public Form
{
private:
FormIce() : Form(transformation::ice_beast) { }
DISALLOW_COPY_AND_ASSIGN(FormIce);
public:
static const FormIce &instance() { static FormIce inst; return inst; }
/**
* Get a message for untransforming from this form.
*/
string get_untransform_message() const override
{
return "You warm up again.";
}
/**
* Get the name displayed in the UI for the form's unarmed-combat 'weapon'.
*/
string get_uc_attack_name(string /*default_name*/) const override
{
const bool singular = you.get_mutation_level(MUT_MISSING_HAND);
return make_stringf("Ice fist%s", singular ? "" : "s");
}
};
class FormDragon : public Form
{
private:
FormDragon() : Form(transformation::dragon) { }
DISALLOW_COPY_AND_ASSIGN(FormDragon);
public:
static const FormDragon &instance() { static FormDragon inst; return inst; }
/**
* Get an monster type corresponding to the transformation.
*
* (Used for console player glyphs.)
*
* @return A monster type corresponding to the player in this form.
*/
monster_type get_equivalent_mons() const override
{
return dragon_form_dragon_type();
}
/**
* The AC bonus of the form, multiplied by 100 to match
* player::armour_class().
*/
int get_ac_bonus() const override
{
if (species_is_draconian(you.species))
return 1000;
return Form::get_ac_bonus();
}
/**
* How many levels of resistance against fire does this form provide?
*/
int res_fire() const override
{
switch (dragon_form_dragon_type())
{
case MONS_FIRE_DRAGON:
return 2;
case MONS_ICE_DRAGON:
return -1;
default:
return 0;
}
}
/**
* How many levels of resistance against cold does this form provide?
*/
int res_cold() const override
{
switch (dragon_form_dragon_type())
{
case MONS_ICE_DRAGON:
return 2;
case MONS_FIRE_DRAGON:
return -1;
default:
return 0;
}
}
bool can_offhand_punch() const override { return true; }
};
class FormLich : public Form
{
private:
FormLich() : Form(transformation::lich) { }
DISALLOW_COPY_AND_ASSIGN(FormLich);
public:
static const FormLich &instance() { static FormLich inst; return inst; }
/**
* Get a message for transforming into this form.
*/
string transform_message(transformation /*previous_trans*/) const override
{
return "Your body is suffused with negative energy!";
}
/**
* Get a message for untransforming from this form.
*/
string get_untransform_message() const override
{
if (you.undead_state() == US_ALIVE)
return "You feel yourself come back to life.";
return "You feel your undeath return to normal.";
// ^^^ vampires only, probably
}
};
class FormBat : public Form
{
private:
FormBat() : Form(transformation::bat) { }
DISALLOW_COPY_AND_ASSIGN(FormBat);
public:
static const FormBat &instance() { static FormBat inst; return inst; }
/**
* Get an monster type corresponding to the transformation.
*
* (Used for console player glyphs.)
*
* @return A monster type corresponding to the player in this form.
*/
monster_type get_equivalent_mons() const override
{
return you.species == SP_VAMPIRE ? MONS_VAMPIRE_BAT : MONS_BAT;
}
string get_description(bool past_tense) const override
{
return make_stringf("You %s in %sbat-form.",
past_tense ? "were" : "are",
you.species == SP_VAMPIRE ? "vampire-" : "");
}
/**
* Get a string describing the form you're turning into. (If not the same
* as the one used to describe this form in @.
*/
string get_transform_description() const override
{
return make_stringf("a %sbat.",
you.species == SP_VAMPIRE ? "vampire " : "");
}
};
class FormPig : public Form
{
private:
FormPig() : Form(transformation::pig) { }
DISALLOW_COPY_AND_ASSIGN(FormPig);
public:
static const FormPig &instance() { static FormPig inst; return inst; }
};
class FormAppendage : public Form
{
private:
FormAppendage() : Form(transformation::appendage) { }
DISALLOW_COPY_AND_ASSIGN(FormAppendage);
public:
static const FormAppendage &instance()
{
static FormAppendage inst;
return inst;
}
string get_description(bool past_tense) const override
{
if (you.attribute[ATTR_APPENDAGE] == MUT_TENTACLE_SPIKE)
{
return make_stringf("One of your tentacles %s a temporary spike.",
past_tense ? "had" : "has");
}
return make_stringf("You %s grown temporary %s.",
past_tense ? "had" : "have",
mutation_name((mutation_type)
you.attribute[ATTR_APPENDAGE]));
}
/**
* Get a message for transforming into this form.
*/
string transform_message(transformation /*previous_trans*/) const override
{
// ATTR_APPENDAGE must be set earlier!
switch (you.attribute[ATTR_APPENDAGE])
{
case MUT_HORNS:
return "You grow a pair of large bovine horns.";
case MUT_TENTACLE_SPIKE:
return "One of your tentacles grows a vicious spike.";
case MUT_TALONS:
return "Your feet morph into talons.";
default:
die("Unknown beastly appendage.");
}
}
/**
* Get a message for untransforming from this form. (Handled elsewhere.)
*/
string get_untransform_message() const override { return ""; }
};
class FormTree : public Form
{
private:
FormTree() : Form(transformation::tree) { }
DISALLOW_COPY_AND_ASSIGN(FormTree);
public:
static const FormTree &instance() { static FormTree inst; return inst; }
/**
* Get a message for untransforming from this form.
*/
string get_untransform_message() const override { return "You feel less wooden."; }
};
#if TAG_MAJOR_VERSION == 34
class FormPorcupine : public Form
{
private:
FormPorcupine() : Form(transformation::porcupine) { }
DISALLOW_COPY_AND_ASSIGN(FormPorcupine);
public:
static const FormPorcupine &instance()
{
static FormPorcupine inst;
return inst;
}
};
#endif
class FormWisp : public Form
{
private:
FormWisp() : Form(transformation::wisp) { }
DISALLOW_COPY_AND_ASSIGN(FormWisp);
public:
static const FormWisp &instance() { static FormWisp inst; return inst; }
};
#if TAG_MAJOR_VERSION == 34
class FormJelly : public Form
{
private:
FormJelly() : Form(transformation::jelly) { }
DISALLOW_COPY_AND_ASSIGN(FormJelly);
public:
static const FormJelly &instance() { static FormJelly inst; return inst; }
};
#endif
class FormFungus : public Form
{
private:
FormFungus() : Form(transformation::fungus) { }
DISALLOW_COPY_AND_ASSIGN(FormFungus);
public:
static const FormFungus &instance() { static FormFungus inst; return inst; }
/**
* Get a message for untransforming from this form.
*/
string get_untransform_message() const override { return "You stop sporulating."; }
};
class FormShadow : public Form
{
private:
FormShadow() : Form(transformation::shadow) { }
DISALLOW_COPY_AND_ASSIGN(FormShadow);
public:
static const FormShadow &instance() { static FormShadow inst; return inst; }
/**
* Get a message for untransforming from this form.
*/
string get_untransform_message() const override
{
if (you.invisible())
return "You feel less shadowy.";
return "You emerge from the shadows.";
}
};
/**
* Set the number of hydra heads that the player currently has.
*
* @param heads the new number of heads you should have.
*/
void set_hydra_form_heads(int heads)
{
you.props[HYDRA_FORM_HEADS_KEY] = min(MAX_HYDRA_HEADS, max(1, heads));
you.wield_change = true;
}
class FormHydra : public Form
{
private:
FormHydra() : Form(transformation::hydra) { }
DISALLOW_COPY_AND_ASSIGN(FormHydra);
public:
static const FormHydra &instance() { static FormHydra inst; return inst; }
/**
* Get a string describing the form you're turning into.
*/
string get_transform_description() const override
{
const auto heads = you.heads();
const string headstr = (heads < 11 ? number_in_words(heads)
: to_string(heads))
+ "-headed hydra.";
return article_a(headstr);
}
/**
* @ description
*/
string get_description(bool past_tense) const override
{
return make_stringf("You %s %s",
past_tense ? "were" : "are",
get_transform_description().c_str());
}
/**
* Get the name displayed in the UI for the form's unarmed-combat 'weapon'.
*/
string get_uc_attack_name(string /*default_name*/) const override
{
return make_stringf("Bite (x%d)", you.heads());
}
/**
* Find the player's base unarmed damage in this form.
*/
int get_base_unarmed_damage() const override
{
// 3 damage per head for 1-10
const int normal_heads_damage = min(you.heads(), 10) * 3;
// 3/2 damage per head for 11-20 (they get in each-other's way)
// (and also a 62-base-damage form scares me)
const int too_many_heads_damage = max(0, you.heads() - 10)
* 3 / 2;
// 2-47 (though more like 14-32 in practical ranges...)
return 2 + normal_heads_damage + too_many_heads_damage;
}
};
static const Form* forms[] =
{
&FormNone::instance(),
&FormSpider::instance(),
&FormBlade::instance(),
&FormStatue::instance(),
&FormIce::instance(),
&FormDragon::instance(),
&FormLich::instance(),
&FormBat::instance(),
&FormPig::instance(),
&FormAppendage::instance(),
&FormTree::instance(),
#if TAG_MAJOR_VERSION == 34
&FormPorcupine::instance(),
#endif
&FormWisp::instance(),
#if TAG_MAJOR_VERSION == 34
&FormJelly::instance(),
#endif
&FormFungus::instance(),
&FormShadow::instance(),
&FormHydra::instance(),
};
const Form* get_form(transformation xform)
{
COMPILE_CHECK(ARRAYSZ(forms) == NUM_TRANSFORMS);
const int form = static_cast<int>(xform);
ASSERT_RANGE(form, 0, NUM_TRANSFORMS);
return forms[form];
}
/**
* Get the wizmode name of a form.
*
* @param form The form in question.
* @return The form's casual, wizmode name.
*/
const char* transform_name(transformation form)
{
return get_form(form)->wiz_name.c_str();
}
/**
* Can the player (w)ield weapons when in the given form?
*
* @param form The form in question.
* @return Whether the player can wield items when in that form.
*/
bool form_can_wield(transformation form)
{
return get_form(form)->can_wield();
}
/**
* Can the player (W)ear armour when in the given form?
*
* @param form The form in question.
* @return Whether the player can wear armour when in that form.
*/
bool form_can_wear(transformation form)
{
return !testbits(get_form(form)->blocked_slots, EQF_WEAR);
}
/**
* Can the player fly, if in this form?
*
* DOES consider player state besides form.
* @param form The form in question.
* @return Whether the player will be able to fly in this form.
*/
bool form_can_fly(transformation form)
{
return get_form(form)->player_can_fly();
}
/**
* Can the player swim, if in this form?
*
* (Swimming = traversing deep & shallow water without penalties; includes
* floating (ice form) and wading forms (giants - currently just dragon form,
* which normally flies anyway...))
*
* DOES consider player state besides form.
* @param form The form in question.
* @return Whether the player will be able to swim in this form.
*/
bool form_can_swim(transformation form)
{
return get_form(form)->player_can_swim();
}
/**
* Can the player survive in deep water when in the given form?
*
* Doesn't count flight or beogh water-walking.
*
* @param form The form in question.
* @return Whether the player won't be killed when entering deep water
* in that form.
*/
bool form_likes_water(transformation form)
{
// Grey dracs can't swim, so can't statue form merfolk/octopodes
// -- yet they can still survive in water.
if (species_likes_water(you.species)
&& (form == transformation::statue
|| !get_form(form)->forbids_swimming()))
{
return true;
}
// otherwise, you gotta swim to survive!
return form_can_swim(form);
}
// Used to mark transformations which override species intrinsics.
bool form_changed_physiology(transformation form)
{
return form != transformation::none
&& form != transformation::appendage
&& form != transformation::blade_hands;
}
/**
* Does this form have blood?
*
* @param form The form in question.
* @return Whether the form can bleed, sublime, etc.
*/
bool form_can_bleed(transformation form)
{
return get_form(form)->can_bleed != FC_FORBID;
}
// Used to mark forms which keep most form-based mutations.
bool form_keeps_mutations(transformation form)
{
return get_form(form)->keeps_mutations;
}
static set<equipment_type>
_init_equipment_removal(transformation form)
{
set<equipment_type> result;
if (!form_can_wield(form) && you.weapon() || you.melded[EQ_WEAPON])
result.insert(EQ_WEAPON);
// Liches can't wield holy weapons.
if (form == transformation::lich && you.weapon()
&& is_holy_item(*you.weapon()))
{
result.insert(EQ_WEAPON);
}
for (int i = EQ_FIRST_EQUIP; i < NUM_EQUIP; ++i)
{
if (i == EQ_WEAPON)
continue;
const equipment_type eq = static_cast<equipment_type>(i);
const item_def *pitem = you.slot_item(eq, true);
if (pitem && (get_form(form)->blocked_slots & SLOTF(i)
|| (i != EQ_RING_AMULET
&& !get_form(form)->can_wear_item(*pitem))))
{
result.insert(eq);
}
}
return result;
}
static void _remove_equipment(const set<equipment_type>& removed,
transformation form,
bool meld = true, bool mutation = false)
{
// Meld items into you in (reverse) order. (set is a sorted container)
for (const equipment_type e : removed)
{
item_def *equip = you.slot_item(e, true);
if (equip == nullptr)
continue;
bool unequip = !meld;
if (!unequip && e == EQ_WEAPON)
{
if (form_can_wield(form))
unequip = true;
if (!is_weapon(*equip))
unequip = true;
}
mprf("%s %s%s %s", equip->name(DESC_YOUR).c_str(),
unequip ? "fall" : "meld",
equip->quantity > 1 ? "" : "s",
unequip ? "away!" : "into your body.");
if (unequip)
{
if (e == EQ_WEAPON)
{
unwield_item(!you.berserk());
canned_msg(MSG_EMPTY_HANDED_NOW);
}
else
unequip_item(e);
if (mutation)
{
// A mutation made us not only lose an equipment slot
// but actually removed a worn item: Funny!
xom_is_stimulated(is_artefact(*equip) ? 200 : 100);
}
}
else
meld_slot(e);
}
if (meld)
{
for (const equipment_type e : removed)
if (you.slot_item(e, true) != nullptr)
unequip_effect(e, you.equip[e], true, true);
}
}
static void _unmeld_equipment_type(equipment_type e)
{
item_def& item = you.inv[you.equip[e]];
bool force_remove = false;
if (e == EQ_WEAPON)
{
if (you.slot_item(EQ_SHIELD)
&& is_shield_incompatible(item, you.slot_item(EQ_SHIELD)))
{
force_remove = true;
}
}
else if (item.base_type != OBJ_JEWELLERY)
{
// This could happen if the player was mutated during the form.
if (!can_wear_armour(item, false, false))
force_remove = true;
// If you switched weapons during the transformation, make
// sure you can still wear your shield.
// (This is only possible with Statue Form.)
if (e == EQ_SHIELD && you.weapon()
&& is_shield_incompatible(*you.weapon(), &item))
{
force_remove = true;
}
}
if (force_remove)
{
mprf("%s is pushed off your body!", item.name(DESC_YOUR).c_str());
unequip_item(e);
}
else
{
mprf("%s unmelds from your body.", item.name(DESC_YOUR).c_str());
unmeld_slot(e);
}
}
static void _unmeld_equipment(const set<equipment_type>& melded)
{
// Unmeld items in order.
for (const equipment_type e : melded)
{
if (you.equip[e] == -1)
continue;
_unmeld_equipment_type(e);
}
for (const equipment_type e : melded)
if (you.equip[e] != -1)
equip_effect(e, you.equip[e], true, true);
}
void unmeld_one_equip(equipment_type eq)
{
if (eq >= EQ_HELMET && eq <= EQ_BOOTS)
{
const item_def* arm = you.slot_item(EQ_BODY_ARMOUR, true);
if (arm && is_unrandom_artefact(*arm, UNRAND_LEAR))
eq = EQ_BODY_ARMOUR;
}
set<equipment_type> e;
e.insert(eq);
_unmeld_equipment(e);
}
void remove_one_equip(equipment_type eq, bool meld, bool mutation)
{
if (player_equip_unrand(UNRAND_LEAR) && eq >= EQ_HELMET && eq <= EQ_BOOTS)
eq = EQ_BODY_ARMOUR;
set<equipment_type> r;
r.insert(eq);
_remove_equipment(r, you.form, meld, mutation);
}
/**
* Get an monster type corresponding to the player's current form.
*
* (Used for console player glyphs.)
*
* @return A monster type corresponding to the player in the form.
*/
monster_type transform_mons()
{
return get_form()->get_equivalent_mons();
}
string blade_parts(bool terse)
{
string str;
if (you.species == SP_FELID)
str = terse ? "paw" : "front paw";
else if (you.species == SP_OCTOPODE)
str = "tentacle";
else
str = "hand";
if (!you.get_mutation_level(MUT_MISSING_HAND))
str = pluralise(str);
return str;
}
// with a denominator of 10
int form_hp_mod()
{
return get_form()->hp_mod;
}
static bool _flying_in_new_form(transformation which_trans)
{
if (get_form(which_trans)->forbids_flight())
return false;
// If our flight is uncancellable (or tenguish) then it's not from evoking
if (you.attribute[ATTR_FLIGHT_UNCANCELLABLE]
|| you.permanent_flight() && you.racial_permanent_flight())
{
return true;
}
if (!you.duration[DUR_FLIGHT] && !you.attribute[ATTR_PERM_FLIGHT])
return false;
int sources = you.evokable_flight();
int sources_removed = 0;
for (auto eq : _init_equipment_removal(which_trans))
{
item_def *item = you.slot_item(eq, true);
if (item == nullptr)
continue;
item_info inf = get_item_info(*item);
//similar code to safe_to_remove from item-use.cc
if (inf.is_type(OBJ_JEWELLERY, RING_FLIGHT))
sources_removed++;
if (inf.base_type == OBJ_ARMOUR && inf.brand == SPARM_FLYING)
sources_removed++;
if (is_artefact(inf) && artefact_known_property(inf, ARTP_FLY))
sources_removed++;
}
return sources > sources_removed;
}
/**
* Check if it'd be lethal for the player to enter a form in a given terrain.
*
* In addition to checking whether the feature is dangerous for the form
* itself (form_likes_*), the function checks to see if the player is safe
* due to flying or similar effects.
*
* @param which_trans The form being checked.
* @param feat The dungeon feature to be checked for danger.
* @return If the feat is lethal for the player in the form.
*/
bool feat_dangerous_for_form(transformation which_trans,
dungeon_feature_type feat)
{
// Everything is okay if we can fly.
if (form_can_fly(which_trans) || _flying_in_new_form(which_trans))
return false;
if (feat == DNGN_LAVA)
return true;
if (feat == DNGN_DEEP_WATER)
return !you.can_water_walk() && !form_likes_water(which_trans);
return false;
}
static mutation_type appendages[] =
{
MUT_HORNS,
MUT_TENTACLE_SPIKE,
MUT_TALONS,
};
static bool _slot_conflict(equipment_type eq)
{
// Choose uncovered slots only. Melding could make people re-cast
// until they get something that doesn't conflict with their randart
// of überness.
if (you.equip[eq] != -1)
{
// Horns + hat is fine.
if (eq != EQ_HELMET
|| you.melded[eq]
|| is_hard_helmet(*(you.slot_item(eq))))
{
return true;
}
}
for (int mut = 0; mut < NUM_MUTATIONS; mut++)
if (you.has_mutation(static_cast<mutation_type>(mut)) && eq == beastly_slot(mut))
return true;
return false;
}
static mutation_type _beastly_appendage()
{
mutation_type chosen = NUM_MUTATIONS;
int count = 0;
for (mutation_type app : appendages)
{
if (_slot_conflict(beastly_slot(app)))
continue;
if (physiology_mutation_conflict(app))
continue;
if (one_chance_in(++count))
chosen = app;
}
return chosen;
}
static bool _transformation_is_safe(transformation which_trans,
dungeon_feature_type feat,
string *fail_reason)
{
if (!feat_dangerous_for_form(which_trans, feat))
return true;
if (fail_reason)
{
*fail_reason = make_stringf("You would %s in your new form.",
feat == DNGN_DEEP_WATER ? "drown" : "burn");
}
return false;
}
/**
* If we transform into the given form, will all of our stats remain above 0,
* based purely on the stat modifiers of the current & destination form?
*
* May prompt the player.
*
* @param new_form The form to check the safety of.
* @param quiet Whether to prompt the player.
* @return Whether it's okay to go ahead with the transformation.
*/
bool check_form_stat_safety(transformation new_form, bool quiet)
{
const int str_mod = get_form(new_form)->str_mod - get_form()->str_mod;
const int dex_mod = get_form(new_form)->dex_mod - get_form()->dex_mod;
const bool bad_str = you.strength() > 0 && str_mod + you.strength() <= 0;
const bool bad_dex = you.dex() > 0 && dex_mod + you.dex() <= 0;
if (!bad_str && !bad_dex)
return true;
if (quiet)
return false;
string prompt = make_stringf("%s will reduce your %s to zero. Continue?",
new_form == transformation::none
? "Turning back"
: "Transforming",
bad_str ? "strength" : "dexterity");
if (yesno(prompt.c_str(), false, 'n'))
return true;
canned_msg(MSG_OK);
return false;
}
static int _transform_duration(transformation which_trans, int pow)
{
return get_form(which_trans)->get_duration(pow);
}
static int _beastly_appendage_level(int appendage)
{
switch (appendage)
{
case MUT_HORNS: return 2;
default: return 3;
}
}
/**
* Print an appropriate message when the number of heads the player has
* changes during a refresh of hydra form.
*/
static void _print_head_change_message(int old_heads, int new_heads)
{
if (old_heads == new_heads)
return;
const int delta = abs(old_heads - new_heads);
const bool plural = delta != 1;
if (old_heads > new_heads)
{
if (plural)
mprf("%d of your heads shrink away.", delta);
else
mpr("One of your heads shrinks away.");
return;
}
if (plural)
mprf("%d new heads grow.", delta);
else
mpr("A new head grows.");
}
/**
* Is the player alive enough to become the given form?
*
* All undead can enter shadow form; vampires also can enter batform, and, when
* full, other forms (excepting lichform).
*
* @param which_trans The tranformation which the player is undergoing
* (default you.form).
* @param involuntary Whether the transformation is involuntary or not.
* @return UFR_GOOD if the player is not blocked from entering the
* given form by their undead race; UFR_TOO_ALIVE if the
* player is too satiated as a vampire; UFR_TOO_DEAD if
* the player is too dead (or too thirsty as a vampire).
*/
undead_form_reason lifeless_prevents_form(transformation which_trans,
bool involuntary)
{
if (!you.undead_state(false))
return UFR_GOOD; // not undead!
if (which_trans == transformation::none)
return UFR_GOOD; // everything can become itself
if (which_trans == transformation::shadow)
return UFR_GOOD; // even the undead can use dith's shadow form
if (you.species != SP_VAMPIRE)
return UFR_TOO_DEAD; // ghouls & mummies can't become anything else
if (which_trans == transformation::lich)
return UFR_TOO_DEAD; // vampires can never lichform
if (which_trans == transformation::bat) // can batform bloodless
{
if (involuntary)
return UFR_TOO_DEAD; // but not as a forced polymorph effect
return !you.vampire_alive ? UFR_GOOD : UFR_TOO_ALIVE;
}
// other forms can only be entered when alive
return you.vampire_alive ? UFR_GOOD : UFR_TOO_DEAD;
}
/**
* Attempts to transform the player into the specified form.
*
* If the player is already in that form, attempt to refresh its duration and
* power.
*
* @param pow Thw power of the transformation (equivalent to
* spellpower of form spells)
* @param which_trans The form which the player should become.
* @param involuntary Checks for inscription warnings are skipped, and
* failure is silent.
* @param just_check A dry run; just check to see whether the player
* *can* enter the given form, but don't actually
* transform them.
* @return If the player was transformed, or if they were
* already in the given form, returns true.
* Otherwise, false.
* If just_check is set, returns true if the player
* could enter the form (or is in it already) and
* false otherwise.
* N.b. that transform() can fail even when a
* just_check run returns true; e.g. when Zin decides
* to intervene. (That may be the only case.)
*/
bool transform(int pow, transformation which_trans, bool involuntary,
bool just_check, string *fail_reason)
{
const transformation previous_trans = you.form;
const bool was_flying = you.airborne();
bool success = true;
string msg;
// Zin's protection.
if (!just_check && have_passive(passive_t::resist_polymorph)
&& x_chance_in_y(you.piety, MAX_PIETY)
&& which_trans != transformation::none)
{
simple_god_message(" protects your body from unnatural transformation!");
return false;
}
if (!involuntary && crawl_state.is_god_acting())
involuntary = true;
if (you.transform_uncancellable)
{
msg = "You are stuck in your current form!";
success = false;
}
else if (!_transformation_is_safe(which_trans, env.grid(you.pos()), &msg))
success = false;
if (!success)
{
// Message is not printed if we're updating fail_reason.
if (fail_reason)
*fail_reason = msg;
else if (!involuntary)
mpr(msg);
return false;
}
// This must occur before the untransform() and the undead_state() check.
if (previous_trans == which_trans)
{
if (just_check)
return true;
// update power
if (which_trans != transformation::none)
{
you.props[TRANSFORM_POW_KEY] = pow;
you.redraw_armour_class = true;
// ^ could check more carefully for the exact cases, but I'm
// worried about making the code too fragile
if (which_trans == transformation::hydra)
{
const int heads = you.heads();
set_hydra_form_heads(div_rand_round(pow, 10));
_print_head_change_message(heads, you.heads());
}
}
int dur = _transform_duration(which_trans, pow);
if (you.duration[DUR_TRANSFORMATION] < dur * BASELINE_DELAY)
{
mpr("You extend your transformation's duration.");
you.duration[DUR_TRANSFORMATION] = dur * BASELINE_DELAY;
}
else if (!involuntary && which_trans != transformation::none)
mpr("You fail to extend your transformation any further.");
return true;
}
// the undead cannot enter most forms.
if (lifeless_prevents_form(which_trans, involuntary) == UFR_TOO_DEAD)
{
msg = "Your unliving flesh cannot be transformed in this way.";
success = false;
}
else if (which_trans == transformation::lich
&& you.duration[DUR_DEATHS_DOOR])
{
msg = "You cannot become a lich while in death's door.";
success = false;
}
if (!just_check && previous_trans != transformation::none)
untransform(true);
set<equipment_type> rem_stuff = _init_equipment_removal(which_trans);
// if going into lichform causes us to drop a holy weapon with consequences
// for unwielding (e.g. contam), warn first.
item_def nil_item;
nil_item.link = -1;
if (just_check && !involuntary
&& which_trans == transformation::lich && rem_stuff.count(EQ_WEAPON)
&& !check_old_item_warning(nil_item, OPER_WIELD))
{
canned_msg(MSG_OK);
return false;
}
if (which_trans == transformation::appendage)
{
const mutation_type app = _beastly_appendage();
if (app == NUM_MUTATIONS)
{
msg = "You have no appropriate body parts free.";
success = false; // XXX: VERY dubious, since an untransform occurred
}
if (!just_check)
{
you.attribute[ATTR_APPENDAGE] = app; // need to set it here so
// the message correlates
}
}
if (!success)
{
// Message is not printed if we're updating fail_reason.
if (fail_reason)
*fail_reason = msg;
else if (!involuntary)
mpr(msg);
return false;
}
// If we're just pretending return now.
if (just_check)
return true;
// All checks done, transformation will take place now.
you.redraw_quiver = true;
you.redraw_evasion = true;
you.redraw_armour_class = true;
you.wield_change = true;
if (form_changed_physiology(which_trans))
merfolk_stop_swimming();
if (which_trans == transformation::hydra)
set_hydra_form_heads(div_rand_round(pow, 10));
// Give the transformation message.
mpr(get_form(which_trans)->transform_message(previous_trans));
// Update your status.
// Order matters here, take stuff off (and handle attendant HP and stat
// changes) before adjusting the player to be transformed.
_remove_equipment(rem_stuff, which_trans);
you.form = which_trans;
you.set_duration(DUR_TRANSFORMATION, _transform_duration(which_trans, pow));
update_player_symbol();
you.props[TRANSFORM_POW_KEY] = pow;
const int str_mod = get_form(which_trans)->str_mod;
const int dex_mod = get_form(which_trans)->dex_mod;
if (str_mod)
notify_stat_change(STAT_STR, str_mod, true);
if (dex_mod)
notify_stat_change(STAT_DEX, dex_mod, true);
calc_hp(true, false);
if (you.digging && !form_keeps_mutations(which_trans))
{
mpr("Your mandibles meld away.");
you.digging = false;
}
// Extra effects
switch (which_trans)
{
case transformation::statue:
if (you.duration[DUR_ICY_ARMOUR])
{
mprf(MSGCH_DURATION, "Your new body cracks your icy armour.");
you.duration[DUR_ICY_ARMOUR] = 0;
}
break;
case transformation::spider:
leave_web();
break;
case transformation::tree:
mpr("Your roots penetrate the ground.");
if (you.duration[DUR_TELEPORT])
{
you.duration[DUR_TELEPORT] = 0;
mpr("You feel strangely stable.");
}
you.duration[DUR_FLIGHT] = 0;
// break out of webs/nets as well
case transformation::dragon:
if (you.attribute[ATTR_HELD])
{
trap_def *trap = trap_at(you.pos());
if (trap && trap->type == TRAP_WEB)
{
mpr("You shred the web into pieces!");
destroy_trap(you.pos());
}
int net = get_trapping_net(you.pos());
if (net != NON_ITEM)
{
mpr("The net rips apart!");
destroy_item(net);
}
stop_being_held();
}
break;
case transformation::lich:
you.hunger_state = HS_SATIATED; // no hunger effects while transformed
you.redraw_status_lights = true;
break;
case transformation::appendage:
{
int app = you.attribute[ATTR_APPENDAGE];
ASSERT(app != NUM_MUTATIONS);
ASSERT(beastly_slot(app) != EQ_NONE);
you.mutation[app] = _beastly_appendage_level(app);
}
break;
case transformation::shadow:
drain_player(25, true, true);
if (you.invisible())
mpr("You fade into the shadows.");
else
mpr("You feel less conspicuous.");
break;
default:
break;
}
// Stop constricting if we can no longer constrict. If any size-changing
// transformations were to allow constriction, we would have to check
// relative sizes as well. Likewise, if any transformations were to allow
// normally non-constricting players to constrict, this would need to
// be changed.
if (!form_keeps_mutations(which_trans))
you.stop_directly_constricting_all(false);
// Stop being constricted if we are now too large.
if (you.is_directly_constricted())
{
actor* const constrictor = actor_by_mid(you.constricted_by);
ASSERT(constrictor);
if (you.body_size(PSIZE_BODY) > constrictor->body_size(PSIZE_BODY))
you.stop_being_constricted();
}
// If we are no longer living, end an effect that afflicts only the living
if (you.duration[DUR_FLAYED] && !(you.holiness() & MH_NATURAL))
{
// Heal a little extra if we gained max hp from this transformation
if (form_hp_mod() != 10)
{
int dam = you.props["flay_damage"].get_int();
you.heal((dam * form_hp_mod() / 10) - dam);
}
heal_flayed_effect(&you);
}
// This only has an effect if the transformation happens passively,
// for example if Xom decides to transform you while you're busy
// running around or butchering corpses.
// If you're turned into a tree, you stop taking stairs.
stop_delay(which_trans == transformation::tree);
if (crawl_state.which_god_acting() == GOD_XOM)
you.transform_uncancellable = true;
// Land the player if we stopped flying.
if (was_flying && !you.airborne())
move_player_to_grid(you.pos(), false);
// Stop emergency flight if it's activated and this form can fly
if (you.props[EMERGENCY_FLIGHT_KEY]
&& form_can_fly()
&& you.airborne())
{
you.props.erase(EMERGENCY_FLIGHT_KEY);
}
// Update merfolk swimming for the form change.
if (you.species == SP_MERFOLK)
merfolk_check_swimming(false);
if (you.hp <= 0)
{
ouch(0, KILLED_BY_FRAILTY, MID_NOBODY,
make_stringf("gaining the %s transformation",
transform_name(which_trans)).c_str());
}
return true;
}
/**
* End the player's transformation and return them to their normal
* form.
* @param skip_move If true, skip any move that was in progress before
* the transformation ended.
*/
void untransform(bool skip_move)
{
const bool was_flying = you.airborne();
you.redraw_quiver = true;
you.redraw_evasion = true;
you.redraw_armour_class = true;
you.wield_change = true;
you.received_weapon_warning = false;
if (you.props.exists(TRANSFORM_POW_KEY))
you.props.erase(TRANSFORM_POW_KEY);
if (you.props.exists(HYDRA_FORM_HEADS_KEY))
you.props.erase(HYDRA_FORM_HEADS_KEY);
// Must be unset first or else infinite loops might result. -- bwr
const transformation old_form = you.form;
// We may have to unmeld a couple of equipment types.
set<equipment_type> melded = _init_equipment_removal(old_form);
you.form = transformation::none;
you.duration[DUR_TRANSFORMATION] = 0;
update_player_symbol();
if (old_form == transformation::appendage)
{
mutation_type app = static_cast<mutation_type>(you.attribute[ATTR_APPENDAGE]);
ASSERT(beastly_slot(app) != EQ_NONE);
const int levels = you.get_base_mutation_level(app);
// Preserve extra mutation levels acquired after transforming.
const int beast_levels = _beastly_appendage_level(app);
const int extra = max(0, levels - you.get_innate_mutation_level(app)
- beast_levels);
you.mutation[app] = you.get_innate_mutation_level(app) + extra;
you.attribute[ATTR_APPENDAGE] = 0;
// The mutation might have been removed already by a conflicting
// demonspawn innate mutation; no message then.
if (levels)
{
const char * const verb = you.has_mutation(app) ? "shrink"
: "disappear";
mprf(MSGCH_DURATION, "Your %s %s%s.",
mutation_name(app), verb,
app == MUT_TENTACLE_SPIKE ? "s" : "");
}
}
calc_hp(true, false);
const string message = get_form(old_form)->get_untransform_message();
if (!message.empty())
mprf(MSGCH_DURATION, "%s", message.c_str());
const int str_mod = get_form(old_form)->str_mod;
const int dex_mod = get_form(old_form)->dex_mod;
if (str_mod)
notify_stat_change(STAT_STR, -str_mod, true);
if (dex_mod)
notify_stat_change(STAT_DEX, -dex_mod, true);
_unmeld_equipment(melded);
if (!skip_move)
{
// Land the player if we stopped flying.
if (is_feat_dangerous(grd(you.pos())))
enable_emergency_flight();
else if (was_flying && !you.airborne())
move_player_to_grid(you.pos(), false);
// Update merfolk swimming for the form change.
if (you.species == SP_MERFOLK)
merfolk_check_swimming(false);
}
#ifdef USE_TILE
if (you.species == SP_MERFOLK)
init_player_doll();
#endif
// If nagas wear boots while transformed, they fall off again afterwards:
// I don't believe this is currently possible, and if it is we
// probably need something better to cover all possibilities. -bwr
// Removed barding check, no transformed creatures can wear barding
// anyway.
// *coughs* Ahem, blade hands... -- jpeg
if (you.species == SP_NAGA || you.species == SP_CENTAUR)
{
const int arm = you.equip[EQ_BOOTS];
if (arm != -1 && you.inv[arm].sub_type == ARM_BOOTS)
remove_one_equip(EQ_BOOTS);
}
// End Ozocubu's Icy Armour if you unmelded wearing heavy armour
if (you.duration[DUR_ICY_ARMOUR]
&& !player_effectively_in_light_armour())
{
you.duration[DUR_ICY_ARMOUR] = 0;
const item_def *armour = you.slot_item(EQ_BODY_ARMOUR, false);
mprf(MSGCH_DURATION, "%s cracks your icy armour.",
armour->name(DESC_YOUR).c_str());
}
if (you.hp <= 0)
{
ouch(0, KILLED_BY_FRAILTY, MID_NOBODY,
make_stringf("losing the %s form",
transform_name(old_form)).c_str());
}
// Stop being constricted if we are now too large.
if (you.is_directly_constricted())
{
actor* const constrictor = actor_by_mid(you.constricted_by);
if (you.body_size(PSIZE_BODY) > constrictor->body_size(PSIZE_BODY))
you.stop_being_constricted();
}
you.turn_is_over = true;
if (you.transform_uncancellable)
you.transform_uncancellable = false;
}
void emergency_untransform()
{
mpr("You quickly transform back into your natural form.");
untransform(true); // We're already entering the water.
if (you.species == SP_MERFOLK)
merfolk_start_swimming(false);
}
/**
* Update whether a merfolk should be swimming.
*
* Idempotent, so can be called after position/transformation change without
* redundantly checking conditions.
*
* @param stepped Whether the player is performing a normal walking move.
*/
void merfolk_check_swimming(bool stepped)
{
const dungeon_feature_type grid = env.grid(you.pos());
if (you.ground_level()
&& feat_is_water(grid)
&& !form_changed_physiology(you.form))
{
merfolk_start_swimming(stepped);
}
else if (!is_feat_dangerous(grid)) // don't bother, the player is dying
merfolk_stop_swimming();
}
void merfolk_start_swimming(bool stepped)
{
if (you.fishtail)
return;
if (stepped)
mpr("Your legs become a tail as you enter the water.");
else
mpr("Your legs become a tail as you dive into the water.");
if (you.invisible())
mpr("...but don't expect to remain undetected.");
you.fishtail = true;
remove_one_equip(EQ_BOOTS);
you.redraw_evasion = true;
#ifdef USE_TILE
init_player_doll();
#endif
}
void merfolk_stop_swimming()
{
if (!you.fishtail)
return;
you.fishtail = false;
unmeld_one_equip(EQ_BOOTS);
you.redraw_evasion = true;
#ifdef USE_TILE
init_player_doll();
#endif
}
void vampire_update_transformations()
{
const undead_form_reason form_reason = lifeless_prevents_form();
if (form_reason != UFR_GOOD && you.duration[DUR_TRANSFORMATION])
{
print_stats();
mprf(MSGCH_WARN,
"Your blood-%s body can't sustain your transformation.",
form_reason == UFR_TOO_DEAD ? "deprived" : "filled");
untransform();
}
}
↑ V648 Priority of the '&&' operation is higher than that of the '||' operation.
↑ V648 Priority of the '&&' operation is higher than that of the '||' operation.
↑ V648 Priority of the '&&' operation is higher than that of the '||' operation.
↑ V768 The expression 'you.undead_state(false)' is of enum type. It is odd that it is used as an expression of a Boolean-type.


{% if request.user.unlimited_access or request.user.harvard_access %}
Unrestricted access
{% if request.user.unlimited_access_until %}
{% if request.user.unlimited_access_in_effect %}expires{% else %}expired{% endif %}
{{ request.user.unlimited_access_until }}
{% else %}
approved
{% endif %}
{% if request.user.harvard_access and not request.user.harvard_ip %}
Your Harvard unrestricted access will only work when accessing this website from a Harvard IP address.
Your current IP address of {{ request.user.ip_address }} is not a Harvard IP address.
{% endif %}
{% else %}
Case allowance
{{ request.user.case_allowance_remaining }} cases left today
{{ request.user.total_case_allowance }} total per day
Unrestricted access
{% if research_contract %}
You submitted an application for unrestricted access on
{{ research_contract.user_signature_date|date:"F j, Y" }}.
{% if research_contract.status == "denied" %}
Your application was denied by LexisNexis. Please contact us if you would like to discuss further options.
{% else %}
Your application is pending.
{% endif %}
{% elif research_request %}
You submitted a request for unrestricted access on {{ research_request.submitted_date }}
{% else %}
Are you a research scholar? Request access
{% endif %}
{% endif %}
History
{% if user.track_history %}
We are tracking the cases you access
{% else %}
We are not tracking the cases you access
{% endif %}
Manage history tracking


Home
Profile
mail_outline
Requests
Contact Us
CLASSROOM INVITATION REQUESTS
New Requests
Name
Building Name
Class Number
Beginning Time
End Time
date


yaha_analyzer module¶
-
class
yaha_analyzer.
yaha_analyzer
¶ Bases:
object
-
check_data
(json_name, hdf5_name)¶ Checks for the existance of either file under the DATA_PATH, returns False if either is missing
Parameters: - hdf5_name (string) – name of the hdf5 file
- json_name (string) – name of the json file
Returns: False if either is missing, True otherwise
Return type: bool
-
create_heatmap
(x, y, z, df, title, layout=None, text=None)¶ Creates a heatmap x, y, and z
Parameters: - x (string) – name of the x value column
- y (string) – name of the y value column
- z (string) – name of the z value column
- df (pandas dataframe) – dataframe
- title (string) – heatmap title
- layout (dictionary) – dictionary for plotly layout. Autogenerated if None is passed
- text (string) – column to be displayed for hover text
Returns: one dictionary to be used with plotly.utils.PlotlyJSONEncoder
Return type: list
-
create_stacked_chart
(iter_column, x_col, y_col, df, layout=None)¶ Creates a stacked chart from a cards groupby object
-
create_stacked_histogram
(df, title, level='p_deck_type', agg_level='win')¶ Creates a stacked histogram of the card for it’s win counts
Parameters: - df (pandas dataframe) – the card dataframe to generate a histogram for
- card_name (string) – the card name for the title
- level (string) – the level of filtering, e.g. the stacks the histogram has
Returns: one dictionary to be used with plotly.utils.PlotlyJSONEncoder
Return type: dictionary
-
generate_card_stats
(game_mode='ranked', game_threshold=2)¶ Returns a groupby object with [‘card’, ‘p_deck_type’, ‘o_deck_type’, ‘turn’, ‘loss’, ‘win’] as [str, str, str, int, int, int] :param game_mode: game type :param card_threshold: the minimum amount of time the card has to show up :type game_mode: str :type card_threshold: str
Returns: cards Return type: pandas groupby object
-
generate_cards
(filtered)¶ Generates a grouped win/loss count for specific cards
Parameters: filtered (pandas dataframe) – subset of self.games filtered Returns: p_df, o_df – cards marked as ‘me’ for player, index is the card name [‘card’], columns are win count and loss count [‘win’, ‘loss’], cards marked as ‘opponent’ for player, index is the card name [‘card’], columns are win count and loss count [‘win’, ‘loss’] Return type: pandas groupby, pandas groupby
-
generate_collectobot_data
()¶ Generates collect-o-bot data from the database, writes it to a hdf5 file
Returns: list of games Return type: pandas dataframe
-
generate_decklist_matchups
(game_mode='ranked', game_threshold=2)¶ Generates a dataframe with a list of cards, and the matchups where the card won and lost in the format of: [‘card’, ‘p_deck_type’, ‘winning_matchups’, ‘losing_matchups’]
Parameters: - game_mode (string) – the game mode, ‘ranked’, ‘casual’, or ‘both
- game_threshold (int) – the minimum amount of games the deck has to show up
Returns: cards with [‘card’, ‘p_deck_type’, ‘o_deck_type’, ‘loss’, ‘win’, ‘win%’]
Return type: pandas groupby
-
generate_decks
(dates=True)¶ Differentiates between the different deck types, and sorts them into their individual lists (history is a massive array, transform into a pandas dataframe for processing)
Parameters: dates (bool) – generate specific dates into their own columns Returns: list of games Return type: pandas dataframe
-
generate_matchups
(game_mode='ranked', game_threshold=0)¶ Generates a pandas groupby table with duration, count, coin, win #, win%, and card_history
Parameters: - game_mode (string) – the game mode, ‘ranked’, ‘casual’, or ‘both
- game_threshold (int) – the minimum amount of games the deck has to show up
Returns: grouped, indicies are player ‘p_deck_type’ then opponent ‘o_deck_type’
Return type: pandas groupby
-
get_graph_data
(name)¶ Returns plotly json for the specified name
Parameters: name (string) – name to match in the database Returns: plotly json data Return type: string
-
get_name_list
()¶ Iterates through the database and creates a list of strings for deck names and card names
Returns: list of deck and card names Return type: (list, list)
-
make_graph_data
()¶ Iterates through all the cards & decks above the game threshold, makes plotly json for each one
-
open_collectobot_data
()¶ Loads the collectobot data from a hdf5 file
-
pull_data
(username, api_key)¶ Grabs the data from the trackobot servers, writes it out to a new files and the database if it doesn’t exist/outdated
Parameters: - username (string) – trackobot username
- api_key (string) – trackobot api key
Returns: contents of the json_files
Return type: dictionary
-
read_data
(json_name=None, hdf5_name=None)¶ Takes the names of the files and loads them into memory for processing
Parameters: - hdf5_name (string) – name of the hdf5 file
- json_name (string) – name of the json file
Returns: complete history of games and metadata
Return type: dictionary
-
rebuild_and_update
()¶ Pull collectobot data and remake the graphs
-
remake_graphs
()¶ Remake the graphs
-
store_data
()¶ Stores the python data by using the filename as the sha5 hash of the username and api_key -> hash is stored in a database for lookups later, data is stored using the hdf5 format Table is in the format of [‘user_hash’, ‘total_items’, ‘json_name’, ‘hdf5_name’]
Returns: total items, json_name, and hdf5_name Return type: [int, string, string]
-
title_format
(*titles)¶ Formats the titles
Parameters: titles (list of strings) – titles to be replaced Returns: list of replaced titles Return type: list of strings
-
update_count
(user_hash, total_items)¶ Updates the given total items count for the user with user_hash
-
write_hdf5
(hdf5_name)¶ Writes out self.games into a hdf5_file
Parameters: hdf5_name (string) – name of the hdf5 file
-


Hypertext Markup Language
From wikimediaHypertext Markup Language (HTML) is the standard markup language for creating web pages and web applications. With Cascading Style Sheets (CSS) and JavaScript, it forms a triad of cornerstone technologies for the World Wide Web. [4]
Web browsers receive HTML documents from a web server or from local storage and render the documents into multimedia web pages. HTML describes the structure of a web page semantically and originally included cues for the appearance of the document.


ALDSense Free Minecraft Hack!
Download
Version:Z1.1 Beta2
Download
Other↓
LiquidBounce!
Sigma Client!
Flux Client!
Novoline!
FDP CLient!
Debug Client 国货之光
非纪 客户端
Smoke CLient
Badlion
Lunar Client FPS+++!


--- layout: default title: subtitle: title_tag: Continuous Deployment Software | Continuous Integration Tool | Go CD meta_tag_description: Go continuous deployment, continuous integration and automated testing allow software to be developed to a high standard, easily packaged and deployed to test environments meta_tag_keywords: continuous deployment software, continuous integration tools, automated deployment software, automated testing, go page_name: need_help ---
ThoughtWorks offers commercial support for GoCD. Here are some great things you will get when you sign up
Submit a ticket right now and get support from the creators of GoCD
Tell us about a problem you are having and our support specialists will contact you soon
A huge part of GoCD’s success as an OSS product has been the support of a very active community. We encourage you to join in the discussions to both learn and contribute.
Join the ongoing GoCD community chatter
Review open bugs or log a new one


THE TIGGER MOVIE (Disney) Voices: Jim Cummings, Nikita Hopkins, Ken Sansom, John Fiedler, Peter Cullen, Andre Stojka, Kath Soucie, John Hurt. Screenplay: Jun Falkenstein, based on characters created by A. A. Milne. Producer: Cheryl Abood. Director: Jun Falkenstein. MPAA Rating: G. Running Time: 75 minutes. Reviewed by Scott Renshaw.
Disney has been responsible for plenty of icons of childhood over the past 60 years, but if my son's wardrobe and stuffed animal collection are any indication, no libretto has been kinder to Uncle Walt's Place over the years than the works of A. A. Milne. Edward Bear (d.b.a. Winnie the Pooh) and friends have made Disney a mint in licensing fees, TV programs and the like, with Pooh's roly-poly visage become the very image of cuddly innocence. Kids adore these characters beyond measure, as befits characters based on a real child's own beloved playthings.
THE TIGGER MOVIE is by no stretch of the imagination an embarrassing chapter in Disney's relationship with the Pooh gang; indeed, it's light and generally pleasant. It just seems a shame for these characters to be wasted on filler between Disney's _real_ animated films. The story finds the titular bouncy, pouncy fellow (voiced by Jim Cummings) struggling a bit with the fact that, as the song says about Tiggers, "(he's) the only one." Convinced that there must be a Tigger family out there somewhere, Tigger begins a search through the Hundred Acre Wood for his family tree accompanied by a helpful Roo (Nikita Hopkins). When no family is found, Pooh (also voiced by Cummings) and company try to help out, but a letter they write from "Tigger's family" only ends up complicating matters further.
The talent involved in the creation of THE TIGGER MOVIE offered plenty of hope that it could be plenty entertaining. Many longtime voice participants in the Pooh universe, including original Piglet John Fiedler, lend their gifts to the story, providing a sense of continuity from earlier stories. Even more promising was the participation of veteran Disney songwriters Richard and Robert Sherman, the legendary brother tandem behind hummable hits like "The Bear Necessities," "Everybody Wants to Be a Cat," "Supercalifragilisticexpialidocious" and even the original "The Wonderful Thing About Tiggers." This was not the sort of interest you'd expect to find in a cheap knock-off.
And THE TIGGER MOVIE isn't a cheap knock-off. It just never feels particularly inspired, or particularly true to Milne's amiable tales. The story is simple enough, a lesson in the love one can find in a family that doesn't necessarily involve genetic similarity or legal sanction (one can almost hear the reactionary letters being prepared at Disney's insouciance regarding the national security importance of the nuclear family). Yet that's the sort of lesson-mongering one would never associate with Pooh and company. One also wouldn't expect a story that needed to be spiced up with a climactic avalanche to give it a sense of drama. One certainly wouldn't expect that the Shermans' song contributions would be such a lackluster lot, with even the most obvious effort to create a catchy standard -- the pop culture-filled production number "Round My Family Tree" -- falling short. For a Disney film, it sure feels a lot more like one of the more half-hearted attempts to mimic a Disney film.
In all fairness, it should be clear that THE TIGGER MOVIE seemed to delight it's target audience of kindergarteners. There are even some enjoyable moments to delight those of us who are slightly older kids, including the perfectly pitched pessimism of Eeyore (Peter Cullen) and Tigger's colorful way with a malaprop. It's a cute film in its way, but there are those of us who expect more from Disney when some of its most beloved characters are plopped into a new film. The bar is set a little bit higher, because it's too easy to fall back on the audience's good will towards those characters without insuring the vehicle is as tuneful, playful and easy-going as Pooh-bear himself. THE TIGGER MOVIE isn't bad. It just doesn't feel particularly deserving of its stars. Call me a sentimentalist, but I like to think of Pooh as more than just a marketable brand-name.
On the Renshaw scale of 0 to 10 Pooh-bear necessities: 6.
Visit Scott Renshaw's Screening Room http://www.inconnect.com/~renshaw/ *** Subscribe to receive new reviews directly by email! See the Screening Room for details, or reply to this message with subject "Subscribe".
The review above was posted to the
rec.arts.movies.reviews newsgroup (de.rec.film.kritiken for German reviews).
The Internet Movie Database accepts no responsibility for the contents of the
review and has no editorial control. Unless stated otherwise, the copyright
belongs to the author.
Please direct comments/criticisms of the review to relevant newsgroups.
Broken URLs inthe reviews are the responsibility of the author.
The formatting of the review is likely to differ from the original due
to ASCII to HTML conversion.
Related links: index of all rec.arts.movies.reviews reviews


Mobile court operations launched in Dhaka as rumours drive salt prices
by bdnews24.comThe government has launched mobile court drives in Dhaka following allegations of salt price hike due to rumours of a lack of supply.
A mobile court, supervised by Dhaka Metropolitan Police and headed by Executive Magistrate Abdullah Al Mamun, inspected shops at Nayabazar on Tuesday.
The magistrate said they identified a number of shops that were charging extra for salt.
Four shops were together fined Tk 60,000 for selling salt at higher prices.
“The process to extend the drive to other areas is under way,” he said.
Police at Dhanmondi said they were also preparing for such drives.
The rumour of a salt price hike spread in Sylhet, Habiganj, Gopalganj, Thakurgaon and Netrakona districts on Monday evening following weeks of skyrocketing onion prices due to a supply squeeze.
Panicked consumers started stockpiling salt, giving rogue traders the opportunity to charge extra across the country, including Dhaka.
Customers reportedly scuffled at different places in the capital in attempt to buy salt for stockpiling before the rumoured price hike.
Mobile courts have punished four Habiganj businessmen and three in Netrakona while two have been detained in Thakurgaon and Gopalganj.
The government in separate statements vowed action against the rumourmongers and unscrupulous businesses, reassuring the people of enough stock and quick arrival of new supply.


This package generates mass concentration maps and phase distribution maps based on X-ray mapping data and spot analysis data from EPMA.
See “How to” for a usage and Yasumoto et al. (2018) for implementations.
Current version supports data from JEOL-style EPMA.
Copy & paste a following command to R.
source("https://install-github.me/atusy/qntmap")
Details below.
Conversion is performed by utilizing spot analysis data as internal standards. Thus, spot analysis must be done prior to mapping.
.map/1
)..map
directory and .qnt
directoryThe exported data are stored in a directory named by .qnt
in most environments. If using JXA-8230, a directory’s name is {PROJECT}_{#}_QNT
where {PROJECT}
is name of a project’s name defined by user or “PROJECT” if undefined, and{#}
is a variable integer (e.g., PROJECT_0001_QNT
).
| File name | Descriptions |
|---|---|
| .cnd/elemw.cnd or Pos_001/data001.qnt | Metadata including dwell time for peak and background, and relative positions of backgrounds. In some case, .cnd/elemw.qnt is incomplete or missing, and needs to be prepared manually (e.g., https://gist.github.com/atusy/f1577b67b8874c9e915941c0725d0e22). JXA-8230 lacks .cnd/elemw.cnd , but provides Pos_001/data/qnt . |
| bgm.qnt | Minus-side background intensity |
| bgp.qnt | Plus-side background intensity |
| elem.qnt | Element names specified for matrix corrections (e.g., oxide or metal in ZAF) |
| elint.qnt | Element names as is. |
| mes.qnt | Probe current |
| net.qnt | Net intensity |
| peak.qnt | Peak intensity. This file is optional. If missing, peak intensity is calculated from net and background intensities. |
| stg.qnt | Coordinates and comments |
| wt.qnt | Mass concentrations wt |
The exported data are stored in a directory .map/{#}
where {#}
is a variable integer in most environments (e.g., .map/1
). If using JXA-8230, a directory name is {PROJECT}_{#1}_MAP_{#2}_csv
where {PROJECT}
is name of a project’s name defined by user or “PROJECT” if undefined, and{#1}
and {#2}
are variable integers (e.g., PROJECT_0001_MAP_0001_csv
).
| File name | Descriptions |
|---|---|
| *_map.txt or data*.csv | ASCII converted mapping data (e.g., 1_map.txt, 2_map.txt,… or data001.csv, data002.csv, …) |
| *.cnd | Analytical conditions: element name, dwell time, probe current, step size, pixel size, and coordinates. File names must corresponds to mapping data (e.g, 1_map.cnd, data001.cnd) |
*
indicates wild cards.
For data processing.
Follow instructions shown by running the following code.
As a result, phase identification result is saved in “clustering
” directory and mass concentration data as csv files in “qntmap
” directory both under the directory contaning mapping data.
Note that interactive mode has limited functions. Use manual mode for full functionality.
A work-flow is available with an example dataset at https://qntmap.atusy.net/articles/qntmap.html .


Wakulla, A Story of Adventure in Florida
by Kirk Munroe
"Preparing to Leave the Old Home"
Additional Information
- Year Published: 1886
- Language: English
- Country of Origin: United States of America
- Source: Munroe, K. (1886). Wakulla, A Story of Adventure in Florida. New York: Harper.
-
Readability:
- Flesch–Kincaid Level: 9.0
- Word Count: 1,981
- Genre: Adventure
- Keywords: florida
- ✎ Cite This
Downloads
Over and over again had Mark and Ruth Elmer read this paragraph, which appeared among the “Norton Items” of the weekly paper published in a neighboring town:
“We are sorry to learn that our esteemed fellow-townsman, Mark Elmer, Esq., owing to delicate health, feels compelled to remove to a warmer climate. Having disposed of his property in this place, Mr. Elmer has purchased a plantation in Florida, upon which he will settle immediately. As his family accompany him to this new home in the Land of Flowers, the many school-friends and young playmates of his interesting children will miss them sadly.”
“I tell you what, Ruth,” said Mark, after they had read this item for a dozen times or more, “we are somebodies after all, and don’t you forget it. We own a plantation, we do, and have disposed of our PROPERTY in this place.”
As Mark looked from the horse-block on which he was sitting at the little weather-beaten house, nestling in the shadow of its glorious trees, which, with its tiny grass-plot in front, was all the property Mr. Elmer had ever owned, he flung up his hat in ecstasy at the idea of their being property owners, and tumbled over backward in trying to catch it as it fell.
“What I like,” said Ruth, who stood quietly beside him, “is the part about us being interesting children, and to think that the girls and boys at school will miss us.”
“Yes, and won’t they open their eyes when we write them letters about the alligators, and the orange groves, and palm-trees, and bread-fruit, and monkeys, and Indians, and pirates? Whoop-e-e-e! What fun we are going to have!”
“Bread-fruit, and monkeys, and pirates, and Indians in Florida! What are you thinking of, Mark Elmer?”
“Well, I guess ‘Osceola the Seminole’ lived in Florida, and it’s tropical, and pirates and monkeys are tropical too, ain’t they?”
Just then the tea-bell rang, and the children ran in to take the paper which they had been reading to their father, and to eat their last supper in the little old house that had always been their home.
Mr. Elmer had, for fifteen years, been cashier of the Norton Bank; and though his salary was not large, he had, by practicing the little economies of a New England village, supported his family comfortably until this time, and laid by a sum of money for a rainy day. And now the “rainy day” had come. For two years past the steady confinement to his desk had told sadly upon the faithful bank cashier, and the stooping form, hollow cheeks, and hacking cough could no longer be disregarded. For a long time good old Dr. Wing had said,
“You must move South, Elmer; you can’t stand it up here much longer.”
Both Mr. Elmer and his wife knew that this was true; but how could they move South? Where was the money to come from? And how were they to live if they did? Long and anxious had been the consultations after the children were tucked into their beds, and many were the prayers for guidance they had offered up.
At last a way was opened, “and just in time, too,” said the doctor, with a grave shake of his head. Mrs. Elmer’s uncle, Christopher Bangs, whom the children called “Uncle Christmas,” heard of their trouble, and left his saw-mills and lumber camps to come and see “where the jam was,” as he expressed it. When it was all explained to him, his good-natured face, which had been in a wrinkle of perplexity, lit up, and with a resounding slap of his great, hard hand on his knee, he exclaimed,
“Sakes alive! Why didn’t you send for me, Niece Ellen? Why didn’t you tell me all this long ago, eh? I’ve got a place down in Florida, that I bought as a speculation just after the war. I hain’t never seen it, and might have forgot it long ago but for the tax bills coming in reg’lar every year. It’s down on the St. Mark’s River, pretty nigh the Gulf coast, and ef you want to go there and farm it, I’ll give you a ten years’ lease for the taxes, with a chance to buy at your own rigger when the ten years is up.”
“But won’t it cost a great deal to get there, Uncle?” asked Mrs. Elmer, whose face had lighted up as this new hope entered her heart.
“Sakes alive! No; cost nothin’! Why, it’s actually what you might call providential the way things turns out. You can go down, slick as a log through a chute, in the Nancy Bell, of Bangor, which is fitting out in that port this blessed minit. She’s bound to Pensacola in ballast, or with just a few notions of hardware sent out as a venture, for a load of pine lumber to fill out a contract I’ve taken in New York. She can run into the St. Mark’s and drop you jest as well as not. But you’ll have to pick up and raft your fixin’s down to Bangor in a terrible hurry, for she’s going to sail next week, Wednesday, and it’s Tuesday now.”
So it was settled that they should go, and the following week was one of tremendous excitement to the children, who had never been from home in their lives, and were now to become such famous travelers.
Mark Elmer, Jr., as he wrote his name, was as merry, harum-scarum, mischief-loving a boy as ever lived. He was fifteen years old, the leader of the Norton boys in all their games, and the originator of most of their schemes for mischief. But Mark’s mischief was never of a kind to injure anybody, and he was as honest as the day is long, as well as loving and loyal to his parents and sister Ruth.
Although a year younger than Mark, Ruth studied the same books that he did, and was a better scholar. In spite of this she looked up to him in everything, and regarded him with the greatest admiration.
It was Monday when Mark and Ruth walked home from the post-office together, reading the paper, for which they had gone every Monday evening since they could remember, and they were to leave home and begin their journey on the following morning.
During the past week Mr. Elmer had resigned his position in the bank, sold the dear little house which had been a home to him and his wife ever since they were married, and in which their children had been born, and with a heavy heart made the preparations for departure.
With the willing aid of kind neighbors Mrs. Elmer had packed what furniture they were to take with them, and it had been sent to Bangor. Mark and Ruth had not left school until Friday, and had been made young lions of all the week by the other children. To all of her girl friends Ruth had promised to write every single thing that happened, and Mark had promised so many alligator teeth, and other trophies of the chase, that, if he kept all his promises, there would be a decided advance in the value of Florida curiosities that winter.
As the little house was stripped of all its furniture, except some few things that had been sold with it, they were all to go to Dr. Wing’s to sleep that night, and Mrs. Wing had almost felt hurt that they would not take tea with her; but both Mr. and Mrs. Elmer wanted to take this last meal in their own home, and persuaded her to let them have their way. The good woman must have sent over most of the supper she had intended them to eat with her, and this, together with the good things sent in by other neighbors, so loaded the table that Mark declared it looked like a regular surprise-party supper.
A surprise-party it proved to be, sure enough, for early in the evening neighbors and friends began to drop in to say good-bye, until the lower rooms of the little house were filled. As the chairs were all gone, they sat on trunks, boxes, and on the kitchen table, or stood up.
Mark and Ruth had their own party, too, right in among the grown people; for most of the boys and girls of the village had come with their parents to say good-bye, and many of them had brought little gifts that they urged the young Elmers to take with them as keepsakes. Of all these none pleased Ruth so much as the album, filled with the pictures of her school-girl friends, that Edna May brought her.
Edna was the adopted daughter of Captain Bill May, who had brought her home from one of his voyages when she was a little baby, and placed her in his wife’s arms, saying that she was a bit of flotsam and jetsam that belonged to him by right of salvage. His ship had been in a Southern port when a woman, with this child in her arms, had fallen from a pier into the river. Springing into the water after them, Captain May had succeeded in saving the child, but the mother was drowned. As nothing could be learned of its history, and as nobody claimed it, Captain May brought the baby home, and she was baptized Edna May. She was now fourteen years old, and Ruth Elmer’s most intimate friend, and the first picture in the album was a good photograph of herself, taken in Bangor. The others were only tintypes taken in the neighboring town of Skowhegan; but Ruth thought them all beautiful.
The next morning was gray and chill, for it was late in November. The first snow of the season was falling in a hesitating sort of a way, as though it hardly knew whether to come or not, and it was still quite dark when Mrs. Wing woke Mark and Ruth, and told them to hurry, for the stage would be along directly. They were soon dressed and down-stairs, where they found breakfast smoking on the table. A moment later they were joined by their parents, neither of whom could eat, so full were they of the sorrow of departure. The children were also very quiet, even Mark’s high spirits being dampened by thoughts of leaving old friends, and several tears found their way down Ruth’s cheeks during the meal.
After breakfast they said good-bye to the Wings, and went over to their own house to pack a few remaining things into handbags, and wait for the Skowhegan stage.
At six o’clock sharp, with a “toot, toot, toot,” of the driver’s horn, it rattled up to the gate, followed by a wagon for the baggage. A few minutes later, with full hearts and tearful eyes, the Elmers had bidden farewell to the little old house and grand trees they might never see again, and were on their way down the village street, their long journey fairly begun.


Innovation summary
We will ask you some additional information about your product or service in order to match you with the most appropriate organisations.
{% from 'action-link/macro.njk' import actionLink %}
{{ actionLink({
"text": "Continue telling us about your product or service",
"href": "/htc/account/questions/1-product/one"
}) }}
Your progress will be saved here whenever you save complete a section and you can resume at any point by logging in.
1. About the idea or innovation
{{ table({
panel: false,
caption: "About the idea or innovation",
firstCellIsHeader: false,
rows: [
[
{
html: "Do you have a working product, service or prototype?"
},
{
html: "
Incomplete"
}
],
[
{
html: "Is your product or service clinical or non-clinical?"
},
{
html: "
Incomplete"
}
],
[
{
html: "Which categories apply to your product or service? "
},
{
html: "
Incomplete"
}
],
[
{
html: "What is the main purpose of your product or service? "
},
{
html: "
Incomplete"
}
],
[
{
html: " What problem does your product or service solve? "
},
{
html: "
Incomplete"
}
],
[
{
html: "What type of support do you need? "
},
{
html: "
Incomplete"
}
]
]
}) }}
2. Understanding of clinical needs
{{ table({
panel: false,
caption: "Understanding of clinical needs",
firstCellIsHeader: false,
rows: [
[
{
html: "Do you know which population or subgroup your product or service will affect?"
},
{
html: "
Incomplete"
}
]
]
}) }}
3. Understanding the business opportunity
{{ table({
panel: false,
caption: "Understanding the business opportunity",
firstCellIsHeader: false,
rows: [
[
{
html: "Have you undertaken structured market research?"
},
{
html: "
Incomplete"
}
],
[
{
html: "Describe the market research you've undertaken for the UK market"
},
{
html: "
Incomplete"
}
],
[
{
html: "What is the intellectual property status of your product or service?"
},
{
html: "
Incomplete"
}
],
[
{
html: "Have you discussed your product or service with potential customers?"
},
{
html: "
Incomplete"
}
],
[
{
html: "Describe feedback you have had from potential customers"
},
{
html: "
Incomplete"
}
]
]
}) }}
4. Clinical benefits
{{ table({
panel: false,
caption: "Clinical benefits",
firstCellIsHeader: false,
rows: [
[
{
html: "Do you know yet what specific benefits your product or service will bring?"
},
{
html: "
Incomplete"
}
]
]
}) }}
5. Evidence of the benefits
{{ table({
panel: false,
caption: "Evidence of the benefits",
firstCellIsHeader: false,
rows: [
[
{
html: "Do you have evidence to support these benefits of your product or service? "
},
{
html: "
Incomplete"
}
]
]
}) }}
6. Safety and regulatory information
{{ table({
panel: false,
caption: "Safety and regulatory information",
firstCellIsHeader: false,
rows: [
[
{
html: "Do you know of any regulations or standards that apply to your product or service? "
},
{
html: "
Incomplete"
}
],
[
{
html: "What regulations apply to your product or service?"
},
{
html: "
Incomplete"
}
]
]
}) }}
7. Testing in context
{{ table({
panel: false,
caption: "Testing in context",
firstCellIsHeader: false,
rows: [
[
{
html: "Have you tested your product or service with users? "
},
{
html: "
Incomplete"
}
]
]
}) }}
8. Care pathway
{{ table({
panel: false,
caption: "Care pathway",
firstCellIsHeader: false,
rows: [
[
{
html: "Do you know what the current care pathway (current practice) is across the UK? "
},
{
html: "
Incomplete"
}
]
]
}) }}
9. Cost details and comparative benefit
{{ table({
panel: false,
caption: "Cost details and comparative benefit",
firstCellIsHeader: false,
rows: [
[
{
html: "Do you know what the cost is of your product or service?"
},
{
html: "
Incomplete"
}
],
[
{
html: "Do you know what cost savings your product or service would create?"
},
{
html: "
Incomplete"
}
],
[
{
html: "Do you know what the cost is of other products or services or as care is currently given?"
},
{
html: "
Incomplete"
}
]
]
}) }}
10. Commercial model
{{ table({
panel: false,
caption: "Cost details and comparative benefit",
firstCellIsHeader: false,
rows: [
[
{
html: "Do you have a model for generating revenue from your product or service?"
},
{
html: "
Incomplete"
}
],
[
{
html: "What is the revenue model for your product or service?"
},
{
html: "
Incomplete"
}
],
[
{
html: "Which NHS or social care organisation and department would pay for the innovation?"
},
{
html: "
Incomplete"
}
]
]
}) }}
11. Deployment
{{ table({
panel: false,
caption: "Cost details and comparative benefit",
firstCellIsHeader: false,
rows: [
[
{
html: "Do you have an implementation plan for deploying this innovation in NHS or care setting?"
},
{
html: "
Incomplete"
}
],
[
{
html: "Has your product or service been deployed in an NHS or care setting?"
},
{
html: "
Incomplete"
}
]
]
}) }}


{% extends "layout-landing-page.html" %} {% block pageTitle %} {{ serviceName }} {% endblock %} {% block beforeContent %} {% include "./partials/_phase-banner.html" %} {% endblock %} {% block content %}
See all coronavirus guidance on GOV.UK
See specific guidance for Scotland, Wales and Northern Ireland
{% include "./partials/landing-page/_video.html" %} {% include "./partials/landing-page/_announcements.html" %} {% include "./partials/landing-page/_statistics.html" %} {% include "./partials/landing-page/_additional-information.html" %} {% include "./partials/landing-page/_stay-up-to-date.html" %}


Authorize and submit your request
I have received information about Medical Services Plan and agree to abide by its terms and conditions.
I understand the information I have given is collected under the authority of the
Medicare Protection Act and may be used to assess eligibility for other Ministry of Health programs,
and that practitioners who provide service(s) under Medical Services Plan are required under the
Medicare Protection Act to release information relative to those services to Medical Services Plan
to support claims for benefits.
I declare that all information provided is true and I understand that the Ministry of Health
and/or Health Insurance BC may verify this information with immigration authorities, law enforcement
authorities and other public authorities, agencies and persons, as appropriate.
I agree to keep my address up to date with Health Insurance BC, notifying them of any changes within
10 days of moving. I declare that all persons listed are residents of British Columbia. Resident means
a person who is a citizen of Canada or is lawfully admitted to Canada for permanent residence, who makes
his or her home in British Columbia, and is physically present in British Columbia for at least six months
in a calendar year, or a shorter prescribed period, and includes a person who is deemed under the regulations
to be a resident, but does not include a tourist or visitor to British Columbia.


Tanay Toshniwal
Home
Assignments
Assignment_1
Assignment_2
Assignment_3
Assignment_4
Contact<EMAIL_ADDRESS>Hello World
_
!
Here are my
MEAN Stack Training
Assignments
These are the assignments that are completed during my MEAN Stack Training at
Youstart Labs
.


We have great story to tell you
The Internet in Africa is limited by a lower penetration rate when compared to the rest of the world. Measurable parameters such as the number of ISP subscriptions, overall number of hosts, IXP-traffic, and overall available bandwidth all indicate that Africa is way behind the "digital divide". Also a large section of Internet traffic in Africa goes through expensive satellite links making .
A basic broadband connection is most expensive in Africa of all the regions around the world. This is according to an update of the 2017 Affordability Report from the Alliance for Affordable Internet (A4AI) which the internet lobby group says it compiled using more recent pricing and income data.
We sit on the same side of the table as YOU to provide business solutions to business problems. We don’t try to sell you the latest techno gizmo – instead – we listen to your business problem and offer several strategies to resolve the ROOT of the problem and achieve your objectives.
Unlike others in our industry, we can prove and show you how we deliver Peace of Mind, Less Downtime, Faster Problem Resolution, Privacy Protection, Money Savings, Streamlined Communications, and Simplicity in our services for you.
Cheif Audit officer
Cheif Audit officer
Cheif Audit officer
Cheif Audit officer


There are some things that are not allowed to edit. Below is a list of the currently not allowed elements:
.alert
Things that are not allowed to edit are naively replaced meaning all places where you use them in custom CSS will be removedFates List offers a WebSocket API at /api/ws for getting real time stats on your bot. This is the only way to get view events (and potentially other events). All things sent must be as payloads. See below for more information
Upon attempting to connect to /api/ws, you must communicate using payloads. After authentication, the transmissions become one way from server to your client. The below table explains the payload format:
| Key | Description | Type |
|---|---|---|
| payload | This is a payload which is essentially what is being sent to you. This can be a IDENTITY, STATUS, KILL_CONN or EVENTS but this may change in the future | String |
| type | This is the payload type which is how you are supposed to respond or extra information about the payload such as NO_AUTH or API_TOKEN. | String |
| data | If the payload is a data payload like EVENTS_V1, then this the main data sent by the payload. This key is not present on non-data payloads | Optional[String] |
Identity Payloads are what you will get when you first try to connect to the WebSocket API. You must repond using a IDENTITY_RESPONSE payload with the type being API_TOKEN and the data being the list of API Tokens you want events for. If you do not use the correct format, a KILL_CONN payload with the type INVALID_IDENTITY_RESPONSE will be sent to you and the connection will be closed with code 4004. If none of your API Tokens match, you will get a KILL_CONN payload with the type NO_AUTH. Once connections is successful, a STATUS payload with type READY will be sent to you. From here, all transmissions other than ping become server -> client only.
For your reference, here is an example of a IDENTITY_RESPONSE: {"payload": "IDENTITY_RESPONSE", "type": "API_TOKEN", "data": ["TOKEN1", "TOKEN2"]}
Events Payloads are what you will get after connecting to the websocket whenever you have a new event. They will/should always have a STATUS key with the value being READY. This key is not part of the WsEventsObject and should be ignored. Additionally, you will see that the WsEventsObject will be a dictionary with the key being the event id and the value being a WsEvent and the WsEventsObject is part of a dictionary with the key being the bot_ids you connected to the WS using IDENTITY for. The type may be changed if breaking changes are made. A WsEvent has the following format (WsEventsObject is {event_id: WsEvent, event_id_2...}):
| Key | Description | Type |
|---|---|---|
| payload | This is a payload of the event which is essentially what is being sent to you. This will always be 'event' in a WsEvent | String['event'] |
| event | This is the type of WebSocket event you are getting | String |
| context | This is the context of the event | Optional[String] |
For your reference, here is an example of a EVENTS payload: {"payload": "EVENTS", "type": "EVENTS_V1", "data": {"631115725876101150": {"status": "READY", "18741a69-552b-4d7d-ab0b-7ed211a22049": {"payload": "event", "event": "view", "context": {"user": 0, "hidden": 1, "widget": "False"}}}}}


| DOSE: T+ 0:00 |
10 mg |
oral |
DiPT |
(powder / crystals) |
| T+ 0:45 |
5.0 mg |
oral |
DiPT |
(powder / crystals) |
| T+ 1:20 |
|
smoked |
Cannabis |
(plant material) |
After my past experiences with so many visual, emotional and potentially spiritual psychedelics, I thought DiPT should be a little bit different. I had the opportunity to test the prototypical audio hallucinogen Di-isopropyl-tryptamine, which has been both complimented and criticized for its novel and unique nature. I had been forewarned in many trip reports that this substance can be stronger and longer lasting than Tihkal would indicate so I started with a very cautious dose of 15mg. The powder was dissolved in a small amount of water and drank in two mini-doses spaced about 45 minutes apart. I drank two thirds of the water around 11:30AM, felt out the initial physical effects, and finished my dose at 12:15. This was done to hopefully reduce nausea. I will consider 11:30AM my T-Time since that is when the drug first entered my system.
The first reactions were physical. Even by T+0:30 when the dose was only partially finished, I could feel energy coursing through my body. It gave me a slightly spaced out and disoriented feeling, with flutters in my stomach hinting at digestive disruption. I thought I could feel energy transferring from my torso up to my head, as with other tryptamines, but flowing away from both my eyes and my inner mind, in favor of my ears. I feel tingling in my ears mixed with a slight sense of uneasiness. All discomfort settled down and remained within safe and reasonable levels, though, and I finished my dose at the planned time.
At T+1h, the first audio distortions were detected. They initially consisted of sounds being alternately either fuzzier and more faded, or clearer and fuller sounding than normal. I was unable to define the exact difference, but something was changing.
By T+1:20h, the full effects had developed. There was, in fact, a deepening effect, semi-randomly imposed on certain cross-sections of the sound spectrum. Most people's voices sounded dramatically deepened, but if the tone of their voice was outside a certain 'deepening range' it didn't have the expected distortion. In some cases high pitched sounds seemed to jump out with new depth and dimension, though they were emphasized more rarely than the lower pitches.
By this point, I had a bizarre feeling in my ears. It felt as if energy had moved into my ears, melted my inner ear material, and my inner ear had then “hardened” again, recast into a new shape. I know that DiPT’s action is on particular subsections of the brain and not the ears, but it certainly feels as though it is effecting the ears directly.
With regards to music, DiPT is generally considered a musical de-harmonizer. And it does indeed make most orchestrated music sound more dissonant. But what of music which is dissonant or simple in structure to begin with? I found a symphony orchestra performance on YouTube.  Everyone with an instrument seemed to be playing their own music at their own pace, with no concern for harmony. Only by reading the video’s comments from other viewers could I confirm that it was, in fact, a highly trained professional orchestra.
Then I looked up videos of non-harmonic and minimalist music. Such as experimental industrial music from the early 80s. Death metal headbangers. Gangsta-rappers shouting about “gats” over booming basslines. DiPT cannot de-harmonize these because there is not enough order to begin with. They sound the same as normal, but with thickened, echoing bass areas that blend together into a continuous stream. I will not attempt to describe what the Ghost Face Killah's voice sounds like in DiPT space but it made me laugh outrageously.
There was an uncomfortable buzz in my body accompanying the first audio effects, and the more distorted audio I heard the more uncomfortable I seemed to feel. I found turning off my music and going into a quiet area from time to time refreshing. I felt mildly nauseous, but didn't need to vomit. Cannabis helped with the nausea quite a bit. I sometimes felt oddly stimulated and confused and would wander around in search of something new to do. I was in a state where I became disoriented easily, but could function normally if needed.
At T+1:55h, I officially noticed the voice I was speaking with was no longer my own! I found it amusingly odd to speak to myself in a new voice. I drank lots of water to help keep my body going and settle my stomach, and trips to the bathroom became breaks from the world of sound. Spending a few minutes alone in my quiet bathroom was soothing to my mind… until I flushed the toilet! The deep tone and reverberating sound of the toilet flushing resulted in radical distortion every time, and a very clear reminder of my altered state. The phone ringing was even worse.
At T+3:15h I headed outside. The outdoors felt wonderful and it was no problem navigating and blending in with other people. Unfortunately due to the day I had picked many stores were closed down and the world seemed a bit empty.
Around T+4:15h I noted that the novelty of the effects had worn off and ceased to be entertaining. The effects, however, were still going strong.
By T+5h, I was still playing music, but more to track the gradual decline of the effects than to actually listen to the distorted music.
Around T+5:30h my girlfriend got home from work (it was my day off but not hers) and said 'hello' to me in a voice that was not her own. I started playing World of Warcraft, largely just as an excuse to keep to myself for a couple hours until the effects returned to normality. I had a low attention span at this point but no noticeable cognitive impairment.
By T+8h, the effects finally seemed to have tapered mostly off. My inner ear seemed to be returning to it's normal shape and function. It's hard to tell exactly when the effects of DiPT end, but it should be safe to say my 15mg dose was active for at least eight hours. Aside from the audio hallucinations, there were no visual effects at this dose and almost no emotional impact. I slept well after the experience. The next morning I was slightly dizzy and exhausted for the first several hours of my day, which may have been an after-effect of the DiPT. I was fairly sure audio had returned to normal by the next day but couldn’t be 100% certain.
I think this has been an excellent introduction to a most unusual and different hallucinogenic drug. I agree with many of the previous trip reports: Although it is only an audio hallucinogen, this is a powerful audio hallucinogen. It can easily last a great length of time and I'm quite glad I started with a small dose. Will I explore this substance further? Probably. But I suspect there will be nausea and discomfort involved in higher doses. I will treat this compound with respect and caution, and take it out again sometime in the future, on a rainy day, when I'm in the mood for something different.
Experience Reports are the writings and opinions of the individual authors who submit them.
Some of the activities described are dangerous and/or illegal and none are recommended by Erowid.


- Affiliation
- Identity
- Account Creation
- Enroll in MFA
Create a UCLA Logon ID: Security Settings
Multi-factor Authentication Enrollment
Multi-factor Authentication (MFA) adds a second step to your sign-in process to protect your data and accounts in case your password is compromised. It is strongly recommended to that you set up MFA.
Are you Sure?
Without MFA your accounts only defense against intruders is your password. If someone steals your password they will have access to your account. By enrolling in MFA, your account will have an extra layer of protection.