Exemplo n.º 1
0
void map::add_item(int x, int y, item new_item)
{
    if (!inbounds(x, y))
        return;
    if (has_flag(noitem, x, y) || i_at(x, y).size() >= 24) {// Too many items there
        std::vector<point> okay;
        for (int i = x - 1; i <= x + 1; i++) {
            for (int j = y - 1; j <= y + 1; j++) {
                if (inbounds(i, j) && move_cost(i, j) > 0 && !has_flag(noitem, i, j) &&
                        i_at(i, j).size() < 24)
                    okay.push_back(point(i, j));
            }
        }
        if (okay.size() == 0) {
            for (int i = x - 2; i <= x + 2; i++) {
                for (int j = y - 2; j <= y + 2; j++) {
                    if (inbounds(i, j) && move_cost(i, j) > 0 && !has_flag(noitem, i, j) &&
                            i_at(i, j).size()<24)
                        okay.push_back(point(i, j));
                }
            }
        }
        if (okay.size() == 0)	// STILL?
            return;
        point choice = okay[rng(0, okay.size() - 1)];
        add_item(choice.x, choice.y, new_item);
        return;
    }
    int nonant;
    cast_to_nonant(x, y, nonant);
    grid[nonant].itm[x][y].push_back(new_item);
}
Exemplo n.º 2
0
// map::destroy is only called (?) if the terrain is NOT bashable.
void map::destroy(game *g, int x, int y, bool makesound)
{
    switch (ter(x, y)) {
    case t_gas_pump:
        if (one_in(4))
            g->explosion(x, y, 40, 0, true);
        else
            for (int i = x - 2; i <= x + 2; i++) {
                for (int j = y - 2; j <= y + 2; j++) {
                    if (move_cost(i, j) > 0 && one_in(3))
                        add_item(i, j, g->itypes[itm_gasoline], 0);
                    if (move_cost(i, j) > 0 && one_in(6))
                        add_item(i, j, g->itypes[itm_steel_chunk], 0);
                }
            }
        ter(x, y) = t_rubble;
        break;
    case t_door_c:
    case t_door_b:
    case t_door_locked:
    case t_door_boarded:
        ter(x, y) = t_door_frame;
        for (int i = x - 2; i <= x + 2; i++) {
            for (int j = y - 2; j <= y + 2; j++) {
                if (move_cost(i, j) > 0 && one_in(6))
                    add_item(i, j, g->itypes[itm_2x4], 0);
            }
        }
    case t_wall_v:
    case t_wall_h:
        for (int i = x - 2; i <= x + 2; i++) {
            for (int j = y - 2; j <= y + 2; j++) {
                if (move_cost(i, j) > 0 && one_in(5))
                    add_item(i, j, g->itypes[itm_rock], 0);
                if (move_cost(i, j) > 0 && one_in(4))
                    add_item(i, j, g->itypes[itm_2x4], 0);
            }
        }
        ter(x, y) = t_rubble;
        break;
    default:
        if (has_flag(explodes, x, y))
            g->explosion(x, y, 40, 0, true);
        ter(x, y) = t_rubble;
    }
    if (makesound)
        g->sound(x, y, 40, "SMASH!!");
}
static void move_item( player &p, item &it, int quantity, const tripoint &src,
                       const tripoint &dest, vehicle *src_veh, int src_part )
{
    item leftovers = it;

    if( quantity != 0 && it.count_by_charges() ) {
        // Reinserting leftovers happens after item removal to avoid stacking issues.
        leftovers.charges = it.charges - quantity;
        if( leftovers.charges > 0 ) {
            it.charges = quantity;
        }
    } else {
        leftovers.charges = 0;
    }

    // Check that we can pick it up.
    if( !it.made_of_from_type( LIQUID ) ) {
        p.mod_moves( -move_cost( it, src, dest ) );
        put_into_vehicle_or_drop( p, item_drop_reason::deliberate, { it }, dest );
        // Remove from map or vehicle.
        if( src_veh ) {
            src_veh->remove_item( src_part, &it );
        } else {
            g->m.i_rem( src, &it );
        }
    }

    // If we didn't pick up a whole stack, put the remainder back where it came from.
    if( leftovers.charges > 0 ) {
        if( src_veh ) {
            if( !src_veh->add_item( src_part, leftovers ) ) {
                debugmsg( "SortLoot: Source vehicle failed to receive leftover charges." );
            }
        } else {
            g->m.add_item_or_charges( src, leftovers );
        }
    }
}
Exemplo n.º 4
0
bool map::process_fields_in_submap(game *g, int gridn)
{
 bool found_field = false;
 field *cur;
 field_id curtype;
 for (int locx = 0; locx < SEEX; locx++) {
  for (int locy = 0; locy < SEEY; locy++) {
   cur = &(grid[gridn].fld[locx][locy]);
   int x = locx + SEEX * (gridn % my_MAPSIZE),
       y = locy + SEEY * int(gridn / my_MAPSIZE);

   curtype = cur->type;
   if (!found_field && curtype != fd_null)
    found_field = true;
   if (cur->density > 3 || cur->density < 1)
    debugmsg("Whoooooa density of %d", cur->density);

  if (cur->age == 0)	// Don't process "newborn" fields
   curtype = fd_null;

  int part;
  vehicle *veh;
  switch (curtype) {

   case fd_null:
    break;	// Do nothing, obviously.  OBVIOUSLY.

   case fd_blood:
   case fd_bile:
    if (has_flag(swimmable, x, y))	// Dissipate faster in water
     cur->age += 250;
    break;

   case fd_acid:
    if (has_flag(swimmable, x, y))	// Dissipate faster in water
     cur->age += 20;
    for (int i = 0; i < i_at(x, y).size(); i++) {
     item *melting = &(i_at(x, y)[i]);
     if (melting->made_of(LIQUID) || melting->made_of(VEGGY)   ||
         melting->made_of(FLESH)  || melting->made_of(POWDER)  ||
         melting->made_of(COTTON) || melting->made_of(WOOL)    ||
         melting->made_of(PAPER)  || melting->made_of(PLASTIC) ||
         (melting->made_of(GLASS) && !one_in(3)) || one_in(4)) {
// Acid destructable objects here
      melting->damage++;
      if (melting->damage >= 5 ||
          (melting->made_of(PAPER) && melting->damage >= 3)) {
       cur->age += melting->volume();
       for (int m = 0; m < i_at(x, y)[i].contents.size(); m++)
        i_at(x, y).push_back( i_at(x, y)[i].contents[m] );
       i_at(x, y).erase(i_at(x, y).begin() + i);
       i--;
      }
     }
    }
    break;

   case fd_sap:
    break; // It doesn't do anything.

   case fd_fire: {
// Consume items as fuel to help us grow/last longer.
    bool destroyed = false;
    int vol = 0, smoke = 0, consumed = 0;
    for (int i = 0; i < i_at(x, y).size() && consumed < cur->density * 2; i++) {
     destroyed = false;
     vol = i_at(x, y)[i].volume();
     item *it = &(i_at(x, y)[i]);

     if (it->is_ammo() && it->ammo_type() != AT_BATT &&
         it->ammo_type() != AT_NAIL && it->ammo_type() != AT_BB &&
         it->ammo_type() != AT_BOLT && it->ammo_type() != AT_ARROW) {
      cur->age /= 2;
      cur->age -= 600;
      destroyed = true;
      smoke += 6;
      consumed++;

     } else if (it->made_of(PAPER)) {
      destroyed = it->burn(cur->density * 3);
      consumed++;
      if (cur->density == 1)
       cur->age -= vol * 10;
      if (vol >= 4)
       smoke++;

     } else if ((it->made_of(WOOD) || it->made_of(VEGGY))) {
      if (vol <= cur->density * 10 || cur->density == 3) {
       cur->age -= 4;
       destroyed = it->burn(cur->density);
       smoke++;
       consumed++;
      } else if (it->burnt < cur->density) {
       destroyed = it->burn(1);
       smoke++;
      }

     } else if ((it->made_of(COTTON) || it->made_of(WOOL))) {
      if (vol <= cur->density * 5 || cur->density == 3) {
       cur->age--;
       destroyed = it->burn(cur->density);
       smoke++;
       consumed++;
      } else if (it->burnt < cur->density) {
       destroyed = it->burn(1);
       smoke++;
      }

     } else if (it->made_of(FLESH)) {
      if (vol <= cur->density * 5 || (cur->density == 3 && one_in(vol / 20))) {
       cur->age--;
       destroyed = it->burn(cur->density);
       smoke += 3;
       consumed++;
      } else if (it->burnt < cur->density * 5 || cur->density >= 2) {
       destroyed = it->burn(1);
       smoke++;
      }

     } else if (it->made_of(LIQUID)) {
      switch (it->type->id) { // TODO: Make this be not a hack.
       case itm_whiskey:
       case itm_vodka:
       case itm_rum:
       case itm_tequila:
        cur->age -= 300;
        smoke += 6;
        break;
       default:
        cur->age += rng(80 * vol, 300 * vol);
        smoke++;
      }
      destroyed = true;
      consumed++;

     } else if (it->made_of(POWDER)) {
      cur->age -= vol;
      destroyed = true;
      smoke += 2;

     } else if (it->made_of(PLASTIC)) {
      smoke += 3;
      if (it->burnt <= cur->density * 2 || (cur->density == 3 && one_in(vol))) {
       destroyed = it->burn(cur->density);
       if (one_in(vol + it->burnt))
        cur->age--;
      }
     }

     if (destroyed) {
      for (int m = 0; m < i_at(x, y)[i].contents.size(); m++)
       i_at(x, y).push_back( i_at(x, y)[i].contents[m] );
      i_at(x, y).erase(i_at(x, y).begin() + i);
      i--;
     }
    }

    veh = &(veh_at(x, y, part));
    if (veh->type != veh_null && (veh->parts[part].flags & VHP_FUEL_TANK) && veh->fuel_type == AT_GAS)
    {
        if (cur->density > 1 && one_in (8) && veh->fuel > 0)
            veh->explode (g, x, y);
    }
// Consume the terrain we're on
    if (has_flag(explodes, x, y)) {
     ter(x, y) = ter_id(int(ter(x, y)) + 1);
     cur->age = 0;
     cur->density = 3;
     g->explosion(x, y, 40, 0, true);

    } else if (has_flag(inflammable, x, y) && one_in(32 - cur->density * 10)) {
     cur->age -= cur->density * cur->density * 40;
     smoke += 15;
     if (cur->density == 3)
      ter(x, y) = t_ash;
    } else if (has_flag(flammable,  x, y) && one_in(32 - cur->density * 10)) {
     cur->age -= cur->density * cur->density * 40;
     smoke += 15;
     if (cur->density == 3)
      ter(x, y) = t_rubble;
    } else if (has_flag(meltable,  x, y) && one_in(32 - cur->density * 10)) {
     cur->age -= cur->density * cur->density * 40;
     if (cur->density == 3)
      ter(x, y) = t_b_metal;
    } else if (terlist[ter(x, y)].flags & mfb(swimmable))
     cur->age += 800;	// Flames die quickly on water

// If we consumed a lot, the flames grow higher
    while (cur->density < 3 && cur->age < 0) {
     cur->age += 300;
     cur->density++;
    }
// If the flames are in a pit, it can't spread to non-pit
    bool in_pit = (ter(x, y) == t_pit);
// If the flames are REALLY big, they contribute to adjacent flames
    if (cur->density == 3 && cur->age < 0) {
// Randomly offset our x/y shifts by 0-2, to randomly pick a square to spread to
     int starti = rng(0, 2);
     int startj = rng(0, 2);
     for (int i = 0; i < 3 && cur->age < 0; i++) {
      for (int j = 0; j < 3 && cur->age < 0; j++) {
       int fx = x + ((i + starti) % 3) - 1, fy = y + ((j + startj) % 3) - 1;
       if (field_at(fx, fy).type == fd_fire && field_at(fx, fy).density < 3 &&
           (!in_pit || ter(fx, fy) == t_pit)) {
        field_at(fx, fy).density++;
        field_at(fx, fy).age = 0;
        cur->age = 0;
       }
      }
     }
    }
// Consume adjacent fuel / terrain to spread.
// Randomly offset our x/y shifts by 0-2, to randomly pick a square to spread to
    int starti = rng(0, 2);
    int startj = rng(0, 2);
    for (int i = 0; i < 3; i++) {
     for (int j = 0; j < 3; j++) {
      int fx = x + ((i + starti) % 3) - 1, fy = y + ((j + startj) % 3) - 1;
      if (INBOUNDS(fx, fy)) {
       int spread_chance = 20 * (cur->density - 1) + 10 * smoke;
       if (has_flag(explodes, fx, fy) && one_in(8 - cur->density)) {
        ter(fx, fy) = ter_id(int(ter(fx, fy)) + 1);
        g->explosion(fx, fy, 40, 0, true);
       } else if ((i != 0 || j != 0) && rng(1, 100) < spread_chance &&
                  (!in_pit || ter(fx, fy) == t_pit) &&
                  ((cur->density == 3 &&
                    (has_flag(flammable, fx, fy) || one_in(20))) ||
                   flammable_items_at(fx, fy) ||
                   field_at(fx, fy).type == fd_web)) {
        if (field_at(fx, fy).type == fd_smoke ||
            field_at(fx, fy).type == fd_web)
         field_at(fx, fy) = field(fd_fire, 1, 0);
        else
         add_field(g, fx, fy, fd_fire, 1);
       } else {
        bool nosmoke = true;
        for (int ii = -1; ii <= 1; ii++) {
         for (int jj = -1; jj <= 1; jj++) {
          if (field_at(x+ii, y+jj).type == fd_fire &&
              field_at(x+ii, y+jj).density == 3)
           smoke++;
          else if (field_at(x+ii, y+jj).type == fd_smoke)
           nosmoke = false;
         }
        }
// If we're not spreading, maybe we'll stick out some smoke, huh?
        if (move_cost(fx, fy) > 0 &&
            (!one_in(smoke) || (nosmoke && one_in(40))) &&
            rng(3, 35) < cur->density * 10 && cur->age < 1000) {
         smoke--;
         add_field(g, fx, fy, fd_smoke, rng(1, cur->density));
        }
       }
      }
     }
    }
   } break;

   case fd_smoke:
    for (int i = -1; i <= 1; i++) {
     for (int j = -1; j <= 1; j++)
      g->scent(x+i, y+j) = 0;
    }
    if (is_outside(x, y))
     cur->age += 50;
    if (one_in(2)) {
     std::vector <point> spread;
     for (int a = -1; a <= 1; a++) {
      for (int b = -1; b <= 1; b++) {
       if ((field_at(x+a, y+b).type == fd_smoke &&
             field_at(x+a, y+b).density < 3       ) ||
           (field_at(x+a, y+b).is_null() && move_cost(x+a, y+b) > 0))
        spread.push_back(point(x+a, y+b));
      }
     }
     if (cur->density > 0 && cur->age > 0 && spread.size() > 0) {
      point p = spread[rng(0, spread.size() - 1)];
      if (field_at(p.x, p.y).type == fd_smoke &&
          field_at(p.x, p.y).density < 3) {
        field_at(p.x, p.y).density++;
        cur->density--;
      } else if (cur->density > 0 && move_cost(p.x, p.y) > 0 &&
                 add_field(g, p.x, p.y, fd_smoke, 1)){
       cur->density--;
       field_at(p.x, p.y).age = cur->age;
      }
     }
    }
   break;

   case fd_tear_gas:
// Reset nearby scents to zero
    for (int i = -1; i <= 1; i++) {
     for (int j = -1; j <= 1; j++)
      g->scent(x+i, y+j) = 0;
    }
    if (is_outside(x, y))
     cur->age += 30;
// One in three chance that it spreads (less than smoke!)
    if (one_in(3)) {
     std::vector <point> spread;
// Pick all eligible points to spread to
     for (int a = -1; a <= 1; a++) {
      for (int b = -1; b <= 1; b++) {
       if (((field_at(x+a, y+b).type == fd_smoke ||
             field_at(x+a, y+b).type == fd_tear_gas) &&
             field_at(x+a, y+b).density < 3            )      ||
           (field_at(x+a, y+b).is_null() && move_cost(x+a, y+b) > 0))
        spread.push_back(point(x+a, y+b));
      }
     }
// Then, spread to a nearby point
     if (cur->density > 0 && cur->age > 0 && spread.size() > 0) {
      point p = spread[rng(0, spread.size() - 1)];
// Nearby teargas grows thicker
      if (field_at(p.x, p.y).type == fd_tear_gas &&
          field_at(p.x, p.y).density < 3) {
        field_at(p.x, p.y).density++;
        cur->density--;
// Nearby smoke is converted into teargas
      } else if (field_at(p.x, p.y).type == fd_smoke) {
       field_at(p.x, p.y).type = fd_tear_gas;
// Or, just create a new field.
      } else if (cur->density > 0 && move_cost(p.x, p.y) > 0 &&
                 add_field(g, p.x, p.y, fd_tear_gas, 1)) {
       cur->density--;
       field_at(p.x, p.y).age = cur->age;
      }
     }
    }
    break;

   case fd_toxic_gas:
// Reset nearby scents to zero
    for (int i = -1; i <= 1; i++) {
     for (int j = -1; j <= 1; j++)
      g->scent(x+i, y+j) = 0;
    }
    if (is_outside(x, y))
     cur->age += 40;
    if (one_in(2)) {
     std::vector <point> spread;
// Pick all eligible points to spread to
     for (int a = -1; a <= 1; a++) {
      for (int b = -1; b <= 1; b++) {
       if (((field_at(x+a, y+b).type == fd_smoke ||
             field_at(x+a, y+b).type == fd_tear_gas ||
             field_at(x+a, y+b).type == fd_toxic_gas ||
             field_at(x+a, y+b).type == fd_nuke_gas   ) &&
             field_at(x+a, y+b).density < 3            )      ||
           (field_at(x+a, y+b).is_null() && move_cost(x+a, y+b) > 0))
        spread.push_back(point(x+a, y+b));
      }
     }
// Then, spread to a nearby point
     if (cur->density > 0 && cur->age > 0 && spread.size() > 0) {
      point p = spread[rng(0, spread.size() - 1)];
// Nearby toxic gas grows thicker
      if (field_at(p.x, p.y).type == fd_toxic_gas &&
          field_at(p.x, p.y).density < 3) {
        field_at(p.x, p.y).density++;
        cur->density--;
// Nearby smoke & teargas is converted into toxic gas
      } else if (field_at(p.x, p.y).type == fd_smoke ||
                 field_at(p.x, p.y).type == fd_tear_gas) {
       field_at(p.x, p.y).type = fd_toxic_gas;
// Or, just create a new field.
      } else if (cur->density > 0 && move_cost(p.x, p.y) > 0 &&
                 add_field(g, p.x, p.y, fd_toxic_gas, 1)) {
       cur->density--;
       field_at(p.x, p.y).age = cur->age;
      }
     }
    }
    break;


   case fd_nuke_gas:
// Reset nearby scents to zero
    for (int i = -1; i <= 1; i++) {
     for (int j = -1; j <= 1; j++)
      g->scent(x+i, y+j) = 0;
    }
    if (is_outside(x, y))
     cur->age += 40;
// Increase long-term radiation in the land underneath
    radiation(x, y) += rng(0, cur->density);
    if (one_in(2)) {
     std::vector <point> spread;
// Pick all eligible points to spread to
     for (int a = -1; a <= 1; a++) {
      for (int b = -1; b <= 1; b++) {
       if (((field_at(x+a, y+b).type == fd_smoke ||
             field_at(x+a, y+b).type == fd_tear_gas ||
             field_at(x+a, y+b).type == fd_toxic_gas ||
             field_at(x+a, y+b).type == fd_nuke_gas   ) &&
             field_at(x+a, y+b).density < 3            )      ||
           (field_at(x+a, y+b).is_null() && move_cost(x+a, y+b) > 0))
        spread.push_back(point(x+a, y+b));
      }
     }
// Then, spread to a nearby point
     if (cur->density > 0 && cur->age > 0 && spread.size() > 0) {
      point p = spread[rng(0, spread.size() - 1)];
// Nearby nukegas grows thicker
      if (field_at(p.x, p.y).type == fd_nuke_gas &&
          field_at(p.x, p.y).density < 3) {
        field_at(p.x, p.y).density++;
        cur->density--;
// Nearby smoke, tear, and toxic gas is converted into nukegas
      } else if (field_at(p.x, p.y).type == fd_smoke ||
                 field_at(p.x, p.y).type == fd_toxic_gas ||
                 field_at(p.x, p.y).type == fd_tear_gas) {
       field_at(p.x, p.y).type = fd_nuke_gas;
// Or, just create a new field.
      } else if (cur->density > 0 && move_cost(p.x, p.y) > 0 &&
                 add_field(g, p.x, p.y, fd_nuke_gas, 1)) {
       cur->density--;
       field_at(p.x, p.y).age = cur->age;
      }
     }
    }
    break;

   case fd_gas_vent:
    for (int i = x - 1; i <= x + 1; i++) {
     for (int j = y - 1; j <= y + 1; j++) {
      if (field_at(i, j).type == fd_toxic_gas && field_at(i, j).density < 3)
       field_at(i, j).density++;
      else
       add_field(g, i, j, fd_toxic_gas, 3);
     }
    }
    break;

   case fd_fire_vent:
    if (cur->density > 1) {
     if (one_in(3))
      cur->density--;
    } else {
     cur->type = fd_flame_burst;
     cur->density = 3;
    }
    break;

   case fd_flame_burst:
    if (cur->density > 1)
     cur->density--;
    else {
     cur->type = fd_fire_vent;
     cur->density = 3;
    }
    break;

   case fd_electricity:
    if (!one_in(5)) {	// 4 in 5 chance to spread
     std::vector<point> valid;
     if (move_cost(x, y) == 0 && cur->density > 1) { // We're grounded
      int tries = 0;
      while (tries < 10 && cur->age < 50) {
       int cx = x + rng(-1, 1), cy = y + rng(-1, 1);
       if (move_cost(cx, cy) != 0 && field_at(cx, cy).is_null()) {
        add_field(g, cx, cy, fd_electricity, 1);
        cur->density--;
        tries = 0;
       } else
        tries++;
      }
     } else {	// We're not grounded; attempt to ground
      for (int a = -1; a <= 1; a++) {
       for (int b = -1; b <= 1; b++) {
        if (move_cost(x + a, y + b) == 0 && // Grounded tiles first
            field_at(x + a, y + b).is_null())
         valid.push_back(point(x + a, y + b));
       }
      }
      if (valid.size() == 0) {	// Spread to adjacent space, then
       int px = x + rng(-1, 1), py = y + rng(-1, 1);
       if (move_cost(px, py) > 0 && field_at(px, py).type == fd_electricity &&
           field_at(px, py).density < 3)
        field_at(px, py).density++;
       else if (move_cost(px, py) > 0)
        add_field(g, px, py, fd_electricity, 1);
       cur->density--;
      }
      while (valid.size() > 0 && cur->density > 0) {
       int index = rng(0, valid.size() - 1);
       add_field(g, valid[index].x, valid[index].y, fd_electricity, 1);
       cur->density--;
       valid.erase(valid.begin() + index);
      }
     }
    }
    break;

   case fd_fatigue:
    if (cur->density < 3 && int(g->turn) % 3600 == 0 && one_in(10))
     cur->density++;
    else if (cur->density == 3 && one_in(600)) { // Spawn nether creature!
     mon_id type = mon_id(rng(mon_flying_polyp, mon_blank));
     monster creature(g->mtypes[type]);
     creature.spawn(x + rng(-3, 3), y + rng(-3, 3));
     g->z.push_back(creature);
    }
    break;
   }

   cur->age++;
   if (fieldlist[cur->type].halflife > 0) {
    if (cur->age > 0 &&
        dice(3, cur->age) > dice(3, fieldlist[cur->type].halflife)) {
     cur->age = 0;
     cur->density--;
    }
    if (cur->density <= 0) { // Totally dissapated.
     grid[gridn].field_count--;
     grid[gridn].fld[locx][locy] = field();
    }
   }
  }
 }
 return found_field;
}
Exemplo n.º 5
0
bool map::process_fields(game *g)
{
 bool found_field = false;
 field *cur;
 field_id curtype;
 for (int x = 0; x < SEEX * 3; x++) {
  for (int y = 0; y < SEEY * 3; y++) {
   cur = &field_at(x, y);
   curtype = cur->type;
   if (!found_field && curtype != fd_null)
    found_field = true;
   if (cur->density > 3)
    debugmsg("Whoooooa density of %d", cur->density);

  if (cur->age == 0)	// Don't process "newborn" fields
   curtype = fd_null;

  switch (curtype) {

   case fd_null:
    break;	// Do nothing, obviously.  OBVIOUSLY.

   case fd_blood:
   case fd_bile:
    if (has_flag(swimmable, x, y))	// Dissipate faster in water
     cur->age += 250;
    break;

   case fd_acid:
    if (has_flag(swimmable, x, y))	// Dissipate faster in water
     cur->age += 20;
    for (int i = 0; i < i_at(x, y).size(); i++) {
     item *melting = &(i_at(x, y)[i]);
     if (melting->made_of(LIQUID) || melting->made_of(VEGGY)   ||
         melting->made_of(FLESH)  || melting->made_of(POWDER)  ||
         melting->made_of(COTTON) || melting->made_of(WOOL)    ||
         melting->made_of(PAPER)  || melting->made_of(PLASTIC) ||
         (melting->made_of(GLASS) && !one_in(3)) || one_in(4)) {
// Acid destructable objects here
      melting->damage++;
      if (melting->damage >= 5 ||
          (melting->made_of(PAPER) && melting->damage >= 3)) {
       cur->age += melting->volume();
       for (int m = 0; m < i_at(x, y)[i].contents.size(); m++)
        i_at(x, y).push_back( i_at(x, y)[i].contents[m] );
       i_at(x, y).erase(i_at(x, y).begin() + i);
       i--;
      }
     }
    }
    break;

   case fd_fire:
// Consume items as fuel to help us grow/last longer.
    bool destroyed;
    int vol;
    for (int i = 0; i < i_at(x, y).size(); i++) {
     destroyed = false;
     vol = i_at(x, y)[i].volume();
     if (i_at(x, y)[i].is_ammo()) {
      cur->age /= 2;
      cur->age -= 300;
      destroyed = true;
     } else if (i_at(x, y)[i].made_of(PAPER)) {
      cur->age -= vol * 10;
      destroyed = true;
     } else if ((i_at(x, y)[i].made_of(WOOD) || i_at(x, y)[i].made_of(VEGGY)) &&
                (vol <= cur->density*10-(cur->age>0 ? rng(0,cur->age/10) : 0) ||
                 cur->density == 3)) {
      cur->age -= vol * 10;
      destroyed = true;
     } else if ((i_at(x, y)[i].made_of(COTTON) || i_at(x, y)[i].made_of(FLESH)||
                 i_at(x, y)[i].made_of(WOOL)) &&
                (vol <= cur->density*2 || (cur->density == 3 && one_in(vol)))) {
      cur->age -= vol * 5;
      destroyed = true;
     } else if (i_at(x, y)[i].made_of(LIQUID) || i_at(x, y)[i].made_of(POWDER)||
                i_at(x, y)[i].made_of(PLASTIC)||
                (cur->density >= 2 && i_at(x, y)[i].made_of(GLASS)) ||
                (cur->density == 3 && i_at(x, y)[i].made_of(IRON))) {
      switch (i_at(x, y)[i].type->id) { // TODO: Make this be not a hack.
       case itm_whiskey:
       case itm_vodka:
       case itm_rum:
       case itm_tequila:
        cur->age -= 220;
        break;
      }
      destroyed = true;
     }
     if (destroyed) {
      for (int m = 0; m < i_at(x, y)[i].contents.size(); m++)
       i_at(x, y).push_back( i_at(x, y)[i].contents[m] );
      i_at(x, y).erase(i_at(x, y).begin() + i);
      i--;
     }
    }
// Consume the terrain we're on
    if (terlist[ter(x, y)].flags & mfb(flammable) && one_in(8 - cur->density)) {
     cur->age -= cur->density * cur->density * 40;
     if (cur->density == 3)
      ter(x, y) = t_rubble;
    } else if (terlist[ter(x, y)].flags & mfb(explodes)) {
     ter(x, y) = ter_id(int(ter(x, y)) + 1);
     cur->age = 0;
     cur->density = 3;
     g->explosion(x, y, 40, 0, true);
    } else if (terlist[ter(x, y)].flags & mfb(swimmable))
     cur->age += 800;	// Flames die quickly on water
// If we consumed a lot, the flames grow higher
    while (cur->density < 3 && cur->age < 0) {
     cur->age += 300;
     cur->density++;
    }
// If the flames are REALLY big, they contribute to adjacent flames
    if (cur->density == 3 && cur->age < 0) {
// If the flames are in a pit, it can't spread to non-pit
     bool in_pit = (ter(x, y) == t_pit);
// Randomly offset our x/y shifts by 0-2, to randomly pick a square to spread to
     int starti = rng(0, 2);
     int startj = rng(0, 2);
     for (int i = 0; i < 3 && cur->age < 0; i++) {
      for (int j = 0; j < 3 && cur->age < 0; j++) {
       if (field_at(x+((i+starti)%3), y+((j+startj)%3)).type == fd_fire &&
           field_at(x+((i+starti)%3), y+((j+startj)%3)).density < 3 &&
           (!in_pit || ter(x+((i+starti)%3), y+((j+startj)%3)) == t_pit)) {
        field_at(x+((i+starti)%3), y+((j+startj)%3)).density++; 
        field_at(x+((i+starti)%3), y+((j+startj)%3)).age = 0;
        cur->age = 0;
       }
      }
     }
    }
// Consume adjacent fuel / terrain to spread.
    for (int i = -1; i <= 1; i++) {
     for (int j = -1; j <= 1; j++) {
      if (x+i >= 0 && y+j >= 0 && x+i < SEEX * 3 && y+j <= SEEY * 3) {
       if (has_flag(explodes, x + i, y + j) && one_in(8 - cur->density)) {
        ter(x + i, y + i) = ter_id(int(ter(x + i, y + i)) + 1);
        g->explosion(x+i, y+j, 40, 0, true);
       } else if ((i != 0 || j != 0) && (i_at(x+i, y+j).size() > 0 ||
                  rng(15, 120) < cur->density * 10)) {
        if (field_at(x+i, y+j).type == fd_smoke)
         field_at(x+i, y+j) = field(fd_fire, 1, 0);
// Fire in pits can only spread to adjacent pits
        else if (ter(x, y) != t_pit || ter(x + i, y + j) == t_pit)
         add_field(g, x+i, y+j, fd_fire, 1);
// If we're not spreading, maybe we'll stick out some smoke, huh?
       } else if (move_cost(x+i, y+j) > 0 &&
                  rng(7, 40) < cur->density * 10 && cur->age < 1000) {
        add_field(g, x+i, y+j, fd_smoke, rng(1, cur->density));
       }
      }
     }
    }
   break;
  
   case fd_smoke:
    for (int i = -1; i <= 1; i++) {
     for (int j = -1; j <= 1; j++)
      g->scent(x+i, y+j) = 0;
    }
    if (is_outside(x, y))
     cur->age += 50;
    if (one_in(2)) {
     std::vector <point> spread;
     for (int a = -1; a <= 1; a++) {
      for (int b = -1; b <= 1; b++) {
       if ((field_at(x+a, y+b).type == fd_smoke &&
             field_at(x+a, y+b).density < 3)      ||
           (field_at(x+a, y+b).is_null() && move_cost(x+a, y+b) > 0))
        spread.push_back(point(x+a, y+b));
      }
     }
     if (cur->density > 0 && cur->age > 0 && spread.size() > 0) {
      point p = spread[rng(0, spread.size() - 1)];
      if (field_at(p.x, p.y).type == fd_smoke &&
          field_at(p.x, p.y).density < 3) {
        field_at(p.x, p.y).density++;
        cur->density--;
      } else if (cur->density > 0 && move_cost(p.x, p.y) > 0 &&
                 add_field(g, p.x, p.y, fd_smoke, 1)){
       cur->density--;
       field_at(p.x, p.y).age = cur->age;
      }
     }
    }
   break;

   case fd_tear_gas:
// Reset nearby scents to zero
    for (int i = -1; i <= 1; i++) {
     for (int j = -1; j <= 1; j++)
      g->scent(x+i, y+j) = 0;
    }
    if (is_outside(x, y))
     cur->age += 30;
// One in three chance that it spreads (less than smoke!)
    if (one_in(3)) {
     std::vector <point> spread;
// Pick all eligible points to spread to
     for (int a = -1; a <= 1; a++) {
      for (int b = -1; b <= 1; b++) {
       if (((field_at(x+a, y+b).type == fd_smoke ||
             field_at(x+a, y+b).type == fd_tear_gas) &&
             field_at(x+a, y+b).density < 3            )      ||
           (field_at(x+a, y+b).is_null() && move_cost(x+a, y+b) > 0))
        spread.push_back(point(x+a, y+b));
      }
     }
// Then, spread to a nearby point
     if (cur->density > 0 && cur->age > 0 && spread.size() > 0) {
      point p = spread[rng(0, spread.size() - 1)];
// Nearby teargas grows thicker
      if (field_at(p.x, p.y).type == fd_tear_gas &&
          field_at(p.x, p.y).density < 3) {
        field_at(p.x, p.y).density++;
        cur->density--;
// Nearby smoke is converted into teargas
      } else if (field_at(p.x, p.y).type == fd_smoke) {
       field_at(p.x, p.y).type = fd_tear_gas;
// Or, just create a new field.
      } else if (cur->density > 0 && move_cost(p.x, p.y) > 0 &&
                 add_field(g, p.x, p.y, fd_tear_gas, 1)) {
       cur->density--;
       field_at(p.x, p.y).age = cur->age;
      }
     }
    }
    break;

   case fd_nuke_gas:
// Reset nearby scents to zero
    for (int i = -1; i <= 1; i++) {
     for (int j = -1; j <= 1; j++)
      g->scent(x+i, y+j) = 0;
    }
    if (is_outside(x, y))
     cur->age += 40;
// Increase long-term radiation in the land underneath
    radiation(x, y) += rng(0, cur->density);
    if (one_in(2)) {
     std::vector <point> spread;
// Pick all eligible points to spread to
     for (int a = -1; a <= 1; a++) {
      for (int b = -1; b <= 1; b++) {
       if (((field_at(x+a, y+b).type == fd_smoke ||
             field_at(x+a, y+b).type == fd_tear_gas ||
             field_at(x+a, y+b).type == fd_nuke_gas   ) &&
             field_at(x+a, y+b).density < 3            )      ||
           (field_at(x+a, y+b).is_null() && move_cost(x+a, y+b) > 0))
        spread.push_back(point(x+a, y+b));
      }
     }
// Then, spread to a nearby point
     if (cur->density > 0 && cur->age > 0 && spread.size() > 0) {
      point p = spread[rng(0, spread.size() - 1)];
// Nearby nukegas grows thicker
      if (field_at(p.x, p.y).type == fd_nuke_gas &&
          field_at(p.x, p.y).density < 3) {
        field_at(p.x, p.y).density++;
        cur->density--;
// Nearby smoke & teargas is converted into nukegas
      } else if (field_at(p.x, p.y).type == fd_smoke ||
                 field_at(p.x, p.y).type == fd_tear_gas) {
       field_at(p.x, p.y).type = fd_nuke_gas;
// Or, just create a new field.
      } else if (cur->density > 0 && move_cost(p.x, p.y) > 0 &&
                 add_field(g, p.x, p.y, fd_nuke_gas, 1)) {
       cur->density--;
       field_at(p.x, p.y).age = cur->age;
      }
     }
    }
    break;

   case fd_electricity:
    if (!one_in(5)) {	// 4 in 5 chance to spread
     std::vector<point> valid;
     if (move_cost(x, y) == 0 && cur->density > 1) { // We're grounded
      int tries = 0;
      while (tries < 10 && cur->age < 50) {
       int cx = x + rng(-1, 1), cy = y + rng(-1, 1);
       if (move_cost(cx, cy) != 0 && field_at(cx, cy).is_null()) {
        add_field(g, cx, cy, fd_electricity, 1);
        cur->density--;
        tries = 0;
       } else
        tries++;
      }
     } else {	// We're not grounded; attempt to ground
      for (int a = -1; a <= 1; a++) {
       for (int b = -1; b <= 1; b++) {
        if (move_cost(x + a, y + b) == 0 && // Grounded tiles first
            field_at(x + a, y + b).is_null())
         valid.push_back(point(x + a, y + b));
       }
      }
      if (valid.size() == 0) {	// Spread to adjacent space, then
       int px = x + rng(-1, 1), py = y + rng(-1, 1);
       if (move_cost(px, py) > 0 && field_at(px, py).type == fd_electricity &&
           field_at(px, py).density < 3)
        field_at(px, py).density++;
       else if (move_cost(px, py) > 0)
        add_field(g, px, py, fd_electricity, 1);
       cur->density--;
      }
      while (valid.size() > 0 && cur->density > 0) {
       int index = rng(0, valid.size() - 1);
       add_field(g, valid[index].x, valid[index].y, fd_electricity, 1);
       cur->density--;
       valid.erase(valid.begin() + index);
      }
     }
    }
    break;

   case fd_fatigue:
    if (cur->density < 3 && g->turn % 3600 == 0 && one_in(10))
     cur->density++;
    else if (cur->density == 3 && one_in(3600)) { // Spawn nether creature!
     mon_id type = mon_id(rng(mon_flying_polyp, mon_blank));
     monster creature(g->mtypes[type]);
     creature.spawn(x + rng(-3, 3), y + rng(-3, 3));
     g->z.push_back(creature);
    }
    break;
   }
  
   if (fieldlist[cur->type].halflife > 0) {
    cur->age++;
    if (cur->age > 0 &&
        dice(3, cur->age) > dice(3, fieldlist[cur->type].halflife)) {
     cur->age = 0;
     cur->density--;
    }
    if (cur->density <= 0) // Totally dissapated.
     field_at(x, y) = field();
   }
  }
 }
 return found_field;
}
Exemplo n.º 6
0
void map::drawsq(WINDOW* w, player &u, int x, int y, bool invert,
                 bool show_items)
{
    if (!inbounds(x, y))
        return;	// Out of bounds
    int k = x + SEEX - u.posx;
    int j = y + SEEY - u.posy;
    nc_color tercol;
    char sym = terlist[ter(x, y)].sym;
    bool hi = false;
    if (u.has_disease(DI_BOOMERED))
        tercol = c_magenta;
    else if ((u.is_wearing(itm_goggles_nv) && u.has_active_item(itm_UPS_on)) ||
             u.has_active_bionic(bio_night_vision))
        tercol = c_ltgreen;
    else
        tercol = terlist[ter(x, y)].color;
    if (move_cost(x, y) == 0 && has_flag(swimmable, x, y) && !u.underwater)
        show_items = false;	// Can only see underwater items if WE are underwater
// If there's a trap here, and we have sufficient perception, draw that instead
    if (tr_at(x, y) != tr_null &&
            u.per_cur - u.encumb(bp_eyes) >= (*traps)[tr_at(x, y)]->visibility) {
        tercol = (*traps)[tr_at(x, y)]->color;
        if ((*traps)[tr_at(x, y)]->sym == '%') {
            switch(rng(1, 5)) {
            case 1:
                sym = '*';
                break;
            case 2:
                sym = '0';
                break;
            case 3:
                sym = '8';
                break;
            case 4:
                sym = '&';
                break;
            case 5:
                sym = '+';
                break;
            }
        } else
            sym = (*traps)[tr_at(x, y)]->sym;
    }
// If there's a field here, draw that instead (unless its symbol is %)
    if (field_at(x, y).type != fd_null) {
        tercol = fieldlist[field_at(x, y).type].color[field_at(x, y).density - 1];
        if (fieldlist[field_at(x, y).type].sym == '*') {
            switch (rng(1, 5)) {
            case 1:
                sym = '*';
                break;
            case 2:
                sym = '0';
                break;
            case 3:
                sym = '8';
                break;
            case 4:
                sym = '&';
                break;
            case 5:
                sym = '+';
                break;
            }
        } else if (fieldlist[field_at(x, y).type].sym != '%')
            sym = fieldlist[field_at(x, y).type].sym;
    }
// If there's items here, draw those instead
    if (show_items && i_at(x, y).size() > 0 && field_at(x, y).is_null()) {
        if ((terlist[ter(x, y)].sym != '.'))
            hi = true;
        else {
            tercol = i_at(x, y)[i_at(x, y).size() - 1].color();
            if (i_at(x, y).size() > 1)
                invert = !invert;
            sym = i_at(x, y)[i_at(x, y).size() - 1].symbol();
        }
    }
    if (invert)
        mvwputch_inv(w, j, k, tercol, sym);
    else if (hi)
        mvwputch_hi (w, j, k, tercol, sym);
    else
        mvwputch    (w, j, k, tercol, sym);
}
Exemplo n.º 7
0
void map::shoot(game *g, int x, int y, int &dam, bool hit_items, unsigned flags)
{
    if (flags & mfb(WF_AMMO_FLAME) && has_flag(flammable, x, y))
        add_field(g, x, y, fd_fire, 2);

    switch (ter(x, y)) {

    case t_door_c:
    case t_door_locked:
        dam -= rng(15, 30);
        if (dam > 0)
            ter(x, y) = t_door_b;
        break;

    case t_door_b:
        if (hit_items || one_in(8)) {	// 1 in 8 chance of hitting the door
            dam -= rng(10, 30);
            if (dam > 0)
                ter(x, y) = t_door_frame;
        } else
            dam -= rng(0, 1);
        break;

    case t_door_boarded:
        dam -= rng(15, 35);
        if (dam > 0)
            ter(x, y) = t_door_b;
        break;

    case t_window:
        dam -= rng(0, 5);
        if (dam > 0)
            ter(x, y) = t_window_frame;
        break;

    case t_window_boarded:
        dam -= rng(10, 30);
        if (dam > 0)
            ter(x, y) = t_window_frame;
        break;

    case t_wall_glass_h:
    case t_wall_glass_v:
        dam -= rng(0, 8);
        if (dam > 0)
            ter(x, y) = t_floor;
        break;

    case t_paper:
        dam -= rng(4, 16);
        if (dam > 0)
            ter(x, y) = t_dirt;
        if (flags & mfb(WF_AMMO_INCENDIARY))
            add_field(g, x, y, fd_fire, 1);
        break;

    case t_gas_pump:
        if (hit_items || one_in(3)) {
            if (dam > 15) {
                if (flags & mfb(WF_AMMO_INCENDIARY) || flags & mfb(WF_AMMO_FLAME))
                    g->explosion(x, y, 40, 0, true);
                else {
                    for (int i = x - 2; i <= x + 2; i++) {
                        for (int j = y - 2; j <= y + 2; j++) {
                            if (move_cost(i, j) > 0 && one_in(3))
                                add_item(i, j, g->itypes[itm_gasoline], 0);
                        }
                    }
                }
                ter(x, y) = t_gas_pump_smashed;
            }
            dam -= 60;
        }
        break;

    case t_vat:
        if (dam >= 10) {
            g->sound(x, y, 15, "ke-rash!");
            ter(x, y) = t_floor;
        } else
            dam = 0;
        break;

    default:
        if (move_cost(x, y) == 0 && !trans(x, y))
            dam = 0;	// TODO: Bullets can go through some walls?
        else
            dam -= (rng(0, 1) * rng(0, 1) * rng(0, 1));
    }

// Now, destroy items on that tile.

    if ((move_cost(x, y) == 2 && !hit_items) || !inbounds(x, y))
        return;	// Items on floor-type spaces won't be shot up.

    bool destroyed;
    for (int i = 0; i < i_at(x, y).size(); i++) {
        destroyed = false;
        switch (i_at(x, y)[i].type->m1) {
        case GLASS:
        case PAPER:
            if (dam > rng(2, 8) && one_in(i_at(x, y)[i].volume()))
                destroyed = true;
            break;
        case PLASTIC:
            if (dam > rng(2, 10) && one_in(i_at(x, y)[i].volume() * 3))
                destroyed = true;
            break;
        case VEGGY:
        case FLESH:
            if (dam > rng(10, 40))
                destroyed = true;
            break;
        case COTTON:
        case WOOL:
            i_at(x, y)[i].damage++;
            if (i_at(x, y)[i].damage >= 5)
                destroyed = true;
            break;
        }
        if (destroyed) {
            for (int j = 0; j < i_at(x, y)[i].contents.size(); j++)
                i_at(x, y).push_back(i_at(x, y)[i].contents[j]);
            i_rem(x, y, i);
            i--;
        }
    }
}
Exemplo n.º 8
0
bool map::bash(int x, int y, int str, std::string &sound)
{
    sound = "";
    for (int i = 0; i < i_at(x, y).size(); i++) {	// Destroy glass items (maybe)
        if (i_at(x, y)[i].made_of(GLASS) && one_in(2)) {
            if (sound == "")
                sound = "A " + i_at(x, y)[i].tname() + " shatters!  ";
            else
                sound = "Some items shatter!  ";
            for (int j = 0; j < i_at(x, y)[i].contents.size(); j++)
                i_at(x, y).push_back(i_at(x, y)[i].contents[j]);
            i_rem(x, y, i);
            i--;
        }
    }
    switch (ter(x, y)) {
    case t_door_c:
    case t_door_locked:
        if (str >= rng(0, 40)) {
            sound += "smash!";
            ter(x, y) = t_door_b;
            return true;
        } else {
            sound += "whump!";
            return true;
        }
        break;
    case t_door_b:
        if (str >= rng(0, 30)) {
            sound += "crash!";
            ter(x, y) = t_door_frame;
            int num_boards = rng(2, 6);
            for (int i = 0; i < num_boards; i++)
                add_item(x, y, (*itypes)[itm_2x4], 0);
            return true;
        } else {
            sound += "wham!";
            return true;
        }
        break;
    case t_window:
        if (str >= rng(0, 6)) {
            sound += "glass breaking!";
            ter(x, y) = t_window_frame;
            return true;
        } else {
            sound += "whack!";
            return true;
        }
        break;
    case t_door_boarded:
        if (str >= dice(3, 50)) {
            sound += "crash!";
            ter(x, y) = t_door_frame;
            int num_boards = rng(0, 2);
            for (int i = 0; i < num_boards; i++)
                add_item(x, y, (*itypes)[itm_2x4], 0);
            return true;
        } else {
            sound += "wham!";
            return true;
        }
        break;
    case t_window_boarded:
        if (str >= dice(3, 30)) {
            sound += "crash!";
            ter(x, y) = t_window_frame;
            int num_boards = rng(0, 2) * rng(0, 1);
            for (int i = 0; i < num_boards; i++)
                add_item(x, y, (*itypes)[itm_2x4], 0);
            return true;
        } else {
            sound += "wham!";
            return true;
        }
        break;
    case t_paper:
        if (str >= dice(2, 6)) {
            sound += "rrrrip!";
            ter(x, y) = t_dirt;
            return true;
        } else {
            sound += "slap!";
            return true;
        }
        break;
    case t_toilet:
        if (str >= dice(8, 10)) {
            sound += "porcelain breaking!";
            ter(x, y) = t_rubble;
            return true;
        } else {
            sound += "whunk!";
            return true;
        }
        break;
    case t_dresser:
        if (str >= dice(3, 45)) {
            sound += "smash!";
            ter(x, y) = t_floor;
            int num_boards = rng(4, 12);
            for (int i = 0; i < num_boards; i++)
                add_item(x, y, (*itypes)[itm_2x4], 0);
            return true;
        } else {
            sound += "whump.";
            return true;
        }
        break;
    case t_wall_glass_h:
    case t_wall_glass_v:
        if (str >= rng(0, 20)) {
            sound += "glass breaking!";
            ter(x, y) = t_floor;
            return true;
        } else {
            sound += "whack!";
            return true;
        }
        break;
    case t_reinforced_glass_h:
    case t_reinforced_glass_v:
        if (str >= rng(60, 100)) {
            sound += "glass breaking!";
            ter(x, y) = t_floor;
            return true;
        } else {
            sound += "whack!";
            return true;
        }
        break;
    case t_tree_young:
        if (str >= rng(0, 50)) {
            sound += "crunch!";
            ter(x, y) = t_underbrush;
            int num_sticks = rng(0, 3);
            for (int i = 0; i < num_sticks; i++)
                add_item(x, y, (*itypes)[itm_stick], 0);
            return true;
        } else {
            sound += "whack!";
            return true;
        }
        break;
    case t_underbrush:
        if (str >= rng(0, 30) && !one_in(4)) {
            sound += "crunch.";
            ter(x, y) = t_dirt;
            return true;
        } else {
            sound += "brush.";
            return true;
        }
        break;
    case t_marloss:
        if (str > rng(0, 40)) {
            sound += "crunch!";
            ter(x, y) = t_fungus;
            return true;
        } else {
            sound += "whack!";
            return true;
        }
        break;
    case t_vat:
        if (str >= dice(2, 20)) {
            sound += "ker-rash!";
            ter(x, y) = t_floor;
            return true;
        } else {
            sound += "plunk.";
            return true;
        }
    }
    if (move_cost(x, y) == 0) {
        sound += "thump!";
        return true;
    }
    return false;	// If we kick empty space, the action is cancelled
}
Exemplo n.º 9
0
bool map::is_destructable(int x, int y)
{
    return (has_flag(bashable, x, y) ||
            (move_cost(x, y) == 0 && !has_flag(transparent, x, y)));
}