void addict_effect( player &u, addiction &add )
{
    const int in = std::min( 20, add.intensity );

    switch( add.type ) {
        case ADD_CIG:
            if( !one_in( 2000 - 20 * in ) ) {
                break;
            }

            u.add_msg_if_player( rng( 0, 6 ) < in ?
                                 _( "You need some nicotine." ) :
                                 _( "You could use some nicotine." ) );
            u.add_morale( MORALE_CRAVING_NICOTINE, -15, -3 * in );
            if( one_in( 800 - 50 * in ) ) {
                u.mod_fatigue( 1 );
            }
            if( u.stim > -5 * in && one_in( 400 - 20 * in ) ) {
                u.stim--;
            }
            break;

        case ADD_CAFFEINE:
            if( !one_in( 2000 - 20 * in ) ) {
                break;
            }

            u.add_msg_if_player( m_warning, _( "You want some caffeine." ) );
            u.add_morale( MORALE_CRAVING_CAFFEINE, -5, -30 );
            if( u.stim > -10 * in && rng( 0, 10 ) < in ) {
                u.stim--;
            }
            if( rng( 8, 400 ) < in ) {
                u.add_msg_if_player( m_bad, _( "Your hands start shaking... you need it bad!" ) );
                u.add_effect( effect_shakes, 20 );
            }
            break;

        case ADD_ALCOHOL:
        case ADD_DIAZEPAM: {
            static const std::string alc_1 = _( "You could use a drink. " );
            static const std::string alc_2 = _( "Your hands start shaking... you need a drink bad!" ) ;
            static const std::string dia_1 = _( "You could use some diazepam." );
            static const std::string dia_2 = _( "You're shaking... you need some diazepam!" );

            const std::string &msg_1 = add.type == ADD_ALCOHOL ? alc_1 : dia_1;
            const std::string &msg_2 = add.type == ADD_ALCOHOL ? alc_2 : dia_2;

            const auto morale_type = add.type == ADD_ALCOHOL ? MORALE_CRAVING_ALCOHOL : MORALE_CRAVING_DIAZEPAM;

            u.mod_per_bonus( -1 );
            u.mod_int_bonus( -1 );
            if( x_in_y( in, HOURS( 2 ) ) ) {
                u.mod_healthy_mod( -1, -in * 10 );
            }
            if( one_in( 20 ) && rng( 0, 20 ) < in ) {
                u.add_msg_if_player( m_warning, msg_1.c_str() );
                u.add_morale( morale_type, -35, -10 * in );
            } else if( rng( 8, 300 ) < in ) {
                u.add_msg_if_player( m_bad, msg_2.c_str() );
                u.add_morale( morale_type, -35, -10 * in );
                u.add_effect( effect_shakes, 50 );
            } else if( !u.has_effect( effect_hallu ) && rng( 10, 1600 ) < in ) {
                u.add_effect( effect_hallu, 3600 );
            }
            break;
        }

        case ADD_SLEEP:
            // No effects here--just in player::can_sleep()
            // EXCEPT!  Prolong this addiction longer than usual.
            if( one_in( 2 ) && add.sated < 0 ) {
                add.sated++;
            }
            break;

        case ADD_PKILLER:
            if( calendar::once_every( 100 - in * 4 ) && u.get_painkiller() > 20 - in ) {
                u.mod_painkiller( -1 );    // Tolerance increases!
            }
            if( u.get_painkiller() >= 35 ) { // No further effects if we're doped up.
                add.sated = 0;
                break;
            }

            u.mod_str_bonus( -1 );
            u.mod_per_bonus( -1 );
            u.mod_dex_bonus( -1 );
            if( u.get_pain() < in * 2 ) {
                u.mod_pain( 1 );
            }
            if( one_in( 1200 - 30 * in ) ) {
                u.mod_healthy_mod( -1, -in * 30 );
            }
            if( one_in( 20 ) && dice( 2, 20 ) < in ) {
                u.add_msg_if_player( m_bad, _( "Your hands start shaking... you need some painkillers." ) );
                u.add_morale( MORALE_CRAVING_OPIATE, -40, -10 * in );
                u.add_effect( effect_shakes, 20 + in * 5 );
            } else if( one_in( 20 ) && dice( 2, 30 ) < in ) {
                u.add_msg_if_player( m_bad, _( "You feel anxious.  You need your painkillers!" ) );
                u.add_morale( MORALE_CRAVING_OPIATE, -30, -10 * in );
            } else if( one_in( 50 ) && dice( 3, 50 ) < in ) {
                u.vomit();
            }
            break;

        case ADD_SPEED: {
            u.mod_int_bonus( -1 );
            u.mod_str_bonus( -1 );
            if( u.stim > -100 && x_in_y( in, 20 ) ) {
                u.stim--;
            }
            if( rng( 0, 150 ) <= in ) {
                u.mod_healthy_mod( -1, -in );
            }
            if( dice( 2, 100 ) < in ) {
                u.add_msg_if_player( m_warning, _( "You feel depressed.  Speed would help." ) );
                u.add_morale( MORALE_CRAVING_SPEED, -25, -20 * in );
            } else if( one_in( 10 ) && dice( 2, 80 ) < in ) {
                u.add_msg_if_player( m_bad, _( "Your hands start shaking... you need a pick-me-up." ) );
                u.add_morale( MORALE_CRAVING_SPEED, -25, -20 * in );
                u.add_effect( effect_shakes, in * 20 );
            } else if( one_in( 50 ) && dice( 2, 100 ) < in ) {
                u.add_msg_if_player( m_bad, _( "You stop suddenly, feeling bewildered." ) );
                u.moves -= 300;
            } else if( !u.has_effect( effect_hallu ) && one_in( 20 ) && 8 + dice( 2, 80 ) < in ) {
                u.add_effect( effect_hallu, 3600 );
            }
        }
        break;

        case ADD_COKE:
        case ADD_CRACK: {
            static const std::string coke_msg = _( "You feel like you need a bump." );
            static const std::string crack_msg = _( "You're shivering, you need some crack." );
            const std::string &cur_msg = add.type == ADD_COKE ? coke_msg : crack_msg;
            const auto morale_type = add.type == ADD_COKE ? MORALE_CRAVING_COCAINE : MORALE_CRAVING_CRACK;
            u.mod_int_bonus( -1 );
            u.mod_per_bonus( -1 );
            if( one_in( 900 - 30 * in ) ) {
                u.add_msg_if_player( m_warning, cur_msg.c_str() );
                u.add_morale( morale_type, -20, -15 * in );
            }
            if( dice( 2, 80 ) <= in ) {
                u.add_msg_if_player( m_warning, cur_msg.c_str() );
                u.add_morale( morale_type, -20, -15 * in );
                if( u.stim > -150 ) {
                    u.stim -= 3;
                }
            }
            break;
        }

        case ADD_MUTAGEN:
            if( u.has_trait( "MUT_JUNKIE" ) ) {
                if( one_in( 600 - 50 * in ) ) {
                    u.add_msg_if_player( m_warning, rng( 0,
                                                         6 ) < in ? _( "You so miss the exquisite rainbow of post-humanity." ) :
                                         _( "Your body is SOO booorrrring.  Just a little sip to liven things up?" ) );
                    u.add_morale( MORALE_CRAVING_MUTAGEN, -20, -200 );
                }
                if( u.focus_pool > 40 && one_in( 800 - 20 * in ) ) {
                    u.focus_pool -= ( in );
                    u.add_msg_if_player( m_warning,
                                         _( "You daydream what it'd be like if you were *different*.  Different is good." ) );
                }
            } else if( in > 5 || one_in( ( 500 - 15 * in ) ) ) {
                u.add_msg_if_player( m_warning, rng( 0, 6 ) < in ? _( "You haven't had any mutagen lately." ) :
                                     _( "You could use some new parts..." ) );
                u.add_morale( MORALE_CRAVING_MUTAGEN, -5, -50 );
            }
            break;
        case ADD_MARLOSS_R:
            marloss_add( u, in, _( "You daydream about luscious pink berries as big as your fist." ) );
            break;
        case ADD_MARLOSS_B:
            marloss_add( u, in, _( "You daydream about nutty cyan seeds as big as your hand." ) );
            break;
        case ADD_MARLOSS_Y:
            marloss_add( u, in, _( "You daydream about succulent, pale golden gel, sweet but light." ) );
            break;
        case ADD_NULL:
            break;
    }
}
Example #2
0
/**
 * Generate textual weather forecast for the specified radio tower.
 */
