Esempio n. 1
0
void construct::done_move(game *g, point p)
{
 mvprintz(0, 0, c_red, "Press a direction for the furniture to move (. to cancel):");
 int x = 0, y = 0;
 //Keep looping until we get a valid direction or a cancel.
 while(true){
  do
   get_direction(g, x, y, input());
  while (x == -2 || y == -2);
  if(x == 0 && y == 0)
   return;
  x += p.x;
  y += p.y;
  if(!able_empty(g, point(x, y))) {
   mvprintz(0, 0, c_red, "Can't move furniture there! Choose a direction with open floor.");
   continue;
  }
  break;
 }

 g->sound(x, y, furnlist[g->m.furn(p.x, p.y)].move_str_req * 2, "a scraping noise");
 g->m.furn_set(x, y, g->m.furn(p.x, p.y));
 g->m.furn_set(p.x, p.y, f_null);

 //Move all Items within a container
 std::vector <item> vItemMove = g->m.i_at(p.x, p.y);
 for (int i=0; i < vItemMove.size(); i++)
  g->m.add_item(x, y, vItemMove[i]);

 g->m.i_clear(p.x, p.y);
}
Esempio n. 2
0
void construct::done_furniture(game *g, point p)
{
 mvprintz(0, 0, c_red, "Press a direction for the furniture to move (. to cancel):");
 int x = 0, y = 0;
 //Keep looping until we get a valid direction or a cancel.
 while(true){
  do
   get_direction(g, x, y, input());
  while (x == -2 || y == -2);
  if(x == 0 && y == 0)
   return;
  x += p.x;
  y += p.y;
  if(g->m.ter(x, y) != t_floor || !g->is_empty(x, y)) {
   mvprintz(0, 0, c_red, "Can't move furniture there! Choose a direction with open floor.");
   continue;
  }
  break;
 }

 g->m.ter_set(x, y, g->m.ter(p.x, p.y));
 g->m.ter_set(p.x, p.y, t_floor);

 //Move all Items within a container
 std::vector <item> vItemMove = g->m.i_at(p.x, p.y);
 for (int i=0; i < vItemMove.size(); i++)
  g->m.add_item(x, y, vItemMove[i]);

 g->m.i_clear(p.x, p.y);
}
Esempio n. 3
0
void construct::done_tree(game *g, point p)
{
    mvprintz(0, 0, c_red, _("Press a direction for the tree to fall in:"));
    int x = 0, y = 0;
    do get_direction(x, y, input());
    while (x == -2 || y == -2);
    x = p.x + x * 3 + rng(-1, 1);
    y = p.y + y * 3 + rng(-1, 1);
    std::vector<point> tree = line_to(p.x, p.y, x, y, rng(1, 8));
    for (int i = 0; i < tree.size(); i++) {
        g->m.destroy(g, tree[i].x, tree[i].y, true);
        g->m.ter_set(tree[i].x, tree[i].y, t_trunk);
    }
}
Esempio n. 4
0
void iuse::extinguisher(game *g, player *p, item *it, bool t)
{
 g->draw();
 mvprintz(0, 0, c_red, "Pick a direction to spray:");
 int dirx, diry;
 get_direction(dirx, diry, input());
 if (dirx == -2) {
  g->add_msg("Invalid direction!");
  it->charges++;
  return;
 }
 p->moves -= 140;
 int x = dirx + p->posx;
 int y = diry + p->posy;
 if (g->m.field_at(x, y).type == fd_fire) {
  g->m.field_at(x, y).density -= rng(2, 3);
  if (g->m.field_at(x, y).density <= 0) {
   g->m.field_at(x, y).density = 1;
   g->m.field_at(x, y).type = fd_null;
  }
 }
 int mondex = g->mon_at(x, y);
 if (mondex != -1) {
  int linet;
  g->z[mondex].moves -= 150;
  if (g->u_see(&(g->z[mondex]), linet))
   g->add_msg("The %s is sprayed!", g->z[mondex].name().c_str());
  if (g->z[mondex].made_of(LIQUID)) {
   if (g->u_see(&(g->z[mondex]), linet))
    g->add_msg("The %s is frozen!", g->z[mondex].name().c_str());
   if (g->z[mondex].hurt(rng(20, 60)))
    g->kill_mon(mondex);
   else
    g->z[mondex].speed /= 2;
  }
 }
 if (g->m.move_cost(x, y) != 0) {
  x += dirx;
  y += diry;
  if (g->m.field_at(x, y).type == fd_fire) {
   g->m.field_at(x, y).density -= rng(0, 1) + rng(0, 1);
   if (g->m.field_at(x, y).density <= 0) {
    g->m.field_at(x, y).density = 1;
    g->m.field_at(x, y).type = fd_null;
   }
  }
 }
}
Esempio n. 5
0
void game::place_construction(constructable *con)
{
 refresh_all();
 inventory total_inv;
 total_inv.form_from_map(this, point(u.posx, u.posy), PICKUP_RANGE);
 total_inv.add_stack(u.inv_dump());

 std::vector<point> valid;
 for (int x = u.posx - 1; x <= u.posx + 1; x++) {
  for (int y = u.posy - 1; y <= u.posy + 1; y++) {
   if (x == u.posx && y == u.posy)
    y++;
   construct test;
   bool place_okay = (test.*(con->able))(this, point(x, y));
   for (int i = 0; i < con->stages.size() && !place_okay; i++) {
    if (m.ter(x, y) == con->stages[i].terrain)
     place_okay = true;
   }

   if (place_okay) {
// Make sure we're not trying to continue a construction that we can't finish
    int starting_stage = 0, max_stage = 0;
    for (int i = 0; i < con->stages.size(); i++) {
     if (m.ter(x, y) == con->stages[i].terrain)
      starting_stage = i + 1;
     if (player_can_build(u, total_inv, con, i, true))
      max_stage = i;
    }

    if (max_stage >= starting_stage) {
     valid.push_back(point(x, y));
     m.drawsq(w_terrain, u, x, y, true, false);
     wrefresh(w_terrain);
    }
   }
  }
 }
 mvprintz(0, 0, c_red, _("Pick a direction in which to construct:"));
 int dirx, diry;
 get_direction(this, dirx, diry, input());
 if (dirx == -2) {
  add_msg(_("Invalid direction."));
  return;
 }
 dirx += u.posx;
 diry += u.posy;
 bool point_is_okay = false;
 for (int i = 0; i < valid.size() && !point_is_okay; i++) {
  if (valid[i].x == dirx && valid[i].y == diry)
   point_is_okay = true;
 }
 if (!point_is_okay) {
  add_msg(_("You cannot build there!"));
  return;
 }

// Figure out what stage to start at, and what stage is the maximum
 int starting_stage = 0, max_stage = 0;
 for (int i = 0; i < con->stages.size(); i++) {
  if (m.ter(dirx, diry) == con->stages[i].terrain)
   starting_stage = i + 1;
  if (player_can_build(u, total_inv, con, i, true))
   max_stage = i;
 }

 u.activity = player_activity(ACT_BUILD, con->stages[starting_stage].time*1000,
                              con->id);
 u.moves = 0;
 std::vector<int> stages;
 for (int i = starting_stage; i <= max_stage; i++)
  stages.push_back(i);
 u.activity.values = stages;
 u.activity.placement = point(dirx, diry);
}
Esempio n. 6
0
void game::fire(player &p, int tarx, int tary, std::vector<point> &trajectory,
                bool burst)
{
 item ammotmp;
 item* gunmod = p.weapon.active_gunmod();
 it_ammo *curammo = NULL;
 item *weapon = NULL;

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

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

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

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

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

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

 bool is_bolt = false;
 std::set<std::string> *effects = &curammo->ammo_effects;
 // Bolts and arrows are silent
 if (curammo->type == "bolt" || curammo->type == "arrow")
  is_bolt = true;

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

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

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

// Set up a timespec for use in the nanosleep function below
 timespec ts;
 ts.tv_sec = 0;
 ts.tv_nsec = BULLET_SPEED;

 // Use up some ammunition
int trange = rl_dist(p.posx, p.posy, tarx, tary);

 if (trange < int(firing->volume / 3) && firing->ammo != "shot")
  trange = int(firing->volume / 3);
 else if (p.has_bionic("bio_targeting")) {
  if (trange > LONG_RANGE)
   trange = int(trange * .65);
  else
   trange = int(trange * .8);
 }
 if (firing->skill_used == Skill::skill("rifle") && trange > LONG_RANGE)
  trange = LONG_RANGE + .6 * (trange - LONG_RANGE);
 std::string message = "";

 bool missed = false;
 int tart;

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

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

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

       for (
         int radius = 0;                        /* range from last target, not shooter! */
         radius <= 2 + p.skillLevel("gun") &&   /* more skill: wider burst area? */
         radius <= weaponrange &&               /* this seems redundant */
         ( new_targets.empty() ||               /* got target? stop looking. However this breaks random selection, aka, wildly spraying, so: */
            wildly_spraying == true );          /* lets set this based on rng && stress or whatever elsewhere */
         radius++
       ) {                                      /* iterate from last target's position: makes sense for burst fire.*/

           for (std::vector<monster>::iterator it = z.begin(); it != z.end(); it++) {
               int nt_range_to_me = rl_dist(p.posx, p.posy, it->posx, it->posy);
               int dummy;
               if (nt_range_to_me == 0 || nt_range_to_me > weaponrange ||
                   !pl_sees(&p, &(*it), dummy)) {
                   /* reject out of range and unseen targets as well as MY FACE */
                   continue;
               }

               int nt_range_to_lt = rl_dist(tarx,tary,it->posx,it->posy);
               /* debug*/ if ( debug_retarget && nt_range_to_lt <= 5 ) printz(c_red, " r:%d/l:%d/m:%d ..", radius, nt_range_to_lt, nt_range_to_me );
               if (nt_range_to_lt != radius) {
                   continue;                    /* we're spiralling outward, catch you next iteration (maybe) */
               }
               if (it->hp >0 && it->friendly == 0) {
                   new_targets.push_back(point(it->posx, it->posy)); /* oh you're not dead and I don't like you. Hello! */
               }
           }
       }
       if ( new_targets.empty() == false ) {    /* new victim! or last victim moved */
          int target_picked = rng(0, new_targets.size() - 1); /* 1 victim list unless wildly spraying */
          tarx = new_targets[target_picked].x;
          tary = new_targets[target_picked].y;
          if (m.sees(p.posx, p.posy, tarx, tary, 0, tart)) {
              trajectory = line_to(p.posx, p.posy, tarx, tary, tart);
          } else {
              trajectory = line_to(p.posx, p.posy, tarx, tary, 0);
          }

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

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

  // Drop a shell casing if appropriate.
  itype_id casing_type = "null";
  if( curammo->type == "shot" ) casing_type = "shot_hull";
  else if( curammo->type == "9mm" ) casing_type = "9mm_casing";
  else if( curammo->type == "22" ) casing_type = "22_casing";
  else if( curammo->type == "38" ) casing_type = "38_casing";
  else if( curammo->type == "40" ) casing_type = "40_casing";
  else if( curammo->type == "44" ) casing_type = "44_casing";
  else if( curammo->type == "45" ) casing_type = "45_casing";
  else if( curammo->type == "454" ) casing_type = "454_casing";
  else if( curammo->type == "500" ) casing_type = "500_casing";
  else if( curammo->type == "57" ) casing_type = "57mm_casing";
  else if( curammo->type == "46" ) casing_type = "46mm_casing";
  else if( curammo->type == "762" ) casing_type = "762_casing";
  else if( curammo->type == "223" ) casing_type = "223_casing";
  else if( curammo->type == "3006" ) casing_type = "3006_casing";
  else if( curammo->type == "308" ) casing_type = "308_casing";
  else if( curammo->type == "40mm" ) casing_type = "40mm_casing";

  if (casing_type != "null") {
   item casing;
   casing.make(itypes[casing_type]);
   // Casing needs a charges of 1 to stack properly with other casings.
   casing.charges = 1;
    if( weapon->has_gunmod("brass_catcher") != -1 ) {
        p.i_add( casing );
    } else {
       int x = p.posx - 1 + rng(0, 2);
       int y = p.posy - 1 + rng(0, 2);
       m.add_item_or_charges(x, y, casing);
    }
   }

  // Use up a round (or 100)
  if (weapon->has_flag("FIRE_100"))
   weapon->charges -= 100;
  else
   weapon->charges--;

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

  make_gun_sound_effect(this, p, burst, weapon);
  int trange = calculate_range(p, tarx, tary);
  double missed_by = calculate_missed_by(p, trange, weapon);
// Calculate a penalty based on the monster's speed
  double monster_speed_penalty = 1.;
  int target_index = mon_at(tarx, tary);
  if (target_index != -1) {
   monster_speed_penalty = double(z[target_index].speed) / 80.;
   if (monster_speed_penalty < 1.)
    monster_speed_penalty = 1.;
  }

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

  if (missed_by >= 1.) {
// We missed D:
// Shoot a random nearby space?
   int mtarx = tarx + rng(0 - int(sqrt(double(missed_by))), int(sqrt(double(missed_by))));
   int mtary = tary + rng(0 - int(sqrt(double(missed_by))), int(sqrt(double(missed_by))));
   if (m.sees(p.posx, p.posy, x, y, -1, tart))
    trajectory = line_to(p.posx, p.posy, mtarx, mtary, tart);
   else
    trajectory = line_to(p.posx, p.posy, mtarx, mtary, 0);
   missed = true;
   if (!burst) {
       add_msg_player_or_npc( &p, _("You miss!"), _("<npcname> misses!") );
   }
  } else if (missed_by >= .8 / monster_speed_penalty) {
// Hit the space, but not necessarily the monster there
   missed = true;
   if (!burst) {
       add_msg_player_or_npc( &p, _("You barely miss!"), _("<npcname> barely misses!") );
   }
  }

  int dam = weapon->gun_damage();
  int tx = trajectory[0].x;
  int ty = trajectory[0].y;
  int px = trajectory[0].x;
  int py = trajectory[0].y;
  for (int i = 0; i < trajectory.size() &&
         (dam > 0 || (effects->count("FLAME"))); i++) {
      px = tx;
      py = ty;
      tx = trajectory[i].x;
      ty = trajectory[i].y;
// Drawing the bullet uses player u, and not player p, because it's drawn
// relative to YOUR position, which may not be the gunman's position.
   if (u_see(tx, ty)) {
    if (i > 0)
    {
        m.drawsq(w_terrain, u, trajectory[i-1].x, trajectory[i-1].y, false,
                 true, u.posx + u.view_offset_x, u.posy + u.view_offset_y);
    }
    char bullet = '*';
    if (effects->count("FLAME"))
     bullet = '#';
    mvwputch(w_terrain, ty + VIEWY - u.posy - u.view_offset_y,
             tx + VIEWX - u.posx - u.view_offset_x, c_red, bullet);
    wrefresh(w_terrain);
    if (&p == &u)
     nanosleep(&ts, NULL);
   }

   if (dam <= 0 && !(effects->count("FLAME"))) { // Ran out of momentum.
    ammo_effects(this, tx, ty, *effects);
    if (is_bolt && !(effects->count("IGNITE")) &&
        !(effects->count("EXPLOSIVE")) &&
        ((curammo->m1 == "wood" && !one_in(4)) ||
         (curammo->m1 != "wood" && !one_in(15))))
     m.add_item_or_charges(tx, ty, ammotmp);
    if (weapon->num_charges() == 0)
     weapon->curammo = NULL;
    return;
   }

// If there's a monster in the path of our bullet, and either our aim was true,
//  OR it's not the monster we were aiming at and we were lucky enough to hit it
   int mondex = mon_at(tx, ty);
// If we shot us a monster...
   if (mondex != -1 && (!z[mondex].has_flag(MF_DIGS) ||
       rl_dist(p.posx, p.posy, z[mondex].posx, z[mondex].posy) <= 1) &&
       ((!missed && i == trajectory.size() - 1) ||
        one_in((5 - int(z[mondex].type->size))))) {

    double goodhit = missed_by;
    if (i < trajectory.size() - 1) // Unintentional hit
     goodhit = double(rand() / (RAND_MAX + 1.0)) / 2;

// Penalize for the monster's speed
    if (z[mondex].speed > 80)
     goodhit *= double( double(z[mondex].speed) / 80.);

    std::vector<point> blood_traj = trajectory;
    blood_traj.insert(blood_traj.begin(), point(p.posx, p.posy));
    splatter(this, blood_traj, dam, &z[mondex]);
    shoot_monster(this, p, z[mondex], dam, goodhit, weapon);

   } else if ((!missed || one_in(3)) &&
              (npc_at(tx, ty) != -1 || (u.posx == tx && u.posy == ty)))  {
    double goodhit = missed_by;
    if (i < trajectory.size() - 1) // Unintentional hit
     goodhit = double(rand() / (RAND_MAX + 1.0)) / 2;
    player *h;
    if (u.posx == tx && u.posy == ty)
     h = &u;
    else
     h = active_npc[npc_at(tx, ty)];
    if (h->power_level >= 10 && h->uncanny_dodge()) {
     h->power_level -= 7; // dodging bullets costs extra
    }
    else {
     std::vector<point> blood_traj = trajectory;
     blood_traj.insert(blood_traj.begin(), point(p.posx, p.posy));
     splatter(this, blood_traj, dam);
     shoot_player(this, p, h, dam, goodhit);
    }
   } else
    m.shoot(this, tx, ty, dam, i == trajectory.size() - 1, *effects);
  } // Done with the trajectory!

  ammo_effects(this, tx, ty, *effects);
  if (effects->count("BOUNCE"))
  {
    for (int i = 0; i < z.size(); i++)
    {
        // search for monsters in radius 4 around impact site
        if (rl_dist(z[i].posx, z[i].posy, tx, ty) <= 4)
        {
            // don't hit targets that have already been hit
            if (!z[i].has_effect(ME_BOUNCED) && !z[i].dead)
            {
                add_msg(_("The attack bounced to %s!"), z[i].name().c_str());
                trajectory = line_to(tx, ty, z[i].posx, z[i].posy, 0);
                if (weapon->charges > 0)
                    fire(p, z[i].posx, z[i].posy, trajectory, false);
                break;
            }
        }
    }
  }

  if (m.move_cost(tx, ty) == 0) {
      tx = px;
      ty = py;
  }
  if (is_bolt && !(effects->count("IGNITE")) &&
      !(effects->count("EXPLOSIVE")) &&
      ((curammo->m1 == "wood" && !one_in(5)) ||
       (curammo->m1 != "wood" && !one_in(15))  ))
    m.add_item_or_charges(tx, ty, ammotmp);
 }

 if (weapon->num_charges() == 0)
  weapon->curammo = NULL;
}
Esempio n. 7
0
void game::place_construction(constructable *con)
{
 refresh_all();
 inventory total_inv;
 total_inv.form_from_map(this, point(u.posx, u.posy), PICKUP_RANGE);
 total_inv.add_stack(u.inv_dump());

 std::vector<point> valid;
 for (int x = u.posx - 1; x <= u.posx + 1; x++) {
  for (int y = u.posy - 1; y <= u.posy + 1; y++) {
   if (x == u.posx && y == u.posy)
    y++;
   construct test;
// initial function check
   int stage_num = ((test.*(con->able))(this, point(x, y)) ? 0 : -1);
// looking for result tiles from completed previous stages
   for (int i = 0; i < con->stages.size() && stage_num < 0; i++)
    if (m.ter(x, y) == con->stages[i].terrain && i + 1 < con->stages.size())
     stage_num = i + 1;
   if (player_can_build(u, total_inv, con, stage_num, true)) {
    valid.push_back(point(x, y));
    m.drawsq(this, w_terrain, x, y, true, false);
    wrefresh(w_terrain);
   }
  }
 }
 if (valid.empty()) {
  add_msg("There is no proper place here!");
  return;
 }
 mvprintz(0, 0, c_red, "Pick a direction in which to construct:");
 int dirx, diry;
 get_direction(this, dirx, diry, input());
 if (dirx == -2) {
  add_msg("Invalid direction.");
  return;
 }
 dirx += u.posx;
 diry += u.posy;
 bool point_is_okay = false;
 for (int i = 0; i < valid.size() && !point_is_okay; i++) {
  if (valid[i].x == dirx && valid[i].y == diry)
   point_is_okay = true;
 }
 if (!point_is_okay) {
  add_msg("You cannot build there!");
  return;
 }

// Figure out what stage to start at, and what stage is the maximum
 int starting_stage = 0, max_stage = 0;
 for (int i = 0; i < con->stages.size(); i++) {
  if (m.ter(dirx, diry) == con->stages[i].terrain)
   starting_stage = i + 1;
  if (player_can_build(u, total_inv, con, i, true))
   max_stage = i;
 }

 u.assign_activity(ACT_BUILD, con->stages[starting_stage].time * 1000, con->id);

 u.moves = 0;
 std::vector<int> stages;
 for (int i = starting_stage; i <= max_stage; i++)
  stages.push_back(i);
 u.activity.values = stages;
 u.activity.placement = point(dirx, diry);
}
Esempio n. 8
0
void iuse::hammer(game *g, player *p, item *it, bool t)
{
 g->draw();
 mvprintz(0, 0, c_red, "Pick a direction in which to construct:");
 int dirx, diry;
 get_direction(dirx, diry, input());
 if (dirx == -2) {
  g->add_msg("Invalid direction!");
  return;
 }
 dirx += p->posx;
 diry += p->posy;
 WINDOW* w = newwin(7, 40, 9, 30);
 wborder(w, LINE_XOXO, LINE_XOXO, LINE_OXOX, LINE_OXOX,
            LINE_OXXO, LINE_OOXX, LINE_XXOO, LINE_XOOX );
 int nails = 0, boards = 0;
 std::string title;
 ter_id newter;
 switch (g->m.ter(dirx, diry)) {
 case t_door_b:
  title = "Repair Door";
  nails = 12;
  boards = 3;
  newter = t_door_c;
  break;
 case t_door_c:
 case t_door_locked:
  title = "Board Up Door";
  nails = 12;
  boards = 3;
  newter = t_door_boarded;
  break;
 case t_door_frame:
  title = "Board Up Door Frame";
  nails = 24;
  boards = 6;
  newter = t_door_boarded;
  break;
 case t_window:
 case t_window_frame:
  title = "Board Up Window";
  nails = 4;
  boards = 2;
  newter = t_window_boarded;
  break;
 default:
  title = "";
  nails = 0;
  boards = 0;
 }
 if (nails == 0) {
  g->add_msg("Nothing to board up there!");
  return;
 }
 nc_color col;
 mvwprintz(w, 1, 1, c_white, title.c_str());
 col = (p->has_amount(itm_nail, nails) ? c_green : c_red);
 mvwprintz(w, 2, 1, col, "> %d nails", nails);
 col = (p->has_amount(itm_2x4, boards) ? c_green : c_red);
 mvwprintz(w, 3, 1, col, "> %d two by fours", boards);

 if (p->has_amount(itm_nail, nails) && p->has_amount(itm_2x4, boards)) {
  mvwprintz(w, 5, 1, c_yellow, "Perform action? (y/n)");
  wrefresh(w);
  char ch;
  do
   ch = getch();
  while (ch != 'y' && ch != 'Y' && ch != 'n' && ch != 'N');
  if (ch == 'y' || ch == 'Y') {
   p->moves -= boards * 50;
   p->use_up(itm_nail, nails);
   p->use_up(itm_2x4, boards);
   g->m.ter(dirx, diry) = newter;
  }
 } else {
  mvwprintz(w, 5, 1, c_red, "Cannot perform action.");
  wrefresh(w);
  getch();
 }
 delwin(w);
}
Esempio n. 9
0
void game::wish()
{
 int a = 0, shift = 0;
 int line;
 char ch = '.';
 bool search = false, found = false;
 std::string pattern;
 std::string info;
 item tmp;
 tmp.corpse = mtypes[0];
 do {
  erase();
  mvprintw(0, 0, "Wish for a: ");
  if (search) {
   found = false;
   if (ch == '\n') {
    search = false;
    found = true;
    pattern = "";
    ch = '.';
   } else if (ch == KEY_BACKSPACE && pattern.length() > 0)
    pattern.erase(pattern.end() - 1);
   else
    pattern += ch;

   for (int i = 0; i < itypes.size() && !found; i++) {
    if (itypes[i]->name.find(pattern) != std::string::npos) {
     shift = i;
     a = 0;
     if (shift + 23 > itypes.size()) {
      a = shift + 23 - itypes.size();
      shift = itypes.size() - 23;
     }
     found = true;
    }
   }
   if (found)
    mvprintw(1, 0, "%s               ", pattern.c_str());
   else if (search)
    mvprintz(1, 0, c_red, "%s not found!             ", pattern.c_str());
   else
    mvprintw(1, 0, "                      ");
  } else {	// Not searching; scroll by keys
   if (ch == 'j') a++;
   if (ch == 'k') a--;
   if (ch == '/') { 
    search = true;
    pattern =  "";
   }
  }
  if (a < 0) {
   a = 0;
   shift--;
   if (shift < 0) shift = 0;
  }
  if (a > 22) {
   a = 22;
   shift++;
   if (shift + 23 > itypes.size()) shift = itypes.size() - 23;
  }
  for (int i = 1; i < LESS(24, itypes.size()); i++) {
   mvprintz(i, 40, c_white, itypes[i-1+shift]->name.c_str());
   printz(itypes[i-1+shift]->color, "%c%", itypes[i-1+shift]->sym);
  }
  tmp.make(itypes[a + shift]);
  if (tmp.is_tool())
   tmp.charges = dynamic_cast<it_tool*>(tmp.type)->max_charges;
  else if (tmp.is_ammo())
   tmp.charges = 100;
  info = tmp.info();
  line = 2;
  mvprintw(line, 1, info.c_str());
  ch = getch();
 } while (ch != '\n');
 clear();
 mvprintw(0, 0, "\nWish granted.");
 tmp.invlet = nextinv;
 u.i_add(tmp);
 advance_nextinv();
 getch();
}
Esempio n. 10
0
void player::fire_gun(int tarx, int tary, bool burst) {
    item ammotmp;
    item* gunmod = weapon.active_gunmod();
    it_ammo *curammo = NULL;
    item *used_weapon = NULL;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        make_gun_sound_effect(*this, burst, used_weapon);

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

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

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

        int mtarx = tarx;
        int mtary = tary;

        int adjusted_damage = used_weapon->gun_damage();

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

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

    }

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

}