Example #1
0
technique_id player::pick_defensive_technique(game *g, monster *z, player *p)
{
 if (blocks_left == 0)
  return TEC_NULL;

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

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

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

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

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

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

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

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

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

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

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

 blocks_left++; // We didn't use any blocks, so give it back!
 return TEC_NULL;
}
Example #2
0
void monster::melee_attack(Creature &target, bool) {
    mod_moves(-100);
    if (type->melee_dice == 0) { // We don't attack, so just return
        return;
    }
    add_effect("hit_by_player", 3); // Make us a valid target for a few turns

    if (has_flag(MF_HIT_AND_RUN)) {
        add_effect("run", 4);
    }

    bool u_see_me = g->u_see(this);

    body_part bp_hit;
    //int highest_hit = 0;
    int hitstat = std::max(type->melee_skill - 2,0);
    int hitroll = dice(hitstat,10);

    damage_instance damage;
    if(!is_hallucination()) {
        if (type->melee_dice > 0) {
            damage.add_damage(DT_BASH,
                    dice(type->melee_dice,type->melee_sides));
        }
        if (type->melee_cut > 0) {
            damage.add_damage(DT_CUT, type->melee_cut);
        }
    }

    /* TODO: height-related bodypart selection
    //If the player is knocked down or the monster can fly, any body part is a valid target
    if(target.is_on_ground() || has_flag(MF_FLIES)){
        highest_hit = 20;
    }
    else {
        switch (type->size) {
        case MS_TINY:
            highest_hit = 3;
        break;
        case MS_SMALL:
            highest_hit = 12;
        break;
        case MS_MEDIUM:
            highest_hit = 20;
        break;
        case MS_LARGE:
            highest_hit = 28;
        break;
        case MS_HUGE:
            highest_hit = 35;
        break;
        }
        if (digging()){
            highest_hit -= 8;
        }
        if (highest_hit <= 1){
            highest_hit = 2;
        }
    }

    if (highest_hit > 20){
        highest_hit = 20;
    }

    int bp_rand = rng(0, highest_hit - 1);
    if (bp_rand <=  2){
        bp_hit = bp_legs;
    } else if (bp_rand <= 10){
        bp_hit = bp_torso;
    } else if (bp_rand <= 14){
        bp_hit = bp_arms;
    } else if (bp_rand <= 16){
        bp_hit = bp_mouth;
    } else if (bp_rand == 18){
        bp_hit = bp_eyes;
    } else{
        bp_hit = bp_head;
    }
    */

    dealt_damage_instance dealt_dam;
    int hitspread = target.deal_melee_attack(this, hitroll, false, damage, dealt_dam);
    bp_hit = dealt_dam.bp_hit;

    //Hallucinations always produce messages but never actually deal damage
    if (is_hallucination() || dealt_dam.total_damage() > 0) {
        if (target.is_player()) {
            if (u_see_me) {
                g->add_msg(_("The %1$s hits your %2$s."), name().c_str(),
                        body_part_name(bp_hit, random_side(bp_hit)).c_str());
            } else {
                g->add_msg(_("Something hits your %s."),
                        body_part_name(bp_hit, random_side(bp_hit)).c_str());
            }
        } else {
            if (u_see_me) {
                g->add_msg(_("The %1$s hits %2$s's %3$s."), name().c_str(),
                            target.disp_name().c_str(),
                            body_part_name(bp_hit, random_side(bp_hit)).c_str());
            }
        }
    } else if (hitspread < 0) { // a miss
        // TODO: characters practice dodge when a hit misses 'em
        if (target.is_player()) {
            if (u_see_me) {
                g->add_msg(_("You dodge %1$s."), disp_name().c_str());
            } else {
                g->add_msg(_("You dodge an attack from an unseen source."));
            }
        } else {
            if (u_see_me) {
                g->add_msg(_("The %1$s dodges %2$s's attack."), name().c_str(),
                            target.disp_name().c_str());
            }
        }

    }

    if (is_hallucination()) {
        if(one_in(7)) {
            die();
        }
        return;
    }

    // Adjust anger/morale of same-species monsters, if appropriate
    int anger_adjust = 0, morale_adjust = 0;
    if (type->has_anger_trigger(MTRIG_FRIEND_ATTACKED)){
        anger_adjust += 15;
    }
    if (type->has_fear_trigger(MTRIG_FRIEND_ATTACKED)){
        morale_adjust -= 15;
    }
    if (type->has_placate_trigger(MTRIG_FRIEND_ATTACKED)){
        anger_adjust -= 15;
    }

    if (anger_adjust != 0 && morale_adjust != 0)
    {
        for (int i = 0; i < g->num_zombies(); i++)
        {
            g->zombie(i).morale += morale_adjust;
            g->zombie(i).anger += anger_adjust;
        }
    }
}
Example #3
0
bool spec_random_orc (CHAR_DATA * ch)
{
	char mob_long[MSL];
	char mob_name[MSL];
	char mob_short[MSL];
	int name_range = number_range(1, MAX_RMOB_ORC_NAME - 1);
	int long_range = number_range(1, MAX_RMOB_ORC_LONG - 1);
	int other_range = number_range(1, MAX_RMOB_OTHER - 1);
	
	if(ch->wimpy != 0) 
	{
		if(IS_SET(ch->act, ACT_THIEF))
			return spec_thief(ch);
		if(IS_SET(ch->act, ACT_MAGE))
			return spec_cast_mage(ch);
		return false;
	}
	
	
	/* Wimpy isn't used by mobs, so we'll use this as a check. if Wimpy == 1, dont do the script
	prevents mobs from changing every 8 pulses. */
	ch->wimpy = 1;
	
	/* Select Keyword/Short/long */
	sprintf (mob_name, "%s orc warrior", rmob_orc_name_table[name_range].name); // Set keywords
	sprintf (mob_short, "The orc, %s", rmob_orc_name_table[name_range].name);   // Set Short_descr
	sprintf (mob_long, "%s", rmob_orc_long_table[long_range].long_descr);   // Set Long_descr

	/* Now set the names */
	ReplaceString(ch->name, mob_name);
	ReplaceString(ch->short_descr, mob_short);
	ReplaceString(ch->long_descr, mob_long);
	// ch->name = str_dup (mob_name);
	// ch->short_descr = str_dup (mob_short);
	// ch->long_descr = str_dup (mob_long);


	/* play with level ranges a bit, dont want static mobs */
	int level_range = number_range( rmob_orc_other_table[other_range].low_level_range, rmob_orc_other_table[other_range].hig_level_range );
	ch->level += level_range;

	/* Set hitroll/dam/affected flags */
	ch->hitroll = number_range( rmob_orc_other_table[other_range].l_hitroll, rmob_orc_other_table[other_range].h_hitroll );
	ch->damroll = number_range( rmob_orc_other_table[other_range].l_damroll, rmob_orc_other_table[other_range].h_damroll );
	ch->affected_by = 0;
	ch->affected_by = rmob_orc_other_table[other_range].affect_flags;

	// Set Hitpoints/mana/move
	int hit_points = dice(ch->level, rmob_orc_other_table[other_range].hit_dice);
	ch->hit = hit_points;
	ch->max_hit = hit_points;
	ch->mana = 100;
	ch->max_mana = 100;
	ch->move = 100;
	ch->max_move = 100;

	// Give them a Randomized Dam message. I would of put this in a table, but thats overkill
	switch (number_range (1, 3))
	{
		case (1):
		ch->dam_type = 3;
	break; /* slash */
		case (2):
		ch->dam_type = 7;
	break; /* pound */
		case (3):
		ch->dam_type = 11;
	break; /* pierce */
	}

	// And were done!
	return TRUE;

}
Example #4
0
void sounds::process_sound_markers( player *p )
{
    bool is_deaf = p->is_deaf();
    const float volume_multiplier = p->hearing_ability();
    const int weather_vol = weather_data( g->weather ).sound_attn;
    for( const auto &sound_event_pair : sounds_since_last_turn ) {
        const int volume = sound_event_pair.second.volume * volume_multiplier;
        const std::string& sfx_id = sound_event_pair.second.id;
        const std::string& sfx_variant = sound_event_pair.second.variant;
        const int max_volume = std::max( volume, sound_event_pair.second.volume );  // For deafness checks
        int dist = rl_dist( p->pos(), sound_event_pair.first );
        bool ambient = sound_event_pair.second.ambient;
        // Too far away, we didn't hear it!
        if( dist > volume ) {
            continue;
        }
        if( is_deaf ) {
            // Has to be here as well to work for stacking deafness (loud noises prolong deafness)
            if( !p->is_immune_effect( effect_deaf )
                    && rng( ( max_volume - dist ) / 2, ( max_volume - dist ) ) >= 150 ) {
                // Prolong deafness, but not as much as if it was freshly applied
                int duration = std::min( 40, ( max_volume - dist - 130 ) / 8 );
                p->add_effect( effect_deaf, duration );
                if( !p->has_trait( "DEADENED" ) ) {
                    p->add_msg_if_player( m_bad, _( "Your eardrums suddenly ache!" ) );
                    if( p->pain < 10 ) {
                        p->mod_pain( rng( 0, 2 ) );
                    }
                }
            }
            // We're deaf, skip rest of processing.
            continue;
        }
        // Player volume meter includes all sounds from their tile and adjacent tiles
        // TODO: Add noises from vehicle player is in.
        if( dist <= 1 ) {
            p->volume = std::max( p->volume, volume );
        }
        // Check for deafness
        if( !p->is_immune_effect( effect_deaf ) && rng((max_volume - dist) / 2, (max_volume - dist)) >= 150 ) {
            int duration = (max_volume - dist - 130) / 4;
            p->add_effect( effect_deaf, duration );
            if( p->is_deaf() ) {
                // Need to check for actual deafness
                is_deaf = true;
                sfx::do_hearing_loss( duration );
                continue;
            }
        }
        // At this point we are dealing with attention (as opposed to physical effects)
        // so reduce volume by the amount of ambient noise from the weather.
        const int mod_vol = ( sound_event_pair.second.volume - weather_vol ) * volume_multiplier;
        // The noise was drowned out by the surroundings.
        if( mod_vol - dist < 0 ) {
            continue;
        }
        // See if we need to wake someone up
        if( p->has_effect( effect_sleep ) ) {
            if( ( !( p->has_trait( "HEAVYSLEEPER" ) ||
                     p->has_trait( "HEAVYSLEEPER2" ) ) && dice( 2, 15 ) < mod_vol - dist ) ||
                    ( p->has_trait( "HEAVYSLEEPER" ) && dice( 3, 15 ) < mod_vol - dist ) ||
                    ( p->has_trait( "HEAVYSLEEPER2" ) && dice( 6, 15 ) < mod_vol - dist ) ) {
                //Not kidding about sleep-thru-firefight
                p->wake_up();
                add_msg( m_warning, _( "Something is making noise." ) );
            } else {
                continue;
            }
        }
        const tripoint &pos = sound_event_pair.first;
        const std::string &description = sound_event_pair.second.description;
        if( !ambient && ( pos != p->pos() ) && !g->m.pl_sees( pos, dist ) ) {
            if( p->activity.ignore_trivial != true ) {
                std::string query;
                if( description.empty() ) {
                    query = _( "Heard a noise!" );
                } else {
                    query = string_format( _( "Heard %s!" ),
                                           sound_event_pair.second.description.c_str() );
                }
                if( g->cancel_activity_or_ignore_query( query.c_str() ) ) {
                    p->activity.ignore_trivial = true;
                    for( auto activity : p->backlog ) {
                        activity.ignore_trivial = true;
                    }
                }
            }
        }
        // Only print a description if it exists
        if( !description.empty() ) {
            // If it came from us, don't print a direction
            if( pos == p->pos() ) {
                std::string uppercased = description;
                capitalize_letter( uppercased, 0 );
                add_msg( "%s", uppercased.c_str() );
            } else {
                // Else print a direction as well
                std::string direction = direction_name( direction_from( p->pos(), pos ) );
                add_msg( m_warning, _( "From the %s you hear %s" ), direction.c_str(), description.c_str() );
            }
        }
        // Play the sound effect, if any.
        if( !sfx_id.empty() ) {
            // for our sfx API, 100 is "normal" volume, so scale accordingly
            int heard_volume = sfx::get_heard_volume( pos );
            sfx::play_variant_sound( sfx_id, sfx_variant, heard_volume );
            //add_msg("Playing sound effect %s, %s, %d", sfx_id.c_str(), sfx_variant.c_str(), heard_volume);
        }
        // If Z coord is different, draw even when you can see the source
        const bool diff_z = pos.z != p->posz();
        // Place footstep markers.
        if( pos == p->pos() || p->sees( pos ) ) {
            // If we are or can see the source, don't draw a marker.
            continue;
        }
        int err_offset;
        if( mod_vol / dist < 2 ) {
            err_offset = 3;
        } else if( mod_vol / dist < 3 ) {
            err_offset = 2;
        } else {
            err_offset = 1;
        }
        // Enumerate the valid points the player *cannot* see.
        // Unless the source is on a different z-level, then any point is fine
        std::vector<tripoint> unseen_points;
        tripoint newp = pos;
        int &newx = newp.x;
        int &newy = newp.y;
        for( newx = pos.x - err_offset; newx <= pos.x + err_offset; newx++ ) {
            for( newy = pos.y - err_offset; newy <= pos.y + err_offset; newy++ ) {
                if( diff_z || !p->sees( newp ) ) {
                    unseen_points.emplace_back( newp );
                }
            }
        }
        // Then place the sound marker in a random one.
        if( !unseen_points.empty() ) {
            sound_markers.emplace( random_entry( unseen_points ),
                                   sound_event_pair.second );
        }
    }
    sounds_since_last_turn.clear();
}
Example #5
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;
}
Example #6
0
int monster::move_to(game *g, int x, int y, bool force)
{
    // Make sure that we can move there, unless force is true.
    if(!force) if(!g->is_empty(x, y) || !can_move_to(g, x, y)) {
        return 0;
    }

    if (has_effect(ME_BEARTRAP)) {
        moves = 0;
        return 0;
    }

    if (plans.size() > 0) {
        plans.erase(plans.begin());
    }

    moves -= calc_movecost(g, posx(), posy(), x, y);

    //Check for moving into/out of water
    bool was_water = g->m.is_divable(posx(), posy());
    bool will_be_water = g->m.is_divable(x, y);

    if(was_water && !will_be_water && g->u_see(x, y)) {
        //Use more dramatic messages for swimming monsters
        g->add_msg(_("A %s %s from the %s!"), name().c_str(),
                   has_flag(MF_SWIMS) || has_flag(MF_AQUATIC) ? _("leaps") : _("emerges"),
                   g->m.tername(posx(), posy()).c_str());
    } else if(!was_water && will_be_water && g->u_see(x, y)) {
        g->add_msg(_("A %s %s into the %s!"), name().c_str(),
                   has_flag(MF_SWIMS) || has_flag(MF_AQUATIC) ? _("dives") : _("sinks"),
                   g->m.tername(x, y).c_str());
    }

    setpos(x, y);
    footsteps(g, x, y);
    if(is_hallucination()) {
        //Hallucinations don't do any of the stuff after this point
        return 1;
    }
    if (type->size != MS_TINY && g->m.has_flag("SHARP", posx(), posy()) && !one_in(4)) {
        hurt(rng(2, 3));
    }
    if (type->size != MS_TINY && g->m.has_flag("ROUGH", posx(), posy()) && one_in(6)) {
        hurt(rng(1, 2));
    }
    if (!digging() && !has_flag(MF_FLIES) &&
          g->m.tr_at(posx(), posy()) != tr_null) { // Monster stepped on a trap!
        trap* tr = g->traps[g->m.tr_at(posx(), posy())];
        if (dice(3, type->sk_dodge + 1) < dice(3, tr->avoidance)) {
            trapfuncm f;
            (f.*(tr->actm))(g, this, posx(), posy());
        }
    }
    // Diggers turn the dirt into dirtmound
    if (digging()){
        int factor = 0;
        switch (type->size) {
        case MS_TINY:
            factor = 100;
            break;
        case MS_SMALL:
            factor = 30;
            break;
        case MS_MEDIUM:
            factor = 6;
            break;
        case MS_LARGE:
            factor = 3;
            break;
        case MS_HUGE:
            factor = 1;
            break;
        }
        if (has_flag(MF_VERMIN)) {
            factor *= 100;
        }
        if (one_in(factor)) {
            g->m.ter_set(posx(), posy(), t_dirtmound);
        }
    }
    // Acid trail monsters leave... a trail of acid
    if (has_flag(MF_ACIDTRAIL)){
        g->m.add_field(g, posx(), posy(), fd_acid, 3);
    }

    if (has_flag(MF_SLUDGETRAIL)) {
        for (int dx = -1; dx <= 1; dx++) {
            for (int dy = -1; dy <= 1; dy++) {
                const int fstr = 3 - (abs(dx) + abs(dy));
                if (fstr >= 2) {
                    g->m.add_field(g, posx() + dx, posy() + dy, fd_sludge, fstr);
                }
            }
        }
    }

    return 1;
}
Example #7
0
/* returns 1 if polymorph successful */
int polymon(int mntmp)
{
	boolean sticky = sticks(youmonst.data) && u.ustuck && !u.uswallow,
		was_blind = !!Blind, dochange = FALSE;
	boolean could_pass_walls = Passes_walls;
	int mlvl;

	if (mvitals[mntmp].mvflags & G_GENOD) {	/* allow G_EXTINCT */
		pline("You feel rather %s-ish.",mons[mntmp].mname);
		exercise(A_WIS, TRUE);
		return 0;
	}

	/* KMH, conduct */
	u.uconduct.polyselfs++;

	if (!Upolyd) {
		/* Human to monster; save human stats */
		u.macurr = u.acurr;
		u.mamax = u.amax;
		u.mfemale = flags.female;
	} else {
		/* Monster to monster; restore human stats, to be
		 * immediately changed to provide stats for the new monster
		 */
		u.acurr = u.macurr;
		u.amax = u.mamax;
		flags.female = u.mfemale;
	}

	if (youmonst.m_ap_type) {
	    /* stop mimicking immediately */
	    if (multi < 0) unmul("");
	} else if (mons[mntmp].mlet != S_MIMIC) {
	    /* as in polyman() */
	    youmonst.m_ap_type = M_AP_NOTHING;
	}
	if (is_male(&mons[mntmp])) {
		if (flags.female) dochange = TRUE;
	} else if (is_female(&mons[mntmp])) {
		if (!flags.female) dochange = TRUE;
	} else if (!is_neuter(&mons[mntmp]) && mntmp != u.ulycn) {
		if (!rn2(10)) dochange = TRUE;
	}
	if (dochange) {
		flags.female = !flags.female;
		pline("You %s %s%s!",
		    (u.umonnum != mntmp) ? "turn into a" : "feel like a new",
		    (is_male(&mons[mntmp]) || is_female(&mons[mntmp])) ? "" :
			flags.female ? "female " : "male ",
		    mons[mntmp].mname);
	} else {
		if (u.umonnum != mntmp)
			pline("You turn into %s!", an(mons[mntmp].mname));
		else
			pline("You feel like a new %s!", mons[mntmp].mname);
	}
	if (Stoned && poly_when_stoned(&mons[mntmp])) {
		/* poly_when_stoned already checked stone golem genocide */
		pline("You turn to stone!");
		mntmp = PM_STONE_GOLEM;
		Stoned = 0;
		delayed_killer = 0;
	}

	u.mtimedone = rn1(500, 500);
	u.umonnum = mntmp;
	set_uasmon();

	/* New stats for monster, to last only as long as polymorphed.
	 * Currently only strength gets changed.
	 */
	if (strongmonst(&mons[mntmp])) ABASE(A_STR) = AMAX(A_STR) = STR18(100);

	if (Stone_resistance && Stoned) { /* [email protected] */
		Stoned = 0;
		delayed_killer = 0;
		pline("You no longer seem to be petrifying.");
	}
	if (Sick_resistance && Sick) {
		make_sick(0L, NULL, FALSE, SICK_ALL);
		pline("You no longer feel sick.");
	}
	if (Slimed) {
	    if (flaming(youmonst.data)) {
		pline("The slime burns away!");
		Slimed = 0L;
		iflags.botl = 1;
	    } else if (mntmp == PM_GREEN_SLIME) {
		/* do it silently */
		Slimed = 0L;
		iflags.botl = 1;
	    }
	}
	if (nohands(youmonst.data)) Glib = 0;

	/*
	mlvl = adj_lev(&mons[mntmp]);
	 * We can't do the above, since there's no such thing as an
	 * "experience level of you as a monster" for a polymorphed character.
	 */
	mlvl = (int)mons[mntmp].mlevel;
	if (youmonst.data->mlet == S_DRAGON && mntmp >= PM_GRAY_DRAGON) {
		u.mhmax = In_endgame(&u.uz) ? (8*mlvl) : (4*mlvl + dice(mlvl,4));
	} else if (is_golem(youmonst.data)) {
		u.mhmax = golemhp(mntmp);
	} else {
		if (!mlvl) u.mhmax = rnd(4);
		else u.mhmax = dice(mlvl, 8);
		if (is_home_elemental(&u.uz, &mons[mntmp])) u.mhmax *= 3;
	}
	u.mh = u.mhmax;

	if (u.ulevel < mlvl) {
	/* Low level characters can't become high level monsters for long */
		u.mtimedone = u.mtimedone * u.ulevel / mlvl;
	}

	if (uskin && mntmp != armor_to_dragon(uskin->otyp))
		skinback(FALSE);
	break_armor();
	drop_weapon(1);
	if (hides_under(youmonst.data))
		u.uundetected = OBJ_AT(u.ux, u.uy);
	else if (youmonst.data->mlet == S_EEL)
		u.uundetected = is_pool(level, u.ux, u.uy);
	else
		u.uundetected = 0;

	if (u.utraptype == TT_PIT) {
	    if (could_pass_walls && !Passes_walls) {
		u.utrap = rn1(6,2);
	    } else if (!could_pass_walls && Passes_walls) {
		u.utrap = 0;
	    }
	}
	if (was_blind && !Blind) {	/* previous form was eyeless */
	    Blinded = 1L;
	    make_blinded(0L, TRUE);	/* remove blindness */
	}
	newsym(u.ux,u.uy);		/* Change symbol */

	if (!sticky && !u.uswallow && u.ustuck && sticks(youmonst.data)) u.ustuck = 0;
	else if (sticky && !sticks(youmonst.data)) uunstick();
	if (u.usteed) {
	    if (touch_petrifies(u.usteed->data) &&
	    		!Stone_resistance && rnl(3)) {
	    	char buf[BUFSZ];

	    	pline("No longer petrifying-resistant, you touch %s.",
	    			mon_nam(u.usteed));
	    	sprintf(buf, "riding %s", an(u.usteed->data->mname));
	    	instapetrify(buf);
 	    }
	    if (!can_ride(u.usteed)) dismount_steed(DISMOUNT_POLY);
	}

	if (flags.verbose) {
	    static const char use_thec[] = "Use the command #%s to %s.";
	    static const char monsterc[] = "monster";
	    if (can_breathe(youmonst.data))
		pline(use_thec,monsterc,"use your breath weapon");
	    if (attacktype(youmonst.data, AT_SPIT))
		pline(use_thec,monsterc,"spit venom");
	    if (youmonst.data->mlet == S_NYMPH)
		pline(use_thec,monsterc,"remove an iron ball");
	    if (attacktype(youmonst.data, AT_GAZE))
		pline(use_thec,monsterc,"gaze at monsters");
	    if (is_hider(youmonst.data))
		pline(use_thec,monsterc,"hide");
	    if (is_were(youmonst.data))
		pline(use_thec,monsterc,"summon help");
	    if (webmaker(youmonst.data))
		pline(use_thec,monsterc,"spin a web");
	    if (u.umonnum == PM_GREMLIN)
		pline(use_thec,monsterc,"multiply in a fountain");
	    if (is_unicorn(youmonst.data))
		pline(use_thec,monsterc,"use your horn");
	    if (is_mind_flayer(youmonst.data))
		pline(use_thec,monsterc,"emit a mental blast");
	    if (youmonst.data->msound == MS_SHRIEK) /* worthless, actually */
		pline(use_thec,monsterc,"shriek");
	    if (lays_eggs(youmonst.data) && flags.female)
		pline(use_thec,"sit","lay an egg");
	}
	/* you now know what an egg of your type looks like */
	if (lays_eggs(youmonst.data)) {
	    learn_egg_type(u.umonnum);
	    /* make queen bees recognize killer bee eggs */
	    learn_egg_type(egg_type_from_parent(u.umonnum, TRUE));
	}
	find_ac();
	if ((!Levitation && !u.ustuck && !Flying &&
	    (is_pool(level, u.ux,u.uy) || is_lava(level, u.ux,u.uy))) ||
	   (Underwater && !Swimming))
	    spoteffects(TRUE);
	if (Passes_walls && u.utrap && u.utraptype == TT_INFLOOR) {
	    u.utrap = 0;
	    pline("The rock seems to no longer trap you.");
	} else if (likes_lava(youmonst.data) && u.utrap && u.utraptype == TT_LAVA) {
	    u.utrap = 0;
	    pline("The lava now feels soothing.");
	}
	if (amorphous(youmonst.data) || is_whirly(youmonst.data) || unsolid(youmonst.data)) {
	    if (Punished) {
		pline("You slip out of the iron chain.");
		unpunish();
	    }
	}
	if (u.utrap && (u.utraptype == TT_WEB || u.utraptype == TT_BEARTRAP) &&
		(amorphous(youmonst.data) || is_whirly(youmonst.data) || unsolid(youmonst.data) ||
		  (youmonst.data->msize <= MZ_SMALL && u.utraptype == TT_BEARTRAP))) {
	    pline("You are no longer stuck in the %s.",
		    u.utraptype == TT_WEB ? "web" : "bear trap");
	    /* probably should burn webs too if PM_FIRE_ELEMENTAL */
	    u.utrap = 0;
	}
	if (webmaker(youmonst.data) && u.utrap && u.utraptype == TT_WEB) {
	    pline("You orient yourself on the web.");
	    u.utrap = 0;
	}
	iflags.botl = 1;
	vision_full_recalc = 1;
	see_monsters();
	exercise(A_CON, FALSE);
	exercise(A_WIS, TRUE);
	encumber_msg();
	return 1;
}
Example #8
0
void faction::randomize()
{
// Set up values
// TODO: Not always in overmap 0,0
 omx = 0;
 omy = 0;
 mapx = rng(OMAPX / 10, OMAPX - OMAPX / 10);
 mapy = rng(OMAPY / 10, OMAPY - OMAPY / 10);
// Pick an overall goal.
 goal = faction_goal(rng(1, NUM_FACGOALS - 1));
 if (one_in(4))
  goal = FACGOAL_NONE;	// Slightly more likely to not have a real goal
 good     = facgoal_data[goal].good;
 strength = facgoal_data[goal].strength;
 sneak    = facgoal_data[goal].sneak;
 crime    = facgoal_data[goal].crime;
 cult     = facgoal_data[goal].cult;
 job1 = faction_job(rng(1, NUM_FACJOBS - 1));
 do
  job2 = faction_job(rng(0, NUM_FACJOBS - 1));
 while (job2 == job1);
 good     += facjob_data[job1].good     + facjob_data[job2].good;
 strength += facjob_data[job1].strength + facjob_data[job2].strength;
 sneak    += facjob_data[job1].sneak    + facjob_data[job2].sneak;
 crime    += facjob_data[job1].crime    + facjob_data[job2].crime;
 cult     += facjob_data[job1].cult     + facjob_data[job2].cult;

 int num_values = 0;
 int tries = 0;
 values = 0;
 do {
  int v = rng(1, NUM_FACVALS - 1);
  if (!has_value(faction_value(v)) && matches_us(faction_value(v))) {
   values |= mfb(v);
   tries = 0;
   num_values++;
   good     += facval_data[v].good;
   strength += facval_data[v].strength;
   sneak    += facval_data[v].sneak;
   crime    += facval_data[v].crime;
   cult     += facval_data[v].cult;
  } else
   tries++;
 } while((one_in(num_values) || one_in(num_values)) && tries < 15);

 std::string noun;
 int sel = 1, best = strength;
 if (sneak > best) {
  sel = 2;
  best = sneak;
 }
 if (crime > best) {
  sel = 3;
  best = crime;
 }
 if (cult > best)
  sel = 4;
 if (strength <= 0 && sneak <= 0 && crime <= 0 && cult <= 0)
  sel = 0;

 switch (sel) {
 case 1:
  noun  = faction_noun_strong[rng(0, 14)];
  power = dice(5, 20);
  size  = dice(5, 6);
  break;
 case 2:
  noun  = faction_noun_sneak [rng(0, 14)];
  power = dice(5, 8);
  size  = dice(5, 8);
  break;
 case 3:
  noun  = faction_noun_crime [rng(0, 14)];
  power = dice(5, 16);
  size  = dice(5, 8);
  break;
 case 4:
  noun  = faction_noun_cult  [rng(0, 14)];
  power = dice(8, 8);
  size  = dice(4, 6);
  break;
 default:
  noun  = faction_noun_none  [rng(0, 14)];
  power = dice(6, 8);
  size  = dice(6, 6);
 }

 if (one_in(4)) {
  do
   name = _("The ") + noun + _(" of ") + invent_name();
  while (name.length() > MAX_FAC_NAME_SIZE);
 }
 else if (one_in(2)) {
  do
   name = _("The ") + invent_adj() + " " + noun;
  while (name.length() > MAX_FAC_NAME_SIZE);
 }
 else {
  do {
   std::string adj;
   if (good >= 3)
    adj = faction_adj_pos[rng(0, 14)];
   else if  (good <= -3)
    adj = faction_adj_bad[rng(0, 14)];
   else
    adj = faction_adj_neu[rng(0, 14)];
   name = _("The ") + adj + " " + noun;
   if (one_in(4))
    name += _(" of ") + invent_name();
  } while (name.length() > MAX_FAC_NAME_SIZE);
 }
}
Example #9
0
std::string invent_adj()
{
 int syllables = dice(2, 2) - 1;
 std::string ret,  tmp;
 switch (rng(0, 25)) {
  case  0: ret = "Ald";   break;
  case  1: ret = "Brogg"; break;
  case  2: ret = "Cald";  break;
  case  3: ret = "Dredd"; break;
  case  4: ret = "Eld";   break;
  case  5: ret = "Forr";  break;
  case  6: ret = "Gugg";  break;
  case  7: ret = "Horr";  break;
  case  8: ret = "Ill";   break;
  case  9: ret = "Jov";   break;
  case 10: ret = "Kok";   break;
  case 11: ret = "Lill";  break;
  case 12: ret = "Moom";  break;
  case 13: ret = "Nov";   break;
  case 14: ret = "Orb";   break;
  case 15: ret = "Perv";  break;
  case 16: ret = "Quot";  break;
  case 17: ret = "Rar";   break;
  case 18: ret = "Suss";  break;
  case 19: ret = "Torr";  break;
  case 20: ret = "Umbr";  break;
  case 21: ret = "Viv";   break;
  case 22: ret = "Warr";  break;
  case 23: ret = "Xen";   break;
  case 24: ret = "Yend";  break;
  case 25: ret = "Zor";   break;
 }
 for (int i = 0; i < syllables - 2; i++) {
  switch (rng(0, 17)) {
   case  0: tmp = "al";   break;
   case  1: tmp = "arn";  break;
   case  2: tmp = "astr"; break;
   case  3: tmp = "antr"; break;
   case  4: tmp = "ent";  break;
   case  5: tmp = "ell";  break;
   case  6: tmp = "ev";   break;
   case  7: tmp = "emm";  break;
   case  8: tmp = "empr"; break;
   case  9: tmp = "ill";  break;
   case 10: tmp = "ial";  break;
   case 11: tmp = "ior";  break;
   case 12: tmp = "ordr"; break;
   case 13: tmp = "oth";  break;
   case 14: tmp = "omn";  break;
   case 15: tmp = "uv";   break;
   case 16: tmp = "ulv";  break;
   case 17: tmp = "urn";  break;
  }
  ret += tmp;
 }
 switch (rng(0, 24)) {
  case  0: tmp = "";      break;
  case  1: tmp = "al";    break;
  case  2: tmp = "an";    break;
  case  3: tmp = "ard";   break;
  case  4: tmp = "ate";   break;
  case  5: tmp = "e";     break;
  case  6: tmp = "ed";    break;
  case  7: tmp = "en";    break;
  case  8: tmp = "er";    break;
  case  9: tmp = "ial";   break;
  case 10: tmp = "ian";   break;
  case 11: tmp = "iated"; break;
  case 12: tmp = "ier";   break;
  case 13: tmp = "ious";  break;
  case 14: tmp = "ish";   break;
  case 15: tmp = "ive";   break;
  case 16: tmp = "oo";    break;
  case 17: tmp = "or";    break;
  case 18: tmp = "oth";   break;
  case 19: tmp = "old";   break;
  case 20: tmp = "ous";   break;
  case 21: tmp = "ul";    break;
  case 22: tmp = "un";    break;
  case 23: tmp = "ule";   break;
  case 24: tmp = "y";     break;
 }
 ret += tmp;
 return ret;
}
Example #10
0
int player::dodge_roll()
{
 return dice(dodge(), 6);
}
Example #11
0
int player::hit_mon(game *g, monster *z)
{
 bool is_u = (this == &(g->u));	// Affects how we'll display messages
 int j;
 bool can_see = (is_u || g->u_see(posx, posy, j));
 std::string You  = (is_u ? "You"  : name);
 std::string Your = (is_u ? "Your" : name + "'s");
 std::string your = (is_u ? "your" : (male ? "his" : "her"));

// Types of combat (may overlap!)
 bool unarmed  = unarmed_attack(), bashing = weapon.is_bashing_weapon(),
      cutting  = weapon.is_cutting_weapon(),
      stabbing = (weapon.has_weapon_flag(WF_SPEAR) ||
                  weapon.has_weapon_flag(WF_STAB));

// Recoil penalty
 if (recoil <= 30)
  recoil += 6;
// Movement cost
 moves -= weapon.attack_time() + 20 * encumb(bp_torso);
// Different sizes affect your chance to hit
 if (hit_roll() < z->dodge_roll()) {// A miss!
  stumble(g);
  return 0;
 }
 if (z->has_flag(MF_SHOCK) && !wearing_something_on(bp_hands) &&
     (unarmed || weapon.conductive())) {
  if (is_u)
   g->add_msg("The %s's electric body shocks you!", z->name().c_str());
  hurtall(rng(1, 3));
 }
// For very high hit rolls, we crit!
 bool critical_hit = (hit_roll() >= 50 + 10 * z->dodge_roll());
 int dam = base_damage(true);
 int cutting_penalty = 0; // Moves lost from getting a cutting weapon stuck

// Drunken Master damage bonuses
 if (has_trait(PF_DRUNKEN) && has_disease(DI_DRUNK)) {
// Remember, a single drink gives 600 levels of DI_DRUNK
  if (unarmed)
   dam += disease_level(DI_DRUNK) / 250;
  else
   dam += disease_level(DI_DRUNK) / 400;
 }

 if (unarmed) { // Unarmed bonuses
  dam += rng(0, sklevel[sk_unarmed]);
  if (has_trait(PF_TALONS) && z->type->armor - sklevel[sk_unarmed] < 10) {
   int z_armor = (z->type->armor - sklevel[sk_unarmed]);
   if (z_armor < 0)
    z_armor = 0;
   dam += 10 - z_armor;
  }
 } else if (rng(1, 45 - dex_cur) < 2 * sklevel[sk_unarmed] &&
            rng(1, 65 - dex_cur) < 2 * sklevel[sk_unarmed]   ) {
// If we're not unarmed, there's still a possibility of getting in a bonus
// unarmed attack.
  if (is_u || can_see) {
   switch (rng(1, 4)) {
    case 1: g->add_msg("%s kick%s the %s!", You.c_str(), (is_u ? "" : "s"),
                       z->name().c_str()); break;
    case 2: g->add_msg("%s headbutt%s the %s!", You.c_str(), (is_u ? "" : "s"),
                       z->name().c_str()); break;
    case 3: g->add_msg("%s elbow%s the %s!", You.c_str(), (is_u ? "" : "s"),
                       z->name().c_str()); break;
    case 4: g->add_msg("%s knee%s the %s!", You.c_str(), (is_u ? "" : "s"),
                       z->name().c_str()); break;
   }
  }
  dam += rng(1, sklevel[sk_unarmed]);
  practice(sk_unarmed, 2);
 }
// Melee skill bonus
 dam += rng(0, sklevel[sk_melee]);
// Bashing damage bonus
 int bash_dam = weapon.type->melee_dam,
     bash_cap = 5 + str_cur + sklevel[sk_bashing];
 if (bash_dam > bash_cap)// Cap for weak characters
  bash_dam = (bash_cap * 3 + bash_dam) / 4;
 if (bashing)
  bash_dam += rng(0, sklevel[sk_bashing]) * sqrt(str_cur);
 int bash_min = bash_dam / 4;
 if (bash_min < sklevel[sk_bashing] * 2)
  bash_min = sklevel[sk_bashing] * 2;
 dam += rng(bash_dam / 4, bash_dam);
// Take some moves away from the target; at this point it's skill & bash damage
 z->moves -= rng(0, dam * 2);
// Spears treat cutting damage specially.
 if (weapon.has_weapon_flag(WF_SPEAR) &&
     weapon.type->melee_cut > z->type->armor - int(sklevel[sk_stabbing])) {
  int z_armor = z->type->armor - int(sklevel[sk_stabbing]);
  dam += int(weapon.type->melee_cut / 5);
  int minstab = sklevel[sk_stabbing] *  8 + weapon.type->melee_cut * 2,
      maxstab = sklevel[sk_stabbing] * 20 + weapon.type->melee_cut * 4;
  int monster_penalty = rng(minstab, maxstab);
  if (monster_penalty >= 150)
   g->add_msg("You force the %s to the ground!", z->name().c_str());
  else if (monster_penalty >= 80)
   g->add_msg("The %s is skewered and flinches!", z->name().c_str());
  z->moves -= monster_penalty;
  cutting_penalty = weapon.type->melee_cut * 4 + z_armor * 8 -
                    dice(sklevel[sk_stabbing], 10);
  practice(sk_stabbing, 2);
// Cutting damage bonus
 } else if (weapon.type->melee_cut >
            z->type->armor - int(sklevel[sk_cutting] / 2)) {
  int z_armor = z->type->armor - int(sklevel[sk_cutting] / 2);
  if (z_armor < 0)
   z_armor = 0;
  dam += weapon.type->melee_cut - z_armor;
  cutting_penalty = weapon.type->melee_cut * 3 + z_armor * 8 -
                    dice(sklevel[sk_cutting], 10);
 }
 if (weapon.has_weapon_flag(WF_MESSY)) { // e.g. chainsaws
  cutting_penalty /= 6; // Harder to get stuck
  for (int x = z->posx - 1; x <= z->posx + 1; x++) {
   for (int y = z->posy - 1; y <= z->posy + 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);
    }
   }
  }
 }

