Пример #1
0
inline void proc_weather_sum( const weather_type wtype, weather_sum &data,
                              const time_point &t, const time_duration &tick_size )
{
    switch( wtype ) {
        case WEATHER_DRIZZLE:
            data.rain_amount += 4 * to_turns<int>( tick_size );
            break;
        case WEATHER_RAINY:
        case WEATHER_THUNDER:
        case WEATHER_LIGHTNING:
            data.rain_amount += 8 * to_turns<int>( tick_size );
            break;
        case WEATHER_ACID_DRIZZLE:
            data.acid_amount += 4 * to_turns<int>( tick_size );
            break;
        case WEATHER_ACID_RAIN:
            data.acid_amount += 8 * to_turns<int>( tick_size );
            break;
        default:
            break;
    }

    // TODO: Change this sunlight "sampling" here into a proper interpolation
    const float tick_sunlight = calendar( to_turn<int>( t ) ).sunlight() + weather_data(
                                    wtype ).light_modifier;
    data.sunlight += std::max<float>( 0.0f, to_turns<int>( tick_size ) * tick_sunlight );
}
Пример #2
0
void sounds::process_sounds()
{
    std::vector<centroid> sound_clusters = cluster_sounds( recent_sounds );
    const int weather_vol = weather_data( g->weather ).sound_attn;
    for( const auto &this_centroid : sound_clusters ) {
        // Since monsters don't go deaf ATM we can just use the weather modified volume
        // If they later get physical effects from loud noises we'll have to change this
        // to use the unmodified volume for those effects.
        const int vol = this_centroid.volume - weather_vol;
        const tripoint source = tripoint( this_centroid.x, this_centroid.y, this_centroid.z );
        // --- Monster sound handling here ---
        // Alert all hordes
        if( vol > 20 && g->get_levz() == 0 ) {
            int sig_power = ( ( vol > 140 ) ? 140 : vol );
            // With this, volume 100 reaches 20 overmap tiles away.
            sig_power /= 5;
            const point abs_ms = g->m.getabs( source.x, source.y );
            const point abs_sm = ms_to_sm_copy( abs_ms );
            const tripoint target( abs_sm.x, abs_sm.y, source.z );
            overmap_buffer.signal_hordes( target, sig_power );
        }
        // Alert all monsters (that can hear) to the sound.
        for (int i = 0, numz = g->num_zombies(); i < numz; i++) {
            monster &critter = g->zombie(i);
            const int dist = rl_dist( source, critter.pos() );
            if( vol * 2 > dist ) {
                // Exclude monsters that certainly won't hear the sound
                critter.hear_sound( source, vol, dist );
            }
        }
    }
    recent_sounds.clear();
}
Пример #3
0
inline void proc_weather_sum( const weather_type wtype, weather_sum &data,
                              const calendar &turn, const int tick_size )
{
    switch( wtype ) {
    case WEATHER_DRIZZLE:
        data.rain_amount += 4 * tick_size;
        break;
    case WEATHER_RAINY:
    case WEATHER_THUNDER:
    case WEATHER_LIGHTNING:
        data.rain_amount += 8 * tick_size;
        break;
    case WEATHER_ACID_DRIZZLE:
        data.acid_amount += 4 * tick_size;
        break;
    case WEATHER_ACID_RAIN:
        data.acid_amount += 8 * tick_size;
        break;
    default:
        break;
    }

    // TODO: Change this calendar::sunlight "sampling" here into a proper interpolation
    const float tick_sunlight = turn.sunlight() - weather_data( wtype ).light_modifier;
    data.sunlight += std::max<float>( 0.0f, tick_size * tick_sunlight );
}
Пример #4
0
void LH_WeatherBrowserOpener::openBrowser(QString key,int flags,int value)
{
    Q_UNUSED(key);
    Q_UNUSED(flags);
    Q_UNUSED(value);
    bool ok;
    weatherData weather_data(setup_json_weather_->value(), ok);
    if( weather_data.url !="" )
        QDesktopServices::openUrl( QUrl::fromUserInput(weather_data.url) );
}
Пример #5
0
void sounds::process_sounds()
{
    std::vector<centroid> sound_clusters = cluster_sounds( recent_sounds );

    const int weather_vol = weather_data(g->weather).sound_attn;
    for( const auto &this_centroid : sound_clusters ) {
        // Since monsters don't go deaf ATM we can just use the weather modified volume
        // If they later get physical effects from loud noises we'll have to change this
        // to use the unmodified volume for those effects.
        const int vol = this_centroid.volume - weather_vol;
        const tripoint source = tripoint( this_centroid.x, this_centroid.y, this_centroid.z );
        // --- Monster sound handling here ---
        // Alert all hordes
        if( vol > 20 && g->get_levz() == 0 ) {
            int sig_power = ((vol > 140) ? 140 : vol) - 20;
            const point abs_ms = g->m.getabs( source.x, source.y );
            const point abs_sm = overmapbuffer::ms_to_sm_copy( abs_ms );
            const tripoint target( abs_sm.x, abs_sm.y, source.z );
            overmap_buffer.signal_hordes( target, sig_power );
        }
        // Alert all monsters (that can hear) to the sound.
        for (int i = 0, numz = g->num_zombies(); i < numz; i++) {
            monster &critter = g->zombie(i);
            // rl_dist() is faster than critter.has_flag() or critter.can_hear(), so we'll check it first.
            int dist = rl_dist( source, critter.pos3() );
            int vol_goodhearing = vol * 2 - dist;
            if (vol_goodhearing > 0 && critter.can_hear()) {
                const bool goodhearing = critter.has_flag(MF_GOODHEARING);
                int volume = goodhearing ? vol_goodhearing : (vol - dist);
                // Error is based on volume, louder sound = less error
                if (volume > 0) {
                    int max_error = 0;
                    if (volume < 2) {
                        max_error = 10;
                    } else if (volume < 5) {
                        max_error = 5;
                    } else if (volume < 10) {
                        max_error = 3;
                    } else if (volume < 20) {
                        max_error = 1;
                    }

                    int target_x = source.x + rng(-max_error, max_error);
                    int target_y = source.y + rng(-max_error, max_error);
                    // target_z will require some special check due to soil muffling sounds

                    int wander_turns = volume * (goodhearing ? 6 : 1);
                    critter.wander_to( tripoint( target_x, target_y, source.z ), wander_turns);
                    critter.process_trigger(MTRIG_SOUND, volume);
                }
            }
        }
    }
    recent_sounds.clear();
}
Пример #6
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;
    point const abs_ms_pos = overmapbuffer::sm_to_ms_copy( abs_sm_pos );
    // 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;
        for(calendar i(last_hour + 7200 * d); i < last_hour + 7200 * (d + 1); i += 600) {
            w_point w = g->weather_gen->get_weather( abs_ms_pos, i );
            forecast = std::max(forecast, g->weather_gen->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 = rmp_format(_("<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();
}
Пример #7
0
void sounds::process_sound_markers( player *p )
{
    bool is_deaf = p->is_deaf();
    const float volume_multiplier = p->hearing_ability();
    const int safe_volume = p->worn_with_flag("PARTIAL_DEAF") ? 100 : 9999;
    const int weather_vol = weather_data( g->weather ).sound_attn;
    for( const auto &sound_event_pair : sounds_since_last_turn ) {
        const int volume = std::min(safe_volume, (int)(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->get_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() ) {
                add_msg( _( "You hear %s" ), description.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();
}
Пример #8
0
// TODO Consider making this just clear the cache and dynamically fill it in as trans() is called
void map::build_transparency_cache( const int zlev )
{
    auto &map_cache = get_cache( zlev );
    auto &transparency_cache = map_cache.transparency_cache;
    auto &outside_cache = map_cache.outside_cache;

    if( !map_cache.transparency_cache_dirty ) {
        return;
    }

    // Default to just barely not transparent.
    std::uninitialized_fill_n(
        &transparency_cache[0][0], MAPSIZE*SEEX * MAPSIZE*SEEY, LIGHT_TRANSPARENCY_OPEN_AIR);

    // Traverse the submaps in order
    for( int smx = 0; smx < my_MAPSIZE; ++smx ) {
        for( int smy = 0; smy < my_MAPSIZE; ++smy ) {
            auto const cur_submap = get_submap_at_grid( smx, smy, zlev );

            for( int sx = 0; sx < SEEX; ++sx ) {
                for( int sy = 0; sy < SEEY; ++sy ) {
                    const int x = sx + smx * SEEX;
                    const int y = sy + smy * SEEY;

                    auto &value = transparency_cache[x][y];

                    if( !(cur_submap->ter[sx][sy].obj().transparent &&
                          cur_submap->frn[sx][sy].obj().transparent) ) {
                        value = LIGHT_TRANSPARENCY_SOLID;
                        continue;
                    }

                    if( outside_cache[x][y] ) {
                        value *= weather_data(g->weather).sight_penalty;
                    }

                    for( auto const &fld : cur_submap->fld[sx][sy] ) {
                        const field_entry &cur = fld.second;
                        const field_id type = cur.getFieldType();
                        const int density = cur.getFieldDensity();

                        if( fieldlist[type].transparent[density - 1] ) {
                            continue;
                        }

                        // Fields are either transparent or not, however we want some to be translucent
                        switch (type) {
                        case fd_cigsmoke:
                        case fd_weedsmoke:
                        case fd_cracksmoke:
                        case fd_methsmoke:
                        case fd_relax_gas:
                            value *= 5;
                            break;
                        case fd_smoke:
                        case fd_incendiary:
                        case fd_toxic_gas:
                        case fd_tear_gas:
                            if (density == 3) {
                                value = LIGHT_TRANSPARENCY_SOLID;
                            } else if (density == 2) {
                                value *= 10;
                            }
                            break;
                        case fd_nuke_gas:
                            value *= 10;
                            break;
                        case fd_fire:
                            value *= 1.0 - ( density * 0.3 );
                            break;
                        default:
                            value = LIGHT_TRANSPARENCY_SOLID;
                            break;
                        }
                        // TODO: [lightmap] Have glass reduce light as well
                    }
                }
            }
        }
    }
    map_cache.transparency_cache_dirty = false;
}
Пример #9
0
QString LH_WeatherText::getSelectedValueText()
{
    bool ok;
    weatherData weather_data(setup_json_weather_->value(), ok);


    //return QString("%1:\r\n%2%5\r\n%3 (%4)").arg(weather_data.location.city, weather_data.condition.temp, weather_data.condition.text, weather_data.condition.code, weather_data.units.temperature);
    QString selValue = valueTypes.at( setup_value_type_->value() );
    QString valueText;

    const int unit_none = 0;
    const int unit_dist = 1;
    const int unit_press = 2;
    const int unit_speed = 3;
    const int unit_temp = 4;
    const int unit_perc = 5;
    int units;

    valueText = "<not implimented>";

    if(selValue == "Location: City")                    {valueText = weather_data.location.city; units = unit_none;}
    if(selValue == "Location: Region")                  {valueText = weather_data.location.region; units = unit_none;}
    if(selValue == "Location: Country")                 {valueText = weather_data.location.country; units = unit_none;}

    if(selValue == "Current Conditions: Description")   {valueText = weather_data.condition.text; units = unit_none;}
    if(selValue == "Current Conditions: Image Code")    {valueText = weather_data.condition.code; units = unit_none;}
    if(selValue == "Current Conditions: Temperature")   {valueText = weather_data.condition.temp; units = unit_temp;}
    if(selValue == "Current Conditions: Last Updated")  {valueText = weather_data.condition.date; units = unit_none;}

    if(selValue == "Wind: Chill")                       {valueText = weather_data.wind.chill; units = unit_temp;}
    if(selValue == "Wind: Direction")                   {valueText = weather_data.wind.direction; units = unit_none;}
    if(selValue == "Wind: Speed")                       {valueText = weather_data.wind.speed; units = unit_speed;}

    if(selValue == "Atmosphere: Humidity")              {valueText = weather_data.atmosphere.humidity; units = unit_perc;}
    if(selValue == "Atmosphere: Visibility")            {valueText = weather_data.atmosphere.visibility; units = unit_dist;}
    if(selValue == "Atmosphere: Pressure")              {valueText = weather_data.atmosphere.pressure; units = unit_press;}
    if(selValue == "Atmosphere: Barometric Reading")    {valueText = weather_data.atmosphere.barometricReading; units = unit_none;}

    if(selValue == "Astronomy: Sunrise")                {valueText = weather_data.astronomy.sunrise; units = unit_none;}
    if(selValue == "Astronomy: Sunset")                 {valueText = weather_data.astronomy.sunset; units = unit_none;}

    QRegExp rx("Forecast Day ([1-5])[^:]*: (.*)");
    if(rx.indexIn(selValue) != -1)
    {
        int i = rx.cap(1).toInt()-1;
        units = unit_none;
        if(rx.cap(2) == "Day")
            valueText = weather_data.forecast[i].day;
        if(rx.cap(2) == "\"Today\"/\"Tonight\"" || rx.cap(2) == "\"Tomorrow\"")
            valueText = weather_data.forecast[i].relativeDay;
        if(rx.cap(2) == "Date")
            valueText = weather_data.forecast[i].date;
        if(rx.cap(2) == "Low") {
            valueText = weather_data.forecast[i].low;
            units = unit_temp;
        }
        if(rx.cap(2) == "High") {
            valueText = weather_data.forecast[i].high;
            units = unit_temp;
        }
        if(rx.cap(2) == "Description")
            valueText = weather_data.forecast[i].text;
        if(rx.cap(2) == "Image Code")
            valueText = weather_data.forecast[i].code;
    }

    QString resultText = QString(valueText);
    if (resultText=="") {
        resultText = " ";
    } else
        if (setup_append_units_->value())
            switch(units)
            {
            case unit_dist:
                resultText = resultText + QString(weather_data.units.distance);
                break;
            case unit_press:
                resultText = resultText + QString(weather_data.units.pressure);
                break;
            case unit_speed:
                resultText = resultText + QString(weather_data.units.speed);
                break;
            case unit_temp:
                resultText = resultText + QString(weather_data.units.temperature);
                break;
            case unit_perc:
                resultText = resultText + "%";
                break;
            }
    resultText = setup_pre_text_->value() + resultText + setup_post_text_->value();
    return resultText;
}