Example #1
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.
 }
}
Example #2
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;
 }
}
Example #3
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)
{
    bionic bio = my_bionics[b];
    int power_cost = bionics[bio.id]->power_cost;
    if ((weapon.type->id == "bio_claws_weapon" && bio.id == "bio_claws_weapon") ||
        (weapon.type->id == "bio_blade_weapon" && bio.id == "bio_blade_weapon")) {
        power_cost = 0;
    }
    if (power_level < power_cost) {
        if (my_bionics[b].powered) {
            add_msg(m_neutral, _("Your %s powers down."), bionics[bio.id]->name.c_str());
            my_bionics[b].powered = false;
        } else {
            add_msg(m_info, _("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 - 1;
        }
        power_level -= power_cost;
    }

    std::vector<point> traj;
    std::vector<std::string> good;
    std::vector<std::string> bad;
    int dirx, diry;
    item tmp_item;

    if(bio.id == "bio_painkiller") {
        pkill += 6;
        pain -= 2;
        if (pkill > pain) {
            pkill = pain;
        }
    } else if (bio.id == "bio_nanobots") {
        rem_disease("bleed");
        healall(4);
    } else if (bio.id == "bio_night") {
        if (calendar::turn % 5) {
            add_msg(m_neutral, _("Artificial night generator active!"));
        }
    } else if (bio.id == "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 );
                g->m.bash( i, j, 40 ); // Multibash effect, so that doors &c will fall
                g->m.bash( i, j, 40 );
                if (g->m.is_destructable(i, j) && rng(1, 10) >= 4) {
                    g->m.ter_set(i, j, t_rubble);
                }
            }
        }
    } else if (bio.id == "bio_time_freeze") {
        moves += power_level;
        power_level = 0;
        add_msg(m_good, _("Your speed suddenly increases!"));
        if (one_in(3)) {
            add_msg(m_bad, _("Your muscles tear with the strain."));
            apply_damage( nullptr, bp_arm_l, rng( 5, 10 ) );
            apply_damage( nullptr, bp_arm_r, rng( 5, 10 ) );
            apply_damage( nullptr, bp_leg_l, rng( 7, 12 ) );
            apply_damage( nullptr, bp_leg_r, rng( 7, 12 ) );
            apply_damage( nullptr, bp_torso, rng( 5, 15 ) );
        }
        if (one_in(5)) {
            add_disease("teleglow", rng(50, 400));
        }
    } else if (bio.id == "bio_teleport") {
        g->teleport();
        add_disease("teleglow", 300);
    }
    // TODO: More stuff here (and bio_blood_filter)
    else if(bio.id == "bio_blood_anal") {
        WINDOW *w = newwin(20, 40, 3 + ((TERMY > 25) ? (TERMY - 25) / 2 : 0),
                           10 + ((TERMX > 80) ? (TERMX - 80) / 2 : 0));
        draw_border(w);
        if (has_disease("fungus")) {
            bad.push_back(_("Fungal Parasite"));
        }
        if (has_disease("dermatik")) {
            bad.push_back(_("Insect Parasite"));
        }
        if (has_effect("stung")) {
            bad.push_back(_("Stung"));
        }
        if (has_effect("poison")) {
            bad.push_back(_("Poison"));
        }
        if (radiation > 0) {
            bad.push_back(_("Irradiated"));
        }
        if (has_disease("pkill1")) {
            good.push_back(_("Minor Painkiller"));
        }
        if (has_disease("pkill2")) {
            good.push_back(_("Moderate Painkiller"));
        }
        if (has_disease("pkill3")) {
            good.push_back(_("Heavy Painkiller"));
        }
        if (has_disease("pkill_l")) {
            good.push_back(_("Slow-Release Painkiller"));
        }
        if (has_disease("drunk")) {
            good.push_back(_("Alcohol"));
        }
        if (has_disease("cig")) {
            good.push_back(_("Nicotine"));
        }
        if (has_disease("meth")) {
            good.push_back(_("Methamphetamines"));
        }
        if (has_disease("high")) {
            good.push_back(_("Intoxicant: Other"));
        }
        if (has_disease("weed_high")) {
            good.push_back(_("THC Intoxication"));
        }
        if (has_disease("hallu") || has_disease("visuals")) {
            bad.push_back(_("Magic Mushroom"));
        }
        if (has_disease("iodine")) {
            good.push_back(_("Iodine"));
        }
        if (has_disease("datura")) {
            good.push_back(_("Anticholinergic Tropane Alkaloids"));
        }
        if (has_disease("took_xanax")) {
            good.push_back(_("Xanax"));
        }
        if (has_disease("took_prozac")) {
            good.push_back(_("Prozac"));
        }
        if (has_disease("took_flumed")) {
            good.push_back(_("Antihistamines"));
        }
        if (has_disease("adrenaline")) {
            good.push_back(_("Adrenaline Spike"));
        }
        if (has_disease("tapeworm")) {  // This little guy is immune to the blood filter though, as he lives in your bowels.
            good.push_back(_("Intestinal Parasite"));
        }
        if (has_disease("bloodworms")) {
            good.push_back(_("Hemolytic Parasites"));
        }
        if (has_disease("brainworm")) {  // This little guy is immune to the blood filter too, as he lives in your brain.
            good.push_back(_("Intracranial Parasite"));
        }
        if (has_disease("paincysts")) {  // These little guys are immune to the blood filter too, as they live in your muscles.
            good.push_back(_("Intramuscular Parasites"));
        }
        if (has_disease("tetanus")) {  // Tetanus infection.
            good.push_back(_("Clostridium Tetani Infection"));
        }
        if (good.empty() && bad.empty()) {
            mvwprintz(w, 1, 1, c_white, _("No effects."));
        } else {
            for (unsigned line = 1; line < 39 && line <= good.size() + bad.size(); line++) {
                if (line <= bad.size()) {
                    mvwprintz(w, line, 1, c_red, "%s", bad[line - 1].c_str());
                } else {
                    mvwprintz(w, line, 1, c_green, "%s", good[line - 1 - bad.size()].c_str());
                }
            }
        }
        wrefresh(w);
        refresh();
        getch();
        delwin(w);
    } else if(bio.id == "bio_blood_filter") {
        add_msg(m_neutral, _("You activate your blood filtration system."));
        rem_disease("fungus");
        rem_disease("dermatik");
        rem_disease("bloodworms");
        rem_disease("tetanus");
        remove_effect("poison");
        remove_effect("stung");
        rem_disease("pkill1");
        rem_disease("pkill2");
        rem_disease("pkill3");
        rem_disease("pkill_l");
        rem_disease("drunk");
        rem_disease("cig");
        rem_disease("high");
        rem_disease("hallu");
        rem_disease("visuals");
        rem_disease("iodine");
        rem_disease("datura");
        rem_disease("took_xanax");
        rem_disease("took_prozac");
        rem_disease("took_flumed");
        rem_disease("adrenaline");
        rem_disease("meth");
        pkill = 0;
        stim = 0;
    } else if(bio.id == "bio_evap") {
        item water = item("water_clean", 0);
        int humidity = g->weatherGen.get_weather(pos(), calendar::turn).humidity;
        int water_charges = (humidity * 3.0) / 100.0 + 0.5;
        // At 50% relative humidity or more, the player will draw 2 units of water
        // At 16% relative humidity or less, the player will draw 0 units of water
        water.charges = water_charges;
        if (water_charges == 0) {
            add_msg_if_player(m_bad, _("There was not enough moisture in the air from which to draw water!"));
        }
        if (g->handle_liquid(water, true, false)) {
            moves -= 100;
        } else if (query_yn(_("Drink from your hands?"))) {
            inv.push_back(water);
            consume(inv.position_by_type(water.typeId()));
            moves -= 350;
        } else if (water.charges == water_charges && water_charges != 0) {
            power_level += bionics["bio_evap"]->power_cost;
        }
    } else if(bio.id == "bio_lighter") {
        if(!choose_adjacent(_("Start a fire where?"), dirx, diry) ||
           (!g->m.add_field(dirx, diry, fd_fire, 1))) {
            add_msg_if_player(m_info, _("You can't light a fire there."));
            power_level += bionics["bio_lighter"]->power_cost;
        }

    }
    if(bio.id == "bio_leukocyte") {
        add_msg(m_neutral, _("You activate your leukocyte breeder system."));
        g->u.set_healthy(std::min(100, g->u.get_healthy() + 2));
        g->u.mod_healthy_mod(20);
    }
    if(bio.id == "bio_geiger") {
        add_msg(m_info, _("Your radiation level: %d"), radiation);
    }
    if(bio.id == "bio_radscrubber") {
        add_msg(m_neutral, _("You activate your radiation scrubber system."));
        if (radiation > 4) {
            radiation -= 5;
        } else {
            radiation = 0;
        }
    }
    if(bio.id == "bio_adrenaline") {
        add_msg(m_neutral, _("You activate your adrenaline pump."));
        if (has_disease("adrenaline")) {
            add_disease("adrenaline", 50);
        } else {
            add_disease("adrenaline", 200);
        }
    } else if(bio.id == "bio_claws") {
        if (weapon.type->id == "bio_claws_weapon") {
            add_msg(m_neutral, _("You withdraw your claws."));
            weapon = ret_null;
        } else if (weapon.has_flag ("NO_UNWIELD")) {
            add_msg(m_info, _("Deactivate your %s first!"),
                    weapon.tname().c_str());
            power_level += bionics[bio.id]->power_cost;
            return;
        } else if(weapon.type->id != "null") {
            add_msg(m_warning, _("Your claws extend, forcing you to drop your %s."),
                    weapon.tname().c_str());
            g->m.add_item_or_charges(posx, posy, weapon);
            weapon = item("bio_claws_weapon", 0);
            weapon.invlet = '#';
        } else {
            add_msg(m_neutral, _("Your claws extend!"));
            weapon = item("bio_claws_weapon", 0);
            weapon.invlet = '#';
        }
    } else if(bio.id == "bio_blade") {
        if (weapon.type->id == "bio_blade_weapon") {
            add_msg(m_neutral, _("You retract your blade."));
            weapon = ret_null;
        } else if (weapon.has_flag ("NO_UNWIELD")) {
            add_msg(m_info, _("Deactivate your %s first!"),
                    weapon.tname().c_str());
            power_level += bionics[bio.id]->power_cost;
            return;
        } else if(weapon.type->id != "null") {
            add_msg(m_warning, _("Your blade extends, forcing you to drop your %s."),
                    weapon.tname().c_str());
            g->m.add_item_or_charges(posx, posy, weapon);
            weapon = item("bio_blade_weapon", 0);
            weapon.invlet = '#';
        } else {
            add_msg(m_neutral, _("You extend your blade!"));
            weapon = item("bio_blade_weapon", 0);
            weapon.invlet = '#';
        }
    } else if(bio.id == "bio_blaster") {
        tmp_item = weapon;
        weapon = item("bio_blaster_gun", 0);
        g->refresh_all();
        g->plfire(false);
        if(weapon.charges == 1) { // not fired
            power_level += bionics[bio.id]->power_cost;
        }
        weapon = tmp_item;
    } else if (bio.id == "bio_laser") {
        tmp_item = weapon;
        weapon = item("bio_laser_gun", 0);
        g->refresh_all();
        g->plfire(false);
        if(weapon.charges == 1) { // not fired
            power_level += bionics[bio.id]->power_cost;
        }
        weapon = tmp_item;
    } else if(bio.id == "bio_chain_lightning") {
        tmp_item = weapon;
        weapon = item("bio_lightning", 0);
        g->refresh_all();
        g->plfire(false);
        if(weapon.charges == 1) { // not fired
            power_level += bionics[bio.id]->power_cost;
        }
        weapon = tmp_item;
    } else if (bio.id == "bio_emp") {
        if(choose_adjacent(_("Create an EMP where?"), dirx, diry)) {
            g->emp_blast(dirx, diry);
        } else {
            power_level += bionics["bio_emp"]->power_cost;
        }
    } else if (bio.id == "bio_hydraulics") {
        add_msg(m_good, _("Your muscles hiss as hydraulic strength fills them!"));
        // Sound of hissing hydraulic muscle! (not quite as loud as a car horn)
        g->sound(posx, posy, 19, _("HISISSS!"));
    } else if (bio.id == "bio_water_extractor") {
        bool extracted = false;
        for (std::vector<item>::iterator it = g->m.i_at(posx, posy).begin();
             it != g->m.i_at(posx, posy).end(); ++it) {
            if (it->type->id == "corpse" ) {
                int avail = 0;
                if ( it->item_vars.find("remaining_water") != it->item_vars.end() ) {
                    avail = atoi ( it->item_vars["remaining_water"].c_str() );
                } else {
                    avail = it->volume() / 2;
                }
                if(avail > 0 && query_yn(_("Extract water from the %s"), it->tname().c_str())) {
                    item water = item("water_clean", 0);
                    if (g->handle_liquid(water, true, true)) {
                        moves -= 100;
                    } else if (query_yn(_("Drink directly from the condenser?"))) {
                        inv.push_back(water);
                        consume(inv.position_by_type(water.typeId()));
                        moves -= 350;
                    }
                    extracted = true;
                    avail--;
                    it->item_vars["remaining_water"] = string_format("%d", avail);
                    break;
                }
            }
        }
        if (!extracted) {
            power_level += bionics["bio_water_extractor"]->power_cost;
        }
    } else if(bio.id == "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) {
                    int t; //not sure why map:sees really needs this, but w/e
                    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 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);
                        std::vector<point>::iterator it;
                        for (it = traj.begin(); it != traj.end(); ++it) {
                            int index = g->mon_at(it->x, it->y);
                            if (index != -1) {
                                g->zombie(index).apply_damage( this, bp_torso, tmp_item.weight() / 225 );
                                g->m.add_item_or_charges(it->x, it->y, tmp_item);
                                break;
                            } else if (it != traj.begin() && g->m.move_cost(it->x, it->y) == 0) {
                                g->m.bash( it->x, it->y, tmp_item.weight() / 225 );
                                if (g->m.move_cost(it->x, it->y) == 0) {
                                    g->m.add_item_or_charges((it - 1)->x, (it - 1)->y, tmp_item);
                                    break;
                                }
                            }
                        }
                        if (it == traj.end()) {
                            g->m.add_item_or_charges(posx, posy, tmp_item);
                        }
                    }
                }
            }
        }
    } else if(bio.id == "bio_lockpick") {
        if(!choose_adjacent(_("Activate your bio lockpick where?"), dirx, diry)) {
            power_level += bionics["bio_lockpick"]->power_cost;
            return;
        }
        ter_id type = g->m.ter(dirx, diry);
        if (type  == t_door_locked || type == t_door_locked_alarm || type == t_door_locked_interior ) {
            moves -= 40;
            std::string door_name = rm_prefix(_("<door_name>door"));
            add_msg_if_player(m_neutral, _("With a satisfying click, the lock on the %s opens."),
                              door_name.c_str());
            g->m.ter_set(dirx, diry, t_door_c);
            // Locked metal doors are the Lab and Bunker entries.  Those need to stay locked.
        } else if(type == t_door_bar_locked) {
            moves -= 40;
            std::string door_name = rm_prefix(_("<door_name>door"));
            add_msg_if_player(m_neutral, _("The %s swings open..."),
                              door_name.c_str()); //Could better copy the messages from lockpick....
            g->m.ter_set(dirx, diry, t_door_bar_o);
        } else if(type == t_chaingate_l) {
            moves -= 40;
            std::string gate_name = rm_prefix (_("<door_name>gate"));
            add_msg_if_player(m_neutral, _("With a satisfying click, the lock on the %s opens."),
                              gate_name.c_str());
            g->m.ter_set(dirx, diry, t_chaingate_c);
        } else if(type == t_door_c) {
            add_msg(m_info, _("That door isn't locked."));
        } else {
            add_msg_if_player(m_neutral, _("You can't unlock that %s."),
                              g->m.tername(dirx, diry).c_str());
        }
    } else if(bio.id == "bio_flashbang") {
        add_msg_if_player(m_neutral, _("You activate your integrated flashbang generator!"));
        g->flashbang(posx, posy, true);
    } else if(bio.id == "bio_shockwave") {
        g->shockwave(posx, posy, 3, 4, 2, 8, true);
        add_msg_if_player(m_neutral, _("You unleash a powerful shockwave!"));
    }
}