// Bonus attacks!

 bool shock_them = (!z->has_flag(MF_SHOCK) && has_bionic(bio_shock) &&
                    power_level >= 2 && unarmed && one_in(3));
 bool drain_them = (has_bionic(bio_heat_absorb) && power_level >= 1 &&
                    !is_armed() && z->has_flag(MF_WARM));
 bool  bite_them = (has_trait(PF_FANGS) && z->armor() < 18 &&
                    one_in(20 - dex_cur - sklevel[sk_unarmed]));
 bool  peck_them = (has_trait(PF_BEAK)  && z->armor() < 16 &&
                    one_in(15 - dex_cur - sklevel[sk_unarmed]));
 if (drain_them)
  power_level--;
 drain_them &= one_in(2);	// Only works half the time

// Critical hit effects
 if (critical_hit) {
  bool headshot = (!z->has_flag(MF_NOHEAD) && !one_in(3));
// Second chance for shock_them, drain_them, bite_them and peck_them
  shock_them = (shock_them || (!z->has_flag(MF_SHOCK) && has_bionic(bio_shock)&&
                               power_level >= 2 && unarmed && !one_in(3)));
  drain_them = (drain_them || (has_bionic(bio_heat_absorb) && !is_armed() &&
                               power_level >= 1 && z->has_flag(MF_WARM) &&
                               !one_in(3)));
  bite_them  = ( bite_them || (has_trait(PF_FANGS) && z->armor() < 18 &&
                               one_in(5)));
  peck_them  = ( peck_them || (has_trait(PF_BEAK)  && z->armor() < 16 &&
                               one_in(4)));

  if (weapon.has_weapon_flag(WF_SPEAR) || weapon.has_weapon_flag(WF_STAB)) {
   dam += weapon.type->melee_cut;
   dam += weapon.type->melee_cut * double(sklevel[sk_stabbing] / 10);
   practice(sk_stabbing, 5);
  }

  if (unarmed) {
   dam += rng(2, 6) * sklevel[sk_unarmed];
   if (sklevel[sk_unarmed] > 5)
    dam += 4 * (sklevel[sk_unarmed - 3]);
   z->moves -= dam;	// Stunning blow
   if (weapon.type->id == itm_bio_claws) {
    if (sklevel[sk_cutting] >= 3)
     dam += 5;
    headshot &= z->hp < dam && one_in(2);
    if (headshot && can_see)
     g->add_msg("%s claws pierce the %s's skull!", Your.c_str(),
                z->name().c_str());
    else if (can_see)
     g->add_msg("%s claws stab straight through the %s!", Your.c_str(),
                z->name().c_str());
   } else if (has_trait(PF_TALONS)) {
    dam += 2;
    headshot &= z->hp < dam && one_in(2);
    if (headshot && can_see)
     g->add_msg("%s talons tear the %s's head open!", Your.c_str(),
                z->name().c_str());
    else if (can_see)
     g->add_msg("%s bur%s %s talons into the %s!", You.c_str(),(is_u?"y":"ies"),
                your.c_str(), z->name().c_str());
   } else {
    headshot &= z->hp < dam && one_in(2);
    if (headshot && can_see)
     g->add_msg("%s crush%s the %s's skull in a single blow!", 
                You.c_str(), (is_u ? "" : "es"), z->name().c_str());
    else if (can_see)
     g->add_msg("%s deliver%s a crushing punch!",You.c_str(),(is_u ? "" : "s"));
   }
   if (z->hp > 0 && rng(1, 5) < sklevel[sk_unarmed])
    z->add_effect(ME_STUNNED, 1 + sklevel[sk_unarmed]);
  } else {	// Not unarmed
   if (bashing) {
    dam += 8 + (str_cur / 2);
    int turns_stunned = int(dam / 20) + int(sklevel[sk_bashing] / 2);
    if (turns_stunned > 6)
     turns_stunned = 6;
    z->add_effect(ME_STUNNED, turns_stunned);
   }
   if (cutting) {
    double cut_multiplier = double(sklevel[sk_cutting] / 12);
    if (cut_multiplier > 1.5)
     cut_multiplier = 1.5;
    dam += cut_multiplier * weapon.type->melee_cut;
    headshot &= z->hp < dam;
    if (stabbing) {
     if (headshot && can_see)
      g->add_msg("%s %s stabs through the %s's skull!", Your.c_str(),
                 weapon.tname(g).c_str(), z->name().c_str());
     else if (can_see)
      g->add_msg("%s stab %s %s through the %s!", You.c_str(), your.c_str(),
                 weapon.tname(g).c_str(), z->name().c_str());
    } else {
     if (headshot && can_see)
      g->add_msg("%s %s slices the %s's head off!", Your.c_str(),
                 weapon.tname(g).c_str(), z->name().c_str());
     else
      g->add_msg("%s %s cuts the %s deeply!", Your.c_str(),
                 weapon.tname(g).c_str(), z->name().c_str());
    }
   } else {	// Not cutting, probably bashing
    headshot &= z->hp < dam;
    if (headshot && can_see)
     g->add_msg("%s crush%s the %s's skull!", You.c_str(), (is_u ? "" : "es"),
                z->name().c_str());
    else if (can_see)
     g->add_msg("%s crush%s the %s's body!", You.c_str(), (is_u ? "" : "es"),
                z->name().c_str());
   }
  }	// End of not-unarmed
 }	// End of critical hit

 if (shock_them) {
  power_level -= 2;
  if (can_see)
   g->add_msg("%s shock%s the %s!", You.c_str(), (is_u ? "" : "s"),
              z->name().c_str());
  int shock = rng(2, 5);
  dam += shock * rng(1, 3);
  z->moves -= shock * 180;
 }
 if (drain_them) {
  charge_power(rng(0, 4));
  if (can_see)
   g->add_msg("%s drain%s the %s's body heat!", You.c_str(), (is_u ? "" : "s"),
              z->name().c_str());
  dam += rng(4, 10);
  z->moves -= rng(80, 120);
 }
 if (bite_them) {
  if (can_see)
   g->add_msg("%s sink %s fangs into the %s!", You.c_str(), your.c_str(),
              z->name().c_str());
  dam += 18 - z->armor();
 }
 if (peck_them) {
  if (can_see)
   g->add_msg("%s peck%s the %s viciously!", You.c_str(), (is_u ? "" : "s"),
              z->name().c_str());
  dam += 16 - z->armor();
 }

