Пример #1
0
void player::remove_child_flag(std::string flag)
{
    for (int i = 0; i < mutation_data[flag].replacements.size(); i++) {
        std::string tmp = mutation_data[flag].replacements[i];
        if (has_trait(tmp)) {
            remove_mutation(tmp);
            return;
        } else if (has_child_flag(tmp)) {
            remove_child_flag(tmp);
            return;
        }
    }
}
Пример #2
0
void player::remove_child_flag(game *g, pl_flag flag)
{
 for (int i = 0; i < g->mutation_data[flag].replacements.size(); i++) {
  pl_flag tmp = g->mutation_data[flag].replacements[i];
  if (has_trait(tmp)) {
   remove_mutation(g, tmp);
   return;
  } else if (has_child_flag(g, tmp)) {
   remove_child_flag(g, tmp);
   return;
  }
 }
}
Пример #3
0
void player::remove_child_flag( const std::string &flag )
{
    for( auto &elem : mutation_branch::get( flag ).replacements ) {
        std::string tmp = elem;
        if (has_trait(tmp)) {
            remove_mutation(tmp);
            return;
        } else if (has_child_flag(tmp)) {
            remove_child_flag(tmp);
            return;
        }
    }
}
Пример #4
0
void player::remove_child_flag( const trait_id &flag )
{
    for( auto &elem : flag->replacements ) {
        trait_id tmp = elem;
        if (has_trait(tmp)) {
            remove_mutation(tmp);
            return;
        } else if (has_child_flag(tmp)) {
            remove_child_flag(tmp);
            return;
        }
    }
}
Пример #5
0
int player::hit_roll()
{
 int numdice = base_to_hit() + weapon.type->m_to_hit;
 int sides = 10 - encumb(bp_torso);
 int best_bonus = 0;
 if (sides < 2)
  sides = 2;

// Are we unarmed?
 if (unarmed_attack()) {
  best_bonus = sklevel[sk_unarmed];
  if (sklevel[sk_unarmed] > 4)
   best_bonus += sklevel[sk_unarmed] - 2; // Extra bonus for high levels
 }

// Using a bashing weapon?
 if (weapon.is_bashing_weapon()) {
  int bash_bonus = int(sklevel[sk_bashing] / 3);
  if (bash_bonus > best_bonus)
   best_bonus = bash_bonus;
 }

// Using a cutting weapon?
 if (weapon.is_cutting_weapon()) {
  int cut_bonus = int(sklevel[sk_cutting] / 2);
  if (cut_bonus > best_bonus)
   best_bonus = cut_bonus;
 }

// Using a spear?
 if (weapon.has_weapon_flag(WF_SPEAR) || weapon.has_weapon_flag(WF_STAB)) {
  int stab_bonus = int(sklevel[sk_stabbing] / 2);
  if (stab_bonus > best_bonus)
   best_bonus = stab_bonus;
 }

 numdice += best_bonus;
 if (has_trait(PF_DRUNKEN)) {
  if (unarmed_attack())
   numdice += rng(0, 1) + int(disease_level(DI_DRUNK) / 300);
  else
   numdice += int(disease_level(DI_DRUNK) / 400);
 }

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

 return dice(numdice, sides);
}
Пример #6
0
bool Creature::resists_effect(effect e)
{
    for (auto &i : e.get_resist_effects()) {
        if (has_effect(i)) {
            return true;
        }
    }
    for (auto &i : e.get_resist_traits()) {
        if (has_trait(i)) {
            return true;
        }
    }
    return false;
}
Пример #7
0
std::list<item> player::consume_items( const comp_selection<item_comp> &is, int batch )
{
    std::list<item> ret;

    if( has_trait( trait_DEBUG_HS ) ) {
        return ret;
    }

    item_comp selected_comp = is.comp;

    const tripoint &loc = pos();
    const bool by_charges = ( item::count_by_charges( selected_comp.type ) && selected_comp.count > 0 );
    // Count given to use_amount/use_charges, changed by those functions!
    long real_count = ( selected_comp.count > 0 ) ? selected_comp.count * batch : abs(
                          selected_comp.count );
    // First try to get everything from the map, than (remaining amount) from player
    if( is.use_from & use_from_map ) {
        if( by_charges ) {
            std::list<item> tmp = g->m.use_charges( loc, PICKUP_RANGE, selected_comp.type, real_count );
            ret.splice( ret.end(), tmp );
        } else {
            std::list<item> tmp = g->m.use_amount( loc, PICKUP_RANGE, selected_comp.type,
                                                   real_count );
            remove_ammo( tmp, *this );
            ret.splice( ret.end(), tmp );
        }
    }
    if( is.use_from & use_from_player ) {
        if( by_charges ) {
            std::list<item> tmp = use_charges( selected_comp.type, real_count );
            ret.splice( ret.end(), tmp );
        } else {
            std::list<item> tmp = use_amount( selected_comp.type, real_count );
            remove_ammo( tmp, *this );
            ret.splice( ret.end(), tmp );
        }
    }
    // condense those items into one
    if( by_charges && ret.size() > 1 ) {
        std::list<item>::iterator b = ret.begin();
        b++;
        while( ret.size() > 1 ) {
            ret.front().charges += b->charges;
            b = ret.erase( b );
        }
    }
    lastconsumed = selected_comp.type;
    empty_buckets( *this );
    return ret;
}
Пример #8
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;
}
Пример #9
0
int Character::volume_capacity() const
{
    int ret = 0;
    for (auto &i : worn) {
        ret += i.get_storage();
    }
    if (has_bionic("bio_storage")) {
        ret += 8;
    }
    if (has_trait("SHELL")) {
        ret += 16;
    }
    if (has_trait("SHELL2") && !has_active_mutation("SHELL2")) {
        ret += 24;
    }
    if (has_trait("PACKMULE")) {
        ret = int(ret * 1.4);
    }
    if (has_trait("DISORGANIZED")) {
        ret = int(ret * 0.6);
    }
    ret = std::max(ret, 0);
    return ret;
}
Пример #10
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;
}
Пример #11
0
/* we use this if we selected the tool earlier */
void player::consume_tools( const comp_selection<tool_comp> &tool, int batch )
{
    if( has_trait( trait_DEBUG_HS ) ) {
        return;
    }

    if( tool.use_from & use_from_player ) {
        use_charges( tool.comp.type, tool.comp.count * batch );
    }
    if( tool.use_from & use_from_map ) {
        long quantity = tool.comp.count * batch;
        g->m.use_charges( pos(), PICKUP_RANGE, tool.comp.type, quantity );
    }

    // else, use_from_none (or cancel), so we don't use up any tools;
}
Пример #12
0
void player::perform_special_attacks(game *g, monster *z, player *p,
                                     int &bash_dam, int &cut_dam, int &stab_dam)
{
 bool can_poison = false;
 int bash_armor = (z == NULL ? 0 : z->armor_bash());
 int cut_armor  = (z == NULL ? 0 : z->armor_cut());
 std::vector<special_attack> special_attacks = mutation_attacks(z, p);

 for (int i = 0; i < special_attacks.size(); i++) {
  bool did_damage = false;
  if (special_attacks[i].bash > bash_armor) {
   bash_dam += special_attacks[i].bash;
   did_damage = true;
  }
  if (special_attacks[i].cut > cut_armor) {
   cut_dam += special_attacks[i].cut - cut_armor;
   did_damage = true;
  }
  if (special_attacks[i].stab > cut_armor * .8) {
   stab_dam += special_attacks[i].stab - cut_armor * .8;
   did_damage = true;
  }

  if (!can_poison && one_in(2) &&
      (special_attacks[i].cut > cut_armor ||
       special_attacks[i].stab > cut_armor * .8))
   can_poison = true;

  if (did_damage)
   g->add_msg( special_attacks[i].text.c_str() );
 }

 if (can_poison && has_trait(PF_POISONOUS)) {
  if (z != NULL) {
   if (!is_npc() && !z->has_effect(ME_POISONED))
    g->add_msg("You poison the %s!", z->name().c_str());
   z->add_effect(ME_POISONED, 6);
  } else if (p != NULL) {
   if (!is_npc() && !p->has_disease(DI_POISON))
    g->add_msg("You poison %s!", p->name.c_str());
   p->add_disease(DI_POISON, 6, g);
  }
 }
}
Пример #13
0
bool player::mutation_ok( const std::string &mutation, bool force_good, bool force_bad ) const
{
    if (has_trait(mutation) || has_child_flag(mutation)) {
        // We already have this mutation or something that replaces it.
        return false;
    }
    const auto &mdata = mutation_branch::get( mutation );
    if (force_bad && mdata.points > 0) {
        // This is a good mutation, and we're due for a bad one.
        return false;
    }

    if (force_good && mdata.points < 0) {
        // This is a bad mutation, and we're due for a good one.
        return false;
    }

    return true;
}
Пример #14
0
bool player::mutation_ok(std::string mutation, bool force_good, bool force_bad)
{
    if (has_trait(mutation) || has_child_flag(mutation)) {
        // We already have this mutation or something that replaces it.
        return false;
    }

    if (force_bad && traits[mutation].points > 0) {
        // This is a good mutation, and we're due for a bad one.
        return false;
    }

    if (force_good && traits[mutation].points < 0) {
        // This is a bad mutation, and we're due for a good one.
        return false;
    }

    return true;
}
Пример #15
0
void player::mutate_category( const std::string &cat )
{
    // Hacky ID comparison is better than separate hardcoded branch used before
    // @todo: Turn it into the null id
    if( cat == "MUTCAT_ANY" ) {
        mutate();
        return;
    }

    bool force_bad = one_in(3);
    bool force_good = false;
    if (has_trait( trait_ROBUST ) && force_bad) {
        // Robust Genetics gives you a 33% chance for a good mutation,
        // instead of the 33% chance of a bad one.
        force_bad = false;
        force_good = true;
    }

    // Pull the category's list for valid mutations
    std::vector<trait_id> valid;
    valid = mutations_category[cat];

    // Remove anything we already have, that we have a child of, or that
    // goes against our intention of a good/bad mutation
    for (size_t i = 0; i < valid.size(); i++) {
        if (!mutation_ok(valid[i], force_good, force_bad)) {
            valid.erase(valid.begin() + i);
            i--;
        }
    }

    // if we can't mutate in the category do nothing
    if (valid.empty()) {
        return;
    }

    if (mutate_towards(random_entry(valid))) {
        return;
    } else {
        // if mutation failed (errors, post-threshold pick), try again once.
        mutate_towards(random_entry(valid));
    }
}
Пример #16
0
void player::stumble(game *g)
{
 int stumble_pen = 2 * weapon.volume() + weapon.weight();
 if (has_trait(PF_DEFT))
  stumble_pen = int(stumble_pen * .3) - 10;
 if (stumble_pen < 0)
  stumble_pen = 0;
 if (stumble_pen > 0 && (str_cur >= 15 || dex_cur >= 21 ||
                         one_in(16 - str_cur) || one_in(22 - dex_cur)))
  stumble_pen = rng(0, stumble_pen);
 if (!is_npc()) {	// Only display messages if this is the player
  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.");
 }
 moves -= stumble_pen;
}
Пример #17
0
bool player::mutation_ok( const trait_id &mutation, bool force_good, bool force_bad ) const
{
    if (mutation_branch::trait_is_blacklisted(mutation)) {
        return false;
    }
    if (has_trait(mutation) || has_child_flag(mutation)) {
        // We already have this mutation or something that replaces it.
        return false;
    }
    const mutation_branch &mdata = mutation.obj();
    if (force_bad && mdata.points > 0) {
        // This is a good mutation, and we're due for a bad one.
        return false;
    }

    if (force_good && mdata.points < 0) {
        // This is a bad mutation, and we're due for a good one.
        return false;
    }

    return true;
}
Пример #18
0
morale_type player::allergy_type( const item &food ) const
{
    using allergy_tuple = std::tuple<trait_id, std::string, morale_type>;
    static const std::array<allergy_tuple, 8> allergy_tuples = {{
            std::make_tuple( trait_id( "VEGETARIAN" ), "ALLERGEN_MEAT", MORALE_VEGETARIAN ),
            std::make_tuple( trait_id( "MEATARIAN" ), "ALLERGEN_VEGGY", MORALE_MEATARIAN ),
            std::make_tuple( trait_id( "LACTOSE" ), "ALLERGEN_MILK", MORALE_LACTOSE ),
            std::make_tuple( trait_id( "ANTIFRUIT" ), "ALLERGEN_FRUIT", MORALE_ANTIFRUIT ),
            std::make_tuple( trait_id( "ANTIJUNK" ), "ALLERGEN_JUNK", MORALE_ANTIJUNK ),
            std::make_tuple( trait_id( "ANTIWHEAT" ), "ALLERGEN_WHEAT", MORALE_ANTIWHEAT )
        }
    };

    for( const auto &tp : allergy_tuples ) {
        if( has_trait( std::get<0>( tp ) ) &&
            food.has_flag( std::get<1>( tp ) ) ) {
            return std::get<2>( tp );
        }
    }

    return MORALE_NULL;
}
Пример #19
0
void player::mutate_category( const std::string &cat )
{
    bool force_bad = one_in(3);
    bool force_good = false;
    if (has_trait("ROBUST") && force_bad) {
        // Robust Genetics gives you a 33% chance for a good mutation,
        // instead of the 33% chance of a bad one.
        force_bad = false;
        force_good = true;
    }

    // Pull the category's list for valid mutations
    std::vector<std::string> valid;
    valid = mutations_category[cat];

    // Remove anything we already have, that we have a child of, or that
    // goes against our intention of a good/bad mutation
    for (size_t i = 0; i < valid.size(); i++) {
        if (!mutation_ok(valid[i], force_good, force_bad)) {
            valid.erase(valid.begin() + i);
            i--;
        }
    }

    // if we can't mutate in the category do nothing
    if (valid.empty()) {
        return;
    }

    if (mutate_towards(random_entry(valid))) {
        return;
    } else {
        // if mutation failed (errors, post-threshold pick), try again once.
        mutate_towards(random_entry(valid));
    }
}
Пример #20
0
int visitable<Character>::max_quality( const quality_id &qual ) const
{
    int res = INT_MIN;

    auto self = static_cast<const Character *>( this );

    for( const auto &bio : self->my_bionics ) {
        res = std::max( res, bio.get_quality( qual ) );
    }

    static const quality_id BUTCHER( "BUTCHER" );
    if( qual == BUTCHER ) {
        if( self->has_trait( "CLAWS_ST" ) ) {
            res = std::max( res, 8 );
        } else if( self->has_trait( "TALONS" ) || self->has_trait( "MANDIBLES" ) ||
                   self->has_trait( "CLAWS" ) || self->has_trait( "CLAWS_RETRACT" ) ||
                   self->has_trait( "CLAWS_RAT" ) ) {
            res = std::max( res, 4 );
        }
    }

    return std::max( res, max_quality_internal( *this, qual ) );
}
Пример #21
0
// Why put this in a Big Switch?  Why not let bionics have pointers to
// functions, much like monsters and items?
//
// Well, because like diseases, which are also in a Big Switch, bionics don't
// share functions....
void player::activate_bionic(int b, game *g)
{
 bionic bio = my_bionics[b];
 int power_cost = bionics[bio.id].power_cost;
 if (weapon.type->id == itm_bio_claws && bio.id == bio_claws)
  power_cost = 0;
 if (power_level < power_cost) {
  if (my_bionics[b].powered) {
   g->add_msg("Your %s powers down.", bionics[bio.id].name.c_str());
   my_bionics[b].powered = false;
  } else
   g->add_msg("You cannot power your %s", bionics[bio.id].name.c_str());
  return;
 }

 if (my_bionics[b].powered && my_bionics[b].charge > 0) {
// Already-on units just lose a bit of charge
  my_bionics[b].charge--;
 } else {
// Not-on units, or those with zero charge, have to pay the power cost
  if (bionics[bio.id].charge_time > 0) {
   my_bionics[b].powered = true;
   my_bionics[b].charge = bionics[bio.id].charge_time;
  }
  power_level -= power_cost;
 }

 std::string junk;
 std::vector<point> traj;
 std::vector<std::string> good;
 std::vector<std::string> bad;
 WINDOW* w;
 int dirx, diry, t, index;
 unsigned int l;
 item tmp_item;

 switch (bio.id) {
 case bio_painkiller:
  pkill += 6;
  pain -= 2;
  if (pkill > pain)
   pkill = pain;
  break;

 case bio_nanobots:
  healall(4);
  break;

 case bio_resonator:
  g->sound(posx, posy, 30, "VRRRRMP!");
  for (int i = posx - 1; i <= posx + 1; i++) {
   for (int j = posy - 1; j <= posy + 1; j++) {
    g->m.bash(i, j, 40, junk);
    g->m.bash(i, j, 40, junk);	// Multibash effect, so that doors &c will fall
    g->m.bash(i, j, 40, junk);
    if (g->m.is_destructable(i, j) && rng(1, 10) >= 4)
     g->m.ter(i, j) = t_rubble;
   }
  }
  break;

 case bio_time_freeze:
  moves += 100 * power_level;
  power_level = 0;
  g->add_msg("Your speed suddenly increases!");
  if (one_in(3)) {
   g->add_msg("Your muscles tear with the strain.");
   hurt(g, bp_arms, 0, rng(5, 10));
   hurt(g, bp_arms, 1, rng(5, 10));
   hurt(g, bp_legs, 0, rng(7, 12));
   hurt(g, bp_legs, 1, rng(7, 12));
   hurt(g, bp_torso, 0, rng(5, 15));
  }
  if (one_in(5))
   add_disease(DI_TELEGLOW, rng(50, 400), g);
  break;

 case bio_teleport:
  g->teleport();
  add_disease(DI_TELEGLOW, 300, g);
  break;

// TODO: More stuff here (and bio_blood_filter)
 case bio_blood_anal:
  w = newwin(20, 40, 3, 10);
  wborder(w, LINE_XOXO, LINE_XOXO, LINE_OXOX, LINE_OXOX,
             LINE_OXXO, LINE_OOXX, LINE_XXOO, LINE_XOOX );
  if (has_disease(DI_FUNGUS))
   bad.push_back("Fungal Parasite");
  if (has_disease(DI_DERMATIK))
   bad.push_back("Insect Parasite");
  if (has_disease(DI_POISON))
   bad.push_back("Poison");
  if (radiation > 0)
   bad.push_back("Irradiated");
  if (has_disease(DI_PKILL1))
   good.push_back("Minor Painkiller");
  if (has_disease(DI_PKILL2))
   good.push_back("Moderate Painkiller");
  if (has_disease(DI_PKILL3))
   good.push_back("Heavy Painkiller");
  if (has_disease(DI_PKILL_L))
   good.push_back("Slow-Release Painkiller");
  if (has_disease(DI_DRUNK))
   good.push_back("Alcohol");
  if (has_disease(DI_CIG))
   good.push_back("Nicotine");
  if (has_disease(DI_HIGH))
   good.push_back("Intoxicant: Other");
  if (has_disease(DI_TOOK_PROZAC))
   good.push_back("Prozac");
  if (has_disease(DI_TOOK_FLUMED))
   good.push_back("Antihistamines");
  if (has_disease(DI_ADRENALINE))
   good.push_back("Adrenaline Spike");
  if (good.size() == 0 && bad.size() == 0)
   mvwprintz(w, 1, 1, c_white, "No effects.");
  else {
   for (unsigned int line = 1; line < 39 && line <= good.size() + bad.size(); line++) {
    if (line <= bad.size())
     mvwprintz(w, line, 1, c_red, bad[line - 1].c_str());
    else
     mvwprintz(w, line, 1, c_green, good[line - 1 - bad.size()].c_str());
   }
  }
  wrefresh(w);
  refresh();
  getch();
  delwin(w);
  break;

 case bio_blood_filter:
  rem_disease(DI_FUNGUS);
  rem_disease(DI_POISON);
  rem_disease(DI_PKILL1);
  rem_disease(DI_PKILL2);
  rem_disease(DI_PKILL3);
  rem_disease(DI_PKILL_L);
  rem_disease(DI_DRUNK);
  rem_disease(DI_CIG);
  rem_disease(DI_HIGH);
  rem_disease(DI_TOOK_PROZAC);
  rem_disease(DI_TOOK_FLUMED);
  rem_disease(DI_ADRENALINE);
  break;

 case bio_evap:
  if (query_yn("Drink directly? Otherwise you will need a container.")) {
   tmp_item = item(g->itypes[itm_water], 0);
   thirst -= 50;
   if (has_trait(PF_GOURMAND) && thirst < -60) {
     g->add_msg("You can't finish it all!");
     thirst = -60;
   } else if (!has_trait(PF_GOURMAND) && thirst < -20) {
     g->add_msg("You can't finish it all!");
     thirst = -20;
   }
  } else {
   t = g->inv("Choose a container:");
   if (i_at(t).type == 0) {
    g->add_msg("You don't have that item!");
    power_level += bionics[bio_evap].power_cost;
   } else if (!i_at(t).is_container()) {
    g->add_msg("That %s isn't a container!", i_at(t).tname().c_str());
    power_level += bionics[bio_evap].power_cost;
   } else {
    it_container *cont = dynamic_cast<it_container*>(i_at(t).type);
    if (i_at(t).volume_contained() + 1 > cont->contains) {
     g->add_msg("There's no space left in your %s.", i_at(t).tname().c_str());
     power_level += bionics[bio_evap].power_cost;
    } else if (!(cont->flags & con_wtight)) {
     g->add_msg("Your %s isn't watertight!", i_at(t).tname().c_str());
     power_level += bionics[bio_evap].power_cost;
    } else {
     g->add_msg("You pour water into your %s.", i_at(t).tname().c_str());
     i_at(t).put_in(item(g->itypes[itm_water], 0));
    }
   }
  }
  break;

 case bio_lighter:
  g->draw();
  mvprintw(0, 0, "Torch in which direction?");
  get_direction(g, dirx, diry, input());
  if (dirx == -2) {
   g->add_msg("Invalid direction.");
   power_level += bionics[bio_lighter].power_cost;
   return;
  }
  dirx += posx;
  diry += posy;
  if (!g->m.add_field(g, dirx, diry, fd_fire, 1))	// Unsuccessful.
   g->add_msg("You can't light a fire there.");
  break;

 case bio_claws:
  if (weapon.type->id == itm_bio_claws) {
   g->add_msg("You withdraw your claws.");
   weapon = ret_null;
  } else if (weapon.type->id != 0) {
   g->add_msg("Your claws extend, forcing you to drop your %s.",
              weapon.tname().c_str());
   g->m.add_item(posx, posy, weapon);
   weapon = item(g->itypes[itm_bio_claws], 0);
   weapon.invlet = '#';
  } else {
   g->add_msg("Your claws extend!");
   weapon = item(g->itypes[itm_bio_claws], 0);
   weapon.invlet = '#';
  }
  break;

 case bio_blaster:
  tmp_item = weapon;
  weapon = item(g->itypes[itm_bio_blaster], 0);
  weapon.curammo = dynamic_cast<it_ammo*>(g->itypes[itm_bio_fusion]);
  weapon.charges = 1;
  g->refresh_all();
  g->plfire(false);
  weapon = tmp_item;
  break;

 case bio_laser:
  tmp_item = weapon;
  weapon = item(g->itypes[itm_v29], 0);
  weapon.curammo = dynamic_cast<it_ammo*>(g->itypes[itm_laser_pack]);
  weapon.charges = 1;
  g->refresh_all();
  g->plfire(false);
  weapon = tmp_item;
  break;

 case bio_emp:
  g->draw();
  mvprintw(0, 0, "Fire EMP in which direction?");
  get_direction(g, dirx, diry, input());
  if (dirx == -2) {
   g->add_msg("Invalid direction.");
   power_level += bionics[bio_emp].power_cost;
   return;
  }
  dirx += posx;
  diry += posy;
  g->emp_blast(dirx, diry);
  break;

 case bio_hydraulics:
  g->add_msg("Your muscles hiss as hydraulic strength fills them!");
  break;

 case bio_water_extractor:
  for (unsigned int i = 0; i < g->m.i_at(posx, posy).size(); i++) {
   item tmp = g->m.i_at(posx, posy)[i];
   if (tmp.type->id == itm_corpse && query_yn("Extract water from the %s",
                                              tmp.tname().c_str())) {
    i = g->m.i_at(posx, posy).size() + 1;	// Loop is finished
    t = g->inv("Choose a container:");
    if (i_at(t).type == 0) {
     g->add_msg("You don't have that item!");
     power_level += bionics[bio_water_extractor].power_cost;
    } else if (!i_at(t).is_container()) {
     g->add_msg("That %s isn't a container!", i_at(t).tname().c_str());
     power_level += bionics[bio_water_extractor].power_cost;
    } else {
     it_container *cont = dynamic_cast<it_container*>(i_at(t).type);
     if (i_at(t).volume_contained() + 1 > cont->contains) {
      g->add_msg("There's no space left in your %s.", i_at(t).tname().c_str());
      power_level += bionics[bio_water_extractor].power_cost;
     } else {
      g->add_msg("You pour water into your %s.", i_at(t).tname().c_str());
      i_at(t).put_in(item(g->itypes[itm_water], 0));
     }
    }
   }
   if (i == g->m.i_at(posx, posy).size() - 1)	// We never chose a corpse
    power_level += bionics[bio_water_extractor].power_cost;
  }
  break;

 case bio_magnet:
  for (int i = posx - 10; i <= posx + 10; i++) {
   for (int j = posy - 10; j <= posy + 10; j++) {
    if (g->m.i_at(i, j).size() > 0) {
     if (g->m.sees(i, j, posx, posy, -1, t))
      traj = line_to(i, j, posx, posy, t);
     else
      traj = line_to(i, j, posx, posy, 0);
    }
    traj.insert(traj.begin(), point(i, j));
    for (unsigned int k = 0; k < g->m.i_at(i, j).size(); k++) {
     if (g->m.i_at(i, j)[k].made_of(IRON) || g->m.i_at(i, j)[k].made_of(STEEL)){
      tmp_item = g->m.i_at(i, j)[k];
      g->m.i_rem(i, j, k);
      for (l = 0; l < traj.size(); l++) {
       index = g->mon_at(traj[l].x, traj[l].y);
       if (index != -1) {
        if (g->z[index].hurt(tmp_item.weight() * 2))
         g->kill_mon(index, true);
        g->m.add_item(traj[l].x, traj[l].y, tmp_item);
        l = traj.size() + 1;
       } else if (l > 0 && g->m.move_cost(traj[l].x, traj[l].y) == 0) {
        g->m.bash(traj[l].x, traj[l].y, tmp_item.weight() * 2, junk);
        g->sound(traj[l].x, traj[l].y, 12, junk);
        if (g->m.move_cost(traj[l].x, traj[l].y) == 0) {
         g->m.add_item(traj[l - 1].x, traj[l - 1].y, tmp_item);
         l = traj.size() + 1;
        }
       }
      }
      if (l == traj.size())
       g->m.add_item(posx, posy, tmp_item);
     }
    }
   }
  }
  break;

 case bio_lockpick:
  g->draw();
  mvprintw(0, 0, "Unlock in which direction?");
  get_direction(g, dirx, diry, input());
  if (dirx == -2) {
   g->add_msg("Invalid direction.");
   power_level += bionics[bio_lockpick].power_cost;
   return;
  }
  dirx += posx;
  diry += posy;
  if (g->m.ter(dirx, diry) == t_door_locked) {
   moves -= 40;
   g->add_msg("You unlock the door.");
   g->m.ter(dirx, diry) = t_door_c;
  } else
   g->add_msg("You can't unlock that %s.", g->m.tername(dirx, diry).c_str());
  break;

  // Unused enums added for completeness.
 default:
  break;
 }
}
Пример #22
0
bool Player::create_new_character()
{
  Window w_newch(0, 0, 80, 24);
  cuss::interface i_newch;
  if (!i_newch.load_from_file(CUSS_DIR + "/i_newchar_stats.cuss")) {
    return false;
  }

  New_char_screen cur_screen = NCS_STATS;

  Stat_selected cur_stat = STATSEL_STR;
  int* stat_value = &(stats.strength);

/* We need to set up a list of traits which does NOT include the placeholder / 
 * marker "traits" like TRAIT_MAX_GOOD and TRAIT_MAX_NEUTRAL etc.
 */
  std::vector<Trait_id> selectable_traits;
  for (int i = 1; i < TRAIT_MAX_BAD; i++) {
    if (i != TRAIT_MAX_GOOD && i != TRAIT_MAX_NEUTRAL) {
      selectable_traits.push_back( Trait_id(i) );
    }
  }

  std::vector<std::string> traits_list     = get_trait_list     (this);
  std::vector<std::string> profession_list = get_profession_list(this);

  name = "";

  int points = 4;
  int num_traits = 0;

  i_newch.ref_data("num_points", &points);

  i_newch.ref_data("num_strength",     &stats.strength);
  i_newch.ref_data("num_dexterity",    &stats.dexterity);
  i_newch.ref_data("num_perception",   &stats.perception);
  i_newch.ref_data("num_intelligence", &stats.intelligence);
  i_newch.set_data("text_description", get_stat_description(cur_stat));

  i_newch.set_data("text_strength",     "<c=ltblue>Strength<c=/>");
  i_newch.set_data("text_dexterity",    "<c=ltgray>Dexterity<c=/>");
  i_newch.set_data("text_perception",   "<c=ltgray>Perception<c=/>");
  i_newch.set_data("text_intelligence", "<c=ltgray>Intelligence<c=/>");

  bool done = false;

  while (!done) {  // We'll exit this function via keypresses, always
// Always set num_points!

    i_newch.draw(&w_newch);
    w_newch.refresh();

    long ch = getch();
    bool changed_screen = false;

    if (ch == '<') {
      cur_screen = New_char_screen( cur_screen - 1 );
      if (cur_screen == NCS_CANCEL) {
        if (query_yn("Cancel character creation?")) {
          return false;
        }
        cur_screen = NCS_STATS;
      } else {
        changed_screen = true;
      }
    } else if (ch == '>') {
      cur_screen = New_char_screen( cur_screen + 1 );
      if (cur_screen == NCS_DONE) {
        std::string reason_for_fail;
        if (points > 0) {
          reason_for_fail += "\nYou have unspent points!";
        }
        if (profession == NULL) {
          reason_for_fail += "\nYou didn't choose a profession!";
        }
        if (name.empty()) {
          reason_for_fail += "\nYour name is blank!";
        }
        if (!reason_for_fail.empty()) {
          popup("Wait, you can't start the game yet!%s",
                reason_for_fail.c_str());
        } else if (query_yn("Complete character and start the game?")) {
          done = true;
        }
        cur_screen = NCS_DESCRIPTION;
      } else {
        changed_screen = true;
      }
    } else {
// We should be doing this with cuss keybindings, but... that gets complex.
// Maybe one day I'll update cuss to be more friendly.
      switch (cur_screen) {

        case NCS_STATS: {
          bool changed_stat = false;
          switch (ch) {
            case '2':
            case 'j':
            case KEY_DOWN:
              if (cur_stat == STATSEL_INT) {
                cur_stat = STATSEL_STR;
              } else {
                cur_stat = Stat_selected( cur_stat + 1 );
              }
              changed_stat = true;
              break;

            case '8':
            case 'k':
            case KEY_UP:
              if (cur_stat == STATSEL_STR) {
                cur_stat = STATSEL_INT;
              } else {
                cur_stat = Stat_selected( cur_stat - 1 );
              }
              changed_stat = true;
              break;

            case '4':
            case 'h':
            case KEY_LEFT:
              if (*stat_value > 4) {
                if (*stat_value > 16) {
                  points++; // Stats above 16 cost 2 points, so get extra back
                }
                points++;
                (*stat_value)--;
              }
              break;

            case '6':
            case 'l':
            case KEY_RIGHT: {
              int point_req = (*stat_value >= 16 ? 2 : 1);
              if (*stat_value < 20 && points >= point_req) {
                points -= point_req;
                (*stat_value)++;
              }
            } break;
          } // switch (ch)

          if (changed_stat) { // Update stat_value
            i_newch.set_data("text_strength",    "<c=ltgray>Strength<c=/>");
            i_newch.set_data("text_dexterity",   "<c=ltgray>Dexterity<c=/>");
            i_newch.set_data("text_perception",  "<c=ltgray>Perception<c=/>");
            i_newch.set_data("text_intelligence","<c=ltgray>Intelligence<c=/>");

            i_newch.set_data("text_description",
                             get_stat_description(cur_stat));
            switch (cur_stat) {
              case STATSEL_STR:
                stat_value = &(stats.strength);
                i_newch.set_data("text_strength",
                                 "<c=ltblue>Strength<c=/>");
                break;
              case STATSEL_DEX:
                stat_value = &(stats.dexterity);
                i_newch.set_data("text_dexterity",
                                 "<c=ltblue>Dexterity<c=/>");
                break;
              case STATSEL_PER:
                stat_value = &(stats.perception);
                i_newch.set_data("text_perception",
                                 "<c=ltblue>Perception<c=/>");
                break;
              case STATSEL_INT:
                stat_value = &(stats.intelligence);
                i_newch.set_data("text_intelligence",
                                 "<c=ltblue>Intelligence<c=/>");
                break;
            }
          }
        } break;

        case NCS_TRAITS: {
          switch (ch) {
            case '2':
            case 'j':
            case KEY_DOWN:
            {
              i_newch.add_data("list_traits", 1);
              int sel = i_newch.get_int("list_traits");
              Trait_id cur_trait = selectable_traits[sel];
              i_newch.set_data("num_cost", abs(trait_cost(cur_trait)));
              if (trait_cost(cur_trait) >= 0) {
                i_newch.set_data("text_cost", "<c=yellow>Cost:<c=/>");
              } else {
                i_newch.set_data("text_cost", "<c=yellow>Earns:<c=/>");
              }
              if (trait_cost(cur_trait) > points) {
                i_newch.set_data("num_cost", c_red);
              } else {
                i_newch.set_data("num_cost", c_white);
              }
              i_newch.set_data("text_description",
                               trait_description(cur_trait));
            } break;

            case '8':
            case 'k':
            case KEY_UP:
            {
              i_newch.add_data("list_traits", -1);
              int sel = i_newch.get_int("list_traits");
              Trait_id cur_trait = selectable_traits[sel];
              i_newch.set_data("num_cost", abs(trait_cost(cur_trait)));
              if (trait_cost(cur_trait) >= 0) {
                i_newch.set_data("text_cost", "<c=yellow>Cost:<c=/>");
              } else {
                i_newch.set_data("text_cost", "<c=yellow>Earns:<c=/>");
              }
              if (trait_cost(cur_trait) > points) {
                i_newch.set_data("num_cost", c_red);
              } else {
                i_newch.set_data("num_cost", c_white);
              }
              i_newch.set_data("text_description",
                               trait_description(cur_trait));
            } break;

            case '\n':
            case ' ':
            {
              int sel = i_newch.get_int("list_traits");
              Trait_id cur_trait = selectable_traits[sel];
              if (has_trait(cur_trait)) {
                traits[cur_trait] = false;
                points += trait_cost(cur_trait);
                num_traits--;
                traits_list = get_trait_list(this);
              } else if (points >= trait_cost(cur_trait) && num_traits < 5){
                traits[cur_trait] = true;
                points -= trait_cost(cur_trait);
                num_traits++;
                traits_list = get_trait_list(this);
              }
              i_newch.set_data("num_traits_left", 5 - num_traits);
              if (num_traits >= 5) {
                i_newch.set_data("num_traits_left", c_red);
              }
            } break;

          } // switch (ch)
        } break;

        case NCS_PROFESSION: {
          switch (ch) {
            case '2':
            case 'j':
            case KEY_DOWN:
            {
              i_newch.add_data("list_professions", 1);
              std::string prof_name = i_newch.get_str("list_professions");
              prof_name = remove_color_tags(prof_name);
              Profession* cur_prof = PROFESSIONS.lookup_name(prof_name);
              if (!cur_prof) {
                debugmsg("No such profession as '%s'!", prof_name.c_str());
                return false;
              }
              i_newch.set_data("text_description", cur_prof->description);
            } break;

            case '8':
            case 'k':
            case KEY_UP:
            {
              i_newch.add_data("list_professions", -1);
              std::string prof_name = i_newch.get_str("list_professions");
              prof_name = remove_color_tags(prof_name);
              Profession* cur_prof = PROFESSIONS.lookup_name(prof_name);
              if (!cur_prof) {
                debugmsg("No such profession as '%s'!", prof_name.c_str());
                return false;
              }
              i_newch.set_data("text_description", cur_prof->description);
            } break;

            case '\n':
            case ' ':
            {
              std::string prof_name = i_newch.get_str("list_professions");
              prof_name = remove_color_tags(prof_name);
              Profession* cur_prof = PROFESSIONS.lookup_name(prof_name);
              if (!cur_prof) {
                debugmsg("No such profession as '%s'!", prof_name.c_str());
                return false;
              }
              set_profession(cur_prof);
              profession_list = get_profession_list(this);
            } break;

          } // switch (ch)
        } break;

        case NCS_DESCRIPTION: {
          if (ch == '/') {
            male = !male;
            if (male) {
              i_newch.set_data("text_male",   "<c=yellow>Male<c=/>");
              i_newch.set_data("text_female", "<c=dkgray>Female<c=/>");
            } else {
              i_newch.set_data("text_male",   "<c=dkgray>Male<c=/>");
              i_newch.set_data("text_female", "<c=yellow>Female<c=/>");
            }
          } else {
/* Let the interface handle name entry; this includes cursor movement,
 * backspace, etc.  The only downside is that this allows entry of "invalid"
 * name characters like "'&^%$#@ etc.  Bad?
 */
            cuss::element* entry = i_newch.find_by_name("entry_name");
            entry->handle_keypress(ch);
          }
            
        } break;

      } // switch (cur_screen)
    } // key pressed isn't '<' or '>'

    if (changed_screen) {
      std::string filename = CUSS_DIR + "/i_newchar_";
      switch (cur_screen) {
        case NCS_STATS:       filename += "stats.cuss";       break;
        case NCS_TRAITS:      filename += "traits.cuss";      break;
        case NCS_PROFESSION:  filename += "profession.cuss";  break;
        case NCS_DESCRIPTION: filename += "description.cuss"; break;
      }
      if (!i_newch.load_from_file(filename)) {
        return false;
      }

      i_newch.ref_data("num_points", &points);

      switch (cur_screen) {

        case NCS_STATS:
          cur_stat = STATSEL_STR;
          i_newch.set_data("text_strength",     "<c=ltblue>Strength<c=/>");
          i_newch.set_data("text_dexterity",    "<c=ltgray>Dexterity<c=/>");
          i_newch.set_data("text_perception",   "<c=ltgray>Perception<c=/>");
          i_newch.set_data("text_intelligence", "<c=ltgray>Intelligence<c=/>");
          i_newch.ref_data("num_strength",     &stats.strength);
          i_newch.ref_data("num_dexterity",    &stats.dexterity);
          i_newch.ref_data("num_perception",   &stats.perception);
          i_newch.ref_data("num_intelligence", &stats.intelligence);
          i_newch.set_data("text_description", get_stat_description(cur_stat));
          break;

        case NCS_TRAITS: {
          i_newch.select("list_traits");
          i_newch.ref_data("list_traits", &traits_list);
          int sel = i_newch.get_int("list_traits");
          Trait_id cur_trait = selectable_traits[sel];
          i_newch.set_data("text_description", trait_description(cur_trait));
          i_newch.set_data("num_cost", abs(trait_cost(cur_trait)));
          if (trait_cost(cur_trait) >= 0) {
            i_newch.set_data("text_cost", "<c=yellow>Cost:<c=/>");
          } else {
            i_newch.set_data("text_cost", "<c=yellow>Earns:<c=/>");
          }
          if (trait_cost(cur_trait) > points) {
            i_newch.set_data("num_cost", c_red);
          } else {
            i_newch.set_data("num_cost", c_white);
          }
          i_newch.set_data("num_traits_left", 5 - num_traits);
          if (num_traits >= 5) {
            i_newch.set_data("num_traits_left", c_red);
          }
        } break;

        case NCS_PROFESSION: {
          i_newch.select("list_professions");
          i_newch.ref_data("list_professions", &profession_list);
          std::string prof_name = i_newch.get_str("list_professions");
          prof_name = remove_color_tags(prof_name);
          Profession* cur_prof = PROFESSIONS.lookup_name(prof_name);
          if (!cur_prof) {
            debugmsg("No such profession as '%s'!", prof_name.c_str());
            return false;
          }
          i_newch.set_data("text_description", cur_prof->description);
        } break;

        case NCS_DESCRIPTION:
          i_newch.ref_data("entry_name", &name);
          if (male) {
            i_newch.set_data("text_male",   "<c=yellow>Male<c=/>");
            i_newch.set_data("text_female", "<c=dkgray>Female<c=/>");
          } else {
            i_newch.set_data("text_male",   "<c=dkgray>Male<c=/>");
            i_newch.set_data("text_female", "<c=yellow>Female<c=/>");
          }
          break;
      } // switch (cur_screen)
    } // if (changed_screen)
  }

// Now set up our skills and equipment based on our profession
  if (!profession) {
    debugmsg("Character creation finished without a profession!");
    return false;
  }
  std::vector<Item_type_chance> prof_items = profession->items.item_types;
  for (int i = 0; i < prof_items.size(); i++) {
    int count = prof_items[i].number;
    Item tmp_it(prof_items[i].item);
    for (int i = 0; i < count; i++) {
      if (tmp_it.get_item_class() == ITEM_CLASS_CLOTHING) {
        items_worn.push_back(tmp_it);
      } else {
        inventory.push_back(tmp_it);
      }
    }
  }

  skills = profession->skills;

// The "Durable" trait needs to be set up here.
  if (has_trait(TRAIT_DURABLE)) {
    for (int i = 0; i < HP_PART_MAX; i++) {
      current_hp[i] = 115;
      max_hp[i] = 115;
    }
  }

// Myopic characters get free glasses
  if (has_trait(TRAIT_MYOPIC)) {
    Item_type* glasses = ITEM_TYPES.lookup_name("glasses");
    if (!glasses) {
      debugmsg("No item 'glasses' exists - required for the Myopic trait!");
      return false;
    }
    Item tmp_it(glasses);
    items_worn.push_back(tmp_it);
  }

  return true;
}
Пример #23
0
void Character::reset_stats()
{
    // Bionic buffs
    if (has_active_bionic("bio_hydraulics"))
        mod_str_bonus(20);
    if (has_bionic("bio_eye_enhancer"))
        mod_per_bonus(2);
    if (has_bionic("bio_str_enhancer"))
        mod_str_bonus(2);
    if (has_bionic("bio_int_enhancer"))
        mod_int_bonus(2);
    if (has_bionic("bio_dex_enhancer"))
        mod_dex_bonus(2);

    // Trait / mutation buffs
    if (has_trait("THICK_SCALES")) {
        mod_dex_bonus(-2);
    }
    if (has_trait("CHITIN2") || has_trait("CHITIN3") || has_trait("CHITIN_FUR3")) {
        mod_dex_bonus(-1);
    }
    if (has_trait("BIRD_EYE")) {
        mod_per_bonus(4);
    }
    if (has_trait("INSECT_ARMS")) {
        mod_dex_bonus(-2);
    }
    if (has_trait("WEBBED")) {
        mod_dex_bonus(-1);
    }
    if (has_trait("ARACHNID_ARMS")) {
        mod_dex_bonus(-4);
    }
    if (has_trait("ARM_TENTACLES") || has_trait("ARM_TENTACLES_4") ||
            has_trait("ARM_TENTACLES_8")) {
        mod_dex_bonus(1);
    }

    // Dodge-related effects
    if (has_trait("TAIL_LONG")) {
        mod_dodge_bonus(2);
    }
    if (has_trait("TAIL_CATTLE")) {
        mod_dodge_bonus(1);
    }
    if (has_trait("TAIL_RAT")) {
        mod_dodge_bonus(2);
    }
    if (has_trait("TAIL_THICK") && !(has_active_mutation("TAIL_THICK")) ) {
        mod_dodge_bonus(1);
    }
    if (has_trait("TAIL_RAPTOR")) {
        mod_dodge_bonus(3);
    }
    if (has_trait("TAIL_FLUFFY")) {
        mod_dodge_bonus(4);
    }
    if (has_trait("WINGS_BAT")) {
        mod_dodge_bonus(-3);
    }
    if (has_trait("WINGS_BUTTERFLY")) {
        mod_dodge_bonus(-4);
    }

    ///\EFFECT_STR_MAX above 15 decreases Dodge bonus by 1 (NEGATIVE)
    if (str_max >= 16) {mod_dodge_bonus(-1);} // Penalty if we're huge
    ///\EFFECT_STR_MAX below 6 increases Dodge bonus by 1
    else if (str_max <= 5) {mod_dodge_bonus(1);} // Bonus if we're small

    nv_cached = false;

    // Reset our stats to normal levels
    // Any persistent buffs/debuffs will take place in effects,
    // player::suffer(), etc.

    // repopulate the stat fields
    str_cur = str_max + get_str_bonus();
    dex_cur = dex_max + get_dex_bonus();
    per_cur = per_max + get_per_bonus();
    int_cur = int_max + get_int_bonus();

    // Floor for our stats.  No stat changes should occur after this!
    if( dex_cur < 0 ) {
        dex_cur = 0;
    }
    if( str_cur < 0 ) {
        str_cur = 0;
    }
    if( per_cur < 0 ) {
        per_cur = 0;
    }
    if( int_cur < 0 ) {
        int_cur = 0;
    }

    // Does nothing! TODO: Remove
    Creature::reset_stats();
}
Пример #24
0
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;
}
Пример #25
0
// This must be called when any of the following change:
// - effects
// - bionics
// - traits
// - underwater
// - clothes
// With the exception of clothes, all changes to these character attributes must
// occur through a function in this class which calls this function. Clothes are
// typically added/removed with wear() and takeoff(), but direct access to the
// 'wears' vector is still allowed due to refactor exhaustion.
void Character::recalc_sight_limits()
{
    sight_max = 9999;
    vision_mode_cache.reset();

    // Set sight_max.
    if (has_effect("blind") || worn_with_flag("BLIND") || has_active_bionic("bio_blindfold")) {
        sight_max = 0;
    } else if( has_effect("boomered") && (!(has_trait("PER_SLIME_OK"))) ) {
        sight_max = 1;
        vision_mode_cache.set( BOOMERED );
    } else if (has_effect("in_pit") ||
            (underwater && !has_bionic("bio_membrane") &&
                !has_trait("MEMBRANE") && !worn_with_flag("SWIM_GOGGLES") &&
                !has_trait("CEPH_EYES") && !has_trait("PER_SLIME_OK") ) ) {
        sight_max = 1;
    } else if (has_active_mutation("SHELL2")) {
        // You can kinda see out a bit.
        sight_max = 2;
    } else if ( (has_trait("MYOPIC") || has_trait("URSINE_EYE")) &&
            !is_wearing("glasses_eye") && !is_wearing("glasses_monocle") &&
            !is_wearing("glasses_bifocal") && !has_effect("contacts")) {
        sight_max = 4;
    } else if (has_trait("PER_SLIME")) {
        sight_max = 6;
    } else if( has_effect( "darkness" ) ) {
        vision_mode_cache.set( DARKNESS );
        sight_max = 10;
    }

    // Debug-only NV, by vache's request
    if( has_trait("DEBUG_NIGHTVISION") ) {
        vision_mode_cache.set( DEBUG_NIGHTVISION );
    }
    if( has_nv() ) {
        vision_mode_cache.set( NV_GOGGLES );
    }
    if( has_active_mutation("NIGHTVISION3") || is_wearing("rm13_armor_on") ) {
        vision_mode_cache.set( NIGHTVISION_3 );
    }
    if( has_active_mutation("ELFA_FNV") ) {
        vision_mode_cache.set( FULL_ELFA_VISION );
    }
    if( has_active_mutation("CEPH_VISION") ) {
        vision_mode_cache.set( CEPH_VISION );
    }
    if (has_active_mutation("ELFA_NV")) {
        vision_mode_cache.set( ELFA_VISION );
    }
    if( has_active_mutation("NIGHTVISION2") ) {
        vision_mode_cache.set( NIGHTVISION_2 );
    }
    if( has_active_mutation("FEL_NV") ) {
        vision_mode_cache.set( FELINE_VISION );
    }
    if( has_active_mutation("URSINE_EYE") ) {
        vision_mode_cache.set( URSINE_VISION );
    }
    if (has_active_mutation("NIGHTVISION")) {
        vision_mode_cache.set(NIGHTVISION_1);
    }
    if( has_trait("BIRD_EYE") ) {
        vision_mode_cache.set( BIRD_EYE);
    }
}
Пример #26
0
void Character::recalc_hp()
{
    int new_max_hp[num_hp_parts];
    for( auto &elem : new_max_hp ) {
        ///\EFFECT_STR_MAX increases base hp
        elem = 60 + str_max * 3;
        if (has_trait("HUGE")) {
            // Bad-Huge doesn't quite have the cardio/skeletal/etc to support the mass,
            // so no HP bonus from the ST above/beyond that from Large
            elem -= 6;
        }
        // You lose half the HP you'd expect from BENDY mutations.  Your gelatinous
        // structure can help with that, a bit.
        if (has_trait("BENDY2")) {
            elem += 3;
        }
        if (has_trait("BENDY3")) {
            elem += 6;
        }
        // Only the most extreme applies.
        if (has_trait("TOUGH")) {
            elem *= 1.2;
        } else if (has_trait("TOUGH2")) {
            elem *= 1.3;
        } else if (has_trait("TOUGH3")) {
            elem *= 1.4;
        } else if (has_trait("FLIMSY")) {
            elem *= .75;
        } else if (has_trait("FLIMSY2")) {
            elem *= .5;
        } else if (has_trait("FLIMSY3")) {
            elem *= .25;
        }
        // Mutated toughness stacks with starting, by design.
        if (has_trait("MUT_TOUGH")) {
            elem *= 1.2;
        } else if (has_trait("MUT_TOUGH2")) {
            elem *= 1.3;
        } else if (has_trait("MUT_TOUGH3")) {
            elem *= 1.4;
        }
    }
    if( has_trait( "GLASSJAW" ) ) {
        new_max_hp[hp_head] *= 0.8;
    }
    for( int i = 0; i < num_hp_parts; i++ ) {
        hp_cur[i] *= (float)new_max_hp[i] / (float)hp_max[i];
        hp_max[i] = new_max_hp[i];
    }
}
Пример #27
0
void player::remove_mutation(std::string mut)
{
    // Check for dependant mutations first
    std::vector<std::string> dependant;

    for (std::map<std::string, trait>::iterator iter = traits.begin(); iter != traits.end(); ++iter) {
        for (int i = 0; i < mutation_data[iter->first].prereqs.size(); i++) {
            if (mutation_data[iter->first].prereqs[i] == iter->first) {
                dependant.push_back(iter->first);
                break;
            }
        }
    }

    if (dependant.size() > 0) {
        remove_mutation(dependant[rng(0, dependant.size()-1)]);
        return;
    }

    // Check if there's a prereq we should shrink back into
    std::string replacing = "";
    std::vector<std::string> originals = mutation_data[mut].prereqs;
    for (int i = 0; replacing == "" && i < originals.size(); i++) {
        std::string pre = originals[i];
        for (int j = 0; replacing == "" && j < mutation_data[pre].replacements.size(); j++) {
            if (mutation_data[pre].replacements[j] == mut) {
                replacing = pre;
            }
        }
    }
    
    std::string replacing2 = "";
    std::vector<std::string> originals2 = mutation_data[mut].prereqs2;
    for (int i = 0; replacing2 == "" && i < originals2.size(); i++) {
        std::string pre2 = originals2[i];
        for (int j = 0; replacing2 == "" && j < mutation_data[pre2].replacements.size(); j++) {
            if (mutation_data[pre2].replacements[j] == mut) {
                replacing2 = pre2;
            }
        }
    }

    // See if this mutation is cancelled by a base trait
    //Only if there's no prereq to shrink to, thus we're at the bottom of the trait line
    if (replacing == "") {
        //Check each mutation until we reach the end or find a trait to revert to
        for (std::map<std::string, trait>::iterator iter = traits.begin(); replacing == "" && iter != traits.end(); ++iter) {
            //See if it's in our list of base traits but not active
            if (has_base_trait(iter->first) && !has_trait(iter->first)) {
                //See if that base trait cancels the mutation we are using
                std::vector<std::string> traitcheck = mutation_data[iter->first].cancels;
                if (!traitcheck.empty()) {
                    for (int j = 0; replacing == "" && j < traitcheck.size(); j++) {
                        if (traitcheck[j] == mut) {
                            replacing = (iter->first);
                        }
                    }
                }
            }
        }
    }
    
    // Duplicated for prereq2
    if (replacing2 == "") {
        //Check each mutation until we reach the end or find a trait to revert to
        for (std::map<std::string, trait>::iterator iter = traits.begin(); replacing2 == "" && iter != traits.end(); ++iter) {
            //See if it's in our list of base traits but not active
            if (has_base_trait(iter->first) && !has_trait(iter->first)) {
                //See if that base trait cancels the mutation we are using
                std::vector<std::string> traitcheck = mutation_data[iter->first].cancels;
                if (!traitcheck.empty()) {
                    for (int j = 0; replacing2 == "" && j < traitcheck.size(); j++) {
                        if (traitcheck[j] == mut) {
                            replacing2 = (iter->first);
                        }
                    }
                }
            }
        }
    }
    
    // This should revert back to a removed base trait rather than simply removing the mutation
    toggle_mutation(mut);

    bool mutation_replaced = false;
    
    if (replacing != "") {
        g->add_msg(_("Your %1$s mutation turns into %2$s."), traits[mut].name.c_str(),
                   traits[replacing].name.c_str());
        toggle_mutation(replacing);
        mutation_loss_effect(*this, mut);
        mutation_effect(*this, replacing);
        mutation_replaced = true;
    }
    if (replacing2 != "") {
        g->add_msg(_("Your %1$s mutation turns into %2$s."), traits[mut].name.c_str(),
                   traits[replacing2].name.c_str());
        toggle_mutation(replacing2);
        mutation_loss_effect(*this, mut);
        mutation_effect(*this, replacing2);
        mutation_replaced = true;
    }
    if(!mutation_replaced) {
        g->add_msg(_("You lose your %s mutation."), traits[mut].name.c_str());
        mutation_loss_effect(*this, mut);
    }

    set_highest_cat_level();
    drench_mut_calc();
}
Пример #28
0
void player::mutate()
{
    bool force_bad = one_in(3);
    bool force_good = false;
    if (has_trait("ROBUST") && force_bad) {
        // Robust Genetics gives you a 33% chance for a good mutation,
        // instead of the 33% chance of a bad one.
        force_bad = false;
        force_good = true;
    }

    // Determine the highest mutation categorie
    std::string cat = get_highest_category();

    // See if we should ugrade/extend an existing mutation...
    std::vector<std::string> upgrades;

    // ... or remove one that is not in our highest category
    std::vector<std::string> downgrades;

    // For each mutation...
    for (std::map<std::string, trait>::iterator iter = traits.begin(); iter != traits.end(); ++iter) {
        std::string base_mutation = iter->first;

        // ...that we have...
        if (has_trait(base_mutation)) {
            // ...consider the mutations that replace it.
            for (int i = 0; i < mutation_data[base_mutation].replacements.size(); i++) {
                std::string mutation = mutation_data[base_mutation].replacements[i];

                if (mutation_ok(mutation, force_good, force_bad)) {
                    upgrades.push_back(mutation);
                }
            }

            // ...consider the mutations that add to it.
            for (int i = 0; i < mutation_data[base_mutation].additions.size(); i++) {
                std::string mutation = mutation_data[base_mutation].additions[i];

                if (mutation_ok(mutation, force_good, force_bad)) {
                    upgrades.push_back(mutation);
                }
            }

            // ...consider whether its in our highest category
            if( has_trait(base_mutation) && !has_base_trait(base_mutation) ) { // Starting traits don't count toward categories
                std::vector<std::string> group = mutations_category[cat];
                bool in_cat = false;
                for (int j = 0; j < group.size(); j++) {
                    if (group[j] == base_mutation) {
                        in_cat = true;
                        break;
                    }
                }

                // mark for removal
                if(!in_cat) {
                    downgrades.push_back(base_mutation);
                }
            }
        }
    }

    // Preliminary round to either upgrade or remove existing mutations
    if(one_in(2)) {
        if (upgrades.size() > 0) {
            // (upgrade count) chances to pick an upgrade, 4 chances to pick something else.
            int roll = rng(0, upgrades.size() + 4);
            if (roll < upgrades.size()) {
                // We got a valid upgrade index, so use it and return.
                mutate_towards(upgrades[roll]);
                return;
            }
        }
    } else {
      // Remove existing mutations that don't fit into our category
      if (downgrades.size() > 0 && cat != "") {
          int roll = rng(0, downgrades.size() + 4);
          if (roll < downgrades.size()) {
              remove_mutation(downgrades[roll]);
              return;
          }
      }
    }

    std::vector<std::string> valid; // Valid mutations
    bool first_pass = true;

    do {
        // If we tried once with a non-NULL category, and couldn't find anything valid
        // there, try again with MUTCAT_NULL
        if (!first_pass) {
            cat = "";
        }

        if (cat == "") {
            // Pull the full list
            for (std::map<std::string, trait>::iterator iter = traits.begin(); iter != traits.end(); ++iter) {
                if (mutation_data[iter->first].valid) {
                    valid.push_back( iter->first );
                }
            }
        } else {
            // Pull the category's list
            valid = mutations_category[cat];
        }

        // Remove anything we already have, that we have a child of, or that
        // goes against our intention of a good/bad mutation
        for (int i = 0; i < valid.size(); i++) {
            if (!mutation_ok(valid[i], force_good, force_bad)) {
                valid.erase(valid.begin() + i);
                i--;
            }
        }

        if (valid.empty()) {
            // So we won't repeat endlessly
            first_pass = false;
        }
    } while (valid.empty() && cat != "");

    if (valid.empty()) {
        // Couldn't find anything at all!
        return;
    }

    std::string selection = valid[ rng(0, valid.size() - 1) ]; // Pick one!
    mutate_towards(selection);
}
Пример #29
0
void player::mutate_towards(std::string mut)
{
    if (has_child_flag(mut)) {
        remove_child_flag(mut);
        return;
    }

    bool has_prereqs = false;
    bool prereq1 = false;
    bool prereq2 = false;
    std::string canceltrait = "";
    std::vector<std::string> prereq = mutation_data[mut].prereqs;
    std::vector<std::string> prereqs2 = mutation_data[mut].prereqs2;
    std::vector<std::string> cancel = mutation_data[mut].cancels;

    for (int i = 0; i < cancel.size(); i++) {
        if (!has_trait( cancel[i] )) {
            cancel.erase(cancel.begin() + i);
            i--;
        } else if (has_base_trait( cancel[i] )) {
            //If we have the trait, but it's a base trait, don't allow it to be removed normally
            canceltrait = cancel[i];
            cancel.erase(cancel.begin() + i);
            i--;
        }
    }

    if (!cancel.empty()) {
        std::string removed = cancel[ rng(0, cancel.size() - 1) ];
        remove_mutation(removed);
        return;
    }

    for (int i = 0; (!prereq1) && i < prereq.size(); i++) {
        if (has_trait(prereq[i])) {
            prereq1 = true;
        }
    }
    
    for (int i = 0; (!prereq2) && i < prereqs2.size(); i++) {
        if (has_trait(prereqs2[i])) {
            prereq2 = true;
        }
    }

    if (prereq1 && prereq2) {
        has_prereqs = true;
    }
    
    if (!has_prereqs && (!prereq.empty() || !prereqs2.empty())) {
        if (!prereq1 && !prereq.empty()) {
            std::string devel = prereq[ rng(0, prereq.size() - 1) ];
            mutate_towards(devel);
            return;
            }
        else if (!prereq2 && !prereqs2.empty()) {
            std::string devel = prereqs2[ rng(0, prereqs2.size() - 1) ];
            mutate_towards(devel);
            return;
            }
    }
    
    // Check for threshhold mutation, if needed
    bool threshold = mutation_data[mut].threshold;
    bool has_threshreq = false;
    std::vector<std::string> threshreq = mutation_data[mut].threshreq;
    std::vector<std::string> mutcat;
    mutcat = mutation_data[mut].category;
    
    // It shouldn't pick a Threshold anyway (they're supposed to be non-Valid)
    // but if it does, just reroll
    if (threshold) {
        g->add_msg(_("You feel something straining deep inside you, yearning to be free..."));
        mutate();
        return;
    }

    for (int i = 0; !has_threshreq && i < threshreq.size(); i++) {
        if (has_trait(threshreq[i])) {
            has_threshreq = true;
        }
    }

    // No crossing The Threshold by simply not having it
    // Reroll mutation, uncategorized (prevents looping)
    if (!has_threshreq && !threshreq.empty()) {
        g->add_msg(_("You feel something straining deep inside you, yearning to be free..."));
        mutate();
        return;
    }

    // Check if one of the prereqs that we have TURNS INTO this one
    std::string replacing = "";
    prereq = mutation_data[mut].prereqs; // Reset it
    for (int i = 0; i < prereq.size(); i++) {
        if (has_trait(prereq[i])) {
            std::string pre = prereq[i];
            for (int j = 0; replacing == "" && j < mutation_data[pre].replacements.size(); j++) {
                if (mutation_data[pre].replacements[j] == mut) {
                    replacing = pre;
                }
            }
        }
    }

    toggle_mutation(mut);
    if (replacing != "") {
        g->add_msg(_("Your %1$s mutation turns into %2$s!"), traits[replacing].name.c_str(), traits[mut].name.c_str());
        g->u.add_memorial_log(_("'%s' mutation turned into '%s'"), traits[replacing].name.c_str(), traits[mut].name.c_str());
        toggle_mutation(replacing);
        mutation_loss_effect(*this, replacing);
        mutation_effect(*this, mut);

    } else if (canceltrait != "") {
        // If this new mutation cancels a base trait, remove it and add the mutation at the same time
        g->add_msg(_("Your innate %1$s trait turns into %2$s!"), traits[canceltrait].name.c_str(), traits[mut].name.c_str());
        g->u.add_memorial_log(_("'%s' trait turned into '%s'"), traits[canceltrait].name.c_str(), traits[mut].name.c_str());
        toggle_mutation(canceltrait);
        mutation_loss_effect(*this, canceltrait);
        mutation_effect(*this, mut);
    } else {
        g->add_msg(_("You gain a mutation called %s!"), traits[mut].name.c_str());
        g->u.add_memorial_log(_("Gained the mutation '%s'."), traits[mut].name.c_str());
        mutation_effect(*this, mut);
    }

    set_highest_cat_level();
    drench_mut_calc();
}
Пример #30
0
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;
}