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 ); }
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(); }
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 ); }
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) ); }
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(); }
/** * 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(); }
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(); }
// 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; }
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; }