// Make a rather quiet sound, to alert any nearby monsters
 g->sound(posx, posy, 8, "");

// 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()));
  dam += rng(0, 5 + int(weapon.volume() * 1.5));// Hurt the monster extra
  remove_weapon();
 }

 if (dam <= 0) {
  if (is_u)
   g->add_msg("You hit the %s, but do no damage.", z->name().c_str());
  else if (can_see)
   g->add_msg("%s's %s hits the %s, but does no damage.", You.c_str(),
              weapon.tname(g).c_str(), z->name().c_str());
  practice(sk_melee, rng(2, 5));
  if (unarmed)
   practice(sk_unarmed, 2);
  if (bashing)
   practice(sk_bashing, 2);
  if (cutting)
   practice(sk_cutting, 2);
  if (stabbing)
   practice(sk_stabbing, 2);
  return 0;
 }
 if (is_u)
  g->add_msg("You hit the %s for %d damage.", z->name().c_str(), dam);
 else if (can_see)
  g->add_msg("%s hits the %s with %s %s.", You.c_str(), z->name().c_str(),
             (male ? "his" : "her"),
             (weapon.type->id == 0 ? "fists" : weapon.tname(g).c_str()));
 practice(sk_melee, rng(5, 10));
 if (unarmed)
  practice(sk_unarmed, rng(5, 10));
 if (bashing)
  practice(sk_bashing, rng(5, 10));
 if (cutting)
  practice(sk_cutting, rng(5, 10));
 if (stabbing)
  practice(sk_stabbing, rng(5, 10));

// Penalize the player if their cutting weapon got stuck
 if (!unarmed && dam < z->hp && cutting_penalty > dice(str_cur * 2, 20)) {
  if (is_u)
   g->add_msg("Your %s gets stuck in the %s, pulling it out of your hands!",
              weapon.tname().c_str(), z->type->name.c_str());
  z->add_item(remove_weapon());
  if (weapon.has_weapon_flag(WF_SPEAR) || weapon.has_weapon_flag(WF_STAB))
   z->speed *= .7;
  else
   z->speed *= .85;
 } else {
  if (dam >= z->hp) {
   cutting_penalty /= 2;
   cutting_penalty -= rng(sklevel[sk_cutting], sklevel[sk_cutting] * 2 + 2);
  }
  if (cutting_penalty > 0)
   moves -= cutting_penalty;
  if (cutting_penalty >= 50 && is_u)
   g->add_msg("Your %s gets stuck in the %s, but you yank it free.",
              weapon.tname().c_str(), z->type->name.c_str());
  if (weapon.has_weapon_flag(WF_SPEAR) || weapon.has_weapon_flag(WF_STAB))
   z->speed *= .9;
 }

 return dam;
}
Example #12
0
/*  cutworm()
 *
 *  Check for mon->wormno before calling this function!
 *
 *  When hitting a worm (worm) at position x, y, with a weapon (weap),
 *  there is a chance that the worm will be cut in half, and a chance
 *  that both halves will survive.
 */
void
cutworm(struct monst *worm, xchar x, xchar y, struct obj *weap)
{
    struct wseg *curr, *new_tail;
    struct monst *new_worm;
    int wnum = worm->wormno;
    int cut_chance, new_wnum;

    if (!wnum)
        return; /* bullet proofing */

    if (x == worm->mx && y == worm->my)
        return; /* hit on head */

    /* cutting goes best with a bladed weapon */
    cut_chance = rnd(20);       /* Normally 1-16 does not cut */
    /* Normally 17-20 does */

    if (weap && objects[weap->otyp].oc_dir & SLASH)
        cut_chance += 10;       /* With a slashing weapon 1- 6 does not cut */
    /* 7-20 does */

    if (cut_chance < 17)
        return; /* not good enough */

    /* Find the segment that was attacked. */
    curr = level->wtails[wnum];

    while ((curr->wx != x) || (curr->wy != y)) {
        curr = curr->nseg;
        if (!curr) {
            impossible("cutworm: no segment at (%d,%d)", (int)x, (int)y);
            return;
        }
    }

    /* If this is the tail segment, then the worm just loses it. */
    if (curr == level->wtails[wnum]) {
        shrink_worm(wnum);
        return;
    }

    /* 
     *  Split the worm.  The tail for the new worm is the old worm's tail.
     *  The tail for the old worm is the segment that follows "curr",
     *  and "curr" becomes the dummy segment under the new head.
     */
    new_tail = level->wtails[wnum];
    level->wtails[wnum] = curr->nseg;
    curr->nseg = NULL;  /* split the worm */

    /* 
     *  At this point, the old worm is correct.  Any new worm will have
     *  it's head at "curr" and its tail at "new_tail".
     */

    /* Sometimes the tail end dies. */
    if (rn2(3) || !(new_wnum = get_wormno(level)) || !worm->m_lev) {
        cutoff(worm, new_tail);
        return;
    }

    remove_monster(level, x, y);        /* clone_mon puts new head here */
    if (!(new_worm = clone_mon(worm, x, y))) {
        cutoff(worm, new_tail);
        return;
    }
    new_worm->wormno = new_wnum;        /* affix new worm number */

    /* Devalue the monster level of both halves of the worm. */
    worm->m_lev =
        ((unsigned)worm->m_lev <=
         3) ? (unsigned)worm->m_lev : max((unsigned)worm->m_lev - 2, 3);
    new_worm->m_lev = worm->m_lev;

    /* Calculate the mhp on the new_worm for the (lower) monster level. */
    new_worm->mhpmax = new_worm->mhp = dice((int)new_worm->m_lev, 8);

    /* Calculate the mhp on the old worm for the (lower) monster level. */
    if (worm->m_lev > 3) {
        worm->mhpmax = dice((int)worm->m_lev, 8);
        if (worm->mhpmax < worm->mhp)
            worm->mhp = worm->mhpmax;
    }

    level->wtails[new_wnum] = new_tail; /* We've got all the info right now */
    level->wheads[new_wnum] = curr;     /* so we can do this faster than */
    level->wgrowtime[new_wnum] = 0L;    /* trying to call initworm().  */

    /* Place the new monster at all the segment locations. */
    place_wsegs(new_worm);

    if (flags.mon_moving)
        pline(msgc_monneutral, "%s is cut in half.", Monnam(worm));
    else
        pline(msgc_combatgood, "You cut %s in half.", mon_nam(worm));
}
Example #13
0
void game::complete_craft()
{
 recipe making = recipes[u.activity.index]; // Which recipe is it?
 std::vector<component> will_use; // List of all items we're using, w/ count

// Up to 5 components / tools
 for (int i = 0; i < 5; i++) {
  if (making.components[i].size() > 0) {
// For each set of components in the recipe, fill you_have with the list of all
// matching ingredients the player has.
   std::vector<component> you_have;
   for (int j = 0; j < making.components[i].size(); j++) {
    if (u.has_amount(making.components[i][j].type,
                     making.components[i][j].count))
     you_have.push_back(making.components[i][j]);
   }

   if (you_have.size() == 1) // Only one, so we'll definitely use it
    will_use.push_back(component(you_have[0].type, you_have[0].count));
   else {	// Let the player pick which component they want to use
    WINDOW* w = newwin(you_have.size() + 2, 30, 10, 25);
    wborder(w, LINE_XOXO, LINE_XOXO, LINE_OXOX, LINE_OXOX,
               LINE_OXXO, LINE_OOXX, LINE_XXOO, LINE_XOOX );
    mvwprintz(w, 0, 5, c_red, "Use which component?");
    for (int j = 0; j < you_have.size(); j++)
     mvwprintz(w, j + 1, 1, c_white, "%d: %s", j + 1,
               itypes[you_have[j].type]->name.c_str());
    wrefresh(w);
    char ch;
    do
     ch = getch();
    while (ch < '1' || ch >= '1' + you_have.size());
    ch -= '1';
    will_use.push_back(component(you_have[ch].type, you_have[ch].count));
    delwin(w);
   }
  } // Done looking at components

// Use charges of any tools that require charges used
  if (making.tools[i].size() > 0) {
   for (int j = 0; j < making.tools[i].size(); j++) {
    if (making.tools[i][j].count > 0)
     u.use_charges(making.tools[i][j].type, making.tools[i][j].count);
   }
  }
 } // Done finding the components/tools needed

// # of dice is 75% primary skill, 25% secondary (unless secondary is null)
 int skill_dice = u.sklevel[making.sk_primary] * 3;
 if (making.sk_secondary == sk_null)
  skill_dice += u.sklevel[making.sk_primary];
 else
  skill_dice += u.sklevel[making.sk_secondary];
// Sides on dice is 16 plus your current intelligence
 int skill_sides = 16 + u.int_cur;

 int diff_dice = making.difficulty * 4; // Since skill level is * 4 also
 int diff_sides = 24;	// 16 + 8 (default intelligence)

 int skill_roll = dice(skill_dice, skill_sides);
 int diff_roll  = dice(diff_dice,  diff_sides);

 if (making.sk_primary != sk_null)
  u.practice(making.sk_primary, making.difficulty * 5 + 20);
 if (making.sk_secondary != sk_null)
  u.practice(making.sk_secondary, 5);

// Messed up badly; waste some components.
 if (making.difficulty != 0 && diff_roll > skill_roll * (1 + 0.1 * rng(1, 5))) {
  add_msg("You fail to make the %s, and waste some materials.",
          itypes[making.result]->name.c_str());
  int num_lost = rng(1, will_use.size());
  for (int i = 0; i < num_lost; i++) {
   int n = rng(0, will_use.size() - 1);
   if (itypes[will_use[n].type]->is_ammo() && will_use[i].type != itm_gasoline)
    u.use_charges(will_use[n].type, will_use[n].count);
   else
    u.use_amount(will_use[n].type, will_use[n].count);
   will_use.erase(will_use.begin() + n);
  }
  u.activity.type = ACT_NULL;
  return;
// Messed up slightly; no components wasted.
 } else if (diff_roll > skill_roll) {
  add_msg("You fail to make the %s, but don't waste any materials.",
          itypes[making.result]->name.c_str());
  u.activity.type = ACT_NULL;
  return;
 }
// If we're here, the craft was a success!
// Use up the items in will_use
 for (int i = 0; i < will_use.size(); i++) {
  if (itypes[will_use[i].type]->is_ammo() && will_use[i].type != itm_gasoline)
   u.use_charges(will_use[i].type, will_use[i].count);
  else
   u.use_amount(will_use[i].type, will_use[i].count);
 }

// Set up the new item, and pick an inventory letter
 int iter = 0;
 item newit(itypes[making.result], turn, nextinv);
 do {
  newit.invlet = nextinv;
  advance_nextinv();
  iter++;
 } while (u.has_item(newit.invlet) && iter < 52);
 newit = newit.in_its_container(&itypes);

// We might not have space for the item
 if (iter == 52 || u.volume_carried()+newit.volume() > u.volume_capacity()) {
  add_msg("There's no room in your inventory for the %s, so you drop it.",
          newit.tname().c_str());
  m.add_item(u.posx, u.posy, newit);
 } else if (u.weight_carried() + newit.volume() > u.weight_capacity()) {
  add_msg("The %s is too heavy to carry, so you drop it.",
          newit.tname().c_str());
  m.add_item(u.posx, u.posy, newit);
 } else {
  u.i_add(newit);
  add_msg("%c - %s", newit.invlet, newit.tname().c_str());
 }
}
Example #14
0
bool game::grabbed_veh_move( const tripoint &dp )
{
    const optional_vpart_position grabbed_vehicle_vp = m.veh_at( u.pos() + u.grab_point );
    if( !grabbed_vehicle_vp ) {
        add_msg( m_info, _( "No vehicle at grabbed point." ) );
        u.grab( OBJECT_NONE );
        return false;
    }
    vehicle *grabbed_vehicle = &grabbed_vehicle_vp->vehicle();
    const int grabbed_part = grabbed_vehicle_vp->part_index();

    const vehicle *veh_under_player = veh_pointer_or_null( m.veh_at( u.pos() ) );
    if( grabbed_vehicle == veh_under_player ) {
        u.grab_point = -dp;
        return false;
    }

    tripoint dp_veh = -u.grab_point;
    const tripoint prev_grab = u.grab_point;
    tripoint next_grab = u.grab_point;

    bool zigzag = false;

    if( dp == prev_grab ) {
        // We are pushing in the direction of vehicle
        dp_veh = dp;
    } else if( abs( dp.x + dp_veh.x ) != 2 && abs( dp.y + dp_veh.y ) != 2 ) {
        // Not actually moving the vehicle, don't do the checks
        u.grab_point = -( dp + dp_veh );
        return false;
    } else if( ( dp.x == prev_grab.x || dp.y == prev_grab.y ) &&
               next_grab.x != 0 && next_grab.y != 0 ) {
        // Zig-zag (or semi-zig-zag) pull: player is diagonal to vehicle
        // and moves away from it, but not directly away
        dp_veh.x = ( dp.x == -dp_veh.x ) ? 0 : dp_veh.x;
        dp_veh.y = ( dp.y == -dp_veh.y ) ? 0 : dp_veh.y;

        next_grab = -dp_veh;
        zigzag = true;
    } else {
        // We are pulling the vehicle
        next_grab = -dp;
    }

    // Make sure the mass and pivot point are correct
    grabbed_vehicle->invalidate_mass();

    //vehicle movement: strength check
    int mc = 0;
    int str_req = ( grabbed_vehicle->total_mass() / 25_kilogram ); //strength required to move vehicle.

    //if vehicle is rollable we modify str_req based on a function of movecost per wheel.

    // Vehicle just too big to grab & move; 41-45 lets folks have a bit of a window
    // (Roughly 1.1K kg = danger zone; cube vans are about the max)
    if( str_req > 45 ) {
        add_msg( m_info, _( "The %s is too bulky for you to move by hand." ),
                 grabbed_vehicle->name );
        return true; // No shoving around an RV.
    }

    const auto &wheel_indices = grabbed_vehicle->wheelcache;
    if( grabbed_vehicle->valid_wheel_config() ) {
        //determine movecost for terrain touching wheels
        const tripoint vehpos = grabbed_vehicle->global_pos3();
        for( int p : wheel_indices ) {
            const tripoint wheel_pos = vehpos + grabbed_vehicle->parts[p].precalc[0];
            const int mapcost = m.move_cost( wheel_pos, grabbed_vehicle );
            mc += ( str_req / wheel_indices.size() ) * mapcost;
        }
        //set strength check threshold
        //if vehicle has many or only one wheel (shopping cart), it is as if it had four.
        if( wheel_indices.size() > 4 || wheel_indices.size() == 1 ) {
            str_req = mc / 4 + 1;
        } else {
            str_req = mc / wheel_indices.size() + 1;
        }
    } else {
        str_req++;
        //if vehicle has no wheels str_req make a noise.
        if( str_req <= u.get_str() ) {
            sounds::sound( grabbed_vehicle->global_pos3(), str_req * 2, sounds::sound_t::movement,
                           _( "a scraping noise." ), true, "misc", "scraping" );
        }
    }

    //final strength check and outcomes
    ///\EFFECT_STR determines ability to drag vehicles
    if( str_req <= u.get_str() ) {
        //calculate exertion factor and movement penalty
        ///\EFFECT_STR increases speed of dragging vehicles
        u.moves -= 100 * str_req / std::max( 1, u.get_str() );
        const int ex = dice( 1, 3 ) - 1 + str_req;
        if( ex > u.get_str() ) {
            add_msg( m_bad, _( "You strain yourself to move the %s!" ), grabbed_vehicle->name );
            u.moves -= 200;
            u.mod_pain( 1 );
        } else if( ex == u.get_str() ) {
            u.moves -= 200;
            add_msg( _( "It takes some time to move the %s." ), grabbed_vehicle->name );
        }
    } else {
        u.moves -= 100;
        add_msg( m_bad, _( "You lack the strength to move the %s" ), grabbed_vehicle->name );
        return true;
    }

    std::string blocker_name = _( "errors in movement code" );
    const auto get_move_dir = [&]( const tripoint & dir, const tripoint & from ) {
        tileray mdir;

        mdir.init( dir.x, dir.y );
        grabbed_vehicle->turn( mdir.dir() - grabbed_vehicle->face.dir() );
        grabbed_vehicle->face = grabbed_vehicle->turn_dir;
        grabbed_vehicle->precalc_mounts( 1, mdir.dir(), grabbed_vehicle->pivot_point() );

        // Grabbed part has to stay at distance 1 to the player
        // and in roughly the same direction.
        const tripoint new_part_pos = grabbed_vehicle->global_pos3() +
                                      grabbed_vehicle->parts[ grabbed_part ].precalc[ 1 ];
        const tripoint expected_pos = u.pos() + dp + from;
        const tripoint actual_dir = expected_pos - new_part_pos;

        // Set player location to illegal value so it can't collide with vehicle.
        const tripoint player_prev = u.pos();
        u.setpos( tripoint_zero );
        std::vector<veh_collision> colls;
        const bool failed = grabbed_vehicle->collision( colls, actual_dir, true );
        u.setpos( player_prev );
        if( !colls.empty() ) {
            blocker_name = colls.front().target_name;
        }
        return failed ? tripoint_zero : actual_dir;
    };

    // First try the move as intended
    // But if that fails and the move is a zig-zag, try to recover:
    // Try to place the vehicle in the position player just left rather than "flattening" the zig-zag
    tripoint final_dp_veh = get_move_dir( dp_veh, next_grab );
    if( final_dp_veh == tripoint_zero && zigzag ) {
        final_dp_veh = get_move_dir( -prev_grab, -dp );
        next_grab = -dp;
    }

    if( final_dp_veh == tripoint_zero ) {
        add_msg( _( "The %s collides with %s." ), grabbed_vehicle->name, blocker_name );
        u.grab_point = prev_grab;
        return true;
    }

    u.grab_point = next_grab;

    tripoint gp = grabbed_vehicle->global_pos3();
    grabbed_vehicle = m.displace_vehicle( gp, final_dp_veh );

    if( grabbed_vehicle == nullptr ) {
        debugmsg( "Grabbed vehicle disappeared" );
        return false;
    }

    for( int p : wheel_indices ) {
        if( one_in( 2 ) ) {
            tripoint wheel_p = grabbed_vehicle->global_part_pos3( grabbed_part );
            grabbed_vehicle->handle_trap( wheel_p, p );
        }
    }

    return false;

}
int main (int argc, char** argv)
{

	if(argc != 4+1 )
	{
		std::cerr<<" The function :"<<argv[0]<<" should be called with the following parameters: "<< std::endl
				 <<" config_file Puddle_Height[eV] Puddle_Concentration[0-1] Puddle_Range[lat_unit]."<<std::endl;
		return 0;
	}

	//Read the name of the configuration file
	const std::string config_filename(argv[1]);
	const double puddHeight=atof(argv[2]);
	const double puddConcen=atof(argv[3]);
	const double puddRange =atof(argv[4]);


	std::ifstream config_file(config_filename.c_str());
	///Look for the line lattice_info
	std::string line;
	bool found=false;
	for (int line_num = 0; std::getline(config_file, line); ++line_num)
		if(line=="lattice_info")
		{
			found=true;
			break;
		}
	if(!found)
	{
		config_file.close();
		std::cerr<<"The config file does not posses a disorder_info section. The simulation cannot proceed"<<std::endl;
		return 0;
	}

		std::string label;
		int OrbitalNum=0;
		int SpinNum=0;
		int coord=0;
		std::vector<int> SitesInDir(3);
		std::vector < std::vector<double> > lat(3);
		for(int i=0;i<3;i++)
			lat[i]=std::vector<double>(3,0);

		config_file	>>label
					>>lat[0][0]>>lat[0][1]>>lat[0][2]
					>>lat[1][0]>>lat[1][1]>>lat[1][2]
	                >>lat[2][0]>>lat[2][1]>>lat[2][2]
	                >>SitesInDir[0]>>SitesInDir[1]>>SitesInDir[2]
				    >>OrbitalNum>>SpinNum>>coord;

		const double Delta[] = { (lat[0][0]+lat[1][0])/3. , (lat[0][1]+lat[1][1])/3. , 0 };			// THIRD LATTICE VECTOR


		std::string output_name=label+"PuddleHeight"+
								argv[2]+"eVConc"+argv[3]+
								"Range"+argv[4]+"nm.dis";

		std::ofstream output_file(output_name.c_str());


		const double epsilon=std::numeric_limits<double>::epsilon();
		if(puddHeight <= epsilon || puddConcen  <= epsilon)
		{
			output_file.close();
			return 0;
		}


		boost::random::mt19937 rng;         // produces randomness out of thin air
		boost::random::uniform_01<double> dice;
		boost::random::uniform_real_distribution<double> RandomEnergy( -1.0 , 1.0);


		///Number of orbitals in the simulation
		const int TotalOfOrbitals=SitesInDir[0]*SitesInDir[0]*SitesInDir[2]*OrbitalNum*SpinNum;

		///Stimated number of impurities
		const int  estImpNum= (1.3)*puddConcen * TotalOfOrbitals/SpinNum;//The two is to overstimate the value
		std::vector< std::vector< double > > impPosition;
		impPosition.reserve( estImpNum );
		std::cout<<"The estimated number of puddles is set as: "<<estImpNum<<std::endl;


		std::vector< double >
		this_imp_pos(3);										//a singl impurity position

		int impurity_count= 0;


		// first we go through all the possible positions
		for(int i2=0; i2 < SitesInDir[2]  ; i2++ )
			for(int i1=0; i1 < SitesInDir[1]  ; i1++ )
				for(int i0=0; i0 < SitesInDir[0] ; i0++ )
					for(int io=0; io < OrbitalNum ; io++ )
						if( dice(rng) < puddConcen )
						{
							this_imp_pos[0]=lat[0][0]*i0 + lat[1][0]*i1 + lat[2][0]*i2 + io*Delta[0];
							this_imp_pos[1]=lat[0][1]*i0 + lat[1][1]*i1 + lat[2][1]*i2 + io*Delta[1];
							this_imp_pos[1]=lat[0][2]*i0 + lat[1][2]*i1 + lat[2][2]*i2 + io*Delta[2];
							impPosition.push_back(this_imp_pos);
						}

		int counter=0;
		std::vector<double> diagElements( TotalOfOrbitals ,0 );
		//We incorporate the onsite energy of the puddles.
		for(int i2=0; i2 < SitesInDir[2]  ; i2++ )
			for(int i1=0; i1 < SitesInDir[1]  ; i1++ )
				for(int i0=0; i0 < SitesInDir[0] ; i0++ )
					for(int io=0; io < OrbitalNum ; io++ )
					{
						for(int it0=-1; it0 <= 1; it0++ )	// tile index 1
							for(int it1=-1; it1 <= 1; it1++ )	// tile index 2. This is used to take into account the periodic boundary condition
							{
								const int I0=i0+SitesInDir[0]*it0 ;
								const int I1=i1+SitesInDir[1]*it1 ;
								const double
								r[2]={
										lat[0][0]*I0+lat[1][0]*I1+io*Delta[0],
										lat[0][1]*I0+lat[1][1]*I1+io*Delta[1]
								};
								for(int  imp=0;imp< impPosition.size(); imp++)
								{
									const double
									dist = 	( r[0]-impPosition[imp][0] )*( r[0]-impPosition[imp][0] ) +
											( r[1]-impPosition[imp][1] )*( r[1]-impPosition[imp][1] );

									const double
									Ei=RandomEnergy(rng)*puddHeight*exp(-0.5*dist/puddRange/puddRange);
									//Created for periodic puddles
									if( std::abs(Ei) > epsilon )
										for(int is=0; is <SpinNum   ; is++ )
										{
											//compute the site where the energy is going to be changed
											const int
											k0= IndexesToIndex(	I0, SitesInDir[0],
																I1, SitesInDir[1],
																i2, SitesInDir[2],
																io, OrbitalNum,
																is, SpinNum);
											diagElements[k0]=diagElements[k0]+Ei;
										}
								}
							}
						++counter;
						const int checkpoint= int((double)TotalOfOrbitals/SpinNum/100);
						if(counter%checkpoint == 0 )
							std::cout<<"Setting the puddles, there are :"<<counter<<"/"<<TotalOfOrbitals/SpinNum<<" left."<<std::endl;
						}
		// std::cout<<"Setting the hamiltonian in the sparse matrix"<<std::endl;

		double mean=0;
		double stdDev=0;

		for(int k0=0;k0<diagElements.size();k0++)
			if(std::abs(diagElements[k0])>epsilon)
			{
				output_file<<k0<<" "<<diagElements[k0]<<std::endl;
				mean=mean+diagElements[k0];
				stdDev= stdDev +diagElements[k0]*diagElements[k0];
			}

		mean=mean/diagElements.size();
		stdDev=stdDev/diagElements.size();
		stdDev=sqrt(stdDev- mean*mean);

/*		for(int k0=0;k0<diagElements.size();k0++)
			if(std::abs(diagElements[k0])>epsilon)
				stdDev=stdDev+pow(mean-diagElements[k0],2.);
		stdDev=sqrt(stdDev/diagElements.size());
 */
		std::cout<<"The puddle have mean:"<<mean<<" StdDev: "<<stdDev<<std::endl;


	output_file.close();
 return 0;}