std::string weather_forecast( point const &abs_sm_pos )
{
    std::ostringstream weather_report;
    // Local conditions
    const auto cref = overmap_buffer.closest_city( tripoint( abs_sm_pos, 0 ) );
    const std::string city_name = cref ? cref.city->name : std::string( _( "middle of nowhere" ) );
    // Current time
    weather_report << string_format(
                       _("The current time is %s Eastern Standard Time.  At %s in %s, it was %s. The temperature was %s. "),
                       calendar::turn.print_time().c_str(), calendar::turn.print_time(true).c_str(),
                       city_name.c_str(),
                       weather_data(g->weather).name.c_str(), print_temperature(g->temperature).c_str()
                   );

    //weather_report << ", the dewpoint ???, and the relative humidity ???.  ";
    //weather_report << "The wind was <direction> at ? mi/km an hour.  ";
    //weather_report << "The pressure was ??? in/mm and steady/rising/falling.";

    // Regional conditions (simulated by choosing a random range containing the current conditions).
    // Adjusted for weather volatility based on how many weather changes are coming up.
    //weather_report << "Across <region>, skies ranged from <cloudiest> to <clearest>.  ";
    // TODO: Add fake reports for nearby cities

    // TODO: weather forecast
    // forecasting periods are divided into 12-hour periods, day (6-18) and night (19-5)
    // Accumulate percentages for each period of various weather statistics, and report that
    // (with fuzz) as the weather chances.
    // int weather_proportions[NUM_WEATHER_TYPES] = {0};
    double high = -100.0;
    double low = 100.0;
    const tripoint abs_ms_pos = tripoint( sm_to_ms_copy( abs_sm_pos ), 0 );
    // TODO wind direction and speed
    int last_hour = calendar::turn - ( calendar::turn % HOURS(1) );
    for(int d = 0; d < 6; d++) {
        weather_type forecast = WEATHER_NULL;
        const auto wgen = g->get_cur_weather_gen();
        for(calendar i(last_hour + 7200 * d); i < last_hour + 7200 * (d + 1); i += 600) {
            w_point w = wgen.get_weather( abs_ms_pos, i, g->get_seed() );
            forecast = std::max( forecast, wgen.get_weather_conditions( w ) );
            high = std::max(high, w.temperature);
            low = std::min(low, w.temperature);
        }
        std::string day;
        bool started_at_night;
        calendar c(last_hour + 7200 * d);
        if(d == 0 && c.is_night()) {
            day = _("Tonight");
            started_at_night = true;
        } else {
            day = _("Today");
            started_at_night = false;
        }
        if(d > 0 && ((started_at_night && !(d % 2)) || (!started_at_night && d % 2))) {
            day = string_format( pgettext( "Mon Night", "%s Night" ), c.day_of_week().c_str() );
        } else {
            day = c.day_of_week();
        }
        weather_report << string_format(
                           _("%s... %s. Highs of %s. Lows of %s. "),
                           day.c_str(), weather_data(forecast).name.c_str(),
                           print_temperature(high).c_str(), print_temperature(low).c_str()
                       );
    }
    return weather_report.str();
}
Example #3
0
void tutorial_game::per_turn()
{
    if( calendar::turn == HOURS( 12 ) ) {
        add_message( LESSON_INTRO );
        add_message( LESSON_INTRO );
    } else if( calendar::turn == HOURS( 12 ) + 3 ) {
        add_message( LESSON_INTRO );
    }

    if( g->light_level( g->u.posz() ) == 1 ) {
        if( g->u.has_amount( "flashlight", 1 ) ) {
            add_message( LESSON_DARK );
        } else {
            add_message( LESSON_DARK_NO_FLASH );
        }
    }

    if( g->u.get_pain() > 0 ) {
        add_message( LESSON_PAIN );
    }

    if( g->u.recoil >= MIN_RECOIL ) {
        add_message( LESSON_RECOIL );
    }

    if( !tutorials_seen[LESSON_BUTCHER] ) {
        for( size_t i = 0; i < g->m.i_at( g->u.posx(), g->u.posy() ).size(); i++ ) {
            if( g->m.i_at( g->u.posx(), g->u.posy() )[i].is_corpse() ) {
                add_message( LESSON_BUTCHER );
                i = g->m.i_at( g->u.posx(), g->u.posy() ).size();
            }
        }
    }

    bool showed_message = false;
    for( int x = g->u.posx() - 1; x <= g->u.posx() + 1 && !showed_message; x++ ) {
        for( int y = g->u.posy() - 1; y <= g->u.posy() + 1 && !showed_message; y++ ) {
            if( g->m.ter( x, y ) == t_door_o ) {
                add_message( LESSON_OPEN );
                showed_message = true;
            } else if( g->m.ter( x, y ) == t_door_c ) {
                add_message( LESSON_CLOSE );
                showed_message = true;
            } else if( g->m.ter( x, y ) == t_window ) {
                add_message( LESSON_SMASH );
                showed_message = true;
            } else if( g->m.furn( x, y ) == f_rack && !g->m.i_at( x, y ).empty() ) {
                add_message( LESSON_EXAMINE );
                showed_message = true;
            } else if( g->m.ter( x, y ) == t_stairs_down ) {
                add_message( LESSON_STAIRS );
                showed_message = true;
            } else if( g->m.ter( x, y ) == t_water_sh ) {
                add_message( LESSON_PICKUP_WATER );
                showed_message = true;
            }
        }
    }

    if( !g->m.i_at( g->u.posx(), g->u.posy() ).empty() ) {
        add_message( LESSON_PICKUP );
    }
}
Example #4
0
calendar::calendar(int Minute, int Hour, int Day, season_type Season, int Year)
{
    turn_number = MINUTES(Minute) + HOURS(Hour) + DAYS(Day) + Season * to_days<int>( season_length() ) + Year * to_turns<int>( year_length() );
    sync();
}
Example #5
0
//Quantity is adjusted directly as a side effect of this function
MonsterGroupResult MonsterGroupManager::GetResultFromGroup(
        std::string group_name, int *quantity, int turn )
{
    int spawn_chance = rng(1, 1000);
    MonsterGroup group = monsterGroupMap[group_name];

    //Our spawn details specify, by default, a single instance of the default monster
    MonsterGroupResult spawn_details = MonsterGroupResult(group.defaultMonster,1);
    //If the default monster is too difficult, replace this with "mon_null"
    if(turn!=-1 && (turn + 900 < MINUTES(STARTING_MINUTES) + HOURS(GetMType(group.defaultMonster)->difficulty))){
        spawn_details = MonsterGroupResult("mon_null",0);
    }

    bool monster_found = false;
    // Step through spawn definitions from the monster group until one is found or
    for (FreqDef_iter it = group.monsters.begin(); it != group.monsters.end() && !monster_found; ++it){
        // There's a lot of conditions to work through to see if this spawn definition is valid
        bool valid_entry = true;
        // I don't know what turn == -1 is checking for, but it makes monsters always valid for difficulty purposes
        valid_entry = valid_entry && (turn == -1 || (turn+900) >= (MINUTES(STARTING_MINUTES) + HOURS(GetMType(it->name)->difficulty)));
        // If we are in classic mode, require the monster type to be either CLASSIC or WILDLIFE
        if(ACTIVE_WORLD_OPTIONS["CLASSIC_ZOMBIES"]){
            valid_entry = valid_entry && (GetMType(it->name)->in_category("CLASSIC") || GetMType(it->name)->in_category("WILDLIFE"));
        }
        //Insure that the time is not before the spawn first appears or after it stops appearing
        valid_entry = valid_entry && (HOURS(it->starts) < calendar::turn.get_turn());
        valid_entry = valid_entry && (it->lasts_forever() || HOURS(it->ends) > calendar::turn.get_turn());

        std::vector<std::pair<int,int> > valid_times_of_day;
        bool season_limited = false;
        bool season_matched = false;
        //Collect the various spawn conditions, and then insure they are met appropriately
        for(std::vector<std::string>::iterator condition = it->conditions.begin(); condition != it->conditions.end(); ++condition){
            //Collect valid time of day ranges
            if( (*condition) == "DAY" || (*condition) == "NIGHT" || (*condition) == "DUSK" || (*condition) == "DAWN" ){
                int sunset = calendar::turn.sunset().get_turn();
                int sunrise = calendar::turn.sunrise().get_turn();
                if((*condition) == "DAY"){
                    valid_times_of_day.push_back( std::make_pair(sunrise,sunset) );
                } else if((*condition) == "NIGHT"){
                    valid_times_of_day.push_back( std::make_pair(sunset,sunrise) );
                } else if((*condition) == "DUSK"){
                    valid_times_of_day.push_back( std::make_pair(sunset-HOURS(1),sunset+HOURS(1)) );
                } else if((*condition) == "DAWN"){
                    valid_times_of_day.push_back( std::make_pair(sunrise-HOURS(1),sunrise+HOURS(1)) );
                }
            }

            //If we have any seasons listed, we know to limit by season, and if any season matches this season, we are good to spawn
            if( (*condition) == "SUMMER" || (*condition) == "WINTER" || (*condition) == "SPRING" || (*condition) == "AUTUMN" ){
                season_limited = true;
                if( (calendar::turn.get_season() == SUMMER && (*condition) == "SUMMER") ||
                    (calendar::turn.get_season() == WINTER && (*condition) == "WINTER") ||
                    (calendar::turn.get_season() == SPRING && (*condition) == "SPRING") ||
                    (calendar::turn.get_season() == AUTUMN && (*condition) == "AUTUMN") ){
                    season_matched = true;
                }
            }
        }

        //Make sure the current time of day is within one of the valid time ranges for this spawn
        bool is_valid_time_of_day = false;
        if(valid_times_of_day.size() < 1){
            //Then it can spawn whenever, since no times were defined
            is_valid_time_of_day = true;
        } else {
            //Otherwise, it's valid if it matches any of the times of day
            for(std::vector<std::pair<int,int> >::iterator time_pair = valid_times_of_day.begin(); time_pair != valid_times_of_day.end(); ++time_pair){
                int time_now = calendar::turn.get_turn();
                if(time_now > time_pair->first &&  time_now < time_pair->second){
                    is_valid_time_of_day = true;
                }
            }
        }
        if(!is_valid_time_of_day){
            valid_entry = false;
        }

        //If we are limited by season, make sure we matched a season
        if(season_limited && !season_matched){
            valid_entry = false;
        }

        //If the entry was valid, check to see if we actually spawn it
        if(valid_entry){
            //If the monsters frequency is greater than the spawn_chance, select this spawn rule
            if(it->frequency >= spawn_chance){
                if(it->pack_maximum > 1){
                  spawn_details = MonsterGroupResult(it->name, rng(it->pack_minimum,it->pack_maximum));
                } else {
                  spawn_details = MonsterGroupResult(it->name, 1);
                }
                //And if a quantity pointer with remaining value was passed, will modify the external value as a side effect
                //We will reduce it by the spawn rule's cost multiplier
                if(quantity){
                    *quantity -= it->cost_multiplier * spawn_details.pack_size;
                }
                monster_found = true;
            //Otherwise, subtract the frequency from spawn result for the next loop around
            }else{
                spawn_chance -= it->frequency;
            }
        }
    }

    return spawn_details;
}
Example #6
0
calendar::calendar(int Minute, int Hour, int Day, season_type Season, int Year)
{
    turn_number = MINUTES(Minute) + HOURS(Hour) + DAYS(Day) + Season * season_length() + Year * year_turns();
    sync();
}
Example #7
0
        // Disabling 3d tests for now since 3d sight casting is actually
        // different (it sees round corners more).
        if( test_3d ) {
            INFO( "using 3d casting" );
            fov_3d = true;
            test_all_transformations();
        }
        {
            INFO( "using 2d casting" );
            fov_3d = false;
            test_all_transformations();
        }
    }
};

