Exemple #1
0
int player::dodge(game *g)
{
 if (has_disease(DI_SLEEP) || has_disease(DI_LYING_DOWN))
  return 0;
 if (activity.type != ACT_NULL)
  return 0;
 int ret = 4 + (dex_cur / 2);
 ret += skillLevel("dodge");
 ret += disease_intensity(DI_DODGE_BOOST);
 ret -= (encumb(bp_legs) / 2) + encumb(bp_torso);
 ret += int(current_speed(g) / 150);
 if (has_trait(PF_TAIL_LONG))
  ret += 4;
 if (has_trait(PF_TAIL_FLUFFY))
  ret += 8;
 if (has_trait(PF_WHISKERS))
  ret += 1;
 if (has_trait(PF_WINGS_BAT))
  ret -= 3;
 if (str_max >= 16)
  ret--; // Penalty if we're hyuuge
 else if (str_max <= 5)
  ret++; // Bonus if we're small
 if (dodges_left <= 0) { // We already dodged this turn
  if (rng(1, skillLevel("dodge") + dex_cur + 15) <= skillLevel("dodge") + dex_cur)
   ret = rng(0, ret);
  else
   ret = 0;
 }
 dodges_left--;
// If we're over our cap, average it with our cap
 if (ret > int(dex_cur / 2) + skillLevel("dodge") * 2)
  ret = ( ret + int(dex_cur / 2) + skillLevel("dodge") * 2 ) / 2;
 return ret;
}
Exemple #2
0
bool player::install_bionics(it_bionic *type)
{
    if (type == NULL) {
        debugmsg("Tried to install NULL bionic");
        return false;
    }
    if (bionics.count(type->id) == 0) {
        popup("invalid / unknown bionic id %s", type->id.c_str());
        return false;
    }
    if (has_bionic(type->id)) {
        if (!(type->id == "bio_power_storage" || type->id == "bio_power_storage_mkII")) {
            popup(_("You have already installed this bionic."));
            return false;
        }
    }
    int chance_of_success = bionic_manip_cos(int_cur,
                            skillLevel("electronics"),
                            skillLevel("firstaid"),
                            skillLevel("mechanics"),
                            type->difficulty);

    if (!query_yn(
            _("WARNING: %i percent chance of genetic damage, blood loss, or damage to existing bionics! Install anyway?"),
            100 - chance_of_success)) {
        return false;
    }
    int pow_up = 0;
    if (type->id == "bio_power_storage" || type->id == "bio_power_storage_mkII") {
        pow_up = BATTERY_AMOUNT;
        if (type->id == "bio_power_storage_mkII") {
            pow_up = 250;
        }
    }

    practice( "electronics", int((100 - chance_of_success) * 1.5) );
    practice( "firstaid", int((100 - chance_of_success) * 1.0) );
    practice( "mechanics", int((100 - chance_of_success) * 0.5) );
    int success = chance_of_success - rng(1, 100);
    if (success > 0) {
        add_memorial_log(pgettext("memorial_male", "Installed bionic: %s."),
                         pgettext("memorial_female", "Installed bionic: %s."),
                         bionics[type->id]->name.c_str());
        if (pow_up) {
            max_power_level += pow_up;
            add_msg_if_player(m_good, _("Increased storage capacity by %i"), pow_up);
        } else {
            add_msg(m_good, _("Successfully installed %s."), bionics[type->id]->name.c_str());
            add_bionic(type->id);
        }
    } else {
        add_memorial_log(pgettext("memorial_male", "Installed bionic: %s."),
                         pgettext("memorial_female", "Installed bionic: %s."),
                         bionics[type->id]->name.c_str());
        bionics_install_failure(this, type, success);
    }
    g->refresh_all();
    return true;
}
Exemple #3
0
// utility functions for projectile_attack
double player::get_weapon_dispersion(item *weapon) {
    int weapon_skill_level = 0;
    if(weapon->is_gunmod()) {
      it_gunmod* firing = dynamic_cast<it_gunmod *>(weapon->type);
      weapon_skill_level = skillLevel(firing->skill_used);
    } else {
      it_gun* firing = dynamic_cast<it_gun *>(weapon->type);
      weapon_skill_level = skillLevel(firing->skill_used);
    }
    double dispersion = 0.; // Measured in quarter-degrees.
    // Up to 0.75 degrees for each skill point < 8.
    if (weapon_skill_level < 8) {
        dispersion += rng(0, 3 * (8 - weapon_skill_level));
    }
    // Up to 0.25 deg per each skill point < 9.
    if (skillLevel("gun") < 9) {
        dispersion += rng(0, 9 - skillLevel("gun"));
    }

    dispersion += rng(0, ranged_dex_mod());
    dispersion += rng(0, ranged_per_mod());

    dispersion += rng(0, 2 * encumb(bp_arms)) + rng(0, 4 * encumb(bp_eyes));

    dispersion += rng(0, weapon->curammo->dispersion);
    // item::dispersion() doesn't support gunmods.
    dispersion += rng(0, weapon->dispersion());
    int adj_recoil = recoil + driving_recoil;
    dispersion += rng(int(adj_recoil / 4), adj_recoil);

    // this is what the total bonus USED to look like
    // rng(0,x) on each term in the sum
    // 3 * skill + skill + 2 * dex + 2 * per
    // - 2*p.encumb(bp_arms) - 4*p.encumb(bp_eyes) - 5/8 * recoil

    // old targeting bionic suddenly went from 0.8 to 0.65 when LONG_RANGE was
    // crossed, so increasing range by 1 would actually increase accuracy by a
    // lot. This is kind of a compromise
    if (has_bionic("bio_targeting"))
        dispersion *= 0.75;
    if ((is_underwater() && !weapon->has_flag("UNDERWATER_GUN")) || // Range is effectively four times longer when shooting unflagged guns underwater.
            (!is_underwater() && weapon->has_flag("UNDERWATER_GUN"))) { // Range is effectively four times longer when shooting flagged guns out of water.
        dispersion *= 4;
    }

    if (dispersion < 0) { return 0; }
    return dispersion;
}
Exemple #4
0
int player::roll_stuck_penalty(monster *z, bool stabbing)
{
 int ret = 0;
 int basharm = (z == NULL ? 6 : z->armor_bash()),
     cutarm  = (z == NULL ? 6 : z->armor_cut());
 if (stabbing)
  ret = weapon.damage_cut() * 3 + basharm * 3 + cutarm * 3 -
        dice(skillLevel("stabbing"), 10);
 else
  ret = weapon.damage_cut() * 4 + basharm * 5 + cutarm * 4 -
        dice(skillLevel("cutting"), 10);

 if (ret >= weapon.damage_cut() * 10)
  return weapon.damage_cut() * 10;
 return (ret < 0 ? 0 : ret);
}
bool player::can_arm_block() {
  if (martialarts[style_selected].arm_block < 0)
    return false;
  if (skillLevel("unarmed") >= martialarts[style_selected].arm_block &&
      (hp_cur[hp_arm_l] > 0 || hp_cur[hp_arm_r] > 0))
    return true;
  else
    return false;
}
Exemple #6
0
SkillLevel& Character::skillLevel(const skill_id &ident)
{
    if( !ident ) {
        static SkillLevel none;
        none.level( 0 );
        return none;
    }
    return skillLevel( &ident.obj() );
}
Exemple #7
0
int player::roll_stab_damage(monster *z, bool crit)
{
 int ret = 0;
 int z_armor = (z == NULL ? 0 : z->armor_cut() - 3 * skillLevel("stabbing"));

 if (crit)
  z_armor /= 3;
 if (z_armor < 0)
  z_armor = 0;

 if (unarmed_attack() && !wearing_something_on(bp_hands)) {
  ret = 0 - z_armor;
  if (has_trait(PF_CLAWS))
   ret += 6;
  if (has_trait(PF_NAILS) && z_armor == 0)
   ret++;
  if (has_trait(PF_THORNS))
   ret += 4;
 } else if (weapon.has_flag(IF_SPEAR) || weapon.has_flag(IF_STAB))
  ret = int((weapon.damage_cut() - z_armor) / 4);
 else
  return 0; // Can't stab at all!

 if (z != NULL && z->speed > 100) { // Bonus against fast monsters
  int speed_min = (z->speed - 100) / 10, speed_max = (z->speed - 100) / 5;
  int speed_dam = rng(speed_min, speed_max);
  if (speed_dam > ret * 2)
   speed_dam = ret * 2;
  if (speed_dam > 0)
   ret += speed_dam;
 }

 if (ret <= 0)
  return 0; // No negative stabbing!

 if (crit) {
  int multiplier = double( 1.0 + double(skillLevel("stabbing") / 5) );
  if (multiplier > 2.5)
   multiplier = 2.5;
  ret *= multiplier;
 }

 return ret;
}
bool player::can_arm_block() {
  martialart ma = martialarts[style_selected];
  if (ma.arm_block < 0 || !(ma.arm_block_with_bio_armor_arms && has_bionic("bio_armor_arms")))
    return false;
  int unarmed_skill = has_active_bionic("bio_cqb") ? 5 : (int)skillLevel("unarmed");
  if (unarmed_skill < ma.arm_block && !(ma.arm_block_with_bio_armor_arms && has_bionic("bio_armor_arms")))
      return false;
  if (hp_cur[hp_arm_l] > 0 || hp_cur[hp_arm_r] > 0)
    return true;
  else
    return false;
}
Exemple #9
0
int player::dodge(game *g)
//Returns 1/2*DEX + dodge skill level + static bonuses from mutations
//Return numbers range from around 4 (starting player, no boosts) to 29 (20 DEX, 10 dodge, +9 mutations)
{
    //If we're asleep or busy we can't dodge
    if (has_disease(DI_SLEEP) || has_disease(DI_LYING_DOWN)) {return 0;}
    if (activity.type != ACT_NULL) {return 0;}

    int ret = (dex_cur / 2);
    ret += skillLevel("dodge");
    ret += disease_intensity(DI_DODGE_BOOST);
    ret -= (encumb(bp_legs) / 2) + encumb(bp_torso);
    ret += int(current_speed(g) / 150); //Faster = small dodge advantage

    //Mutations
    if (has_trait(PF_TAIL_LONG)) {ret += 4;}
    if (has_trait(PF_TAIL_FLUFFY)) {ret += 8;}
    if (has_trait(PF_WHISKERS)) {ret += 1;}
    if (has_trait(PF_WINGS_BAT)) {ret -= 3;}

    if (str_max >= 16) {ret--;} // Penalty if we're huge
    else if (str_max <= 5) {ret++;} // Bonus if we're small

    if (dodges_left <= 0) // We already dodged this turn
    {
        if (rng(0, skillLevel("dodge") + dex_cur + 15) <= skillLevel("dodge") + dex_cur)
        {
            ret = rng(ret/2, ret); //Penalize multiple dodges per turn
        }
        else
        {
            ret = 0;
        }
    }
    dodges_left--;
    return ret;
}
Exemple #10
0
bool player::can_arm_block()
{
    martialart ma = martialarts[style_selected];
    int unarmed_skill = has_active_bionic("bio_cqb") ? 5 : (int)skillLevel("unarmed");

    // Success conditions.
    if (hp_cur[hp_arm_l] > 0 || hp_cur[hp_arm_r] > 0) {
        if( unarmed_skill >= ma.arm_block ) {
            return true;
        } else if( ma.arm_block_with_bio_armor_arms && has_bionic("bio_armor_arms") ) {
            return true;
        }
    }
    // if not above, can't block.
    return false;
}
Exemple #11
0
int player::roll_cut_damage(monster *z, bool crit)
{
 if (weapon.has_flag(IF_SPEAR))
  return 0;  // Stabs, doesn't cut!
 int z_armor_cut = (z == NULL ? 0 : z->armor_cut() - skillLevel("cutting") / 2);

 if (crit)
  z_armor_cut /= 2;
 if (z_armor_cut < 0)
  z_armor_cut = 0;

 int ret = weapon.damage_cut() - z_armor_cut;

 if (unarmed_attack() && !wearing_something_on(bp_hands)) {
  if (has_trait(PF_CLAWS))
   ret += 6;
  if (has_trait(PF_TALONS))
   ret += 6 + ((int)skillLevel("unarmed") > 8 ? 8 : (int)skillLevel("unarmed"));
  if (has_trait(PF_SLIME_HANDS) && (z == NULL || !z->has_flag(MF_ACIDPROOF)))
   ret += rng(4, 6);
 }

 if (ret <= 0)
  return 0; // No negative damage!

// 80%, 88%, 96%, 104%, 112%, 116%, 120%, 124%, 128%, 132%
 if (skillLevel("cutting") <= 5)
  ret *= double( 0.8 + 0.08 * skillLevel("cutting") );
 else
  ret *= double( 0.92 + 0.04 * skillLevel("cutting") );

 if (crit)
  ret *= double( 1.0 + double(skillLevel("cutting") / 12) );

 return ret;
}
Exemple #12
0
std::vector<special_attack> player::mutation_attacks(monster *z, player *p)
{
 std::vector<special_attack> ret;

 if (z == NULL && p == NULL)
  return ret;

 bool mon = (z != NULL);
 bool is_u = (!is_npc());// Affects how we'll display messages
 std::string You  = (is_u ? "You"  : name);
 std::string Your = (is_u ? "Your" : name + "'s");
 std::string your = (is_u ? "your" : (male ? "his" : "her"));
 std::string target = (mon ? "the " + z->name() : p->name);

 std::stringstream text;

 if (has_trait(PF_FANGS) && !wearing_something_on(bp_mouth) &&
     one_in(20 - dex_cur - skillLevel("unarmed"))) {
  special_attack tmp;
  text << You << " sink" << (is_u ? " " : "s ") << your << " fangs into " <<
          target << "!";
  tmp.text = text.str();
  tmp.stab = 20;
  ret.push_back(tmp);
 }

 if (has_trait(PF_MANDIBLES) && one_in(22 - dex_cur - skillLevel("unarmed"))) {
  special_attack tmp;
  text << You << " slice" << (is_u ? " " : "s ") << target << " with " <<
          your << " mandibles!";
  tmp.text = text.str();
  tmp.cut = 12;
  ret.push_back(tmp);
 }

 if (has_trait(PF_BEAK) && one_in(15 - dex_cur - skillLevel("unarmed"))) {
  special_attack tmp;
  text << You << " peck" << (is_u ? " " : "s ") << target << "!";
  tmp.text = text.str();
  tmp.stab = 15;
  ret.push_back(tmp);
 }

 if (has_trait(PF_HOOVES) && one_in(25 - dex_cur - 2 * skillLevel("unarmed"))) {
  special_attack tmp;
  text << You << " kick" << (is_u ? " " : "s ") << target << " with " <<
          your << " hooves!";
  tmp.text = text.str();
  tmp.bash = str_cur * 3;
  if (tmp.bash > 40)
   tmp.bash = 40;
  ret.push_back(tmp);
 }

 if (has_trait(PF_HORNS) && one_in(20 - dex_cur - skillLevel("unarmed"))) {
  special_attack tmp;
  text << You << " headbutt" << (is_u ? " " : "s ") << target << " with " <<
          your << " horns!";
  tmp.text = text.str();
  tmp.bash = 3;
  tmp.stab = 3;
  ret.push_back(tmp);
 }

 if (has_trait(PF_HORNS_CURLED) && one_in(20 - dex_cur - skillLevel("unarmed"))) {
  special_attack tmp;
  text << You << " headbutt" << (is_u ? " " : "s ") << target << " with " <<
          your << " curled horns!";
  tmp.text = text.str();
  tmp.bash = 14;
  ret.push_back(tmp);
 }

 if (has_trait(PF_HORNS_POINTED) && one_in(22 - dex_cur - skillLevel("unarmed"))){
  special_attack tmp;
  text << You << " stab" << (is_u ? " " : "s ") << target << " with " <<
          your << " pointed horns!";
  tmp.text = text.str();
  tmp.stab = 24;
  ret.push_back(tmp);
 }

 if (has_trait(PF_ANTLERS) && one_in(20 - dex_cur - skillLevel("unarmed"))) {
  special_attack tmp;
  text << You << " butt" << (is_u ? " " : "s ") << target << " with " <<
          your << " antlers!";
  tmp.text = text.str();
  tmp.bash = 4;
  ret.push_back(tmp);
 }

 if (has_trait(PF_TAIL_STING) && one_in(3) && one_in(10 - dex_cur)) {
  special_attack tmp;
  text << You << " sting" << (is_u ? " " : "s ") << target << " with " <<
          your << " tail!";
  tmp.text = text.str();
  tmp.stab = 20;
  ret.push_back(tmp);
 }

 if (has_trait(PF_TAIL_CLUB) && one_in(3) && one_in(10 - dex_cur)) {
  special_attack tmp;
  text << You << " hit" << (is_u ? " " : "s ") << target << " with " <<
          your << " tail!";
  tmp.text = text.str();
  tmp.bash = 18;
  ret.push_back(tmp);
 }

 if (has_trait(PF_ARM_TENTACLES) || has_trait(PF_ARM_TENTACLES_4) ||
     has_trait(PF_ARM_TENTACLES_8)) {
  int num_attacks = 1;
  if (has_trait(PF_ARM_TENTACLES_4))
   num_attacks = 3;
  if (has_trait(PF_ARM_TENTACLES_8))
   num_attacks = 7;
  if (weapon.is_two_handed(this))
   num_attacks--;

  for (int i = 0; i < num_attacks; i++) {
   if (one_in(18 - dex_cur - skillLevel("unarmed"))) {
    special_attack tmp;
    text.str("");
    text << You << " slap" << (is_u ? " " : "s ") << target << " with " <<
            your << " tentacle!";
    tmp.text = text.str();
    tmp.bash = str_cur / 2;
    ret.push_back(tmp);
   }
  }
 }

 return ret;
}
Exemple #13
0
int player::hit_roll()
{
 int stat = dex_cur;
// Some martial arts use something else to determine hits!
 if(weapon.typeId() == "style_tiger"){
   stat = (str_cur * 2 + dex_cur) / 3;
 } else if(weapon.typeId() == "style_leopard"){
   stat = (per_cur + int_cur + dex_cur * 2) / 4;
 } else if(weapon.typeId() == "style_snake"){
   stat = (per_cur + dex_cur) / 2;
 }
 int numdice = base_to_hit(stat) + weapon.type->m_to_hit +
               disease_intensity(DI_ATTACK_BOOST);
 int sides = 10 - encumb(bp_torso);
 int best_bonus = 0;
 if (sides < 2)
  sides = 2;

// Are we unarmed?
 if (unarmed_attack()) {
  best_bonus = skillLevel("unarmed");
  if (skillLevel("unarmed") > 4)
   best_bonus += skillLevel("unarmed") - 4; // Extra bonus for high levels
 }

// Using a bashing weapon?
 if (weapon.is_bashing_weapon()) {
  int bash_bonus = int(skillLevel("bashing") / 3);
  if (bash_bonus > best_bonus)
   best_bonus = bash_bonus;
 }

// Using a cutting weapon?
 if (weapon.is_cutting_weapon()) {
  int cut_bonus = int(skillLevel("cutting") / 2);
  if (cut_bonus > best_bonus)
   best_bonus = cut_bonus;
 }

// Using a spear?
 if (weapon.has_flag(IF_SPEAR) || weapon.has_flag(IF_STAB)) {
  int stab_bonus = int(skillLevel("stabbing") / 2);
  if (stab_bonus > best_bonus)
   best_bonus = stab_bonus;
 }

 numdice += best_bonus; // Use whichever bonus is best.

// Drunken master makes us hit better
 if (has_trait(PF_DRUNKEN)) {
  if (unarmed_attack())
   numdice += int(disease_level(DI_DRUNK) / 300);
  else
   numdice += int(disease_level(DI_DRUNK) / 400);
 }

 if (numdice < 1) {
  numdice = 1;
  sides = 8 - encumb(bp_torso);
 }

 return dice(numdice, sides);
}
Exemple #14
0
int player::roll_bash_damage(monster *z, bool crit)
{
 int ret = 0;
 int stat = str_cur; // Which stat determines damage?
 int skill = skillLevel("bashing"); // Which skill determines damage?
 if (unarmed_attack())
  skill = skillLevel("unarmed");

 if(weapon.typeId() =="style_crane"){
   stat = (dex_cur * 2 + str_cur) / 3;
 } else if(weapon.typeId() == "style_snake"){
   stat = int(str_cur + per_cur) / 2;
 } else if(weapon.typeId() == "style_dragon"){
   stat = int(str_cur + int_cur) / 2;
 }

 ret = base_damage(true, stat);

// Drunken Master damage bonuses
 if (has_trait(PF_DRUNKEN) && has_disease(DI_DRUNK)) {
// Remember, a single drink gives 600 levels of DI_DRUNK
  int mindrunk, maxdrunk;
  if (unarmed_attack()) {
   mindrunk = disease_level(DI_DRUNK) / 600;
   maxdrunk = disease_level(DI_DRUNK) / 250;
  } else {
   mindrunk = disease_level(DI_DRUNK) / 900;
   maxdrunk = disease_level(DI_DRUNK) / 400;
  }
  ret += rng(mindrunk, maxdrunk);
 }

 int bash_dam = int(stat / 2) + weapon.damage_bash(),
     bash_cap = 5 + stat + skill;

 if (unarmed_attack())
  bash_dam = rng(0, int(stat / 2) + skillLevel("unarmed"));

 if (crit) {
  bash_dam *= 1.5;
  bash_cap *= 2;
 }

 if (bash_dam > bash_cap)// Cap for weak characters
  bash_dam = (bash_cap * 3 + bash_dam) / 4;

 if (z != NULL && z->has_flag(MF_PLASTIC))
  bash_dam /= rng(2, 4);

 int bash_min = bash_dam / 4;

 bash_dam = rng(bash_min, bash_dam);

 if (bash_dam < skill + int(stat / 2))
  bash_dam = rng(bash_dam, skill + int(stat / 2));

 ret += bash_dam;

 ret += disease_intensity(DI_DAMAGE_BOOST);

// Finally, extra crit effects
 if (crit) {
  ret += int(stat / 2);
  ret += skill;
  if (z != NULL)
   ret -= z->armor_bash() / 2;
 } else if (z != NULL)
  ret -= z->armor_bash();

 return (ret < 0 ? 0 : ret);
}
void player::json_load_common_variables(JsonObject & data)
{
    JsonArray parray;

// todo/maybe:
// std::map<std::string, int*> strmap_common_variables;
// void player::init_strmap_common_variables() {
//     strmap_common_variables["posx"]=&posx; // + all this below and in save_common_variables
// }
// load:
// for(std::map<std::string, int*>::iterator it...
//     data.read(it->first,it->second);
// save:
// for(...
//     json.member( it->first, it->second );
    if(!data.read("posx",posx) ) { // uh-oh.
         debugmsg("BAD PLAYER/NPC JSON: no 'posx'?");
    }
    data.read("posy",posy);
    data.read("str_cur",str_cur);      data.read("str_max",str_max);
    data.read("dex_cur",dex_cur);      data.read("dex_max",dex_max);
    data.read("int_cur",int_cur);      data.read("int_max",int_max);
    data.read("per_cur",per_cur);      data.read("per_max",per_max);
    data.read("hunger",hunger);        data.read("thirst",thirst);
    data.read("fatigue",fatigue);      data.read("stim",stim);
    data.read("pain",pain);            data.read("pkill",pkill);
    data.read("radiation",radiation);
    data.read("scent",scent);
    data.read("moves",moves);
    data.read("dodges_left",num_dodges);
    data.read("underwater",underwater);
    data.read("oxygen",oxygen);
    data.read("male",male);
    data.read("cash",cash);
    data.read("recoil",recoil);

    parray = data.get_array("hp_cur");
    if ( parray.size() == num_hp_parts ) {
        for(int i=0; i < num_hp_parts; i++) {
            hp_cur[i] = parray.get_int(i);
        }
    } else {
        debugmsg("Error, incompatible hp_cur in save file '%s'",parray.str().c_str());
    }

    parray = data.get_array("hp_max");
    if ( parray.size() == num_hp_parts ) {
        for(int i=0; i < num_hp_parts; i++) {
            hp_max[i] = parray.get_int(i);
        }
    } else {
        debugmsg("Error, incompatible hp_max in save file '%s'",parray.str().c_str());
    }

    data.read("power_level",power_level);
    data.read("max_power_level",max_power_level);
    data.read("traits",my_traits);

    if (data.has_object("skills")) {
        JsonObject pmap = data.get_object("skills");
        for (std::vector<Skill*>::iterator aSkill = Skill::skills.begin(); aSkill != Skill::skills.end(); ++aSkill) {
            if ( pmap.has_object( (*aSkill)->ident() ) ) {
                pmap.read( (*aSkill)->ident(), skillLevel(*aSkill) );
            } else {
                 debugmsg("Load (%s) Missing skill %s","",(*aSkill)->ident().c_str() );
            }
        }
    } else {
        debugmsg("Skills[] no bueno");
    }

    data.read("ma_styles",ma_styles);
    data.read("illness",illness);
    data.read("effects",effects);
    data.read("addictions",addictions);
    data.read("my_bionics",my_bionics);
}
Exemple #16
0
void player::activate_mutation( const std::string &mut )
{
    const auto &mdata = mutation_branch::get( mut );
    auto &tdata = my_mutations[mut];
    int cost = mdata.cost;
    // You can take yourself halfway to Near Death levels of hunger/thirst.
    // Fatigue can go to Exhausted.
    if ((mdata.hunger && get_hunger() >= 700) || (mdata.thirst && get_thirst() >= 260) ||
      (mdata.fatigue && get_fatigue() >= EXHAUSTED)) {
      // Insufficient Foo to *maintain* operation is handled in player::suffer
        add_msg_if_player(m_warning, _("You feel like using your %s would kill you!"), mdata.name.c_str());
        return;
    }
    if (tdata.powered && tdata.charge > 0) {
        // Already-on units just lose a bit of charge
        tdata.charge--;
    } else {
        // Not-on units, or those with zero charge, have to pay the power cost
        if (mdata.cooldown > 0) {
            tdata.charge = mdata.cooldown - 1;
        }
        if (mdata.hunger){
            mod_hunger(cost);
        }
        if (mdata.thirst){
            mod_thirst(cost);
        }
        if (mdata.fatigue){
            mod_fatigue(cost);
        }
        tdata.powered = true;

        // Handle stat changes from activation
        apply_mods(mut, true);
        recalc_sight_limits();
    }

    if( mut == "WEB_WEAVER" ) {
        g->m.add_field(pos(), fd_web, 1, 0);
        add_msg_if_player(_("You start spinning web with your spinnerets!"));
    } else if (mut == "BURROW"){
        if( is_underwater() ) {
            add_msg_if_player(m_info, _("You can't do that while underwater."));
            tdata.powered = false;
            return;
        }
        tripoint dirp;
        if (!choose_adjacent(_("Burrow where?"), dirp)) {
            tdata.powered = false;
            return;
        }

        if( dirp == pos() ) {
            add_msg_if_player(_("You've got places to go and critters to beat."));
            add_msg_if_player(_("Let the lesser folks eat their hearts out."));
            tdata.powered = false;
            return;
        }
        int turns;
        if (g->m.is_bashable(dirp) && g->m.has_flag("SUPPORTS_ROOF", dirp) &&
            g->m.ter(dirp) != t_tree) {
            // Takes about 100 minutes (not quite two hours) base time.
            // Being better-adapted to the task means that skillful Survivors can do it almost twice as fast.
            ///\EFFECT_CARPENTRY speeds up burrowing
            turns = (100000 - 5000 * skillLevel( skill_id( "carpentry" ) ));
        } else if (g->m.move_cost(dirp) == 2 && g->get_levz() == 0 &&
                   g->m.ter(dirp) != t_dirt && g->m.ter(dirp) != t_grass) {
            turns = 18000;
        } else {
            add_msg_if_player(m_info, _("You can't burrow there."));
            tdata.powered = false;
            return;
        }
        assign_activity(ACT_BURROW, turns, -1, 0);
        activity.placement = dirp;
        add_msg_if_player(_("You tear into the %s with your teeth and claws."),
                          g->m.tername(dirp).c_str());
        tdata.powered = false;
        return; // handled when the activity finishes
    } else if (mut == "SLIMESPAWNER") {
        std::vector<tripoint> valid;
        for (int x = posx() - 1; x <= posx() + 1; x++) {
            for (int y = posy() - 1; y <= posy() + 1; y++) {
                tripoint dest(x, y, posz());
                if (g->is_empty(dest)) {
                    valid.push_back( dest );
                }
            }
        }
        // Oops, no room to divide!
        if (valid.size() == 0) {
            add_msg_if_player(m_bad, _("You focus, but are too hemmed in to birth a new slimespring!"));
            tdata.powered = false;
            return;
        }
        add_msg_if_player(m_good, _("You focus, and with a pleasant splitting feeling, birth a new slimespring!"));
        int numslime = 1;
        for (int i = 0; i < numslime && !valid.empty(); i++) {
            const tripoint target = random_entry_removed( valid );
            if (g->summon_mon(mtype_id( "mon_player_blob" ), target)) {
                monster *slime = g->monster_at( target );
                slime->friendly = -1;
            }
        }
        if (one_in(3)) {
            //~ Usual enthusiastic slimespring small voices! :D
            add_msg_if_player(m_good, _("wow! you look just like me! we should look out for each other!"));
        } else if (one_in(2)) {
            //~ Usual enthusiastic slimespring small voices! :D
            add_msg_if_player(m_good, _("come on, big me, let's go!"));
        } else {
            //~ Usual enthusiastic slimespring small voices! :D
            add_msg_if_player(m_good, _("we're a team, we've got this!"));
        }
        tdata.powered = false;
        return;
    } else if ((mut == "NAUSEA") || (mut == "VOMITOUS") ){
        vomit();
        tdata.powered = false;
        return;
    } else if (mut == "M_FERTILE"){
        spores();
        tdata.powered = false;
        return;
    } else if (mut == "M_BLOOM"){
        blossoms();
        tdata.powered = false;
        return;
    } else if (mut == "VINES3"){
        item newit( "vine_30", calendar::turn );
        if (!can_pickVolume(newit.volume())) { //Accounts for result_mult
            add_msg_if_player(_("You detach a vine but don't have room to carry it, so you drop it."));
            g->m.add_item_or_charges(pos(), newit);
        } else if (!can_pickWeight(newit.weight(), !OPTIONS["DANGEROUS_PICKUPS"])) {
            add_msg_if_player(_("Your freshly-detached vine is too heavy to carry, so you drop it."));
            g->m.add_item_or_charges(pos(), newit);
        } else {
            inv.assign_empty_invlet(newit);
            newit = i_add(newit);
            add_msg_if_player(m_info, "%c - %s", newit.invlet == 0 ? ' ' : newit.invlet, newit.tname().c_str());
        }
        tdata.powered = false;
        return;
    } else if( mut == "SELFAWARE" ) {
        print_health();
        tdata.powered = false;
        return;
    }
}
bool player::create(game *g, character_type type, std::string tempname)
{
 weapon = item(g->itypes["null"], 0);
 
 g->u.prof = profession::generic();

 WINDOW* w = newwin(25, 80, (TERMY > 25) ? (TERMY-25)/2 : 0, (TERMX > 80) ? (TERMX-80)/2 : 0);

 int tab = 0, points = 38;
 if (type != PLTYPE_CUSTOM) {
  switch (type) {
   case PLTYPE_RANDOM: {
    str_max = rng(6, 12);
    dex_max = rng(6, 12);
    int_max = rng(6, 12);
    per_max = rng(6, 12);
    points = points - str_max - dex_max - int_max - per_max;
    if (str_max > HIGH_STAT)
     points -= (str_max - HIGH_STAT);
    if (dex_max > HIGH_STAT)
     points -= (dex_max - HIGH_STAT);
    if (int_max > HIGH_STAT)
     points -= (int_max - HIGH_STAT);
    if (per_max > HIGH_STAT)
     points -= (per_max - HIGH_STAT);

    int num_gtraits = 0, num_btraits = 0, rn, tries;
    while (points < 0 || rng(-3, 20) > points) {
     if (num_btraits < MAX_TRAIT_POINTS && one_in(3)) {
      tries = 0;
      do {
       rn = random_bad_trait();
       tries++;
      } while ((has_trait(rn) ||
              num_btraits - traits[rn].points > MAX_TRAIT_POINTS) && tries < 5);
      if (tries < 5) {
       toggle_trait(rn);
       points -= traits[rn].points;
       num_btraits -= traits[rn].points;
      }
     } else {
      switch (rng(1, 4)) {
       case 1: if (str_max > 5) { str_max--; points++; } break;
       case 2: if (dex_max > 5) { dex_max--; points++; } break;
       case 3: if (int_max > 5) { int_max--; points++; } break;
       case 4: if (per_max > 5) { per_max--; points++; } break;
      }
     }
    }
    while (points > 0) {
     switch (rng((num_gtraits < MAX_TRAIT_POINTS ? 1 : 5), 9)) {
     case 1:
     case 2:
     case 3:
     case 4:
      rn = random_good_trait();
      if (!has_trait(rn) && points >= traits[rn].points &&
          num_gtraits + traits[rn].points <= MAX_TRAIT_POINTS) {
       toggle_trait(rn);
       points -= traits[rn].points;
       num_gtraits += traits[rn].points;
      }
      break;
     case 5:
      switch (rng(1, 4)) {
       case 1: if (str_max < HIGH_STAT) { str_max++; points--; } break;
       case 2: if (dex_max < HIGH_STAT) { dex_max++; points--; } break;
       case 3: if (int_max < HIGH_STAT) { int_max++; points--; } break;
       case 4: if (per_max < HIGH_STAT) { per_max++; points--; } break;
      }
      break;
     case 6:
     case 7:
     case 8:
     case 9:
      rn = random_skill();

      Skill *aSkill = Skill::skill(rn);
      int level = skillLevel(aSkill);

      if (level < points) {
        points -= level + 1;
        skillLevel(aSkill).level(level + 2);
      }
      break;
     }
    }
   } break;
   case PLTYPE_TEMPLATE: {
    std::ifstream fin;
    std::stringstream filename;
    filename << "data/" << tempname << ".template";
    fin.open(filename.str().c_str());
    if (!fin.is_open()) {
     debugmsg("Couldn't open %s!", filename.str().c_str());
     return false;
    }
    std::string(data);
    getline(fin, data);
    load_info(g, data);
    points = 0;
   } break;
  }
  tab = 3;
 } else
  points = OPTIONS[OPT_INITIAL_POINTS];

 do {
  werase(w);
  wrefresh(w);
  switch (tab) {
   case 0: tab += set_stats      (w, g, this, points); break;
   case 1: tab += set_traits     (w, g, this, points); break;
   case 2: tab += set_profession (w, g, this, points); break;
   case 3: tab += set_skills     (w, g, this, points); break;
   case 4: tab += set_description(w, g, this, points); break;
  }
 } while (tab >= 0 && tab < 5);
 delwin(w);

 if (tab < 0)
  return false;

 // Character is finalized.  Now just set up HP, &c
 for (int i = 0; i < num_hp_parts; i++) {
  hp_max[i] = calc_HP(str_max, has_trait(PF_TOUGH));
  hp_cur[i] = hp_max[i];
 }
 if (has_trait(PF_GLASSJAW)) {
  hp_max[hp_head] = int(hp_max[hp_head] * .85);
  hp_cur[hp_head] = hp_max[hp_head];
 }
 if (has_trait(PF_SMELLY))
  scent = 800;
 if (has_trait(PF_ANDROID)) {
  std::map<std::string,bionic_data*>::iterator random_bionic = bionics.begin();
  std::advance(random_bionic,rng(0,bionics.size()-1));
  add_bionic(random_bionic->first);// Other
  if (bionics[my_bionics[0].id]->power_cost > 0) {
   add_bionic(bionic_id(power_source_bionics[rng(0,power_source_bionics.size())]));	// Power Source
   max_power_level = 10;
   power_level = 10;
  } else {
   bionic_id tmpbio;
   do
   tmpbio = bionic_id(unpowered_bionics[rng(0, unpowered_bionics.size())]);
   while (bionics[tmpbio]->power_cost > 0);
   add_bionic(tmpbio);
   max_power_level = 0;
   power_level = 0;
  }

/* CHEATER'S STUFF

  add_bionic(bionic_id(rng(0, "bio_ethanol")));	// Power Source
  for (int i = 0; i < 5; i++)
   add_bionic(bionic_id(rng("bio_memory", max_"bio_start" - 1)));// Other
  max_power_level = 80;
  power_level = 80;

End of cheatery */
 }

 if (has_trait(PF_MARTIAL_ARTS)) {
  itype_id ma_type;
  do {
   int choice = menu("Pick your style:",
                     "Karate", "Judo", "Aikido", "Tai Chi", "Taekwondo", NULL);
   if (choice == 1)
    ma_type = "style_karate";
   if (choice == 2)
    ma_type = "style_judo";
   if (choice == 3)
    ma_type = "style_aikido";
   if (choice == 4)
    ma_type = "style_tai_chi";
   if (choice == 5)
    ma_type = "style_taekwondo";
   item tmpitem = item(g->itypes[ma_type], 0);
   full_screen_popup(tmpitem.info(true).c_str());
  } while (!query_yn("Use this style?"));
  styles.push_back(ma_type);
 }
 ret_null = item(g->itypes["null"], 0);
 if (!styles.empty())
  weapon = item(g->itypes[ styles[0] ], 0, ':');
 else
  weapon   = item(g->itypes["null"], 0);
 
 item tmp; //gets used several times

 std::vector<std::string> prof_items = g->u.prof->items();
 for (std::vector<std::string>::const_iterator iter = prof_items.begin(); iter != prof_items.end(); ++iter) {
  item tmp = item(g->itypes.at(*iter), 0, 'a' + worn.size());
  if (tmp.is_armor()) {
   if (tmp.has_flag(IF_VARSIZE))
    tmp.item_flags |= mfb(IF_FIT);      
   worn.push_back(tmp);
  } else {
   inv.push_back(tmp);
  }

  // if we start with drugs, need to start strongly addicted, too
  if (tmp.is_food()) {
   it_comest *comest = dynamic_cast<it_comest*>(tmp.type);
   if (comest->add != ADD_NULL) {
    addiction add(comest->add, 10);
    g->u.addictions.push_back(add);
   }
  }
 }

// The near-sighted get to start with glasses.
 if (has_trait(PF_MYOPIC)) {
  tmp = item(g->itypes["glasses_eye"], 0, 'a' + worn.size());
  worn.push_back(tmp);
 }
// And the far-sighted get to start with reading glasses.
 if (has_trait(PF_HYPEROPIC)) {
  tmp = item(g->itypes["glasses_reading"], 0, 'a' + worn.size());
  worn.push_back(tmp);
 }
// Likewise, the asthmatic start with their medication.
 if (has_trait(PF_ASTHMA)) {
  tmp = item(g->itypes["inhaler"], 0, 'a' + worn.size());
  inv.push_back(tmp);
 }
// Basic starter gear, added independently of profession.
 tmp = item(g->itypes["pockknife"], 0,'a' + worn.size());
  inv.push_back(tmp);
 tmp = item(g->itypes["matches"], 0,'a' + worn.size());
  inv.push_back(tmp);
// make sure we have no mutations
 for (int i = 0; i < PF_MAX2; i++)
  my_mutations[i] = false;
 return true;
}
Exemple #18
0
technique_id player::pick_defensive_technique(game *g, monster *z, player *p)
{
 if (blocks_left == 0)
  return TEC_NULL;

 int foe_melee_skill = 0;
 if (z != NULL)
  foe_melee_skill = z->type->melee_skill;
 else if (p != NULL)
  foe_melee_skill = p->dex_cur + p->skillLevel("melee");

 int foe_dodge = 0;
 if (z != NULL)
  foe_dodge = z->dodge_roll();
 else if (p != NULL)
  foe_dodge = p->dodge_roll(g);

 int foe_size = 0;
 if (z)
  foe_size = 4 + z->type->size * 4;
 else if (p) {
  foe_size = 12;
  if (p->str_max <= 5)
   foe_size -= 3;
  if (p->str_max >= 12)
   foe_size += 3;
 }

 blocks_left--;
 if (weapon.has_technique(TEC_WBLOCK_3) &&
     dice(dex_cur + skillLevel("melee"), 12) > dice(foe_melee_skill, 10))
  return TEC_WBLOCK_3;

 if (weapon.has_technique(TEC_WBLOCK_2) &&
     dice(dex_cur + skillLevel("melee"), 6) > dice(foe_melee_skill, 10))
  return TEC_WBLOCK_2;

 if (weapon.has_technique(TEC_WBLOCK_1) &&
     dice(dex_cur + skillLevel("melee"), 3) > dice(foe_melee_skill, 10))
  return TEC_WBLOCK_1;

 if (weapon.has_technique(TEC_DEF_DISARM, this) &&
     z == NULL && p->weapon.typeId() != "null" &&
     !p->weapon.has_flag(IF_UNARMED_WEAPON) &&
     dice(   dex_cur +    skillLevel("unarmed"), 8) >
     dice(p->dex_cur + p->skillLevel("melee"),  10))
  return TEC_DEF_DISARM;

 if (weapon.has_technique(TEC_DEF_THROW, this) &&
     str_cur + skillLevel("melee") >= foe_size + rng(-4, 4) &&
     hit_roll() > rng(1, 5) + foe_dodge && !one_in(3))
  return TEC_DEF_THROW;

 if (weapon.has_technique(TEC_COUNTER, this) &&
     hit_roll() > rng(1, 10) + foe_dodge && !one_in(3))
  return TEC_COUNTER;

 if (weapon.has_technique(TEC_BLOCK_LEGS, this) &&
     (hp_cur[hp_leg_l] >= 20 || hp_cur[hp_leg_r] >= 20) &&
     dice(dex_cur + skillLevel("unarmed") + skillLevel("melee"), 13) >
     dice(8 + foe_melee_skill, 10))
  return TEC_BLOCK_LEGS;

 if (weapon.has_technique(TEC_BLOCK, this) &&
     (hp_cur[hp_arm_l] >= 20 || hp_cur[hp_arm_r] >= 20) &&
     dice(dex_cur + skillLevel("unarmed") + skillLevel("melee"), 16) >
     dice(6 + foe_melee_skill, 10))
  return TEC_BLOCK;

 blocks_left++; // We didn't use any blocks, so give it back!
 return TEC_NULL;
}
Exemple #19
0
void player::melee_special_effects(game *g, monster *z, player *p, bool crit,
                                   int &bash_dam, int &cut_dam, int &stab_dam)
{
 if (z == NULL && p == NULL)
  return;
 bool mon = (z != NULL);
 int junk;
 bool is_u = (!is_npc());
 bool can_see = (is_u || g->u_see(posx, posy, junk));
 std::string You = (is_u ? "You" : name);
 std::string Your = (is_u ? "Your" : name + "'s");
 std::string your = (is_u ? "your" : name + "'s");
 std::string target = (mon ? "the " + z->name() :
                       (p->is_npc() ? p->name : "you"));
 std::string target_possessive = (mon ? "the " + z->name() + "'s" :
                                  (p->is_npc() ? p->name + "'s" : your));
 int tarposx = (mon ? z->posx : p->posx), tarposy = (mon ? z->posy : p->posy);

// Bashing effecs
 if (mon)
  z->moves -= rng(0, bash_dam * 2);
 else
  p->moves -= rng(0, bash_dam * 2);

// Bashing crit
 if (crit && !unarmed_attack()) {
  int turns_stunned = int(bash_dam / 20) + rng(0, int(skillLevel("bashing") / 2));
  if (turns_stunned > 6)
   turns_stunned = 6;
  if (turns_stunned > 0) {
   if (mon)
    z->add_effect(ME_STUNNED, turns_stunned);
   else
    p->add_disease(DI_STUNNED, 1 + turns_stunned / 2, g);
  }
 }

// Stabbing effects
 int stab_moves = rng(stab_dam / 2, stab_dam * 1.5);
 if (crit)
  stab_moves *= 1.5;
 if (stab_moves >= 150) {
  if (can_see)
   g->add_msg("%s force%s the %s to the ground!", You.c_str(),
              (is_u ? "" : "s"), target.c_str());
  if (mon) {
   z->add_effect(ME_DOWNED, 1);
   z->moves -= stab_moves / 2;
  } else {
   p->add_disease(DI_DOWNED, 1, g);
   p->moves -= stab_moves / 2;
  }
 } else if (mon)
  z->moves -= stab_moves;
 else
  p->moves -= stab_moves;

// Bonus attacks!
 bool shock_them = (has_bionic("bio_shock") && power_level >= 2 &&
                    unarmed_attack() && (!mon || !z->has_flag(MF_ELECTRIC)) &&
                    one_in(3));

 bool drain_them = (has_bionic("bio_heat_absorb") && power_level >= 1 &&
                    !is_armed() && (!mon || z->has_flag(MF_WARM)));

 if (drain_them)
  power_level--;
 drain_them &= one_in(2);	// Only works half the time

 if (shock_them) {
  power_level -= 2;
  int shock = rng(2, 5);
  if (mon) {
   z->hurt( shock * rng(1, 3) );
   z->moves -= shock * 180;
   if (can_see)
    g->add_msg("%s shock%s %s!", You.c_str(), (is_u ? "" : "s"),
               target.c_str());
  } else {
   p->hurt(g, bp_torso, 0, shock * rng(1, 3));
   p->moves -= shock * 80;
  }
 }

 if (drain_them) {
  charge_power(rng(0, 4));
  if (can_see)
   g->add_msg("%s drain%s %s body heat!", You.c_str(), (is_u ? "" : "s"),
               target_possessive.c_str());
  if (mon) {
   z->moves -= rng(80, 120);
   z->speed -= rng(4, 6);
  } else
   p->moves -= rng(80, 120);
 }

 bool conductive = !wearing_something_on(bp_hands) && weapon.conductive();

 if (mon && z->has_flag(MF_ELECTRIC) && conductive) {
  hurtall(rng(0, 1));
  moves -= rng(0, 50);
  if (is_u)
   g->add_msg("Contact with the %s shocks you!", z->name().c_str());
 }

// Glass weapons shatter sometimes
 if (weapon.made_of(GLASS) &&
     rng(0, weapon.volume() + 8) < weapon.volume() + str_cur) {
  if (can_see)
   g->add_msg("%s %s shatters!", Your.c_str(), weapon.tname(g).c_str());
  g->sound(posx, posy, 16, "");
// Dump its contents on the ground
  for (int i = 0; i < weapon.contents.size(); i++)
   g->m.add_item(posx, posy, weapon.contents[i]);
  hit(g, bp_arms, 1, 0, rng(0, weapon.volume() * 2));// Take damage
  if (weapon.is_two_handed(this))// Hurt left arm too, if it was big
   hit(g, bp_arms, 0, 0, rng(0, weapon.volume()));
  cut_dam += rng(0, 5 + int(weapon.volume() * 1.5));// Hurt the monster extra
  remove_weapon();
 }

// Getting your weapon stuck
 int cutting_penalty = roll_stuck_penalty(z, stab_dam > cut_dam);
 if (weapon.has_flag(IF_MESSY)) { // e.g. chainsaws
  cutting_penalty /= 6; // Harder to get stuck
  for (int x = tarposx - 1; x <= tarposx + 1; x++) {
   for (int y = tarposy - 1; y <= tarposy + 1; y++) {
    if (!one_in(3)) {
     if (g->m.field_at(x, y).type == fd_blood &&
         g->m.field_at(x, y).density < 3)
      g->m.field_at(x, y).density++;
     else
      g->m.add_field(g, x, y, fd_blood, 1);
    }
   }
  }
 }
 if (!unarmed_attack() && cutting_penalty > dice(str_cur * 2, 20)) {
  if (is_u)
   g->add_msg("Your %s gets stuck in %s, pulling it out of your hands!",
              weapon.tname().c_str(), target.c_str());
  if (mon) {
   if (weapon.has_flag(IF_SPEAR) || weapon.has_flag(IF_STAB))
    z->speed *= .7;
   else
    z->speed *= .85;
   z->add_item(remove_weapon());
  } else
   g->m.add_item(posx, posy, remove_weapon());
 } else {
  if (mon && (cut_dam >= z->hp || stab_dam >= z->hp)) {
   cutting_penalty /= 2;
   cutting_penalty -= rng(skillLevel("cutting"), skillLevel("cutting") * 2 + 2);
  }
  if (cutting_penalty > 0)
   moves -= cutting_penalty;
  if (cutting_penalty >= 50 && is_u)
   g->add_msg("Your %s gets stuck in %s, but you yank it free.",
              weapon.tname().c_str(), target.c_str());
  if (mon && (weapon.has_flag(IF_SPEAR) || weapon.has_flag(IF_STAB)))
   z->speed *= .9;
 }

// Finally, some special effects for martial arts
 if(weapon.typeId() == "style_karate"){
   dodges_left++;
   blocks_left += 2;
 } else if(weapon.typeId() == "style_aikido"){
   bash_dam /= 2;
 } else if(weapon.typeId() == "style_capoeira"){
   add_disease(DI_DODGE_BOOST, 2, g, 2);
 } else if(weapon.typeId() == "style_muay_thai"){
   if ((mon && z->type->size >= MS_LARGE) || (!mon && p->str_max >= 12))
    bash_dam += rng((mon ? z->type->size : (p->str_max - 8) / 4),
                    3 * (mon ? z->type->size : (p->str_max - 8) / 4));
 } else if(weapon.typeId() == "style_tiger"){
   add_disease(DI_DAMAGE_BOOST, 2, g, 2, 10);
 } else if(weapon.typeId() == "style_centipede"){
   add_disease(DI_SPEED_BOOST, 2, g, 4, 40);
 } else if(weapon.typeId() == "style_venom_snake"){
   if (has_disease(DI_VIPER_COMBO)) {
    if (disease_intensity(DI_VIPER_COMBO) == 1) {
     if (is_u)
      g->add_msg("Snakebite!");
     int dambuf = bash_dam;
     bash_dam = stab_dam;
     stab_dam = dambuf;
     add_disease(DI_VIPER_COMBO, 2, g, 1, 2); // Upgrade to Viper Strike
    } else if (disease_intensity(DI_VIPER_COMBO) == 2) {
     if (hp_cur[hp_arm_l] >= hp_max[hp_arm_l] * .75 &&
         hp_cur[hp_arm_r] >= hp_max[hp_arm_r] * .75   ) {
      if (is_u)
       g->add_msg("Viper STRIKE!");
      bash_dam *= 3;
     } else if (is_u)
      g->add_msg("Your injured arms prevent a viper strike!");
     rem_disease(DI_VIPER_COMBO);
    }
   } else if (crit) {
    if (is_u)
     g->add_msg("Tail whip!  Viper Combo Intiated!");
    bash_dam += 5;
    add_disease(DI_VIPER_COMBO, 2, g, 1, 2);
   }
 } else if(weapon.typeId() == "style_scorpion"){
   if (crit) {
    if (!is_npc())
     g->add_msg("Stinger Strike!");
    if (mon) {
     z->add_effect(ME_STUNNED, 3);
     int zposx = z->posx, zposy = z->posy;
     z->knock_back_from(g, posx, posy);
     if (z->posx != zposx || z->posy != zposy)
      z->knock_back_from(g, posx, posy); // Knock a 2nd time if the first worked
    } else {
     p->add_disease(DI_STUNNED, 2, g);
     int pposx = p->posx, pposy = p->posy;
     p->knock_back_from(g, posx, posy);
     if (p->posx != pposx || p->posy != pposy)
      p->knock_back_from(g, posx, posy); // Knock a 2nd time if the first worked
    }
   }
 } else if(weapon.typeId() == "style_zui_quan"){
   dodges_left = 50; // Basically, unlimited.
 }
}
Exemple #20
0
bool player::install_bionics(game *g, it_bionic* type)
{
 if (type == NULL) {
  debugmsg("Tried to install NULL bionic");
  return false;
 }
 std::string bio_name = type->name.substr(5);	// Strip off "CBM: "

 WINDOW* w = newwin(FULL_SCREEN_HEIGHT, FULL_SCREEN_WIDTH, (TERMY > FULL_SCREEN_HEIGHT) ? (TERMY-FULL_SCREEN_HEIGHT)/2 : 0, (TERMX > FULL_SCREEN_WIDTH) ? (TERMX-FULL_SCREEN_WIDTH)/2 : 0);
 WINDOW* w_description = newwin(3, FULL_SCREEN_WIDTH-2, 21 + getbegy(w), 1 + getbegx(w));

 werase(w);
 wborder(w, LINE_XOXO, LINE_XOXO, LINE_OXOX, LINE_OXOX,
            LINE_OXXO, LINE_OOXX, LINE_XXOO, LINE_XOOX );

 int pl_skill = int_cur +
   skillLevel("electronics") * 4 +
   skillLevel("firstaid")    * 3 +
   skillLevel("mechanics")   * 2;

 int skint = int(pl_skill / 4);
 int skdec = int((pl_skill * 10) / 4) % 10;

// Header text
 mvwprintz(w, 1,  1, c_white, "Installing bionics:");
 mvwprintz(w, 1, 21, type->color, bio_name.c_str());

// Dividing bars
 for (int i = 1; i < 79; i++) {
  mvwputch(w,  2, i, c_ltgray, LINE_OXOX);
  mvwputch(w, 20, i, c_ltgray, LINE_OXOX);
 }

 mvwputch(w, 2,  0, c_ltgray, LINE_XXXO); // |-
 mvwputch(w, 2, 79, c_ltgray, LINE_XOXX); // -|

 mvwputch(w, 20,  0, c_ltgray, LINE_XXXO); // |-
 mvwputch(w, 20, 79, c_ltgray, LINE_XOXX); // -|

// Init the list of bionics
 for (int i = 1; i < type->options.size(); i++) {
  bionic_id bio_id = type->options[i];
  mvwprintz(w, i + 3, 1, (has_bionic(bio_id) ? c_ltred : c_ltblue),
            bionics[bio_id]->name.c_str());
 }
// Helper text
 mvwprintz(w, 3, 39, c_white,        "Difficulty of this module: %d",
           type->difficulty);
 mvwprintz(w, 4, 39, c_white,        "Your installation skill:   %d.%d",
           skint, skdec);
 mvwprintz(w, 5, 39, c_white,       "Installation requires high intelligence,");
 mvwprintz(w, 6, 39, c_white,       "and skill in electronics, first aid, and");
 mvwprintz(w, 7, 39, c_white,       "mechanics (in that order of importance).");

 int chance_of_success = int((100 * pl_skill) /
                             (pl_skill + 4 * type->difficulty));

 mvwprintz(w, 9, 39, c_white,        "Chance of success:");

 nc_color col_suc;
 if (chance_of_success >= 95)
  col_suc = c_green;
 else if (chance_of_success >= 80)
  col_suc = c_ltgreen;
 else if (chance_of_success >= 60)
  col_suc = c_yellow;
 else if (chance_of_success >= 35)
  col_suc = c_ltred;
 else
  col_suc = c_red;

 mvwprintz(w, 9, 59, col_suc, "%d%%%%", chance_of_success);

 mvwprintz(w, 11, 39, c_white,       "Failure may result in crippling damage,");
 mvwprintz(w, 12, 39, c_white,       "loss of existing bionics, genetic damage");
 mvwprintz(w, 13, 39, c_white,       "or faulty installation.");
 wrefresh(w);

 if (type->id == "bio_power_storage" || type->id == "bio_power_storage_mkII") { // No selection list; just confirm
   int pow_up = BATTERY_AMOUNT;

   if (type->id == "bio_power_storage_mkII") {
     pow_up = 10;
   }

  mvwprintz(w, 3, 1, h_ltblue, "Power Storage +%d", pow_up);
  mvwprintz(w_description, 0, 0, c_ltblue, "\
Installing this bionic will increase your total power storage by %d.\n\
Power is necessary for most bionics to function. You also require a\n\
charge mechanism, which must be installed from another CBM.", pow_up);

  InputEvent input;
  wrefresh(w_description);
  wrefresh(w);
  do
   input = get_input();
  while (input != Confirm && input != Cancel);
  if (input == Confirm) {
   practice(g->turn, "electronics", (100 - chance_of_success) * 1.5);
   practice(g->turn, "firstaid", (100 - chance_of_success) * 1.0);
   practice(g->turn, "mechanics", (100 - chance_of_success) * 0.5);
   int success = chance_of_success - rng(1, 100);
   if (success > 0) {
    g->add_msg("Successfully installed batteries.");
    max_power_level += pow_up;
   } else
    bionics_install_failure(g, this, success);
   werase(w);
   delwin(w);
   g->refresh_all();
   return true;
  }
  werase(w);
  delwin(w);
  g->refresh_all();
  return false;
 }
Exemple #21
0
technique_id player::pick_technique(game *g, monster *z, player *p,
                                    bool crit, bool allowgrab)
{
 if (z == NULL && p == NULL)
  return TEC_NULL;

 std::vector<technique_id> possible;
 bool downed = ((z && !z->has_effect(ME_DOWNED)) ||
                (p && !p->has_disease(DI_DOWNED))  );
 int base_str_req = 0;

 if (z)
  base_str_req = z->type->size;
 else if (p)
  base_str_req = 1 + (2 + p->str_cur) / 4;

 if (allowgrab) { // Check if grabs AREN'T REALLY ALLOWED
  if (z && z->has_flag(MF_PLASTIC))
   allowgrab = false;
 }

 if (crit) { // Some are crit-only

  if (weapon.has_technique(TEC_SWEEP, this) &&
      (!z || !z->has_flag(MF_FLIES)) && !downed)
   possible.push_back(TEC_SWEEP);

  if (weapon.has_technique(TEC_PRECISE, this))
   possible.push_back(TEC_PRECISE);

  if (weapon.has_technique(TEC_BRUTAL, this) && !downed &&
      str_cur + skillLevel("melee") >= 4 + base_str_req)
   possible.push_back(TEC_BRUTAL);

 }

 if (possible.empty()) { // Use non-crits only if any crit-onlies aren't used

  if (weapon.has_technique(TEC_DISARM, this) && !z &&
      p->weapon.typeId() != "null" && !p->weapon.has_flag(IF_UNARMED_WEAPON) &&
      dice(   dex_cur +    skillLevel("unarmed"),  8) >
      dice(p->dex_cur + p->skillLevel("melee"),   10))
   possible.push_back(TEC_DISARM);

  if (weapon.has_technique(TEC_GRAB, this) && allowgrab)
   possible.push_back(TEC_GRAB);

  if (weapon.has_technique(TEC_RAPID, this))
   possible.push_back(TEC_RAPID);

  if (weapon.has_technique(TEC_THROW, this) && !downed &&
      str_cur + skillLevel("melee") >= 4 + base_str_req * 4 + rng(-4, 4))
   possible.push_back(TEC_THROW);

  if (weapon.has_technique(TEC_WIDE, this)) { // Count monsters
   int enemy_count = 0;
   for (int x = posx - 1; x <= posx + 1; x++) {
    for (int y = posy - 1; y <= posy + 1; y++) {
     int mondex = g->mon_at(x, y);
     if (mondex != -1) {
      if (g->z[mondex].friendly == 0)
       enemy_count++;
      else
       enemy_count -= 2;
     }
     int npcdex = g->npc_at(x, y);
     if (npcdex != -1) {
      if (g->active_npc[npcdex].attitude == NPCATT_KILL)
       enemy_count++;
      else
       enemy_count -= 2;
     }
    }
   }
   if (enemy_count >= (possible.empty() ? 2 : 3)) {
    possible.push_back(TEC_WIDE);
   }
  }
 } // if (possible.empty())

 if (possible.empty())
  return TEC_NULL;

 possible.push_back(TEC_NULL); // Always a chance to not use any technique

 return possible[ rng(0, possible.size() - 1) ];
}
Exemple #22
0
void player::hit_player(game *g, player &p, bool allow_grab)
{
 bool is_u = (this == &(g->u));	// Affects how we'll display messages

 if (is_u && p.is_npc()) {
  npc* npcPtr = dynamic_cast<npc*>(&p);
  npcPtr->make_angry();
 }

 std::string You  = (is_u ? "You"  : name);
 std::string Your = (is_u ? "Your" : name + "'s");
 std::string your = (is_u ? "your" : (male ? "his" : "her"));
 std::string verb = "hit";

// Divide their dodge roll by 2 if this is a grab
 int target_dodge = (allow_grab ? p.dodge_roll(g) : p.dodge_roll(g) / 2);
 int hit_value = hit_roll() - target_dodge;
 bool missed = (hit_roll() <= 0);

 int move_cost = attack_speed(*this, missed);

 if (missed) {
  int stumble_pen = stumble(*this);
  if (is_u) {	// Only display messages if this is the player
   if (weapon.has_technique(TEC_FEINT, this))
    g->add_msg("You feint.");
   else if (stumble_pen >= 60)
    g->add_msg("You miss and stumble with the momentum.");
   else if (stumble_pen >= 10)
    g->add_msg("You swing wildly and miss.");
   else
    g->add_msg("You miss.");
  }
  melee_practice(*this, false, unarmed_attack(),
                 weapon.is_bashing_weapon(), weapon.is_cutting_weapon(),
                 (weapon.has_flag(IF_SPEAR) || weapon.has_flag(IF_STAB)));
  move_cost += stumble_pen;
  if (weapon.has_technique(TEC_FEINT, this))
   move_cost = rng(move_cost / 3, move_cost);
  moves -= move_cost;
  return;
 }
 moves -= move_cost;

 body_part bp_hit;
 int side = rng(0, 1);
 hit_value += rng(-10, 10);
 if (hit_value >= 30)
  bp_hit = bp_eyes;
 else if (hit_value >= 20)
  bp_hit = bp_head;
 else if (hit_value >= 10)
  bp_hit = bp_torso;
 else if (one_in(4))
  bp_hit = bp_legs;
 else
  bp_hit = bp_arms;

 std::string target = (p.is_npc() ? p.name + "'s " : "your ");
 target += body_part_name(bp_hit, side);

 bool critical_hit = scored_crit(target_dodge);

 int bash_dam = roll_bash_damage(NULL, critical_hit);
 int cut_dam  = roll_cut_damage(NULL, critical_hit);
 int stab_dam = roll_stab_damage(NULL, critical_hit);

 technique_id tech_def = p.pick_defensive_technique(g, NULL, this);
 p.perform_defensive_technique(tech_def, g, NULL, this, bp_hit, side,
                               bash_dam, cut_dam, stab_dam);

 if (bash_dam + cut_dam + stab_dam <= 0)
  return; // Defensive technique canceled our attack!

 if (critical_hit) // Crits cancel out Toad Style's armor boost
  p.rem_disease(DI_ARMOR_BOOST);

 int pain = 0; // Boost to pain; required for perform_technique

// Moves lost to getting your weapon stuck
 int stuck_penalty = roll_stuck_penalty(NULL, (stab_dam >= cut_dam));
 if (weapon.is_style())
  stuck_penalty = 0;

// Pick one or more special attacks
 technique_id technique = pick_technique(g, NULL, &p, critical_hit, allow_grab);

// Handles effects as well; not done in melee_affect_*
 perform_technique(technique, g, NULL, &p, bash_dam, cut_dam, stab_dam, pain);
 p.pain += pain;

// Mutation-based attacks
 perform_special_attacks(g, NULL, &p, bash_dam, cut_dam, stab_dam);

// Handles speed penalties to monster & us, etc
 melee_special_effects(g, NULL, &p, critical_hit, bash_dam, cut_dam, stab_dam);

// Make a rather quiet sound, to alert any nearby monsters
 if (weapon.typeId() != "style_ninjutsu") // Ninjutsu is silent!
  g->sound(posx, posy, 8, "");

 p.hit(g, bp_hit, side, bash_dam, (cut_dam > stab_dam ? cut_dam : stab_dam));

 verb = melee_verb(technique, your, *this, bash_dam, cut_dam, stab_dam);
 int dam = bash_dam + (cut_dam > stab_dam ? cut_dam : stab_dam);
 hit_message(g, You.c_str(), verb.c_str(), target.c_str(), dam, critical_hit);

 bool bashing = (bash_dam >= 10 && !unarmed_attack());
 bool cutting = (cut_dam >= 10 && cut_dam >= stab_dam);
 bool stabbing = (stab_dam >= 10 && stab_dam >= cut_dam);
 melee_practice(*this, true, unarmed_attack(), bashing, cutting, stabbing);

 if (dam >= 5 && has_artifact_with(AEP_SAP_LIFE))
  healall( rng(dam / 10, dam / 5) );

 if (allow_grab && technique == TEC_GRAB) {
// Move our weapon to a temp slot, if it's not unarmed
  if (p.weapon.has_technique(TEC_BREAK, &p) &&
      dice(p.dex_cur + p.skillLevel("melee"), 12) >
      dice(dex_cur + skillLevel("melee"), 10)) {
   if (is_u)
    g->add_msg("%s break%s the grab!", target.c_str(), (p.is_npc() ? "s" : ""));
  } else if (!unarmed_attack()) {
   item tmpweap = remove_weapon();
   hit_player(g, p, false); // False means a second grab isn't allowed
   weapon = tmpweap;
  } else
   hit_player(g, p, false); // False means a second grab isn't allowed
 }
 if (tech_def == TEC_COUNTER) {
  if (!p.is_npc())
   g->add_msg("Counter-attack!");
  p.hit_player(g, *this);
 }
}
bool player::create(game *g, character_type type, std::string tempname)
{
 weapon = item(g->itypes["null"], 0);

 g->u.prof = profession::generic();

 WINDOW* w = newwin(FULL_SCREEN_HEIGHT, FULL_SCREEN_WIDTH,
                    (TERMY > FULL_SCREEN_HEIGHT) ? (TERMY-FULL_SCREEN_HEIGHT)/2 : 0,
                    (TERMX > FULL_SCREEN_WIDTH) ? (TERMX-FULL_SCREEN_WIDTH)/2 : 0);

 int tab = 0, points = 38, max_trait_points = 12;
 if (type != PLTYPE_CUSTOM) {
  switch (type) {
   case PLTYPE_RANDOM: {
    str_max = rng(6, 12);
    dex_max = rng(6, 12);
    int_max = rng(6, 12);
    per_max = rng(6, 12);
    points = points - str_max - dex_max - int_max - per_max;
    if (str_max > HIGH_STAT)
     points -= (str_max - HIGH_STAT);
    if (dex_max > HIGH_STAT)
     points -= (dex_max - HIGH_STAT);
    if (int_max > HIGH_STAT)
     points -= (int_max - HIGH_STAT);
    if (per_max > HIGH_STAT)
     points -= (per_max - HIGH_STAT);

    int num_gtraits = 0, num_btraits = 0, rn, tries;
    while (points < 0 || rng(-3, 20) > points) {
     if (num_btraits < max_trait_points && one_in(3)) {
      tries = 0;
      do {
       rn = random_bad_trait();
       tries++;
      } while ((has_trait(rn) ||
              num_btraits - traits[rn].points > max_trait_points) && tries < 5);
      if (tries < 5) {
       toggle_trait(rn);
       points -= traits[rn].points;
       num_btraits -= traits[rn].points;
      }
     } else {
      switch (rng(1, 4)) {
       case 1: if (str_max > 5) { str_max--; points++; } break;
       case 2: if (dex_max > 5) { dex_max--; points++; } break;
       case 3: if (int_max > 5) { int_max--; points++; } break;
       case 4: if (per_max > 5) { per_max--; points++; } break;
      }
     }
    }
    while (points > 0) {
     switch (rng((num_gtraits < max_trait_points ? 1 : 5), 9)) {
     case 1:
     case 2:
     case 3:
     case 4:
      rn = random_good_trait();
      if (!has_trait(rn) && points >= traits[rn].points &&
          num_gtraits + traits[rn].points <= max_trait_points) {
       toggle_trait(rn);
       points -= traits[rn].points;
       num_gtraits += traits[rn].points;
      }
      break;
     case 5:
      switch (rng(1, 4)) {
       case 1: if (str_max < HIGH_STAT) { str_max++; points--; } break;
       case 2: if (dex_max < HIGH_STAT) { dex_max++; points--; } break;
       case 3: if (int_max < HIGH_STAT) { int_max++; points--; } break;
       case 4: if (per_max < HIGH_STAT) { per_max++; points--; } break;
      }
      break;
     case 6:
     case 7:
     case 8:
     case 9:
      rn = random_skill();

      Skill *aSkill = Skill::skill(rn);
      int level = skillLevel(aSkill);

      if (level < points) {
        points -= level + 1;
        skillLevel(aSkill).level(level + 2);
      }
      break;
     }
    }
   } break;
   case PLTYPE_TEMPLATE: {
    std::ifstream fin;
    std::stringstream filename;
    filename << "data/" << tempname << ".template";
    fin.open(filename.str().c_str());
    if (!fin.is_open()) {
     debugmsg("Couldn't open %s!", filename.str().c_str());
     return false;
    }
    std::string(data);
    getline(fin, data);
    load_info(g, data);
    points = 0;
   } break;
  }
  tab = NEWCHAR_TAB_MAX;
 } else
  points = OPTIONS[OPT_INITIAL_POINTS];
  max_trait_points = OPTIONS[OPT_MAX_TRAIT_POINTS];

 do {
  werase(w);
  wrefresh(w);
  switch (tab) {
   case 0: tab += set_stats      (w, g, this, points); break;
   case 1: tab += set_traits     (w, g, this, points, max_trait_points); break;
   case 2: tab += set_profession (w, g, this, points); break;
   case 3: tab += set_skills     (w, g, this, points); break;
   case 4: tab += set_description(w, g, this, points); break;
  }
 } while (tab >= 0 && tab <= NEWCHAR_TAB_MAX);
 delwin(w);

 if (tab < 0)
  return false;

 // Character is finalized.  Now just set up HP, &c
 for (int i = 0; i < num_hp_parts; i++) {
  hp_max[i] = calc_HP(str_max, has_trait(PF_TOUGH));
  hp_cur[i] = hp_max[i];
 }
 if (has_trait(PF_HARDCORE)) {
  for (int i = 0; i < num_hp_parts; i++) {
   hp_max[i] = int(hp_max[i] * .25);
   hp_cur[i] = hp_max[i];
  }
 } if (has_trait(PF_GLASSJAW)) {
  hp_max[hp_head] = int(hp_max[hp_head] * .80);
  hp_cur[hp_head] = hp_max[hp_head];
 }
 if (has_trait(PF_SMELLY))
  scent = 800;
 if (has_trait(PF_ANDROID)) {
  bionic_id first_bio;
  do {
   first_bio = g->random_good_bionic();
  } while (bionics[first_bio]->power_cost > 10);
  add_bionic(first_bio);
  add_bionic(bionic_id(power_source_bionics[rng(0,power_source_bionics.size()-1)]));	// Power Source
  max_power_level = 10;
  power_level = 10;
 }

 if (has_trait(PF_MARTIAL_ARTS)) {
  itype_id ma_type;
  do {
   int choice = menu(false, _("Pick your style:"),
                     _("Karate"), _("Judo"), _("Aikido"), _("Tai Chi"),
                     _("Taekwondo"), NULL);
   if (choice == 1)
    ma_type = "style_karate";
   if (choice == 2)
    ma_type = "style_judo";
   if (choice == 3)
    ma_type = "style_aikido";
   if (choice == 4)
    ma_type = "style_tai_chi";
   if (choice == 5)
    ma_type = "style_taekwondo";
   item tmpitem = item(g->itypes[ma_type], 0);
   full_screen_popup(tmpitem.info(true).c_str());
  } while (!query_yn(_("Use this style?")));
  styles.push_back(ma_type);
  style_selected=ma_type;
 }

    if (has_trait(PF_MARTIAL_ARTS2)) {
  itype_id ma_type;
  do {
   int choice = menu(false, _("Pick your style:"),
                     _("Capoeira"), _("Krav Maga"), _("Muay Thai"),
                     _("Ninjutsu"), _("Zui Quan"), NULL);
   if (choice == 1)
    ma_type = "style_capoeira";
   if (choice == 2)
    ma_type = "style_krav_maga";
   if (choice == 3)
    ma_type = "style_muay_thai";
   if (choice == 4)
    ma_type = "style_ninjutsu";
   if (choice == 5)
    ma_type = "style_zui_quan";
   item tmpitem = item(g->itypes[ma_type], 0);
   full_screen_popup(tmpitem.info(true).c_str());
  } while (!query_yn(_("Use this style?")));
  styles.push_back(ma_type);
  style_selected=ma_type;
 }
 if (has_trait(PF_MARTIAL_ARTS3)) {
  itype_id ma_type;
  do {
   int choice = menu(false, _("Pick your style:"),
                     _("Tiger"), _("Crane"), _("Leopard"), _("Snake"),
                     _("Dragon"), NULL);
   if (choice == 1)
    ma_type = "style_tiger";
   if (choice == 2)
    ma_type = "style_crane";
   if (choice == 3)
    ma_type = "style_leopard";
   if (choice == 4)
    ma_type = "style_snake";
   if (choice == 5)
    ma_type = "style_dragon";
   item tmpitem = item(g->itypes[ma_type], 0);
   full_screen_popup(tmpitem.info(true).c_str());
  } while (!query_yn(_("Use this style?")));
  styles.push_back(ma_type);
  style_selected=ma_type;
 }
 if (has_trait(PF_MARTIAL_ARTS4)) {
  itype_id ma_type;
  do {
   int choice = menu(false, _("Pick your style:"),
                     _("Centipede"), _("Viper"), _("Scorpion"), _("Lizard"),
                     _("Toad"), NULL);
   if (choice == 1)
    ma_type = "style_centipede";
   if (choice == 2)
    ma_type = "style_venom_snake";
   if (choice == 3)
    ma_type = "style_scorpion";
   if (choice == 4)
    ma_type = "style_lizard";
   if (choice == 5)
    ma_type = "style_toad";
   item tmpitem = item(g->itypes[ma_type], 0);
   full_screen_popup(tmpitem.info(true).c_str());
  } while (!query_yn(_("Use this style?")));
  styles.push_back(ma_type);
  style_selected=ma_type;
 }
 ret_null = item(g->itypes["null"], 0);
 weapon = get_combat_style();
 
 
 item tmp; //gets used several times

 std::vector<std::string> prof_items = g->u.prof->items();
 for (std::vector<std::string>::const_iterator iter = prof_items.begin(); iter != prof_items.end(); ++iter)
 {
    tmp = item(item_controller->find_template(*iter), 0);
    inv.push_back(tmp);
 }

 std::vector<addiction> prof_addictions = g->u.prof->addictions();
 for (std::vector<addiction>::const_iterator iter = prof_addictions.begin(); iter != prof_addictions.end(); ++iter)
 {
     g->u.addictions.push_back(*iter);
 }

 // Grab the skills from the profession, if there are any
 profession::StartingSkillList prof_skills = g->u.prof->skills();
 for (profession::StartingSkillList::const_iterator iter = prof_skills.begin(); 
      iter != prof_skills.end(); ++iter)
 {
     assert(Skill::skill(iter->first));
     if (Skill::skill(iter->first))
     {
        g->u.boost_skill_level(iter->first, iter->second);
     }
 }

 // Those who are both near-sighted and far-sighted start with bifocal glasses.
 if (has_trait(PF_HYPEROPIC) && has_trait(PF_MYOPIC))
 {
    tmp = item(g->itypes["glasses_bifocal"], 0);
    inv.push_back(tmp);
 }
 // The near-sighted start with eyeglasses.
 else if (has_trait(PF_MYOPIC))
 {
    tmp = item(g->itypes["glasses_eye"], 0);
    inv.push_back(tmp);
 }
 // The far-sighted start with reading glasses.
 else if (has_trait(PF_HYPEROPIC))
 {
    tmp = item(g->itypes["glasses_reading"], 0);
    inv.push_back(tmp);
 }

// Likewise, the asthmatic start with their medication.
 if (has_trait(PF_ASTHMA)) {
  tmp = item(g->itypes["inhaler"], 0);
  inv.push_back(tmp);
 }
// Basic starter gear, added independently of profession.
 tmp = item(g->itypes["pockknife"], 0);
  inv.push_back(tmp);
 tmp = item(g->itypes["matches"], 0);
  inv.push_back(tmp);
// make sure we have no mutations
 for (int i = 0; i < PF_MAX2; i++)
  if (!has_base_trait(i))
	my_mutations[i] = false;
	
	// Equip any armor from our inventory. If we are unable to wear some of it due to encumberance, it will silently fail.
    std::vector<item*> tmp_inv;
    inv.dump(tmp_inv);
    
    for(std::vector<item*>::iterator i = tmp_inv.begin(); i != tmp_inv.end(); ++i)
    {
        if( (*i)->is_armor())
        {
            if( (*i)->has_flag("VARSIZE"))
            {
                (*i)->item_tags.insert("FIT");
            }
            // It might be more elegant to use player::wear_item, but then we have to implement our own inventory removal.
            wear(g, (*i)->invlet, false);
        }
    }

 // Ensure that persistent morale effects (e.g. Optimist) are present at the start.
 apply_persistent_morale();
 return true;
}
Exemple #24
0
bool player::scored_crit(int target_dodge)
{
 int num_crits = 0;

// Weapon to-hit roll
 int chance = 25;
 if (unarmed_attack()) { // Unarmed attack: 1/2 of unarmed skill is to-hit
  for (int i = 1; i <= int(skillLevel("unarmed") * .5); i++)
   chance += (50 / (2 + i));
 }
 if (weapon.type->m_to_hit > 0) {
  for (int i = 1; i <= weapon.type->m_to_hit; i++)
   chance += (50 / (2 + i));
 } else if (chance < 0) {
  for (int i = 0; i > weapon.type->m_to_hit; i--)
   chance /= 2;
 }
 if (rng(0, 99) < chance + 4 * disease_intensity(DI_ATTACK_BOOST))
  num_crits++;

// Dexterity to-hit roll
// ... except sometimes we don't use dexteiry!
 int stat = dex_cur;
// Some martial arts use something else to determine hits!
 if(weapon.typeId() == "style_tiger"){
   stat = (str_cur * 2 + dex_cur) / 3;
 } else if(weapon.typeId() == "style_leopard"){
   stat = (per_cur + int_cur + dex_cur * 2) / 4;
 } else if(weapon.typeId() == "style_snake"){
   stat = (per_cur + dex_cur) / 2;
 }
 chance = 25;
 if (stat > 8) {
  for (int i = 9; i <= stat; i++)
   chance += (21 - i); // 12, 11, 10...
 } else {
  int decrease = 5;
  for (int i = 7; i >= stat; i--) {
   chance -= decrease;
   if (i % 2 == 0)
    decrease--;
  }
 }
 if (rng(0, 99) < chance)
  num_crits++;

// Skill level roll
 int best_skill = 0;

 if (weapon.is_bashing_weapon() && skillLevel("bashing") > best_skill)
  best_skill = skillLevel("bashing");
 if (weapon.is_cutting_weapon() && skillLevel("cutting") > best_skill)
  best_skill = skillLevel("cutting");
 if ((weapon.has_flag(IF_SPEAR) || weapon.has_flag(IF_STAB)) &&
     skillLevel("stabbing") > best_skill)
  best_skill = skillLevel("stabbing");
 if (unarmed_attack() && skillLevel("unarmed") > best_skill)
  best_skill = skillLevel("unarmed");

 best_skill += int(skillLevel("melee") / 2.5);

 chance = 25;
 if (best_skill > 3) {
  for (int i = 3; i < best_skill; i++)
   chance += (50 / (2 + i));
 } else if (chance < 3) {
  for (int i = 3; i > best_skill; i--)
   chance /= 2;
 }
 if (rng(0, 99) < chance + 4 * disease_intensity(DI_ATTACK_BOOST))
  num_crits++;

 if (num_crits == 3)
  return true;
 else if (num_crits == 2)
  return (hit_roll() >= target_dodge * 1.5 && !one_in(4));

 return false;
}
bool player::create(game *g, character_type type, std::string tempname)
{
 weapon = item(g->itypes[0], 0);

 int iMaxX = (g->VIEWX < 12) ? 80 : (g->VIEWX*2)+56;
 int iMaxY = (g->VIEWY < 12) ? 25 : (g->VIEWY*2)+1;

 WINDOW* w = newwin(25, 80, (iMaxY > 25) ? (iMaxY-25)/2 : 0, (iMaxX > 80) ? (iMaxX-80)/2 : 0);

 int tab = 0, points = 38;
 if (type != PLTYPE_CUSTOM) {
  switch (type) {
   case PLTYPE_RANDOM: {
    str_max = rng(6, 12);
    dex_max = rng(6, 12);
    int_max = rng(6, 12);
    per_max = rng(6, 12);
    points = points - str_max - dex_max - int_max - per_max;
    if (str_max > HIGH_STAT)
     points -= (str_max - HIGH_STAT);
    if (dex_max > HIGH_STAT)
     points -= (dex_max - HIGH_STAT);
    if (int_max > HIGH_STAT)
     points -= (int_max - HIGH_STAT);
    if (per_max > HIGH_STAT)
     points -= (per_max - HIGH_STAT);

    int num_gtraits = 0, num_btraits = 0, rn, tries;
    while (points < 0 || rng(-3, 20) > points) {
     if (num_btraits < MAX_TRAIT_POINTS && one_in(3)) {
      tries = 0;
      do {
       rn = random_bad_trait();
       tries++;
      } while ((has_trait(rn) ||
              num_btraits - traits[rn].points > MAX_TRAIT_POINTS) && tries < 5);
      if (tries < 5) {
       toggle_trait(rn);
       points -= traits[rn].points;
       num_btraits -= traits[rn].points;
      }
     } else {
      switch (rng(1, 4)) {
       case 1: if (str_max > 5) { str_max--; points++; } break;
       case 2: if (dex_max > 5) { dex_max--; points++; } break;
       case 3: if (int_max > 5) { int_max--; points++; } break;
       case 4: if (per_max > 5) { per_max--; points++; } break;
      }
     }
    }
    while (points > 0) {
     switch (rng((num_gtraits < MAX_TRAIT_POINTS ? 1 : 5), 9)) {
     case 1:
     case 2:
     case 3:
     case 4:
      rn = random_good_trait();
      if (!has_trait(rn) && points >= traits[rn].points &&
          num_gtraits + traits[rn].points <= MAX_TRAIT_POINTS) {
       toggle_trait(rn);
       points -= traits[rn].points;
       num_gtraits += traits[rn].points;
      }
      break;
     case 5:
      switch (rng(1, 4)) {
       case 1: if (str_max < HIGH_STAT) { str_max++; points--; } break;
       case 2: if (dex_max < HIGH_STAT) { dex_max++; points--; } break;
       case 3: if (int_max < HIGH_STAT) { int_max++; points--; } break;
       case 4: if (per_max < HIGH_STAT) { per_max++; points--; } break;
      }
      break;
     case 6:
     case 7:
     case 8:
     case 9:
      rn = random_skill();

      Skill *aSkill = Skill::skill(rn);
      int level = skillLevel(aSkill);

      if (level < points) {
        points -= level + 1;
        skillLevel(aSkill).level(level + 2);
      }
      break;
     }
    }
   } break;
   case PLTYPE_TEMPLATE: {
    std::ifstream fin;
    std::stringstream filename;
    filename << "data/" << tempname << ".template";
    fin.open(filename.str().c_str());
    if (!fin.is_open()) {
     debugmsg("Couldn't open %s!", filename.str().c_str());
     return false;
    }
    std::string(data);
    getline(fin, data);
    load_info(g, data);
    points = 0;
   } break;
  }
  tab = 3;
 } else
  points = OPTIONS[OPT_INITIAL_POINTS];

 do {
  werase(w);
  wrefresh(w);
  switch (tab) {
   case 0: tab += set_stats      (w, this, points); break;
   case 1: tab += set_traits     (w, this, points); break;
   case 2: tab += set_skills     (w, this, points); break;
   case 3: tab += set_description(w, this, points); break;
  }
 } while (tab >= 0 && tab < 4);
 delwin(w);

 if (tab < 0)
  return false;

 // Character is finalized.  Now just set up HP, &c
 for (int i = 0; i < num_hp_parts; i++) {
  hp_max[i] = calc_HP(str_max, has_trait(PF_TOUGH));
  hp_cur[i] = hp_max[i];
 }
 if (has_trait(PF_GLASSJAW)) {
  hp_max[hp_head] = int(hp_max[hp_head] * .85);
  hp_cur[hp_head] = hp_max[hp_head];
 }
 if (has_trait(PF_SMELLY))
  scent = 800;
 if (has_trait(PF_ANDROID)) {
  add_bionic(bionic_id(rng(bio_memory, max_bio_start - 1)));// Other
  if (bionics[my_bionics[0].id].power_cost > 0) {
   add_bionic(bionic_id(rng(1, bio_ethanol)));	// Power Source
   max_power_level = 10;
   power_level = 10;
  } else {
   bionic_id tmpbio;
   do
    tmpbio = bionic_id(rng(bio_ethanol + 1, bio_armor_legs));
   while (bionics[tmpbio].power_cost > 0);
   add_bionic(tmpbio);
   max_power_level = 0;
   power_level = 0;
  }

/* CHEATER'S STUFF

  add_bionic(bionic_id(rng(0, bio_ethanol)));	// Power Source
  for (int i = 0; i < 5; i++)
   add_bionic(bionic_id(rng(bio_memory, max_bio_start - 1)));// Other
  max_power_level = 80;
  power_level = 80;

End of cheatery */
 }

 if (has_trait(PF_MARTIAL_ARTS)) {
  itype_id ma_type;
  do {
   int choice = menu("Pick your style:",
                     "Karate", "Judo", "Aikido", "Tai Chi", "Taekwando", NULL);
   if (choice == 1)
    ma_type = itm_style_karate;
   if (choice == 2)
    ma_type = itm_style_judo;
   if (choice == 3)
    ma_type = itm_style_aikido;
   if (choice == 4)
    ma_type = itm_style_tai_chi;
   if (choice == 5)
    ma_type = itm_style_taekwando;
   item tmpitem = item(g->itypes[ma_type], 0);
   full_screen_popup(tmpitem.info(true).c_str());
  } while (!query_yn("Use this style?"));
  styles.push_back(ma_type);
 }
 ret_null = item(g->itypes[0], 0);
 if (!styles.empty())
  weapon = item(g->itypes[ styles[0] ], 0, ':');
 else
  weapon   = item(g->itypes[0], 0);
// Nice to start out less than naked.
 item tmp(g->itypes[itm_jeans_fit], 0, 'a');
 worn.push_back(tmp);
 tmp = item(g->itypes[itm_tshirt_fit], 0, 'b');
 worn.push_back(tmp);
 tmp = item(g->itypes[itm_sneakers_fit], 0, 'c');
 worn.push_back(tmp);
// The near-sighted get to start with glasses.
 if (has_trait(PF_MYOPIC)) {
  tmp = item(g->itypes[itm_glasses_eye], 0, 'd');
  worn.push_back(tmp);
 }
// Likewise, the asthmatic start with their medication.
 if (has_trait(PF_ASTHMA)) {
  tmp = item(g->itypes[itm_inhaler], 0, 'a' + worn.size());
  inv.push_back(tmp);
 }
 // Basic starter gear, added independently of profession.
 tmp = item(g->itypes[itm_pockknife], 0,'a' + worn.size());
  inv.push_back(tmp);
 tmp = item(g->itypes[itm_lighter], 0,'a' + worn.size());
  inv.push_back(tmp);
// make sure we have no mutations
 for (int i = 0; i < PF_MAX2; i++)
  my_mutations[i] = false;
 return true;
}
Exemple #26
0
void player::fire_gun(int tarx, int tary, bool burst) {
    item ammotmp;
    item* gunmod = weapon.active_gunmod();
    it_ammo *curammo = NULL;
    item *used_weapon = NULL;

    if (weapon.has_flag("CHARGE")) { // It's a charger gun, so make up a type
        // Charges maxes out at 8.
        int charges = weapon.num_charges();
        it_ammo *tmpammo = dynamic_cast<it_ammo*>(itypes["charge_shot"]);

        tmpammo->damage = charges * charges;
        tmpammo->pierce = (charges >= 4 ? (charges - 3) * 2.5 : 0);
        if (charges <= 4)
            tmpammo->dispersion = 14 - charges * 2;
        else // 5, 12, 21, 32
            tmpammo->dispersion = charges * (charges - 4);
        tmpammo->recoil = tmpammo->dispersion * .8;
        tmpammo->ammo_effects.clear(); // Reset effects.
        if (charges == 8) { tmpammo->ammo_effects.insert("EXPLOSIVE_BIG"); }
        else if (charges >= 6) { tmpammo->ammo_effects.insert("EXPLOSIVE"); }

        if (charges >= 5){ tmpammo->ammo_effects.insert("FLAME"); }
        else if (charges >= 4) { tmpammo->ammo_effects.insert("INCENDIARY"); }

        if (gunmod != NULL) { // TODO: range calculation in case of active gunmod.
            used_weapon = gunmod;
        } else {
            used_weapon = &weapon;
        }

        curammo = tmpammo;
        used_weapon->curammo = tmpammo;
    } else if (gunmod != NULL) {
        used_weapon = gunmod;
        curammo = used_weapon->curammo;
    } else {// Just a normal gun. If we're here, we know curammo is valid.
        curammo = weapon.curammo;
        used_weapon = &weapon;
    }

    ammotmp = item(curammo, 0);
    ammotmp.charges = 1;

    if (!used_weapon->is_gun() && !used_weapon->is_gunmod()) {
        debugmsg("%s tried to fire a non-gun (%s).", name.c_str(),
                                                    used_weapon->tname().c_str());
        return;
    }

    projectile proj; // damage will be set later
    proj.aoe_size = 0;
    proj.ammo = curammo;
    proj.speed = 1000;

    std::set<std::string> *curammo_effects = &curammo->ammo_effects;
    if(gunmod == NULL){
        std::set<std::string> *gun_effects = &dynamic_cast<it_gun*>(used_weapon->type)->ammo_effects;
        proj.proj_effects.insert(gun_effects->begin(),gun_effects->end());
    }
    proj.proj_effects.insert(curammo_effects->begin(),curammo_effects->end());

    proj.wide = (curammo->phase == LIQUID ||
            proj.proj_effects.count("SHOT") || proj.proj_effects.count("BOUNCE"));
    proj.drops = (curammo->type == "bolt" || curammo->type == "arrow");

    //int x = xpos(), y = ypos();
    // Have to use the gun, gunmods don't have a type
    it_gun* firing = dynamic_cast<it_gun*>(weapon.type);
    if (has_trait("TRIGGERHAPPY") && one_in(30))
        burst = true;
    if (burst && used_weapon->burst_size() < 2)
        burst = false; // Can't burst fire a semi-auto

    // Use different amounts of time depending on the type of gun and our skill
    if (!proj.proj_effects.count("BOUNCE")) {
        moves -= time_to_fire(*this, firing);
    }
    // Decide how many shots to fire
    int num_shots = 1;
    if (burst)
        num_shots = used_weapon->burst_size();
    if (num_shots > used_weapon->num_charges() && !used_weapon->has_flag("CHARGE") && !used_weapon->has_flag("NO_AMMO"))
        num_shots = used_weapon->num_charges();

    if (num_shots == 0)
        debugmsg("game::fire() - num_shots = 0!");

    int ups_drain = 0;
    int adv_ups_drain = 0;
    if (weapon.has_flag("USE_UPS")) {
        ups_drain = 5;
        adv_ups_drain = 3;
    } else if (weapon.has_flag("USE_UPS_20")) {
        ups_drain = 20;
        adv_ups_drain = 12;
    } else if (weapon.has_flag("USE_UPS_40")) {
        ups_drain = 40;
        adv_ups_drain = 24;
    }

    // cap our maximum burst size by the amount of UPS power left
    if (ups_drain > 0 || adv_ups_drain > 0)
    while (!(has_charges("UPS_off", ups_drain*num_shots) ||
                has_charges("UPS_on", ups_drain*num_shots) ||
                has_charges("adv_UPS_off", adv_ups_drain*num_shots) ||
                has_charges("adv_UPS_on", adv_ups_drain*num_shots))) {
        num_shots--;
    }

    const bool debug_retarget = false;  // this will inevitably be needed
    //const bool wildly_spraying = false; // stub for now. later, rng based on stress/skill/etc at the start,
    int weaponrange = weapon.range(); // this is expensive, let's cache. todo: figure out if we need weapon.range(&p);

    for (int curshot = 0; curshot < num_shots; curshot++) {
        // Burst-fire weapons allow us to pick a new target after killing the first
        int zid = g->mon_at(tarx, tary);
        if ( curshot > 0 && (zid == -1 || g->zombie(zid).hp <= 0) ) {
            std::vector<point> new_targets;
            new_targets.clear();

            if ( debug_retarget == true ) {
                mvprintz(curshot,5,c_red,"[%d] %s: retarget: mon_at(%d,%d)",curshot,name.c_str(),tarx,tary);
                if(zid == -1) {
                    printz(c_red, " = -1");
                } else {
                    printz(c_red, ".hp=%d", g->zombie(zid).hp);
                }
            }

            for (unsigned long int i = 0; i < g->num_zombies(); i++) {
                monster &z = g->zombie(i);
                int dummy;
                // search for monsters in radius
                if (rl_dist(z.posx(), z.posy(), tarx, tary) <= std::min(2 + skillLevel("gun"), weaponrange) &&
                        rl_dist(xpos(),ypos(),z.xpos(),z.ypos()) <= weaponrange &&
                        sees(&z, dummy) ) {
                    if (!z.is_dead_state())
                        new_targets.push_back(point(z.xpos(), z.ypos())); // oh you're not dead and I don't like you. Hello!
                }
            }

            if ( new_targets.empty() == false ) {    /* new victim! or last victim moved */
                int target_picked = rng(0, new_targets.size() - 1); /* 1 victim list unless wildly spraying */
                tarx = new_targets[target_picked].x;
                tary = new_targets[target_picked].y;
                zid = g->mon_at(tarx, tary);

                /* debug */ if (debug_retarget) printz(c_ltgreen, " NEW:(%d:%d,%d) %d,%d (%s)[%d] hp: %d",
                    target_picked, new_targets[target_picked].x, new_targets[target_picked].y,
                    tarx, tary, g->zombie(zid).name().c_str(), zid, g->zombie(zid).hp);

            } else if (
                (
                    !has_trait("TRIGGERHAPPY") ||   /* double ta TRIPLE TAP! wait, no... */
                    one_in(3)                          /* on second though...everyone double-taps at times. */
                ) && (
                    skillLevel("gun") >= 7 ||        /* unless trained */
                    one_in(7 - skillLevel("gun"))    /* ...sometimes */
                ) ) {
                return;                               // No targets, so return
            } else if (debug_retarget) {
                printz(c_red, " new targets.empty()!");
            }
        } else if (debug_retarget) {
            const int zid = g->mon_at(tarx, tary);
            mvprintz(curshot,5,c_red,"[%d] %s: target == mon_at(%d,%d)[%d] %s hp %d",curshot, name.c_str(), tarx ,tary,
            zid,
            g->zombie(zid).name().c_str(),
            g->zombie(zid).hp);
        }

        // Drop a shell casing if appropriate.
        itype_id casing_type = curammo->casing;
        if (casing_type != "NULL" && !casing_type.empty()) {
            item casing;
            casing.make(itypes[casing_type]);
            // Casing needs a charges of 1 to stack properly with other casings.
            casing.charges = 1;
            if( used_weapon->has_gunmod("brass_catcher") != -1 ) {
                i_add( casing );
            } else {
                int x = 0;
                int y = 0;
                int count = 0;
                do {
                    x = xpos() - 1 + rng(0, 2);
                    y = ypos() - 1 + rng(0, 2);
                    count++;
                    // Try not to drop the casing on a wall if at all possible.
                } while( g->m.move_cost( x, y ) == 0 && count < 10 );
                g->m.add_item_or_charges(x, y, casing);
            }
        }

        // Use up a round (or 100)
        if (used_weapon->has_flag("FIRE_100")) {
            used_weapon->charges -= 100;
        } else if (used_weapon->has_flag("FIRE_50")) {
            used_weapon->charges -= 50;
        } else if (used_weapon->has_flag("CHARGE")) {
            used_weapon->active = false;
            used_weapon->charges = 0;
        } else if (!used_weapon->has_flag("NO_AMMO")) {
            used_weapon->charges--;
        }

        // Drain UPS power
        if (has_charges("adv_UPS_off", adv_ups_drain)) {
            use_charges("adv_UPS_off", adv_ups_drain);
        } else if (has_charges("adv_UPS_on", adv_ups_drain)) {
            use_charges("adv_UPS_on", adv_ups_drain);
        } else if (has_charges("UPS_off", ups_drain)) {
            use_charges("UPS_off", ups_drain);
        } else if (has_charges("UPS_on", ups_drain)) {
            use_charges("UPS_on", ups_drain);
        }

        if (firing->skill_used != Skill::skill("archery") &&
            firing->skill_used != Skill::skill("throw")) {
            // Current guns have a durability between 5 and 9.
            // Misfire chance is between 1/64 and 1/1024.
            if (is_underwater() && !weapon.has_flag("WATERPROOF_GUN") && one_in(firing->durability)) {
                g->add_msg_player_or_npc(this, _("Your weapon misfires with a wet click!"),
                                         _("<npcname>'s weapon misfires with a wet click!") );
                return;
            } else if (one_in(2 << firing->durability)) {
                g->add_msg_player_or_npc(this, _("Your weapon misfires!"),
                                         _("<npcname>'s weapon misfires!") );
                return;
            }
        }

        make_gun_sound_effect(*this, burst, used_weapon);

        double total_dispersion = get_weapon_dispersion(used_weapon);
        //debugmsg("%f",total_dispersion);
        int range = rl_dist(xpos(), ypos(), tarx, tary);
        // penalties for point-blank
        if (range < (firing->volume/3) && firing->ammo != "shot")
            total_dispersion *= double(firing->volume/3) / double(range);

        // rifle has less range penalty past LONG_RANGE
        if (firing->skill_used == Skill::skill("rifle") && range > LONG_RANGE)
            total_dispersion *= 1 - 0.4*double(range - LONG_RANGE) / double(range);

        if (curshot > 0) {
            if (recoil_add(*this) % 2 == 1) {
                recoil++;
            }
            recoil += recoil_add(*this) / 2;
        } else {
            recoil += recoil_add(*this);
        }

        int mtarx = tarx;
        int mtary = tary;

        int adjusted_damage = used_weapon->gun_damage();

        proj.impact = damage_instance::physical(0,adjusted_damage,0);

        double missed_by = projectile_attack(proj, mtarx, mtary, total_dispersion);
        if (missed_by <= .1) { // TODO: check head existence for headshot
            practice(g->turn, firing->skill_used, 5);
            lifetime_stats()->headshots++;
        } else if (missed_by <= .2) {
            practice(g->turn, firing->skill_used, 3);
        } else if (missed_by <= .4) {
            practice(g->turn, firing->skill_used, 2);
        } else if (missed_by <= .6) {
            practice(g->turn, firing->skill_used, 1);
        }

    }

    if (used_weapon->num_charges() == 0) {
        used_weapon->curammo = NULL;
    }

}
Exemple #27
0
SkillLevel& Character::skillLevel(Skill const &_skill)
{
    return skillLevel(&_skill);
}
Exemple #28
0
bool player::uninstall_bionic(bionic_id b_id)
{
    // malfunctioning bionics don't have associated items and get a difficulty of 12
    int difficulty = 12;
    if( item_controller->has_template(b_id) > 0) {
        const it_bionic *type = dynamic_cast<it_bionic *> (item_controller->find_template(b_id));
        difficulty = type->difficulty;
    }

    if (!has_bionic(b_id)) {
        popup(_("You don't have this bionic installed."));
        return false;
    }
    if (!(inv.has_items_with_quality("CUT", 1, 1) && has_amount("1st_aid", 1))) {
        popup(_("Removing bionics requires a cutting tool and a first aid kit."));
        return false;
    }

    if ( b_id == "bio_blaster" ) {
        popup(_("Removing your Fusion Blaster Arm would leave you with a useless stump."));
        return false;
    }

    // removal of bionics adds +2 difficulty over installation
    int chance_of_success = bionic_manip_cos(int_cur,
                            skillLevel("electronics"),
                            skillLevel("firstaid"),
                            skillLevel("mechanics"),
                            difficulty + 2);

    if (!query_yn(_("WARNING: %i percent chance of SEVERE bodily damage! Remove anyway?"),
                  100 - chance_of_success)) {
        return false;
    }

    use_charges("1st_aid", 1);

    practice( "electronics", int((100 - chance_of_success) * 1.5) );
    practice( "firstaid", int((100 - chance_of_success) * 1.0) );
    practice( "mechanics", int((100 - chance_of_success) * 0.5) );

    int success = chance_of_success - rng(1, 100);

    if (success > 0) {
        add_memorial_log(pgettext("memorial_male", "Removed bionic: %s."),
                         pgettext("memorial_female", "Removed bionic: %s."),
                         bionics[b_id]->name.c_str());
        // until bionics can be flagged as non-removable
        add_msg(m_neutral, _("You jiggle your parts back into their familiar places."));
        add_msg(m_good, _("Successfully removed %s."), bionics[b_id]->name.c_str());
        remove_bionic(b_id);
        g->m.spawn_item(posx, posy, "burnt_out_bionic", 1);
    } else {
        add_memorial_log(pgettext("memorial_male", "Removed bionic: %s."),
                         pgettext("memorial_female", "Removed bionic: %s."),
                         bionics[b_id]->name.c_str());
        bionics_uninstall_failure(this);
    }
    g->refresh_all();
    return true;
}
Exemple #29
0
bool player::install_bionics(game *g, it_bionic* type)
{
 if (type == NULL) {
  debugmsg("Tried to install NULL bionic");
  return false;
 }
 std::string bio_name = type->name.substr(5);	// Strip off "CBM: "
 WINDOW* w = newwin(25, 80, 0, 0);

 int pl_skill = int_cur +
   skillLevel("electronics").level() * 4 +
   skillLevel("firstaid").level()    * 3 +
   skillLevel("mechanics").level()   * 2;

 int skint = int(pl_skill / 4);
 int skdec = int((pl_skill * 10) / 4) % 10;

// Header text
 mvwprintz(w, 0,  0, c_white, "Installing bionics:");
 mvwprintz(w, 0, 20, type->color, bio_name.c_str());

// Dividing bars
 for (int i = 0; i < 80; i++) {
  mvwputch(w,  1, i, c_ltgray, LINE_OXOX);
  mvwputch(w, 21, i, c_ltgray, LINE_OXOX);
 }
// Init the list of bionics
 for (unsigned int i = 1; i < type->options.size(); i++) {
  bionic_id id = type->options[i];
  mvwprintz(w, i + 2, 0, (has_bionic(id) ? c_ltred : c_ltblue),
            bionics[id].name.c_str());
 }
// Helper text
 mvwprintz(w, 2, 40, c_white,        "Difficulty of this module: %d",
           type->difficulty);
 mvwprintz(w, 3, 40, c_white,        "Your installation skill:   %d.%d",
           skint, skdec);
 mvwprintz(w, 4, 40, c_white,       "Installation requires high intelligence,");
 mvwprintz(w, 5, 40, c_white,       "and skill in electronics, first aid, and");
 mvwprintz(w, 6, 40, c_white,       "mechanics (in that order of importance).");

 int chance_of_success = int((100 * pl_skill) /
                             (pl_skill + 4 * type->difficulty));

 mvwprintz(w, 8, 40, c_white,        "Chance of success:");

 nc_color col_suc;
 if (chance_of_success >= 95)
  col_suc = c_green;
 else if (chance_of_success >= 80)
  col_suc = c_ltgreen;
 else if (chance_of_success >= 60)
  col_suc = c_yellow;
 else if (chance_of_success >= 35)
  col_suc = c_ltred;
 else
  col_suc = c_red;

 mvwprintz(w, 8, 59, col_suc, "%d%%%%", chance_of_success);

 mvwprintz(w, 10, 40, c_white,       "Failure may result in crippling damage,");
 mvwprintz(w, 11, 40, c_white,       "loss of existing bionics, genetic damage");
 mvwprintz(w, 12, 40, c_white,       "or faulty installation.");
 wrefresh(w);

 if (type->id == itm_bionics_battery) {	// No selection list; just confirm
  mvwprintz(w,  2, 0, h_ltblue, "Battery Level +%d", BATTERY_AMOUNT);
  mvwprintz(w, 22, 0, c_ltblue, "\
Installing this bionic will increase your total battery capacity by %d.\n\
Batteries are necessary for most bionics to function.  They also require a\n\
charge mechanism, which must be installed from another CBM.", BATTERY_AMOUNT);
  char ch;
  wrefresh(w);
  do
   ch = getch();
  while (ch != 'q' && ch != '\n' && ch != KEY_ESCAPE);
  if (ch == '\n') {
   practice("electronics", (100 - chance_of_success) * 1.5);
   practice("firstaid", (100 - chance_of_success) * 1.0);
   practice("mechanics", (100 - chance_of_success) * 0.5);
   int success = chance_of_success - rng(1, 100);
   if (success > 0) {
    g->add_msg("Successfully installed batteries.");
    max_power_level += BATTERY_AMOUNT;
   } else
    bionics_install_failure(g, this, success);
   werase(w);
   delwin(w);
   g->refresh_all();
   return true;
  }
  werase(w);
  delwin(w);
  g->refresh_all();
  return false;
 }
Exemple #30
0
int player::base_to_hit(bool real_life, int stat)
{
 if (stat == -999)
  stat = (real_life ? dex_cur : dex_max);
 return 1 + int(stat / 2) + skillLevel("melee");
}