Example #16
0
void weather_change(void)
{
	int diff = 0, sky_change, temp_change, i,
			   grainlevel = 0, gsnowlevel = 0, icelevel = 0, snowdec = 0,
											raincast = 0, snowcast = 0, avg_day_temp, avg_week_temp, cweather_type = 0, temp;

	weather_info.hours_go++;
	if (weather_info.hours_go > HOURS_PER_DAY)
	{
		weather_info.press_last_day = weather_info.press_last_day * (HOURS_PER_DAY - 1) / HOURS_PER_DAY;
		weather_info.temp_last_day = weather_info.temp_last_day * (HOURS_PER_DAY - 1) / HOURS_PER_DAY;
	}
	// Average pressure and temperature per 24 hours
	weather_info.press_last_day += weather_info.pressure;
	weather_info.temp_last_day += weather_info.temperature;
	if (weather_info.hours_go > (DAYS_PER_WEEK * HOURS_PER_DAY))
	{
		weather_info.press_last_week =
			weather_info.press_last_week * (DAYS_PER_WEEK * HOURS_PER_DAY -
											1) / (DAYS_PER_WEEK * HOURS_PER_DAY);
		weather_info.temp_last_week =
			weather_info.temp_last_week * (DAYS_PER_WEEK * HOURS_PER_DAY - 1) / (DAYS_PER_WEEK * HOURS_PER_DAY);
	}
	// Average pressure and temperature per week
	weather_info.press_last_week += weather_info.pressure;
	weather_info.temp_last_week += weather_info.temperature;
	avg_day_temp = average_day_temp();
	avg_week_temp = average_week_temp();

	calc_basic(weather_info.weather_type, weather_info.sky, &grainlevel, &gsnowlevel);

	// Ice and show change by temperature
	if (!(time_info.hours % 6) && weather_info.hours_go)
	{
		if (avg_day_temp < -15)
			icelevel += 4;
		else if (avg_day_temp < -10)
			icelevel += 3;
		else if (avg_day_temp < -5)
			icelevel += 2;
		else if (avg_day_temp < -1)
			icelevel += 1;
		else if (avg_day_temp < 1)
		{
			icelevel += 0;
			gsnowlevel -= 1;
			snowdec += 1;
		}
		else if (avg_day_temp < 5)
		{
			icelevel -= 1;
			gsnowlevel -= 2;
			snowdec += 2;
		}
		else if (avg_day_temp < 10)
		{
			icelevel -= 2;
			gsnowlevel -= 3;
			snowdec += 3;
		}
		else
		{
			icelevel -= 3;
			gsnowlevel -= 4;
			snowdec += 4;
		}
	}

	weather_info.icelevel = MAX(0, MIN(100, weather_info.icelevel + icelevel));
	if (gsnowlevel < -1 && weather_info.rainlevel < 20)
		weather_info.rainlevel -= (gsnowlevel / 2);
	weather_info.snowlevel = MAX(0, MIN(120, weather_info.snowlevel + gsnowlevel));
	weather_info.rainlevel = MAX(0, MIN(80, weather_info.rainlevel + grainlevel));


	// Change some values for world
	for (i = FIRST_ROOM; i <= top_of_world; i++)
	{
		raincast = snowcast = 0;
		if (ROOM_FLAGGED(i, ROOM_NOWEATHER))
			continue;
		if (world[i]->weather.duration)
		{
			calc_basic(world[i]->weather.weather_type, world[i]->weather.sky, &raincast, &snowcast);
			snowcast -= snowdec;
		}
		else
		{
			raincast = grainlevel;
			snowcast = gsnowlevel;
		}
		if (world[i]->weather.duration <= 0)
			world[i]->weather.duration = 0;
		else
			world[i]->weather.duration--;

		world[i]->weather.icelevel = MAX(0, MIN(100, world[i]->weather.icelevel + icelevel));
		if (snowcast < -1 && world[i]->weather.rainlevel < 20)
			world[i]->weather.rainlevel -= (snowcast / 2);
		world[i]->weather.snowlevel = MAX(0, MIN(120, world[i]->weather.snowlevel + snowcast));
		world[i]->weather.rainlevel = MAX(0, MIN(80, world[i]->weather.rainlevel + raincast));
	}


	switch (time_info.month)
	{
	case 0:		// Jan
		diff = (weather_info.pressure > 985 ? -2 : 2);
		break;
	case 1:		// Feb
		diff = (weather_info.pressure > 985 ? -2 : 2);
		break;
	case 2:		// Mar
		diff = (weather_info.pressure > 985 ? -2 : 2);
		break;
	case 3:		// Apr
		diff = (weather_info.pressure > 985 ? -2 : 2);
		break;
	case 4:		// May
		diff = (weather_info.pressure > 1015 ? -2 : 2);
		break;
	case 5:		// Jun
		diff = (weather_info.pressure > 1015 ? -2 : 2);
		break;
	case 6:		// Jul
		diff = (weather_info.pressure > 1015 ? -2 : 2);
		break;
	case 7:		// Aug
		diff = (weather_info.pressure > 1015 ? -2 : 2);
		break;
	case 8:		// Sep
		diff = (weather_info.pressure > 1015 ? -2 : 2);
		break;
	case 9:		// Oct
		diff = (weather_info.pressure > 1015 ? -2 : 2);
		break;
	case 10:		// Nov
		diff = (weather_info.pressure > 985 ? -2 : 2);
		break;
	case 11:		// Dec
		diff = (weather_info.pressure > 985 ? -2 : 2);
		break;
	default:
		break;
	}

	// if ((time_info.month >= 9) && (time_info.month <= 16))
	//    diff = (weather_info.pressure > 985 ? -2 : 2);
	// else
	//    diff = (weather_info.pressure > 1015 ? -2 : 2);

	weather_info.change += (dice(1, 4) * diff + dice(2, 6) - dice(2, 6));

	weather_info.change = MIN(weather_info.change, 12);
	weather_info.change = MAX(weather_info.change, -12);

	weather_info.pressure += weather_info.change;

	weather_info.pressure = MIN(weather_info.pressure, 1040);
	weather_info.pressure = MAX(weather_info.pressure, 960);

	if (time_info.month == MONTH_MAY)
		weather_info.season = SEASON_SPRING;
	else if (time_info.month >= MONTH_JUNE && time_info.month <= MONTH_AUGUST)
		weather_info.season = SEASON_SUMMER;
	else if (time_info.month >= MONTH_SEPTEMBER && time_info.month <= MONTH_OCTOBER)
		weather_info.season = SEASON_AUTUMN;
	else if (time_info.month >= MONTH_DECEMBER || time_info.month <= MONTH_FEBRUARY)
		weather_info.season = SEASON_WINTER;


	switch (weather_info.season)
	{
	case SEASON_WINTER:
		if ((time_info.month == MONTH_MART && avg_week_temp > 5
				&& weather_info.snowlevel == 0) || (time_info.month == MONTH_APRIL && weather_info.snowlevel == 0))
			weather_info.season = SEASON_SPRING;
	case SEASON_AUTUMN:
		if (time_info.month == MONTH_NOVEMBER && (avg_week_temp < 2 || weather_info.snowlevel >= 5))
			weather_info.season = SEASON_WINTER;
	}

	sky_change = 0;
	temp_change = 0;

	switch (weather_info.sky)
	{
	case SKY_CLOUDLESS:
		if (weather_info.pressure < 990)
			sky_change = 1;
		else if (weather_info.pressure < 1010)
			if (dice(1, 4) == 1)
				sky_change = 1;
		break;
	case SKY_CLOUDY:
		if (weather_info.pressure < 970)
			sky_change = 2;
		else if (weather_info.pressure < 990)
		{
			if (dice(1, 4) == 1)
				sky_change = 2;
			else
				sky_change = 0;
		}
		else if (weather_info.pressure > 1030)
			if (dice(1, 4) == 1)
				sky_change = 3;

		break;
	case SKY_RAINING:
		if (weather_info.pressure < 970)
		{
			if (dice(1, 4) == 1)
				sky_change = 4;
			else
				sky_change = 0;
		}
		else if (weather_info.pressure > 1030)
			sky_change = 5;
		else if (weather_info.pressure > 1010)
			if (dice(1, 4) == 1)
				sky_change = 5;

		break;
	case SKY_LIGHTNING:
		if (weather_info.pressure > 1010)
			sky_change = 6;
		else if (weather_info.pressure > 990)
			if (dice(1, 4) == 1)
				sky_change = 6;

		break;
	default:
		sky_change = 0;
		weather_info.sky = SKY_CLOUDLESS;
		break;
	}

	switch (sky_change)
	{
	case 1:		// CLOUDLESS -> CLOUDY
		if (time_info.month >= MONTH_MAY && time_info.month <= MONTH_AUGUST)
		{
			if (time_info.hours >= 8 && time_info.hours <= 16)
				temp_change += number(-3, -1);
			else if (time_info.hours >= 5 && time_info.hours <= 20)
				temp_change += number(-1, 0);

		}
		else
			temp_change += number(-2, + 2);
		break;
	case 2:		// CLOUDY -> RAINING
		if (time_info.month >= MONTH_MAY && time_info.month <= MONTH_AUGUST)
			temp_change += number(-1, + 1);
		else
			temp_change += number(-2, + 2);
		break;
	case 3:		// CLOUDY -> CLOUDLESS
		if (time_info.month >= MONTH_MAY && time_info.month <= MONTH_AUGUST)
		{
			if (time_info.hours >= 7 && time_info.hours <= 19)
				temp_change += number( + 1, + 2);
			else
				temp_change += number(0, + 1);
		}
		else
			temp_change += number(-1, + 1);
		break;
	case 4:		// RAINING -> LIGHTNING
		if (time_info.month >= MONTH_MAY && time_info.month <= MONTH_AUGUST)
		{
			if (time_info.hours >= 10 && time_info.hours <= 18)
				temp_change += number( + 1, + 3);
			else
				temp_change += number(0, + 2);
		}
		else
			temp_change += number(-3, + 3);
		break;
	case 5:		// RAINING -> CLOUDY
		if (time_info.month >= MONTH_JUNE && time_info.month <= MONTH_AUGUST)
			temp_change += number(0, + 1);
		else
			temp_change += number(-1, + 1);
		break;
	case 6:		// LIGHTNING -> RAINING
		if (time_info.month >= MONTH_MAY && time_info.month <= MONTH_AUGUST)
		{
			if (time_info.hours >= 10 && time_info.hours <= 17)
				temp_change += number(-3, + 1);
			else
				temp_change += number(-1, + 2);
		}
		else
			temp_change += number( + 1, + 3);
		break;
	case 0:
	default:
		if (dice(1, 4) == 1)
			temp_change += number(-1, + 1);
		break;
	}

	temp_change += day_temp_change[time_info.hours][weather_info.sky];
	if (time_info.day >= 22)
	{
		temp = weather_info.temperature +
			   (time_info.month >= MONTH_DECEMBER ? year_temp[0].med : year_temp[time_info.month + 1].med);
		temp /= 2;
	}
	else if (time_info.day <= 8)
	{
		temp = weather_info.temperature + year_temp[time_info.month].med;
		temp /= 2;
	}
	else
		temp = weather_info.temperature;

	temp += temp_change;
	cweather_type = 0;
	*buf = '\0';
	if (weather_info.temperature - temp > 6)
	{
		strcat(buf, "Резкое похолодание.\r\n");
		SET_BIT(cweather_type, WEATHER_QUICKCOOL);
	}
	else if (weather_info.temperature - temp < -6)
	{
		strcat(buf, "Резкое потепление.\r\n");
		SET_BIT(cweather_type, WEATHER_QUICKHOT);
	}
	weather_info.temperature = MIN(year_temp[time_info.month].max, MAX(year_temp[time_info.month].min, temp));


	if (weather_info.change >= 10 || weather_info.change <= -10)
	{
		strcat(buf, "Сильный ветер.\r\n");
		SET_BIT(cweather_type, WEATHER_BIGWIND);
	}
	else if (weather_info.change >= 6 || weather_info.change <= -6)
	{
		strcat(buf, "Умеренный ветер.\r\n");
		SET_BIT(cweather_type, WEATHER_MEDIUMWIND);
	}
	else if (weather_info.change >= 2 || weather_info.change <= -2)
	{
		strcat(buf, "Слабый ветер.\r\n");
		SET_BIT(cweather_type, WEATHER_LIGHTWIND);
	}
	else if (IS_SET(weather_info.weather_type, WEATHER_BIGWIND | WEATHER_MEDIUMWIND | WEATHER_LIGHTWIND))
	{
		strcat(buf, "Ветер утих.\r\n");
		if (IS_SET(weather_info.weather_type, WEATHER_BIGWIND))
			SET_BIT(cweather_type, WEATHER_MEDIUMWIND);
		else if (IS_SET(weather_info.weather_type, WEATHER_MEDIUMWIND))
			SET_BIT(cweather_type, WEATHER_LIGHTWIND);
	}

	switch (sky_change)
	{
	case 1:		// CLOUDLESS -> CLOUDY
		strcat(buf, "Небо затянуло тучами.\r\n");
		weather_info.sky = SKY_CLOUDY;
		break;
	case 2:		// CLOUDY -> RAINING
		switch (time_info.month)
		{
		case MONTH_MAY:
		case MONTH_JUNE:
		case MONTH_JULY:
		case MONTH_AUGUST:
		case MONTH_SEPTEMBER:
			strcat(buf, "Начался дождь.\r\n");
			create_rainsnow(&cweather_type, WEATHER_LIGHTRAIN, 30, 40, 30);
			break;
		case MONTH_DECEMBER:
		case MONTH_JANUARY:
		case MONTH_FEBRUARY:
			strcat(buf, "Пошел снег.\r\n");
			create_rainsnow(&cweather_type, WEATHER_LIGHTSNOW, 30, 40, 30);
			break;
		case MONTH_OCTOBER:
		case MONTH_APRIL:
			if (IS_SET(cweather_type, WEATHER_QUICKCOOL)
					&& weather_info.temperature <= 5)
			{
				strcat(buf, "Пошел снег.\r\n");
				SET_BIT(cweather_type, WEATHER_LIGHTSNOW);
			}
			else
			{
				strcat(buf, "Начался дождь.\r\n");
				create_rainsnow(&cweather_type, WEATHER_LIGHTRAIN, 40, 60, 0);
			}
			break;
		case MONTH_NOVEMBER:
			if (avg_day_temp <= 3 || IS_SET(cweather_type, WEATHER_QUICKCOOL))
			{
				strcat(buf, "Пошел снег.\r\n");
				create_rainsnow(&cweather_type, WEATHER_LIGHTSNOW, 40, 60, 0);
			}
			else
			{
				strcat(buf, "Начался дождь.\r\n");
				create_rainsnow(&cweather_type, WEATHER_LIGHTRAIN, 40, 60, 0);
			}
			break;
		case MONTH_MART:
			if (avg_day_temp >= 3 || IS_SET(cweather_type, WEATHER_QUICKHOT))
			{
				strcat(buf, "Начался дождь.\r\n");
				create_rainsnow(&cweather_type, WEATHER_LIGHTRAIN, 80, 20, 0);
			}
			else
			{
				strcat(buf, "Пошел снег.\r\n");
				create_rainsnow(&cweather_type, WEATHER_LIGHTSNOW, 60, 30, 10);
			}
			break;
		}
		weather_info.sky = SKY_RAINING;
		break;
	case 3:		// CLOUDY -> CLOUDLESS
		strcat(buf, "Начало проясняться.\r\n");
		weather_info.sky = SKY_CLOUDLESS;
		break;
	case 4:		// RAINING -> LIGHTNING
		strcat(buf, "Налетевший ветер разогнал тучи.\r\n");
		weather_info.sky = SKY_LIGHTNING;
		break;
	case 5:		// RAINING -> CLOUDY
		if (IS_SET(weather_info.weather_type, WEATHER_LIGHTRAIN | WEATHER_MEDIUMRAIN | WEATHER_BIGRAIN))
			strcat(buf, "Дождь прекратился.\r\n");
		else if (IS_SET(weather_info.weather_type, WEATHER_LIGHTSNOW | WEATHER_MEDIUMSNOW | WEATHER_BIGSNOW))
			strcat(buf, "Снегопад прекратился.\r\n");
		else if (IS_SET(weather_info.weather_type, WEATHER_GRAD))
			strcat(buf, "Град прекратился.\r\n");
		weather_info.sky = SKY_CLOUDY;
		break;
	case 6:		// LIGHTNING -> RAINING
		switch (time_info.month)
		{
		case MONTH_MAY:
		case MONTH_JUNE:
		case MONTH_JULY:
		case MONTH_AUGUST:
		case MONTH_SEPTEMBER:
			if (IS_SET(cweather_type, WEATHER_QUICKCOOL))
			{
				strcat(buf, "Начался град.\r\n");
				SET_BIT(cweather_type, WEATHER_GRAD);
			}
			else
			{
				strcat(buf, "Полил дождь.\r\n");
				create_rainsnow(&cweather_type, WEATHER_LIGHTRAIN, 10, 40, 50);
			}
			break;
		case MONTH_DECEMBER:
		case MONTH_JANUARY:
		case MONTH_FEBRUARY:
			strcat(buf, "Повалил снег.\r\n");
			create_rainsnow(&cweather_type, WEATHER_LIGHTSNOW, 10, 40, 50);
			break;
		case MONTH_OCTOBER:
		case MONTH_APRIL:
			if (IS_SET(cweather_type, WEATHER_QUICKCOOL)
					&& weather_info.temperature <= 5)
			{
				strcat(buf, "Повалил снег.\r\n");
				create_rainsnow(&cweather_type, WEATHER_LIGHTSNOW, 40, 60, 0);
			}
			else
			{
				strcat(buf, "Начался дождь.\r\n");
				create_rainsnow(&cweather_type, WEATHER_LIGHTRAIN, 40, 60, 0);
			}
			break;
		case MONTH_NOVEMBER:
			if (avg_day_temp <= 3 || IS_SET(cweather_type, WEATHER_QUICKCOOL))
			{
				strcat(buf, "Повалил снег.\r\n");
				create_rainsnow(&cweather_type, WEATHER_LIGHTSNOW, 40, 60, 0);
			}
			else
			{
				strcat(buf, "Начался дождь.\r\n");
				create_rainsnow(&cweather_type, WEATHER_LIGHTRAIN, 40, 60, 0);
			}
			break;
		case MONTH_MART:
			if (avg_day_temp >= 3 || IS_SET(cweather_type, WEATHER_QUICKHOT))
			{
				strcat(buf, "Начался дождь.\r\n");
				create_rainsnow(&cweather_type, WEATHER_LIGHTRAIN, 80, 20, 0);
			}
			else
			{
				strcat(buf, "Пошел снег.\r\n");
				create_rainsnow(&cweather_type, WEATHER_LIGHTSNOW, 60, 30, 10);
			}
			break;
		}
		weather_info.sky = SKY_RAINING;
		break;
	case 0:
	default:
		if (IS_SET(weather_info.weather_type, WEATHER_GRAD))
		{
			strcat(buf, "Град прекратился.\r\n");
			create_rainsnow(&cweather_type, WEATHER_LIGHTRAIN, 10, 40, 50);
		}
		else if (IS_SET(weather_info.weather_type, WEATHER_BIGRAIN))
		{
			if (weather_info.change >= 5)
			{
				strcat(buf, "Дождь утих.\r\n");
				create_rainsnow(&cweather_type, WEATHER_LIGHTRAIN, 20, 80, 0);
			}
			else
				SET_BIT(cweather_type, WEATHER_BIGRAIN);
		}
		else if (IS_SET(weather_info.weather_type, WEATHER_MEDIUMRAIN))
		{
			if (weather_info.change <= -5)
			{
				strcat(buf, "Дождь усилился.\r\n");
				SET_BIT(cweather_type, WEATHER_BIGRAIN);
			}
			else if (weather_info.change >= 5)
			{
				strcat(buf, "Дождь утих.\r\n");
				SET_BIT(cweather_type, WEATHER_LIGHTRAIN);
			}
			else
				SET_BIT(cweather_type, WEATHER_MEDIUMRAIN);
		}
		else if (IS_SET(weather_info.weather_type, WEATHER_LIGHTRAIN))
		{
			if (weather_info.change <= -5)
			{
				strcat(buf, "Дождь усилился.\r\n");
				create_rainsnow(&cweather_type, WEATHER_LIGHTRAIN, 0, 70, 30);
			}
			else
				SET_BIT(cweather_type, WEATHER_LIGHTRAIN);
		}
		else if (IS_SET(weather_info.weather_type, WEATHER_BIGSNOW))
		{
			if (weather_info.change >= 5)
			{
				strcat(buf, "Снегопад утих.\r\n");
				create_rainsnow(&cweather_type, WEATHER_LIGHTSNOW, 20, 80, 0);
			}
			else
				SET_BIT(cweather_type, WEATHER_BIGSNOW);
		}
		else if (IS_SET(weather_info.weather_type, WEATHER_MEDIUMSNOW))
		{
			if (weather_info.change <= -5)
			{
				strcat(buf, "Снегопад усилился.\r\n");
				SET_BIT(cweather_type, WEATHER_BIGSNOW);
			}
			else if (weather_info.change >= 5)
			{
				strcat(buf, "Снегопад утих.\r\n");
				SET_BIT(cweather_type, WEATHER_LIGHTSNOW);
			}
			else
				SET_BIT(cweather_type, WEATHER_MEDIUMSNOW);
		}
		else if (IS_SET(weather_info.weather_type, WEATHER_LIGHTSNOW))
		{
			if (weather_info.change <= -5)
			{
				strcat(buf, "Снегопад усилился.\r\n");
				create_rainsnow(&cweather_type, WEATHER_LIGHTSNOW, 0, 70, 30);
			}
			else
				SET_BIT(cweather_type, WEATHER_LIGHTSNOW);
		}
		break;
	}

	if (*buf)
		send_to_outdoor(buf, WEATHER_CONTROL);
	weather_info.weather_type = cweather_type;
}
Example #17
0
void monster::hit_player(game *g, player &p, bool can_grab)
{
    moves -= 100;

    if (type->melee_dice == 0) // We don't attack, so just return
    {
        return;
    }
    add_effect(ME_HIT_BY_PLAYER, 3); // Make us a valid target for a few turns
    if (has_flag(MF_HIT_AND_RUN))
    {
        add_effect(ME_RUN, 4);
    }
    bool is_npc = p.is_npc();
    bool u_see = (!is_npc || g->u_see(p.posx, p.posy));
    std::string you  = (is_npc ? p.name : "you");
    std::string You  = (is_npc ? p.name : "You");
    std::string your = (is_npc ? p.name + "'s" : "your");
    std::string Your = (is_npc ? p.name + "'s" : "Your");
    body_part bphit;
    int dam = hit(g, p, bphit), cut = type->melee_cut, stab = 0;
    int side = random_side(bphit);

    //110*e^(-.3*[melee skill of monster]) = % chance to miss. *100 to track .01%'s
    //Returns ~80% at 1, drops quickly to 33% at 4, then slowly to 5% at 10 and 1% at 16
    if (rng(0, 10000) < 11000 * exp(-.3 * type->melee_skill))
    {
        if (u_see) {
            g->add_msg(_("The %s misses."), name().c_str());
        }
    }
    else
    {
        if (!g->u.uncanny_dodge())
        {
            //Reduce player's ability to dodge by monster's ability to hit
            int dodge_ii = p.dodge(g) - rng(0, type->melee_skill);
            if (dodge_ii < 0)
            {
                dodge_ii = 0;
            }

            // 100/(1+99*e^(-.6*[dodge() return modified by monster's skill])) = % chance to dodge
            // *100 to track .01%'s
            // 1% minimum, scales slowly to 16% at 5, then rapidly to 80% at 10,
            // then returns less with each additional point, reaching 99% at 16
            if (rng(0, 10000) < 10000/(1 + 99 * exp(-.6 * dodge_ii)))
            {
                if (is_npc) {
                    if(u_see) {
                        g->add_msg(_("%1$s dodges the %2$s."), p.name.c_str(), name().c_str());
                    }
                } else {
                    g->add_msg(_("You dodge the %s."), name().c_str());
                }
                p.practice(g->turn, "dodge", type->melee_skill * 2); //Better monster = more skill gained
            }

            //Successful hit with damage
            else if (dam > 0)
            {
                p.practice(g->turn, "dodge", type->melee_skill);

                if(!p.block_hit(g, this, NULL, bphit, side, dam, cut, stab) && u_see) {
                    if (is_npc) {
                        if( u_see ) {
                            g->add_msg(_("The %1$s hits %2$s's %3$s."), name().c_str(),
                                       p.name.c_str(), body_part_name(bphit, side).c_str());
                        }
                    } else {
                        g->add_msg(_("The %1$s hits your %2$s."), name().c_str(),
                                   body_part_name(bphit, side).c_str());
                    }
                }

                // Attempt defensive moves
                if (!is_npc)
                {
                    if (g->u.activity.type == ACT_RELOAD)
                    {
                        g->add_msg(_("You stop reloading."));
                    }
                    else if (g->u.activity.type == ACT_READ)
                    {
                        g->add_msg(_("You stop reading."));
                    }
                    else if (g->u.activity.type == ACT_CRAFT || g->u.activity.type == ACT_LONGCRAFT)
                    {
                        g->add_msg(_("You stop crafting."));
                        g->u.activity.type = ACT_NULL;
                    }
                }

                if (p.has_active_bionic("bio_ods"))
                {
                    if (!is_npc) {
                        g->add_msg(_("Your offensive defense system shocks it!"),
                                   p.name.c_str());
                    } else if (u_see) {
                        g->add_msg(_("%s's offensive defense system shocks it!"),
                                   p.name.c_str());
                    }
                    hurt(rng(10, 40));
                }
                if (p.encumb(bphit) == 0 &&(p.has_trait("SPINES") || p.has_trait("QUILLS")))
                {
                    int spine = rng(1, (p.has_trait("QUILLS") ? 20 : 8));
                    if (is_npc) {
                        if( u_see ) {
                            g->add_msg(_("%1$s's %2$s puncture it!"), p.name.c_str(),
                                       (g->u.has_trait("QUILLS") ? _("quills") : _("spines")));
                        }
                    } else {
                        g->add_msg(_("Your %s puncture it!"),
                                   (g->u.has_trait("QUILLS") ? _("quills") : _("spines")));
                    }
                    hurt(spine);
                }

                if (dam + cut <= 0)
                {
                    return; // Defensive technique canceled damage.
                }

                //Hallucinations don't actually hurt the player, but do produce the message
                if(is_hallucination()) {

                    //~14% chance of vanishing after hitting the player
                    if(one_in(7)) {
                      die(g);
                      return;
                    }

                } else {

                    //Hurt the player
                    dam = p.hit(g, bphit, side, dam, cut);

                    //Monster effects
                    if (dam > 0 && has_flag(MF_VENOM)) {
                        g->add_msg_if_player(&p, _("You're poisoned!"));
                        p.add_disease("poison", 30);
                    } else if (dam > 0 && has_flag(MF_BADVENOM)) {
                        g->add_msg_if_player(&p, _("You feel poison flood your body, wracking you with pain..."));
                        p.add_disease("badpoison", 40);
                    } else if (dam > 0 && has_flag(MF_PARALYZE)) {
                        g->add_msg_if_player(&p, _("You feel poison enter your body!"));
                        p.add_disease("paralyzepoison", 100, false, 1, 20, 100);
                    }

                    if (has_flag(MF_BLEED) && dam > 6 && cut > 0) {
                        g->add_msg_if_player(&p, _("You're Bleeding!"));
                        p.add_disease("bleed", 60, false, 1, 3, 120, 1, bphit, side, true);
                    }

                    //Same as monster's chance to not miss
                    if (can_grab && has_flag(MF_GRABS) &&
                        (rng(0, 10000) > 11000 * exp(-.3 * type->melee_skill)))
                    {
                        g->add_msg(_("The %s grabs you!"), name().c_str());
                        if (p.has_grab_break_tec() &&
                            dice(p.dex_cur + p.skillLevel("melee"), 12) > dice(type->melee_dice, 10))
                        {
                            g->add_msg_if_player(&p, _("You break the grab!"));
                        } else {
                            hit_player(g, p, false); //We grabed, so hit them again
                        }
                    }

                }
                // TODO: readd with counter mechanic
            }
        }
    }

    // if dam > 0
    if (is_npc)
    {
        if (p.hp_cur[hp_head] <= 0 || p.hp_cur[hp_torso] <= 0)
        {
            npc* tmp = dynamic_cast<npc*>(&p);
            tmp->die(g);
            int index = g->npc_at(p.posx, p.posy);
            if (index != -1 && index < g->active_npc.size())
            {
                g->active_npc.erase(g->active_npc.begin() + index);
            }
            plans.clear();
        }
    }

    // Adjust anger/morale of same-species monsters, if appropriate
    int anger_adjust = 0, morale_adjust = 0;
    if (type->has_anger_trigger(MTRIG_FRIEND_ATTACKED)){
        anger_adjust += 15;
    }
    if (type->has_fear_trigger(MTRIG_FRIEND_ATTACKED)){
        morale_adjust -= 15;
    }
    if (type->has_placate_trigger(MTRIG_FRIEND_ATTACKED)){
        anger_adjust -= 15;
    }

    if (anger_adjust != 0 && morale_adjust != 0)
    {
        for (int i = 0; i < g->num_zombies(); i++)
        {
            g->zombie(i).morale += morale_adjust;
            g->zombie(i).anger += anger_adjust;
        }
    }
}
Example #18
0
void Person::threadRun() {
	{
		std::unique_lock<std::mutex> lock(cout_mutex);
		++threads_ready;
		start_condition.wait(lock);
	}
	while (!areTasksDone()) {
		if (_timeLeftInShop != 0) {
			_timeLeftInShop--;
		}
		if (_currentShop) {
			bool canEnter = false;
			bool doneShopping = false;
			bool justLeft = false;
			if (_shops.size() != 0 && _shops[0]->enterShop(this)) {
				canEnter = true;
			} else if (_shops.size() == 0) {
				doneShopping = true;
			}
			{
				std::lock_guard<std::mutex> lock(cout_mutex);
				if (canEnter) {
					std::cout << *this << " makes a reservation at the " << _shops[0]->getName() << " shop." <<  std::endl;
					std::cout << *this << " leaves the " << _currentShop->getName() << " shop to apparate to the next destination." << std::endl;
					justLeft = true;
				} else if (doneShopping) {
					std::cout << *this << " is done with shopping, so he leaves the " << _currentShop->getName() << " shop." << std::endl;
					justLeft = true;
				} else if (_timeLeftInShop == 0) {
					std::cout << *this << " is bored talking to the salesperson, so he leaves the " << _currentShop->getName() << " shop without a reservation for the next shop to go for a walk." << std::endl;
					justLeft = true;
				}
			}
			if (justLeft) {
				_currentShop->leaveShop(this);
				_currentShop = nullptr;
				if (canEnter) {
					_currentShop = _shops[0];
					_shops.erase(_shops.begin());
					{
						std::lock_guard<std::mutex> lock(cout_mutex);
						std::cout << *this << " enters the " << _currentShop->getName() << " shop." <<  std::endl;
					}
				}
			}
		}

		if (!_currentShop && _shops.size() != 0 && _shops[0]->enterShop(this)) {
			_currentShop = _shops[0];
			{
				std::lock_guard<std::mutex> lock(cout_mutex);
				std::cout << *this << " makes a reservation at the " << _currentShop->getName() << " shop." <<  std::endl;
				std::cout << *this << " enters the " << _currentShop->getName() << " shop." <<  std::endl;
			}
			_shops.erase(_shops.begin());
			_timeLeftInShop = dice();
		}
		std::this_thread::sleep_for(std::chrono::milliseconds(1000));
		++_second;
	}
}
Example #19
0
void weather_change(void)
{
	int diff, change;

	if((time_info.month>=9)&&(time_info.month<=16))
		diff=(weather_info.pressure>985 ? -2 : 2);
	else
		diff=(weather_info.pressure>1015? -2 : 2);

	weather_info.change += (dice(1,4)*diff+dice(2,6)-dice(2,6));

	weather_info.change = MIN(weather_info.change,12);
	weather_info.change = MAX(weather_info.change,-12);

	weather_info.pressure += weather_info.change;

	weather_info.pressure = MIN(weather_info.pressure,1040);
	weather_info.pressure = MAX(weather_info.pressure,960);

	change = 0;

	switch(weather_info.sky){
		case SKY_CLOUDLESS :
		{
			if (weather_info.pressure<990)
				change = 1;
			else if (weather_info.pressure<1010)
				if(dice(1,4)==1)
					change = 1;
			break;
		}
		case SKY_CLOUDY :
		{
			if (weather_info.pressure<970)
				change = 2;
			else if (weather_info.pressure<990)
				if(dice(1,4)==1)
					change = 2;
				else
					change = 0;
			else if (weather_info.pressure>1030)
				if(dice(1,4)==1)
					change = 3;

			break;
		}
		case SKY_RAINING :
		{
			if (weather_info.pressure<970)
				if(dice(1,4)==1)
					change = 4;
				else
					change = 0;
			else if (weather_info.pressure>1030)
					change = 5;
			else if (weather_info.pressure>1010)
				if(dice(1,4)==1)
					change = 5;

			break;
		}
		case SKY_LIGHTNING :
		{
			if (weather_info.pressure>1010)
					change = 6;
			else if (weather_info.pressure>990)
				if(dice(1,4)==1)
					change = 6;

			break;
		}
		default : 
		{
			change = 0;
			weather_info.sky=SKY_CLOUDLESS;
			break;
		}
	}

        ChangeWeather(change);

}
Example #20
0
void make_land(void)
{
	int x,
		y,
		temp;
	FILE *fp1,
		*fp2;
	byte land1,
		land2;
	char name1[] = "land1.dat",
		name2[] = "land2.dat";

	if(!(fp1=fopen(name1,"wb")) || !(fp2=fopen(name2,"wb")))
	{
		cprintf("\nCannot open file.");
	}
	else
	{
		for(x=0;x<MAXX;x++)
		{
			for(y=0;y<MAXY;y++)
			{
				temp = dice(2,1);
				if(temp == 1)
				{
					land1.bit0 = 1;
					temp = dice(2,1);
					if(temp == 1)
						land2.bit0 = 0;
					else
						land2.bit0 = 1;
				}
				else
				{
					land1.bit0 = 0;
				}
				temp = dice(2,1);
				if(temp == 1)
				{
					land1.bit1 = 1;
					temp = dice(2,1);
					if(temp == 1)
						land2.bit1 = 0;
					else
						land2.bit1 = 1;
				}
				else
				{
					land1.bit1 = 0;
				}
				temp = dice(2,1);
				if(temp == 1)
				{
					land1.bit2 = 1;
					temp = dice(2,1);
					if(temp == 1)
						land2.bit2 = 0;
					else
						land2.bit2 = 1;
				}
				else
				{
					land1.bit2 = 0;
				}
				temp = dice(2,1);
				if(temp == 1)
				{
					land1.bit3 = 1;
					temp = dice(2,1);
					if(temp == 1)
						land2.bit3 = 0;
					else
						land2.bit3 = 1;
				}
				else
				{
					land1.bit3 = 0;
				}
				temp = dice(2,1);
				if(temp == 1)
				{
					land1.bit4 = 1;
					temp = dice(2,1);
					if(temp == 1)
						land2.bit4 = 0;
					else
						land2.bit4 = 1;
				}
				else
				{
					land1.bit4 = 0;
				}
				temp = dice(2,1);
				if(temp == 1)
				{
					land1.bit5 = 1;
					temp = dice(2,1);
					if(temp == 1)
						land2.bit5 = 0;
					else
						land2.bit5 = 1;
				}
				else
				{
					land1.bit5 = 0;
				}
				temp = dice(2,1);
				if(temp == 1)
				{
					land1.bit6 = 1;
					temp = dice(2,1);
					if(temp == 1)
						land2.bit6 = 0;
					else
						land2.bit6 = 1;
				}
				else
				{
					land1.bit6 = 0;
				}
				temp = dice(2,1);
				if(temp == 1)
				{
					land1.bit7 = 1;
					temp = dice(2,1);
					if(temp == 1)
						land2.bit7 = 0;
					else
						land2.bit7 = 1;
				}
				else
				{
					land1.bit7 = 0;
				}
				fwrite(&land1,sizeof(byte),1,fp1);
				fwrite(&land2,sizeof(byte),1,fp2);
			}
			printf(".");
		}
		fclose(fp1);
		fclose(fp2);
	}
}
Example #21
0
int dogaze(void)
{
	struct monst *mtmp;
	int looked = 0;
	char qbuf[QBUFSZ];
	int i;
	uchar adtyp = 0;

	for (i = 0; i < NATTK; i++) {
	    if (youmonst.data->mattk[i].aatyp == AT_GAZE) {
		adtyp = youmonst.data->mattk[i].adtyp;
		break;
	    }
	}
	if (adtyp != AD_CONF && adtyp != AD_FIRE) {
	    impossible("gaze attack %d?", adtyp);
	    return 0;
	}


	if (Blind) {
	    pline("You can't see anything to gaze at.");
	    return 0;
	}
	if (u.uen < 15) {
	    pline("You lack the energy to use your special gaze!");
	    return 0;
	}
	u.uen -= 15;
	iflags.botl = 1;

	for (mtmp = level->monlist; mtmp; mtmp = mtmp->nmon) {
	    if (DEADMONSTER(mtmp)) continue;
	    if (canseemon(mtmp) && couldsee(mtmp->mx, mtmp->my)) {
		looked++;
		if (Invis && !perceives(mtmp->data))
		    pline("%s seems not to notice your gaze.", Monnam(mtmp));
		else if (mtmp->minvis && !See_invisible)
		    pline("You can't see where to gaze at %s.", Monnam(mtmp));
		else if (mtmp->m_ap_type == M_AP_FURNITURE
			|| mtmp->m_ap_type == M_AP_OBJECT) {
		    looked--;
		    continue;
		} else if (flags.safe_dog && !Confusion && !Hallucination
		  && mtmp->mtame) {
		    pline("You avoid gazing at %s.", y_monnam(mtmp));
		} else {
		    if (flags.confirm && mtmp->mpeaceful && !Confusion
							&& !Hallucination) {
			sprintf(qbuf, "Really %s %s?",
			    (adtyp == AD_CONF) ? "confuse" : "attack",
			    mon_nam(mtmp));
			if (yn(qbuf) != 'y') continue;
			setmangry(mtmp);
		    }
		    if (!mtmp->mcanmove || mtmp->mstun || mtmp->msleeping ||
				    !mtmp->mcansee || !haseyes(mtmp->data)) {
			looked--;
			continue;
		    }
		    /* No reflection check for consistency with when a monster
		     * gazes at *you*--only medusa gaze gets reflected then.
		     */
		    if (adtyp == AD_CONF) {
			if (!mtmp->mconf)
			    pline("Your gaze confuses %s!", mon_nam(mtmp));
			else
			    pline("%s is getting more and more confused.",
							Monnam(mtmp));
			mtmp->mconf = 1;
		    } else if (adtyp == AD_FIRE) {
			int dmg = dice(2,6);
			pline("You attack %s with a fiery gaze!", mon_nam(mtmp));
			if (resists_fire(mtmp)) {
			    pline("The fire doesn't burn %s!", mon_nam(mtmp));
			    dmg = 0;
			}
			if ((int) u.ulevel > rn2(20))
			    destroy_mitem(mtmp, SCROLL_CLASS, AD_FIRE);
			if ((int) u.ulevel > rn2(20))
			    destroy_mitem(mtmp, POTION_CLASS, AD_FIRE);
			if ((int) u.ulevel > rn2(25))
			    destroy_mitem(mtmp, SPBOOK_CLASS, AD_FIRE);
			if (dmg && !DEADMONSTER(mtmp)) mtmp->mhp -= dmg;
			if (mtmp->mhp <= 0) killed(mtmp);
		    }
		    /* For consistency with passive() in uhitm.c, this only
		     * affects you if the monster is still alive.
		     */
		    if (!DEADMONSTER(mtmp) &&
			  (mtmp->data==&mons[PM_FLOATING_EYE]) && !mtmp->mcan) {
			if (!Free_action) {
			    pline("You are frozen by %s gaze!",
					     s_suffix(mon_nam(mtmp)));
			    nomul((u.ulevel > 6 || rn2(4)) ?
				    -dice((int)mtmp->m_lev+1,
					    (int)mtmp->data->mattk[0].damd)
				    : -200, "frozen by a monster's gaze");
			    return 1;
			} else
			    pline("You stiffen momentarily under %s gaze.",
				    s_suffix(mon_nam(mtmp)));
		    }
		    /* Technically this one shouldn't affect you at all because
		     * the Medusa gaze is an active monster attack that only
		     * works on the monster's turn, but for it to *not* have an
		     * effect would be too weird.
		     */
		    if (!DEADMONSTER(mtmp) &&
			    (mtmp->data == &mons[PM_MEDUSA]) && !mtmp->mcan) {
			pline(
			 "Gazing at the awake %s is not a very good idea.",
			    l_monnam(mtmp));
			/* as if gazing at a sleeping anything is fruitful... */
			pline("You turn to stone...");
			killer_format = KILLED_BY;
			killer = "deliberately meeting Medusa's gaze";
			done(STONING);
		    }
		}
	    }
	}
	if (!looked) pline("You gaze at no place in particular.");
	return 1;
}
Example #22
0
/*
 * Every spell that does damage comes through here.  This calculates the
 * amount of damage, adds in any modifiers, determines what the saves are,
 * tests for save and calls damage().
 *
 * -1 = dead, otherwise the amount of damage done.
 */