static constexpr int midnight = HOURS( 0 );
static constexpr int midday = HOURS( 12 );

// The following characters are used in these setups:
// ' ' - empty, outdoors
// '-' - empty, indoors
// 'U' - player, outdoors
// 'u' - player, indoors
// 'L' - light, indoors
// '#' - wall
// '=' - window frame

TEST_CASE( "vision_daylight", "[shadowcasting][vision]" )
{
    vision_test_case t {
        {
Example #8
0
void player::consume_effects( const item &food )
{
    if( !food.is_comestible() ) {
        debugmsg( "called player::consume_effects with non-comestible" );
        return;
    }
    const auto &comest = *food.type->comestible;

    const int capacity = stomach_capacity();
    if( has_trait( trait_id( "THRESH_PLANT" ) ) && food.type->can_use( "PLANTBLECH" ) ) {
        // Just keep nutrition capped, to prevent vomiting
        cap_nutrition_thirst( *this, capacity, true, true );
        return;
    }
    if( ( has_trait( trait_id( "HERBIVORE" ) ) || has_trait( trait_id( "RUMINANT" ) ) ) &&
        food.has_any_flag( herbivore_blacklist ) ) {
        // No good can come of this.
        return;
    }

    // Rotten food causes health loss
    const float relative_rot = food.get_relative_rot();
    if( relative_rot > 1.0f && !has_trait( trait_id( "SAPROPHAGE" ) ) &&
        !has_trait( trait_id( "SAPROVORE" ) ) && !has_bionic( bio_digestion ) ) {
        const float rottedness = clamp( 2 * relative_rot - 2.0f, 0.1f, 1.0f );
        // ~-1 health per 1 nutrition at halfway-rotten-away, ~0 at "just got rotten"
        // But always round down
        int h_loss = -rottedness * comest.nutr;
        mod_healthy_mod( h_loss, -200 );
        add_msg( m_debug, "%d health from %0.2f%% rotten food", h_loss, rottedness );
    }

    const auto nutr = nutrition_for( food );
    mod_hunger( -nutr );
    mod_thirst( -comest.quench );
    mod_stomach_food( nutr );
    mod_stomach_water( comest.quench );
    if( comest.healthy != 0 ) {
        // Effectively no cap on health modifiers from food
        mod_healthy_mod( comest.healthy, ( comest.healthy >= 0 ) ? 200 : -200 );
    }

    if( comest.stim != 0 &&
        ( abs( stim ) < ( abs( comest.stim ) * 3 ) ||
          sgn( stim ) != sgn( comest.stim ) ) ) {
        if( comest.stim < 0 ) {
            stim = std::max( comest.stim * 3, stim + comest.stim );
        } else {
            stim = std::min( comest.stim * 3, stim + comest.stim );
        }
    }
    add_addiction( comest.add, comest.addict );
    if( addiction_craving( comest.add ) != MORALE_NULL ) {
        rem_morale( addiction_craving( comest.add ) );
    }

    // Morale is in minutes
    int morale_time = HOURS( 2 ) / MINUTES( 1 );
    if( food.has_flag( "HOT" ) && food.has_flag( "EATEN_HOT" ) ) {
        morale_time = HOURS( 3 ) / MINUTES( 1 );
        int clamped_nutr = std::max( 5, std::min( 20, nutr / 10 ) );
        add_morale( MORALE_FOOD_HOT, clamped_nutr, 20, morale_time, morale_time / 2 );
    }

    std::pair<int, int> fun = fun_for( food );
    if( fun.first < 0 ) {
        add_morale( MORALE_FOOD_BAD, fun.first, fun.second, morale_time, morale_time / 2, false,
                    food.type );
    } else if( fun.first > 0 ) {
        add_morale( MORALE_FOOD_GOOD, fun.first, fun.second, morale_time, morale_time / 2, false,
                    food.type );
    }

    const bool hibernate = has_active_mutation( trait_id( "HIBERNATE" ) );
    if( hibernate ) {
        if( ( nutr > 0 && get_hunger() < -60 ) || ( comest.quench > 0 && get_thirst() < -60 ) ) {
            //Tell the player what's going on
            add_msg_if_player( _( "You gorge yourself, preparing to hibernate." ) );
            if( one_in( 2 ) ) {
                //50% chance of the food tiring you
                mod_fatigue( nutr );
            }
        }
        if( ( nutr > 0 && get_hunger() < -200 ) || ( comest.quench > 0 && get_thirst() < -200 ) ) {
            //Hibernation should cut burn to 60/day
            add_msg_if_player( _( "You feel stocked for a day or two. Got your bed all ready and secured?" ) );
            if( one_in( 2 ) ) {
                //And another 50%, intended cumulative
                mod_fatigue( nutr );
            }
        }

        if( ( nutr > 0 && get_hunger() < -400 ) || ( comest.quench > 0 && get_thirst() < -400 ) ) {
            add_msg_if_player(
                _( "Mmm.  You can still fit some more in...but maybe you should get comfortable and sleep." ) );
            if( !one_in( 3 ) ) {
                //Third check, this one at 66%
                mod_fatigue( nutr );
            }
        }
        if( ( nutr > 0 && get_hunger() < -600 ) || ( comest.quench > 0 && get_thirst() < -600 ) ) {
            add_msg_if_player( _( "That filled a hole!  Time for bed..." ) );
            // At this point, you're done.  Schlaf gut.
            mod_fatigue( nutr );
        }
    }

    // Moved here and changed a bit - it was too complex
    // Incredibly minor stuff like this shouldn't require complexity
    if( !is_npc() && has_trait( trait_id( "SLIMESPAWNER" ) ) &&
        ( get_hunger() < capacity + 40 || get_thirst() < capacity + 40 ) ) {
        add_msg_if_player( m_mixed,
                           _( "You feel as though you're going to split open!  In a good way?" ) );
        mod_pain( 5 );
        std::vector<tripoint> valid;
        for( const tripoint &dest : g->m.points_in_radius( pos(), 1 ) ) {
            if( g->is_empty( dest ) ) {
                valid.push_back( dest );
            }
        }
        int numslime = 1;
        for( int i = 0; i < numslime && !valid.empty(); i++ ) {
            const tripoint target = random_entry_removed( valid );
            if( monster *const slime = g->summon_mon( mon_player_blob, target ) ) {
                slime->friendly = -1;
            }
        }
        mod_hunger( 40 );
        mod_thirst( 40 );
        //~slimespawns have *small voices* which may be the Nice equivalent
        //~of the Rat King's ALL CAPS invective.  Probably shared-brain telepathy.
        add_msg_if_player( m_good, _( "hey, you look like me! let's work together!" ) );
    }

    // Last thing that happens before capping hunger
    if( get_hunger() < capacity && has_trait( trait_id( "EATHEALTH" ) ) ) {
        int excess_food = capacity - get_hunger();
        add_msg_player_or_npc( _( "You feel the %s filling you out." ),
                               _( "<npcname> looks better after eating the %s." ),
                               food.tname().c_str() );
        // Guaranteed 1 HP healing, no matter what.  You're welcome.  ;-)
        if( excess_food <= 5 ) {
            healall( 1 );
        } else {
            // Straight conversion, except it's divided amongst all your body parts.
            healall( excess_food /= 5 );
        }

        // Note: We want this here to prevent "you can't finish this" messages
        set_hunger( capacity );
    }

    cap_nutrition_thirst( *this, capacity, nutr > 0, comest.quench > 0 );
}
Example #9
0
constexpr int FULL_HOURS_IN( int n )
{
    return n / HOURS( 1 );
}