int mag_damage(int level, struct char_data *ch, struct char_data *victim,
		     int spellnum, int savetype)
{
  int dam = 0;

  if (victim == NULL || ch == NULL)
    return (0);

  switch (spellnum) {
    /* Mostly mages */
  case SPELL_MAGIC_MISSILE:
  case SPELL_CHILL_TOUCH:	/* chill touch also has an affect */
    if (IS_MAGIC_USER(ch))
      dam = dice(1, 8) + 1;
    else
      dam = dice(1, 6) + 1;
    break;
  case SPELL_BURNING_HANDS:
    if (IS_MAGIC_USER(ch))
      dam = dice(3, 8) + 3;
    else
      dam = dice(3, 6) + 3;
    break;
  case SPELL_SHOCKING_GRASP:
    if (IS_MAGIC_USER(ch))
      dam = dice(5, 8) + 5;
    else
      dam = dice(5, 6) + 5;
    break;
  case SPELL_LIGHTNING_BOLT:
    if (IS_MAGIC_USER(ch))
      dam = dice(7, 8) + 7;
    else
      dam = dice(7, 6) + 7;
    break;
  case SPELL_COLOR_SPRAY:
    if (IS_MAGIC_USER(ch))
      dam = dice(9, 8) + 9;
    else
      dam = dice(9, 6) + 9;
    break;
  case SPELL_FIREBALL:
    if (IS_MAGIC_USER(ch))
      dam = dice(11, 8) + 11;
    else
      dam = dice(11, 6) + 11;
    break;

    /* Mostly clerics */
  case SPELL_DISPEL_EVIL:
    dam = dice(6, 8) + 6;
    if (IS_EVIL(ch)) {
      victim = ch;
      dam = GET_HIT(ch) - 1;
    } else if (IS_GOOD(victim)) {
      act("The gods protect $N.", FALSE, ch, 0, victim, TO_CHAR);
      return (0);
    }
    break;
  case SPELL_DISPEL_GOOD:
    dam = dice(6, 8) + 6;
    if (IS_GOOD(ch)) {
      victim = ch;
      dam = GET_HIT(ch) - 1;
    } else if (IS_EVIL(victim)) {
      act("The gods protect $N.", FALSE, ch, 0, victim, TO_CHAR);
      return (0);
    }
    break;


  case SPELL_CALL_LIGHTNING:
    dam = dice(7, 8) + 7;
    break;

  case SPELL_HARM:
    dam = dice(8, 8) + 8;
    break;

  case SPELL_ENERGY_DRAIN:
    if (GET_LEVEL(victim) <= 2)
      dam = 100;
    else
      dam = dice(1, 10);
    break;

    /* Area spells */
  case SPELL_EARTHQUAKE:
    dam = dice(2, 8) + level;
    break;

  } /* switch(spellnum) */


  /* divide damage by two if victim makes his saving throw */
  if (mag_savingthrow(victim, savetype, 0))
    dam /= 2;

  /* and finally, inflict the damage */
  return (damage(ch, victim, dam, spellnum));
}
Example #23
0
/**
 * Attempts to harm a creature with a projectile.
 *
 * @param source Pointer to the creature who shot the projectile.
 * @param attack A structure describing the attack and its results.
 */
void Creature::deal_projectile_attack( Creature *source, dealt_projectile_attack &attack )
{
    const double missed_by = attack.missed_by;
    if( missed_by >= 1.0 ) {
        // Total miss
        return;
    }

    const projectile &proj = attack.proj;
    dealt_damage_instance &dealt_dam = attack.dealt_dam;
    const auto &proj_effects = proj.proj_effects;

    const bool u_see_this = g->u.sees(*this);

    const int avoid_roll = dodge_roll();
    // Do dice(10, speed) instead of dice(speed, 10) because speed could potentially be > 10000
    const int diff_roll = dice( 10, proj.speed );
    // Partial dodge, capped at [0.0, 1.0], added to missed_by
    const double dodge_rescaled = avoid_roll / static_cast<double>( diff_roll );
    const double goodhit = missed_by + std::max( 0.0, std::min( 1.0, dodge_rescaled ) ) ;

    if( goodhit >= 1.0 ) {
        // "Avoid" rather than "dodge", because it includes removing self from the line of fire
        //  rather than just Matrix-style bullet dodging
        if( source != nullptr && g->u.sees( *source ) ) {
            add_msg_player_or_npc(
                m_warning,
                _("You avoid %s projectile!"),
                _("<npcname> avoids %s projectile."),
                source->disp_name(true).c_str() );
        } else {
            add_msg_player_or_npc(
                m_warning,
                _("You avoid an incoming projectile!"),
                _("<npcname> avoids an incoming projectile.") );
        }

        attack.missed_by = 1.0; // Arbitrary value
        return;
    }

    // Bounce applies whether it does damage or not.
    if( proj.proj_effects.count( "BOUNCE" ) ) {
        add_effect( effect_bounced, 1);
    }

    body_part bp_hit;
    double hit_value = missed_by + rng_float(-0.5, 0.5);
    // Headshots considered elsewhere
    if( hit_value <= 0.4 ) {
        bp_hit = bp_torso;
    } else if (one_in(4)) {
        if( one_in(2)) {
            bp_hit = bp_leg_l;
        } else {
            bp_hit = bp_leg_r;
        }
    } else {
        if( one_in(2)) {
            bp_hit = bp_arm_l;
        } else {
            bp_hit = bp_arm_r;
        }
    }

    double damage_mult = 1.0;

    std::string message = "";
    game_message_type gmtSCTcolor = m_neutral;

    if( goodhit < 0.1 ) {
        message = _("Headshot!");
        gmtSCTcolor = m_headshot;
        damage_mult *= rng_float(2.45, 3.35);
        bp_hit = bp_head; // headshot hits the head, of course
    } else if( goodhit < 0.2 ) {
        message = _("Critical!");
        gmtSCTcolor = m_critical;
        damage_mult *= rng_float(1.75, 2.3);
    } else if( goodhit < 0.4 ) {
        message = _("Good hit!");
        gmtSCTcolor = m_good;
        damage_mult *= rng_float(1, 1.5);
    } else if( goodhit < 0.6 ) {
        damage_mult *= rng_float(0.5, 1);
    } else if( goodhit < 0.8 ) {
        message = _("Grazing hit.");
        gmtSCTcolor = m_grazing;
        damage_mult *= rng_float(0, .25);
    } else {
        damage_mult *= 0;
    }

    if( source != nullptr && !message.empty() ) {
        source->add_msg_if_player(m_good, message.c_str());
    }

    attack.missed_by = goodhit;

    // copy it, since we're mutating
    damage_instance impact = proj.impact;
    if( proj_effects.count("NOGIB") > 0 ) {
        impact.add_effect("NOGIB");
    }
    if( damage_mult > 0.0f && proj_effects.count( "NO_DAMAGE_SCALING" ) ) {
        damage_mult = 1.0f;
    }

    impact.mult_damage(damage_mult);

    dealt_dam = deal_damage(source, bp_hit, impact);
    dealt_dam.bp_hit = bp_hit;

    // Apply ammo effects to target.
    if (proj.proj_effects.count("FLAME")) {
        if (made_of( material_id( "veggy" ) ) || made_of( material_id( "cotton" ) ) ||
                made_of( material_id( "wool" ) ) || made_of( material_id( "paper" ) ) ||
                made_of( material_id( "wood" ) ) ) {
            add_effect( effect_onfire, rng(8, 20));
        } else if (made_of( material_id( "flesh" ) ) || made_of( material_id( "iflesh" ) ) ) {
            add_effect( effect_onfire, rng(5, 10));
        }
    } else if (proj.proj_effects.count("INCENDIARY") ) {
        if (made_of( material_id( "veggy" ) ) || made_of( material_id( "cotton" ) ) ||
                made_of( material_id( "wool" ) ) || made_of( material_id( "paper" ) ) ||
                made_of( material_id( "wood" ) ) ) {
            add_effect( effect_onfire, rng(2, 6));
        } else if ( (made_of( material_id( "flesh" ) ) || made_of( material_id( "iflesh" ) ) ) &&
                    one_in(4) ) {
            add_effect( effect_onfire, rng(1, 4));
        }
    } else if (proj.proj_effects.count("IGNITE")) {
        if (made_of( material_id( "veggy" ) ) || made_of( material_id( "cotton" ) ) ||
                made_of( material_id( "wool" ) ) || made_of( material_id( "paper" ) ) ||
                made_of( material_id( "wood" ) ) ) {
            add_effect( effect_onfire, rng(6, 6));
        } else if (made_of( material_id( "flesh" ) ) || made_of( material_id( "iflesh" ) ) ) {
            add_effect( effect_onfire, rng(10, 10));
        }
    }

    if( bp_hit == bp_head && proj_effects.count( "BLINDS_EYES" ) ) {
        // TODO: Change this to require bp_eyes
        add_env_effect( effect_blind, bp_eyes, 5, rng( 3, 10 ) );
    }

    if( proj_effects.count( "APPLY_SAP" ) ) {
        add_effect( effect_sap, dealt_dam.total_damage() );
    }

    int stun_strength = 0;
    if (proj.proj_effects.count("BEANBAG")) {
        stun_strength = 4;
    }
    if (proj.proj_effects.count("LARGE_BEANBAG")) {
        stun_strength = 16;
    }
    if( stun_strength > 0 ) {
        switch( get_size() ) {
        case MS_TINY:
            stun_strength *= 4;
            break;
        case MS_SMALL:
            stun_strength *= 2;
            break;
        case MS_MEDIUM:
        default:
            break;
        case MS_LARGE:
            stun_strength /= 2;
            break;
        case MS_HUGE:
            stun_strength /= 4;
            break;
        }
        add_effect( effect_stunned, rng(stun_strength / 2, stun_strength) );
    }

    if(u_see_this) {
        if( damage_mult == 0 ) {
            if( source != nullptr ) {
                add_msg( source->is_player() ? _("You miss!") : _("The shot misses!") );
            }
        } else if( dealt_dam.total_damage() == 0 ) {
            //~ 1$ - monster name, 2$ - character's bodypart or monster's skin/armor
            add_msg( _("The shot reflects off %1$s %2$s!"), disp_name(true).c_str(),
                     is_monster() ?
                     skin_name().c_str() :
                     body_part_name_accusative(bp_hit).c_str() );
        } else if( is_player() ) {
            //monster hits player ranged
            //~ Hit message. 1$s is bodypart name in accusative. 2$d is damage value.
            add_msg_if_player(m_bad, _( "You were hit in the %1$s for %2$d damage." ),
                              body_part_name_accusative(bp_hit).c_str(),
                              dealt_dam.total_damage());
        } else if( source != nullptr ) {
            if( source->is_player() ) {
                //player hits monster ranged
                SCT.add(posx(), posy(),
                        direction_from(0, 0, posx() - source->posx(), posy() - source->posy()),
                        get_hp_bar(dealt_dam.total_damage(), get_hp_max(), true).first,
                        m_good, message, gmtSCTcolor);

                if (get_hp() > 0) {
                    SCT.add(posx(), posy(),
                            direction_from(0, 0, posx() - source->posx(), posy() - source->posy()),
                            get_hp_bar(get_hp(), get_hp_max(), true).first, m_good,
                            //~ "hit points", used in scrolling combat text
                            _("hp"), m_neutral, "hp");
                } else {
                    SCT.removeCreatureHP();
                }

                add_msg(m_good, _("You hit %s for %d damage."),
                        disp_name().c_str(), dealt_dam.total_damage());
            } else if( u_see_this ) {
                //~ 1$ - shooter, 2$ - target
                add_msg(_("%1$s shoots %2$s."),
                        source->disp_name().c_str(), disp_name().c_str());
            }
        }
    }
    check_dead_state();
    attack.hit_critter = this;
    attack.missed_by = goodhit;
}
Example #24
0
int Creature::deal_projectile_attack(Creature *source, double missed_by,
                                     const projectile &proj, dealt_damage_instance &dealt_dam)
{
    bool u_see_this = g->u_see(this);
    body_part bp_hit;
    int side = rng(0, 1);

    // do 10,speed because speed could potentially be > 10000
    if (dodge_roll() >= dice(10, proj.speed)) {
        if (is_player())
            add_msg(_("You dodge %s projectile!"),
                       source->disp_name(true).c_str());
        else if (u_see_this)
            add_msg(_("%s dodges %s projectile."),
                       disp_name().c_str(), source->disp_name(true).c_str());
        return 0;
    }

    // Bounce applies whether it does damage or not.
    if (proj.proj_effects.count("BOUNCE")) {
        add_effect("bounced", 1);
    }

    double hit_value = missed_by + rng_float(-0.5, 0.5);
    // headshots considered elsewhere
    if (hit_value <= 0.4) {
        bp_hit = bp_torso;
    } else if (one_in(4)) {
        bp_hit = bp_legs;
    } else {
        bp_hit = bp_arms;
    }

    double monster_speed_penalty = std::max(double(get_speed()) / 80., 1.0);
    double goodhit = missed_by / monster_speed_penalty;
    double damage_mult = 1.0;

    std::string message = "";
    game_message_type gmtSCTcolor = m_neutral;

    if (goodhit <= .1) {
        message = _("Headshot!");
        source->add_msg_if_player(m_good, message.c_str());
        gmtSCTcolor = m_headshot;
        damage_mult *= rng_float(2.45, 3.35);
        bp_hit = bp_head; // headshot hits the head, of course
    } else if (goodhit <= .2) {
        message = _("Critical!");
        source->add_msg_if_player(m_good, message.c_str());
        gmtSCTcolor = m_critical;
        damage_mult *= rng_float(1.75, 2.3);
    } else if (goodhit <= .4) {
        message = _("Good hit!");
        source->add_msg_if_player(m_good, message.c_str());
        gmtSCTcolor = m_good;
        damage_mult *= rng_float(1, 1.5);
    } else if (goodhit <= .6) {
        damage_mult *= rng_float(0.5, 1);
    } else if (goodhit <= .8) {
        message = _("Grazing hit.");
        source->add_msg_if_player(m_good, message.c_str());
        gmtSCTcolor = m_grazing;
        damage_mult *= rng_float(0, .25);
    } else {
        damage_mult *= 0;
    }

    // copy it, since we're mutating
    damage_instance impact = proj.impact;
    if( item(proj.ammo->id, 0).has_flag("NOGIB") ) {
        impact.add_effect("NOGIB");
    }
    impact.mult_damage(damage_mult);

    dealt_dam = deal_damage(source, bp_hit, side, impact);
    dealt_dam.bp_hit = bp_hit;

    // Apply ammo effects to target.
    const std::string target_material = get_material();
    if (proj.proj_effects.count("FLAME")) {
        if (0 == target_material.compare("veggy") || 0 == target_material.compare("cotton") ||
            0 == target_material.compare("wool") || 0 == target_material.compare("paper") ||
            0 == target_material.compare("wood" ) ) {
            add_effect("onfire", rng(8, 20));
        } else if (0 == target_material.compare("flesh") || 0 == target_material.compare("iflesh") ) {
            add_effect("onfire", rng(5, 10));
        }
    } else if (proj.proj_effects.count("INCENDIARY") ) {
        if (0 == target_material.compare("veggy") || 0 == target_material.compare("cotton") ||
            0 == target_material.compare("wool") || 0 == target_material.compare("paper") ||
            0 == target_material.compare("wood") ) {
            add_effect("onfire", rng(2, 6));
        } else if ( (0 == target_material.compare("flesh") || 0 == target_material.compare("iflesh") ) &&
                    one_in(4) ) {
            add_effect("onfire", rng(1, 4));
        }
    } else if (proj.proj_effects.count("IGNITE")) {
        if (0 == target_material.compare("veggy") || 0 == target_material.compare("cotton") ||
            0 == target_material.compare("wool") || 0 == target_material.compare("paper") ||
            0 == target_material.compare("wood") ) {
            add_effect("onfire", rng(6, 6));
        } else if (0 == target_material.compare("flesh") || 0 == target_material.compare("iflesh") ) {
            add_effect("onfire", rng(10, 10));
        }
    }
    int stun_strength = 0;
    if (proj.proj_effects.count("BEANBAG")) {
        stun_strength = 4;
    }
    if(proj.proj_effects.count("WHIP")) {
        stun_strength = rng(4, 10);
    }
    if (proj.proj_effects.count("LARGE_BEANBAG")) {
        stun_strength = 16;
    }
    if( stun_strength > 0 ) {
        switch( get_size() ) {
            case MS_TINY:
                stun_strength *= 4;
                break;
            case MS_SMALL:
                stun_strength *= 2;
                break;
            case MS_MEDIUM:
            default:
                break;
            case MS_LARGE:
                stun_strength /= 2;
                break;
            case MS_HUGE:
                stun_strength /= 4;
                break;
        }
        add_effect( "stunned", rng(stun_strength / 2, stun_strength) );
    }

    if(u_see_this) {
        if (damage_mult == 0) {
            if(source != NULL) {
                add_msg(source->is_player() ? _("You miss!") : _("The shot misses!"));
            }
        } else if (dealt_dam.total_damage() == 0) {
            add_msg(_("The shot reflects off %s %s!"), disp_name(true).c_str(),
                       skin_name().c_str());
        } else if (source != NULL) {
            if (source->is_player()) {
                //player hits monster ranged
                nc_color color;
                std::string health_bar = "";
                get_HP_Bar(dealt_dam.total_damage(), this->get_hp_max(), color, health_bar, true);

                SCT.add(this->xpos(),
                        this->ypos(),
                        direction_from(0, 0, this->xpos() - source->xpos(), this->ypos() - source->ypos()),
                        health_bar, m_good,
                        message, gmtSCTcolor);

                if (this->get_hp() > 0) {
                    get_HP_Bar(this->get_hp(), this->get_hp_max(), color, health_bar, true);

                    SCT.add(this->xpos(),
                            this->ypos(),
                            direction_from(0, 0, this->xpos() - source->xpos(), this->ypos() - source->ypos()),
                            health_bar, m_good,
                            "hp", m_neutral,
                            "hp");
                } else {
                    SCT.removeCreatureHP();
                }

                add_msg(m_good, _("You hit the %s for %d damage."),
                           disp_name().c_str(), dealt_dam.total_damage());

            } else if(this->is_player()) {
                //monster hits player ranged
                add_msg_if_player( m_bad, _( "You were hit in the %s for %d damage." ),
                                          body_part_name( bp_hit, side ).c_str( ),
                                          dealt_dam.total_damage( ) );
            } else if( u_see_this ) {
                add_msg(_("%s shoots %s."),
                           source->disp_name().c_str(), disp_name().c_str());
            }
        }
    }

    return 0;
}
Example #25
0
void monster::melee_attack(Creature &target, bool, matec_id) {
    mod_moves(-100);
    if (type->melee_dice == 0) { // We don't attack, so just return
        return;
    }
    add_effect("hit_by_player", 3); // Make us a valid target for a few turns

    if (has_flag(MF_HIT_AND_RUN)) {
        add_effect("run", 4);
    }

    bool u_see_me = g->u_see(this);

    body_part bp_hit;
    //int highest_hit = 0;

    damage_instance damage;
    if(!is_hallucination()) {
        if (type->melee_dice > 0) {
            damage.add_damage(DT_BASH,
                    dice(type->melee_dice,type->melee_sides));
        }
        if (type->melee_cut > 0) {
            damage.add_damage(DT_CUT, type->melee_cut);
        }
    }

    dealt_damage_instance dealt_dam;
    int hitspread = target.deal_melee_attack(this, hit_roll());
    if (hitspread >= 0) {
        target.deal_melee_hit(this, hitspread, false, damage, dealt_dam);
    }
    bp_hit = dealt_dam.bp_hit;

    if (hitspread < 0) { // a miss
        // TODO: characters practice dodge when a hit misses 'em
        if (target.is_player()) {
            if (u_see_me) {
                add_msg(_("You dodge %s."), disp_name().c_str());
            } else {
                add_msg(_("You dodge an attack from an unseen source."));
            }
        } else {
            if (u_see_me) {
                add_msg(_("The %1$s dodges %2$s attack."), name().c_str(),
                            target.disp_name(true).c_str());
            }
        }
    //Hallucinations always produce messages but never actually deal damage
    } else if (is_hallucination() || dealt_dam.total_damage() > 0) {
        if (target.is_player()) {
            if (u_see_me) {
                //~ 1$s is attacker name, 2$s is bodypart name in accusative.
                add_msg(m_bad, _("The %1$s hits your %2$s."), name().c_str(),
                        body_part_name_accusative(bp_hit).c_str());
            } else {
                //~ %s is bodypart name in accusative.
                add_msg(m_bad, _("Something hits your %s."),
                        body_part_name_accusative(bp_hit).c_str());
            }
        } else {
            if (u_see_me) {
                //~ 1$s is attacker name, 2$s is target name, 3$s is bodypart name in accusative.
                add_msg(_("The %1$s hits %2$s %3$s."), name().c_str(),
                            target.disp_name(true).c_str(),
                            body_part_name_accusative(bp_hit).c_str());
            }
        }
    } else {
        if (target.is_player()) {
            if (u_see_me) {
                //~ 1$s is attacker name, 2$s is bodypart name in accusative, 3$s is armor name
                add_msg(_("The %1$s hits your %2$s, but your %3$s protects you."), name().c_str(),
                        body_part_name_accusative(bp_hit).c_str(), target.skin_name().c_str());
            } else {
                //~ 1$s is bodypart name in accusative, 2$s is armor name.
                add_msg(_("Something hits your %1$s, but your %2$s protects you."),
                        body_part_name_accusative(bp_hit).c_str(), target.skin_name().c_str());
            }
        } else {
            if (u_see_me) {
                //~ $1s is monster name, %2$s is that monster target name,
                //~ $3s is target bodypart name in accusative, 4$s is target armor name.
                add_msg(_("The %1$s hits %2$s %3$s but is stopped by %2$s %4$s."), name().c_str(),
                            target.disp_name(true).c_str(),
                            body_part_name_accusative(bp_hit).c_str(),
                            target.skin_name().c_str());
            }
        }
    }

    if (is_hallucination()) {
        if(one_in(7)) {
            die( nullptr );
        }
        return;
    }

    // Adjust anger/morale of same-species monsters, if appropriate
    int anger_adjust = 0, morale_adjust = 0;
    if (type->has_anger_trigger(MTRIG_FRIEND_ATTACKED)){
        anger_adjust += 15;
    }
    if (type->has_fear_trigger(MTRIG_FRIEND_ATTACKED)){
        morale_adjust -= 15;
    }
    if (type->has_placate_trigger(MTRIG_FRIEND_ATTACKED)){
        anger_adjust -= 15;
    }

    if (anger_adjust != 0 && morale_adjust != 0)
    {
        for (size_t i = 0; i < g->num_zombies(); i++)
        {
            g->zombie(i).morale += morale_adjust;
            g->zombie(i).anger += anger_adjust;
        }
    }
}
Example #26
0
int Creature::deal_projectile_attack(Creature *source, double missed_by,
                                     const projectile &proj, dealt_damage_instance &dealt_dam)
{
    bool u_see_this = g->u_see(this);
    body_part bp_hit;
    int side = rng(0, 1);

    // do 10,speed because speed could potentially be > 10000
    if (dodge_roll() >= dice(10, proj.speed)) {
        if (is_player())
            g->add_msg(_("You dodge %s's projectile!"),
                       skin_name().c_str());
        else if (u_see_this)
            g->add_msg(_("%s dodges %s's projectile."),
                       disp_name().c_str(), source->disp_name().c_str());
        return 0;
    }


    double hit_value = missed_by + rng_float(-0.5, 0.5);
    // headshots considered elsewhere
    if (hit_value <= 0.4) {
        bp_hit = bp_torso;
    } else if (one_in(4)) {
        bp_hit = bp_legs;
    } else {
        bp_hit = bp_arms;
    }

    double monster_speed_penalty = std::max(double(get_speed()) / 80., 1.0);
    double goodhit = missed_by / monster_speed_penalty;
    double damage_mult = 1.0;

    if (goodhit <= .1) {
        g->add_msg_if_player(source, _("Headshot!"));
        damage_mult *= rng_float(2.45, 3.35);
        bp_hit = bp_head; // headshot hits the head, of course
    } else if (goodhit <= .2) {
        g->add_msg_if_player(source, _("Critical!"));
        damage_mult *= rng_float(1.75, 2.3);
    } else if (goodhit <= .4) {
        g->add_msg_if_player(source, _("Good hit!"));
        damage_mult *= rng_float(1, 1.5);
    } else if (goodhit <= .6) {
        damage_mult *= rng_float(0.5, 1);
    } else if (goodhit <= .8) {
        g->add_msg_if_player(source, _("Grazing hit."));
        damage_mult *= rng_float(0, .25);
    } else {
        damage_mult *= 0;
    }

    // copy it, since we're mutating
    damage_instance impact = proj.impact;
    impact.mult_damage(damage_mult);

    dealt_dam = deal_damage(source, bp_hit, side, impact);
    dealt_dam.bp_hit = bp_hit;

    if(u_see_this) {
        if (damage_mult == 0) {
            if(source != NULL) {
                g->add_msg(source->is_player() ? _("You miss!") : _("The shot misses!"));
            }
        } else if (dealt_dam.total_damage() == 0) {
            g->add_msg(_("The shot reflects off the %s!"),
                       skin_name().c_str());
        } else if (source != NULL) {
            if (source->is_player()) {
                g->add_msg(_("You hit the %s for %d damage."),
                           disp_name().c_str(), dealt_dam.total_damage());
            } else if( this->is_player() && g->u.has_trait("SELFAWARE")) {
                g->add_msg_if_player( this, _( "You were hit in the %s for %d damage." ),
                                      body_part_name( bp_hit, side ).c_str( ), dealt_dam.total_damage( ) );
            } else if( u_see_this ) {
                g->add_msg(_("%s shoots %s."),
                           source->disp_name().c_str(), disp_name().c_str());
            }
        }
    }

    return 0;
}
Example #27
0
void CItem::InitStats(int iGenLevel)
{
	DWORD statType, statValue, stat2Type, stat2Value;
	int iResult;

	switch(m_sItemEffectType)
	{
	default:
		return;
	case ITEMEFFECTTYPE_ATTACK_MANASAVE:
	case ITEMEFFECTTYPE_ATTACK:
		if(m_sItemEffectType == ITEMEFFECTTYPE_ATTACK_MANASAVE)
		{
			statType = ITEMSTAT_CASTPROB;
			m_cItemColor = 5;
		}else
		{
			iResult = dice(1,10000);
			if ((iResult >= 1) && (iResult <= 299)) {
				statType = ITEMSTAT_LIGHT; 
				m_cItemColor = 2; 
			}
			else if ((iResult >= 300) && (iResult <= 999)) {
				statType = ITEMSTAT_STRONG; 
				m_cItemColor = 3;
			}
			else if ((iResult >= 1000) && (iResult <= 2499)) {
				statType = ITEMSTAT_CRITICAL;
				m_cItemColor = 5;
			}
			else if ((iResult >= 2500) && (iResult <= 4499)) {
				statType = ITEMSTAT_AGILE;
				m_cItemColor = 1;
			}
			else if ((iResult >= 4500) && (iResult <= 6499)) {
				statType = ITEMSTAT_RIGHTEOUS;
				m_cItemColor = 7;
			}
			else if ((iResult >= 6500) && (iResult <= 8099)) {
				statType = ITEMSTAT_POISONING;
				m_cItemColor = 4;
			}
			else if ((iResult >= 8100) && (iResult <= 9699)) {
				statType = ITEMSTAT_SHARP;
				m_cItemColor = 6;
			}
			else if ((iResult >= 9700) && (iResult <= 10000)) {
				statType = ITEMSTAT_ANCIENT;
				m_cItemColor = 8;
			}
		}

		iResult = dice(1, 30000);
		if ((iResult >= 1) && (iResult < 10000))           statValue = 1;  // 10000/29348 = 34%
		else if ((iResult >= 10000) && (iResult < 17400))  statValue = 2;  // 6600/29348 = 22.4%
		else if ((iResult >= 17400) && (iResult < 22400))  statValue = 3;  // 4356/29348 = 14.8%
		else if ((iResult >= 22400) && (iResult < 25400))  statValue = 4;  // 2874/29348 = 9.7%
		else if ((iResult >= 25400) && (iResult < 27400))  statValue = 5;  // 1897/29348 = 6.4%
		else if ((iResult >= 27400) && (iResult < 28400))  statValue = 6;  // 1252/29348 = 4.2%
		else if ((iResult >= 28400) && (iResult < 28900))  statValue = 7;  // 826/29348 = 2.8%
		else if ((iResult >= 28900) && (iResult < 29300))  statValue = 8;  // 545/29348 = 1.85%
		else if ((iResult >= 29300) && (iResult < 29600))  statValue = 9;  // 360/29348 = 1.2%
		else if ((iResult >= 29600) && (iResult < 29800))  statValue = 10; // 237/29348 = 0.8%
		else if ((iResult >= 29800) && (iResult < 29900))  statValue = 11; // 156/29348 = 0.5%
		else if ((iResult >= 29900) && (iResult < 29970))  statValue = 12; // 103/29348 = 0.3%
		else if ((iResult >= 29970) && (iResult <= 30000))  statValue = 13; // 68/29348 = 0.1%
		else statValue = 1; 

		switch (statType) 
		{
		case ITEMSTAT_CRITICAL: 						
			if (statValue <= 5) statValue = 5;
			break; 
		case ITEMSTAT_POISONING: 
			if (statValue <= 4) statValue = 4;
			break; 
		case ITEMSTAT_LIGHT: 
			if (statValue <= 4) statValue = 4;
			break; 
		case ITEMSTAT_STRONG: 						
			if (statValue <= 2) statValue = 2;
			break; 
		}

		if ((iGenLevel <= 2) && (statValue > 7)) statValue = 7;

		SetNibble(m_dwAttribute, 5, statType);
		SetNibble(m_dwAttribute, 4, statValue);


		if (dice(1,10000) >= 6000) {
			iResult = dice(1,10000);
			if ((iResult >= 1) && (iResult <= 4999))          stat2Type = ITEMSTAT2_HITPROB;
			else if ((iResult >= 5000) && (iResult <= 8499))  stat2Type = ITEMSTAT2_CAD;
			else if ((iResult >= 8500) && (iResult <= 9499))  stat2Type = ITEMSTAT2_GOLD;
			else if ((iResult >= 9500) && (iResult <= 10000)) stat2Type = ITEMSTAT2_EXP;

			iResult = dice(1, 30000);
			if ((iResult >= 1) && (iResult < 10000))           stat2Value = 1;  // 33.33%
			else if ((iResult >= 10000) && (iResult < 17400))  stat2Value = 2;  // 24.67%
			else if ((iResult >= 17400) && (iResult < 22400))  stat2Value = 3;  // 16.67%
			else if ((iResult >= 22400) && (iResult < 25400))  stat2Value = 4;  // 10.00%
			else if ((iResult >= 25400) && (iResult < 27100))  stat2Value = 5;  // 5.67%
			else if ((iResult >= 27100) && (iResult < 28200))  stat2Value = 6;  // 3.67%
			else if ((iResult >= 28200) && (iResult < 28900))  stat2Value = 7;  // 2.34%
			else if ((iResult >= 28900) && (iResult < 29400))  stat2Value = 8;  // 1.67%
			else if ((iResult >= 29400) && (iResult < 29720))  stat2Value = 9;  // 1.07%
			else if ((iResult >= 29720) && (iResult < 29900))  stat2Value = 10; // 0.60%
			else if ((iResult >= 29900) && (iResult < 29970))  stat2Value = 11; // 0.24%
			else if ((iResult >= 29970) && (iResult < 29994))  stat2Value = 12; // 0.08%
			else if ((iResult >= 29994) && (iResult <= 30000))  stat2Value = 13; // 0.02%
			else stat2Value = 1; 

			switch (stat2Type) 
			{
			case 2: 
				if (stat2Value <= 3) stat2Value = 3;
				break; 
			case 10: 							
				if (stat2Value > 7) stat2Value = 7; 
				break; 
			case 11: 
				stat2Value = 2;
				break; 
			case 12: 
				stat2Value = 5;
				break; 
			}

			if ((iGenLevel <= 2) && (stat2Value > 7)) stat2Value = 7;

			SetNibble(m_dwAttribute, 3, stat2Type);
			SetNibble(m_dwAttribute, 2, stat2Value);
		}
		break;

	case ITEMEFFECTTYPE_DEFENSE:
		iResult = dice(1,10000);
		if ((iResult >= 1) && (iResult <= 5999))          statType = ITEMSTAT_STRONG;
		else if ((iResult >= 6000) && (iResult <= 8999))  statType = ITEMSTAT_LIGHT;
		else if ((iResult >= 9000) && (iResult <= 9554))  statType = ITEMSTAT_MANACONV;
		else if ((iResult >= 9555) && (iResult <= 10000)) statType = ITEMSTAT_CRITICAL2;


		iResult = dice(1, 30000);
		if ((iResult >= 1) && (iResult < 10000))           statValue = 1;
		else if ((iResult >= 10000) && (iResult < 17400))  statValue = 2; 
		else if ((iResult >= 17400) && (iResult < 22400))  statValue = 3;
		else if ((iResult >= 22400) && (iResult < 25400))  statValue = 4;
		else if ((iResult >= 25400) && (iResult < 27400))  statValue = 5;
		else if ((iResult >= 27400) && (iResult < 28400))  statValue = 6;
		else if ((iResult >= 28400) && (iResult < 28900))  statValue = 7;
		else if ((iResult >= 28900) && (iResult < 29300))  statValue = 8;
		else if ((iResult >= 29300) && (iResult < 29600))  statValue = 9;
		else if ((iResult >= 29600) && (iResult < 29800))  statValue = 10;
		else if ((iResult >= 29800) && (iResult < 29900))  statValue = 11;
		else if ((iResult >= 29900) && (iResult < 29970))  statValue = 12;
		else if ((iResult >= 29970) && (iResult <= 30000))  statValue = 13;
		else statValue = 1; 

		switch (statType) 
		{
		case ITEMSTAT_LIGHT: 
			if (statValue <= 4) statValue = 4;
			break; 
		case ITEMSTAT_STRONG: 						
			if (statValue <= 2) statValue = 2;
			break; 
		case ITEMSTAT_MANACONV:
		case ITEMSTAT_CRITICAL2:
			statValue = (statValue+1) / 2;
			if (statValue < 1) statValue = 1;
			if ((iGenLevel <= 3) && (statValue > 2)) statValue = 2;
			break;
		}

		if ((iGenLevel <= 2) && (statValue > 7)) statValue = 7;

		SetNibble(m_dwAttribute, 5, statType);
		SetNibble(m_dwAttribute, 4, statValue);

		if (dice(1,10000) <= 8500) {
			iResult = dice(1,10000);
			if (iResult <= 1000)       stat2Type = ITEMSTAT2_PSNRES;	// 10
			else if (iResult <= 2200)  stat2Type = ITEMSTAT2_DEF;		// 12
			else if (iResult <= 3800)  stat2Type = ITEMSTAT2_SPREC;	// 16
			else if (iResult <= 6100)  stat2Type = ITEMSTAT2_HPREC;	// 23
			else if (iResult <= 8400)  stat2Type = ITEMSTAT2_MPREC;	// 23
			else if (iResult <= 9600)  stat2Type = ITEMSTAT2_MR;		// 12
			else if (iResult <= 9900)  stat2Type = ITEMSTAT2_PA;		// 3
			else if (iResult <= 10000) stat2Type = ITEMSTAT2_MA;		// 1

			iResult = dice(1, 30017);
			if ((iResult >= 1) && (iResult < 11800))           stat2Value = 1;
			else if ((iResult >= 11800) && (iResult < 19800))  stat2Value = 2;
			else if ((iResult >= 19800) && (iResult < 24300))  stat2Value = 3;
			else if ((iResult >= 24300) && (iResult < 27000))  stat2Value = 4;
			else if ((iResult >= 27000) && (iResult < 28500))  stat2Value = 5;
			else if ((iResult >= 28500) && (iResult < 29250))  stat2Value = 6;
			else if ((iResult >= 29250) && (iResult < 29650))  stat2Value = 7;
			else if ((iResult >= 29650) && (iResult < 29850))  stat2Value = 8;
			else if ((iResult >= 29850) && (iResult < 29950))  stat2Value = 9;
			else if ((iResult >= 29950) && (iResult < 29995))  stat2Value = 10;
			else if ((iResult >= 29995) && (iResult < 30011))  stat2Value = 11;
			else if ((iResult >= 30011) && (iResult < 30016))  stat2Value = 12;
			else if ((iResult >= 30016) && (iResult <= 30017))  stat2Value = 13;
			else stat2Value = 1;

			switch (stat2Type) 
			{
			case ITEMSTAT2_PSNRES:
			case ITEMSTAT2_DEF:
			case ITEMSTAT2_MR:
			case ITEMSTAT2_PA:
			case ITEMSTAT2_MA:
				if (stat2Value <= 3) stat2Value = 3;
				break; 
			}

			if ((iGenLevel <= 2) && (stat2Value > 7)) stat2Value = 7;

			SetNibble(m_dwAttribute, 3, stat2Type);
			SetNibble(m_dwAttribute, 2, stat2Value);
#ifdef LOG_ARMORSTATS
			wsprintf(g_cTxt, "[I] Armor Drop: %s %s+%u (%u)", 
				m_cName, itemStats2[stat2Type].desc, stat2Value * itemStats2[stat2Type].mult, stat2Value);
			PutLogList(g_cTxt);
#endif
		}
		break;

	case ITEMEFFECTTYPE_JEWELRY:
		iResult = dice(1,10000);
		if ((iResult >= 1) && (iResult <= 4999))  statType = ITEMSTAT_LIGHT;
		else if ((iResult >= 5000) && (iResult <= 7999))  statType = ITEMSTAT_MANACONV;
		else if ((iResult >= 8000) && (iResult <= 10000)) statType = ITEMSTAT_CRITICAL2;


		uint32 bonus = m_sItemEffectValue1;

		iResult = dice(1, 30000-bonus) + bonus;
		if ((iResult >= 1) && (iResult < 10000))           statValue = 1;
		else if ((iResult >= 10000) && (iResult < 17400))  statValue = 2; 
		else if ((iResult >= 17400) && (iResult < 22400))  statValue = 3;
		else if ((iResult >= 22400) && (iResult < 25400))  statValue = 4;
		else if ((iResult >= 25400) && (iResult < 27400))  statValue = 5;
		else if ((iResult >= 27400) && (iResult < 28400))  statValue = 6;
		else if ((iResult >= 28400) && (iResult < 28900))  statValue = 7;
		else if ((iResult >= 28900) && (iResult < 29300))  statValue = 8;
		else if ((iResult >= 29300) && (iResult < 29600))  statValue = 9;
		else if ((iResult >= 29600) && (iResult < 29800))  statValue = 10;
		else if ((iResult >= 29800) && (iResult < 29900))  statValue = 11;
		else if ((iResult >= 29900) && (iResult < 29970))  statValue = 12;
		else if ((iResult >= 29970) && (iResult <= 30000))  statValue = 13;
		else statValue = 1; 

		switch (statType) 
		{
		case ITEMSTAT_LIGHT: 
			if (statValue <= 4) statValue = 4;
			break; 
		case ITEMSTAT_STRONG: 						
			if (statValue <= 2) statValue = 2;
			break; 
		case ITEMSTAT_MANACONV:
		case ITEMSTAT_CRITICAL2:
			statValue = (statValue+1) / 2;
			if (statValue < 1) statValue = 1;
			if ((iGenLevel <= 3) && (statValue > 2)) statValue = 2;
			break;
		}

		if ((iGenLevel <= 2) && (statValue > 7)) statValue = 7;

		SetNibble(m_dwAttribute, 5, statType);
		SetNibble(m_dwAttribute, 4, statValue);

		if (dice(1,10000) <= 8000) {
			iResult = dice(1,13000);
			if (iResult <= 1000)       stat2Type = ITEMSTAT2_PSNRES;	// 10
			else if (iResult <= 2000)  stat2Type = ITEMSTAT2_DEF;		// 10
			else if (iResult <= 3000)  stat2Type = ITEMSTAT2_SPREC;	// 16
			else if (iResult <= 5400)  stat2Type = ITEMSTAT2_HPREC;	// 24
			else if (iResult <= 7800)  stat2Type = ITEMSTAT2_MPREC;	// 24
			else if (iResult <= 9000)  stat2Type = ITEMSTAT2_MR;		// 12
			else if (iResult <= 11000)  stat2Type = ITEMSTAT2_EXP;
			else if (iResult <= 13000)  stat2Type = ITEMSTAT2_GOLD;

			iResult = dice(1, 29980 - bonus) + bonus;
			if ((iResult >= 1) && (iResult < 15000))           stat2Value = 1; 
			else if ((iResult >= 15000) && (iResult < 22400))  stat2Value = 2; 
			else if ((iResult >= 23000) && (iResult < 26100))  stat2Value = 3; 
			else if ((iResult >= 26100) && (iResult < 27700))  stat2Value = 4;  
			else if ((iResult >= 27700) && (iResult < 28700))  stat2Value = 5; 
			else if ((iResult >= 28700) && (iResult < 29200))  stat2Value = 6;  
			else if ((iResult >= 29200) && (iResult < 29450))  stat2Value = 7;  
			else if ((iResult >= 29450) && (iResult < 29649))  stat2Value = 8; 
			else if ((iResult >= 29649) && (iResult < 29793))  stat2Value = 9; 
			else if ((iResult >= 29793) && (iResult < 29888))  stat2Value = 10;
			else if ((iResult >= 29888) && (iResult < 29935))  stat2Value = 11; 
			else if ((iResult >= 29935) && (iResult < 29967))  stat2Value = 12;
			else if ((iResult >= 29967) && (iResult <= 29980))  stat2Value = 13;
			else stat2Value = 1;

			switch (stat2Type) 
			{
			case ITEMSTAT2_PSNRES:
			case ITEMSTAT2_DEF:
			case ITEMSTAT2_MR:
				if (stat2Value <= 3) stat2Value = 3;
				break; 
			}

			if (iGenLevel <= 2 && stat2Value > 7) stat2Value = 7;

			SetNibble(m_dwAttribute, 3, stat2Type);
			SetNibble(m_dwAttribute, 2, stat2Value);
		}
		break;
	}

	AdjustByStat();
}
Example #28
0
void monster::hit_player(game *g, player &p, bool can_grab)
{
    moves -= 100;

    if (type->melee_dice == 0) // We don't attack, so just return
    {
        return;
    }
    add_effect(ME_HIT_BY_PLAYER, 3); // Make us a valid target for a few turns
    if (has_flag(MF_HIT_AND_RUN))
    {
        add_effect(ME_RUN, 4);
    }
    bool is_npc = p.is_npc();
    bool u_see = (!is_npc || g->u_see(p.posx, p.posy));
    std::string you  = (is_npc ? p.name : "you");
    std::string You  = (is_npc ? p.name : "You");
    std::string your = (is_npc ? p.name + "'s" : "your");
    std::string Your = (is_npc ? p.name + "'s" : "Your");
    body_part bphit;
    int side = rng(0, 1);
    int dam = hit(g, p, bphit), cut = type->melee_cut, stab = 0;
    technique_id tech = p.pick_defensive_technique(g, this, NULL);
    p.perform_defensive_technique(tech, g, this, NULL, bphit, side, dam, cut, stab);

    //110*e^(-.3*[melee skill of monster]) = % chance to miss. *100 to track .01%'s
    //Returns ~80% at 1, drops quickly to 33% at 4, then slowly to 5% at 10 and 1% at 16
    if (rng(0, 10000) < 11000 * exp(-.3 * type->melee_skill))
    {
        g->add_msg("The %s misses.", name().c_str());
    }
    else
    {
        if (!g->u.uncanny_dodge())
        {
            //Reduce player's ability to dodge by monster's ability to hit
            int dodge_ii = p.dodge(g) - rng(0, type->melee_skill);
            if (dodge_ii < 0)
            {
                dodge_ii = 0;
            }

            // 100/(1+99*e^(-.6*[dodge() return modified by monster's skill])) = % chance to dodge
            // *100 to track .01%'s
            // 1% minimum, scales slowly to 16% at 5, then rapidly to 80% at 10,
            // then returns less with each additional point, reaching 99% at 16
            if (rng(0, 10000) < 10000/(1 + 99 * exp(-.6 * dodge_ii)))
            {
                g->add_msg("%s dodge the %s.", You.c_str(), name().c_str());
                p.practice(g->turn, "dodge", type->melee_skill * 2); //Better monster = more skill gained
            }

            //Successful hit with damage
            else if (dam > 0)
            {
                p.practice(g->turn, "dodge", type->melee_skill);
                if (u_see && tech != TEC_BLOCK)
                {
                    g->add_msg("The %s hits %s %s.", name().c_str(), your.c_str(),
                            body_part_name(bphit, side).c_str());
                }

                // Attempt defensive moves
                if (!is_npc)
                {
                    if (g->u.activity.type == ACT_RELOAD)
                    {
                        g->add_msg("You stop reloading.");
                    }
                    else if (g->u.activity.type == ACT_READ)
                    {
                        g->add_msg("You stop reading.");
                    }
                    else if (g->u.activity.type == ACT_CRAFT || g->u.activity.type == ACT_LONGCRAFT)
                    {
                        g->add_msg("You stop crafting.");
                        g->u.activity.type = ACT_NULL;
                    }
                }

                if (p.has_active_bionic("bio_ods"))
                {
                    if (u_see)
                    {
                        g->add_msg("%s offensive defense system shocks it!", Your.c_str());
                    }
                    if (hurt(rng(10, 40)))
                        die(g);
                }
                if (p.encumb(bphit) == 0 &&(p.has_trait(PF_SPINES) || p.has_trait(PF_QUILLS)))
                {
                    int spine = rng(1, (p.has_trait(PF_QUILLS) ? 20 : 8));
                    g->add_msg("%s %s puncture it!", Your.c_str(),
                            (g->u.has_trait(PF_QUILLS) ? "quills" : "spines"));
                    if (hurt(spine))
                        die(g);
                }

                if (dam + cut <= 0)
                {
                    return; // Defensive technique canceled damage.
                }

                //Hurt the player
                dam = p.hit(g, bphit, side, dam, cut);

                //Monster effects
                if (dam > 0 && has_flag(MF_VENOM))
                {
                    if (!is_npc)
                    {
                        g->add_msg("You're poisoned!");
                    }
                    p.add_disease("poison", 30);
                }
                else if (dam > 0 && has_flag(MF_BADVENOM))
                {
                    if (!is_npc)
                    {
                        g->add_msg("You feel poison flood your body, wracking you with pain...");
                    }
                    p.add_disease("badpoison", 40);
                }
                if (has_flag(MF_BLEED) && dam > 6 && cut > 0)
                {
                    if (!is_npc)
                    {
                        g->add_msg("You're Bleeding!");
                    }
                    p.add_disease("bleed", 60);
                }

                //Same as monster's chance to not miss
                if (can_grab && has_flag(MF_GRABS) && (rng(0, 10000) > 11000 * exp(-.3 * type->melee_skill)))
                {
                    if (!is_npc)
                    {
                        g->add_msg("The %s grabs you!", name().c_str());
                    }
                    if (p.weapon.has_technique(TEC_BREAK, &p) &&
                        dice(p.dex_cur + p.skillLevel("melee"), 12) > dice(type->melee_dice, 10))
                    {
                        if (!is_npc)
                        {
                            g->add_msg("You break the grab!");
                        }
                    }
                    else
                        hit_player(g, p, false); //We grabed, so hit them again
                }
                //Counter-attack?
                if (tech == TEC_COUNTER && !is_npc)
                {
                    // A counterattack is a free action to avoid stunlocking the player.
                    int player_moves = p.moves;
                    hurt( p.hit_mon(g, this) );
                    p.moves = player_moves;
                }
            }
        }
    }

    // if dam > 0
    if (is_npc)
    {
        if (p.hp_cur[hp_head] <= 0 || p.hp_cur[hp_torso] <= 0)
        {
            npc* tmp = dynamic_cast<npc*>(&p);
            tmp->die(g);
            int index = g->npc_at(p.posx, p.posy);
            if (index != -1 && index < g->active_npc.size())
            {
                g->active_npc.erase(g->active_npc.begin() + index);
            }
            plans.clear();
        }
    }

    // Adjust anger/morale of same-species monsters, if appropriate
    int anger_adjust = 0, morale_adjust = 0;
    for (int i = 0; i < type->anger.size(); i++)
    {
        if (type->anger[i] == MTRIG_FRIEND_ATTACKED)
        {
            anger_adjust += 15;
        }
    }
    for (int i = 0; i < type->placate.size(); i++)
    {
        if (type->placate[i] == MTRIG_FRIEND_ATTACKED)
        {
            anger_adjust -= 15;
        }
    }
    for (int i = 0; i < type->fear.size(); i++)
    {
        if (type->fear[i] == MTRIG_FRIEND_ATTACKED)
        {
            morale_adjust -= 15;
        }
    }
    if (anger_adjust != 0 && morale_adjust != 0)
    {
        for (int i = 0; i < g->z.size(); i++)
        {
            g->z[i].morale += morale_adjust;
            g->z[i].anger += anger_adjust;
        }
    }
}
Example #29
0
int Creature::deal_melee_attack(Creature *source, int hitroll, bool critical_hit,
                                const damage_instance &dam, dealt_damage_instance &dealt_dam)
{
    int dodgeroll = dodge_roll();
    int hit_spread = hitroll - dodgeroll;
    bool missed = hit_spread <= 0;

    damage_instance d = dam; // copy, since we will mutate in block_hit

    if (missed) {
        return hit_spread;
    }

    //bool critical_hit = hit_spread > 30; //scored_crit(dodgeroll);

    body_part bp_hit;
    int side = rng(0, 1);
    int hit_value = hit_spread + dice(10, 6) - 35;
    if (hit_value >= 40) {
        bp_hit = bp_eyes;
    } else if (hit_value >= 30) {
        bp_hit = bp_head;
    } else if (hit_value >= 5) {
        bp_hit = bp_torso;
    } else if (one_in(4)) {
        bp_hit = bp_legs;
    } else {
        bp_hit = bp_arms;
    }

    // Bashing crit
    if (critical_hit) {
        int turns_stunned = (d.type_damage(DT_BASH) + hit_spread) / 20;
        if (turns_stunned > 6) {
            turns_stunned = 6;
        }
        if (turns_stunned > 0) {
            add_effect("stunned", turns_stunned);
        }
    }

    // Stabbing effects
    int stab_moves = rng(d.type_damage(DT_STAB) / 2, d.type_damage(DT_STAB) * 1.5);
    if (critical_hit) {
        stab_moves *= 1.5;
    }
    if (stab_moves >= 150) {
        if (is_player()) {
            // can the player force their self to the ground? probably not.
            g->add_msg_if_npc(source, _("<npcname> forces you to the ground!"));
        } else {
            g->add_msg_player_or_npc(source, _("You force %s to the ground!"),
                                     _("<npcname> forces %s to the ground!"),
                                     disp_name().c_str() );
        }
        add_effect("downed", 1);
        mod_moves(-stab_moves / 2);
    } else {
        mod_moves(-stab_moves);
    }
    block_hit(bp_hit, side, d);

    on_gethit(source, bp_hit, d); // trigger on-gethit events
    dealt_dam = deal_damage(source, bp_hit, side, d);
    dealt_dam.bp_hit = bp_hit;

    /* TODO: add grabs n shit back in
    if (allow_special && technique.grabs) {
        // TODO: make this depend on skill (through grab_resist stat) again
        if (t.get_grab_resist() > 0 &&
                dice(t.get_dex() , 12) >
                dice(get_dex(), 10)) {
            g->add_msg_player_or_npc(&t, _("You break the grab!"),
                                        _("<npcname> breaks the grab!"));
        } else if (!unarmed_attack()) {
            // Move our weapon to a temp slot, if it's not unarmed
            item tmpweap = remove_weapon();
            melee_attack(t, false); // False means a second grab isn't allowed
            weapon = tmpweap;
        } else
            melee_attack(t, false); // False means a second grab isn't allowed
    }
    */

    return hit_spread;
}
Example #30
0
technique_id player::pick_technique(game *g, monster *z, player *p,
                                    bool crit, bool allowgrab)
{
 if (z == NULL && p == NULL)
  return TEC_NULL;

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

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

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

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

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

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

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

 }

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

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

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

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

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

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

 if (possible.empty())
  return TEC_NULL;

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

 return possible[ rng(0, possible.size() - 1) ];
}