Skip to content

Commit

Permalink
Allow multiple body part effects for field types
Browse files Browse the repository at this point in the history
+updated json format for smoke field
  • Loading branch information
ZhilkinSerg committed Nov 22, 2019
1 parent 4b261b5 commit b518e05
Show file tree
Hide file tree
Showing 7 changed files with 176 additions and 71 deletions.
46 changes: 30 additions & 16 deletions data/json/field_type.json
Original file line number Diff line number Diff line change
Expand Up @@ -185,34 +185,48 @@
"sym": "8",
"dangerous": true,
"translucency": 1,
"effect_id": "smoke",
"effect_body_part": "MOUTH",
"effect_intensity": 1,
"effect_min_duration": "2 seconds",
"effect_max_duration": "2 seconds",
"inside_immune": true
"effects": [
{
"effect_id": "smoke",
"body_part": "MOUTH",
"intensity": 1,
"min_duration": "2 seconds",
"max_duration": "2 seconds",
"immune_inside_vehicle": true
}
]
},
{
"name": "smoke",
"color": "light_gray",
"transparent": false,
"translucency": 10,
"effect_id": "smoke",
"effect_body_part": "MOUTH",
"effect_intensity": 2,
"effect_min_duration": "7 seconds",
"effect_max_duration": "7 seconds",
"effects": [
{
"effect_id": "smoke",
"body_part": "MOUTH",
"intensity": 2,
"min_duration": "7 seconds",
"max_duration": "7 seconds",
"immune_inside_vehicle": true
}
],
"scent_neutralization": 1
},
{
"name": "thick smoke",
"color": "dark_gray",
"translucency": 0,
"effect_id": "smoke",
"effect_body_part": "MOUTH",
"effect_intensity": 4,
"effect_min_duration": "15 seconds",
"effect_max_duration": "15 seconds",
"effects": [
{
"effect_id": "smoke",
"body_part": "MOUTH",
"intensity": 4,
"min_duration": "15 seconds",
"max_duration": "15 seconds",
"immune_inside_vehicle": true
}
],
"scent_neutralization": 5
}
],
Expand Down
6 changes: 6 additions & 0 deletions src/enums.h
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,12 @@ enum game_message_type : int {
m_headshot,
m_critical,
m_grazing,
num_game_message_type
};

template<>
struct enum_traits<game_message_type> {
static constexpr game_message_type last = game_message_type::num_game_message_type;
};

enum game_message_flags {
Expand Down
15 changes: 2 additions & 13 deletions src/field.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -265,18 +265,7 @@ int field::total_move_cost() const
return current_cost;
}

effect field_entry::field_effect() const
std::vector<field_effect> field_entry::field_effects() const
{
const field_effect_data &field_effect = type->get_intensity_level( intensity - 1 ).field_effect;
const efftype_id fx_id = field_effect.id;
if( fx_id.is_empty() || fx_id.is_null() ) {
return effect();
}
return effect( &field_effect.id.obj(), rng( field_effect.min_duration, field_effect.max_duration ),
field_effect.bp, false, field_effect.intensity, calendar::turn );
}

bool field_entry::inside_immune() const
{
return type->get_intensity_level( intensity - 1 ).field_effect.inside_immune;
return type->get_intensity_level( intensity - 1 ).field_effects;
}
3 changes: 1 addition & 2 deletions src/field.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,7 @@ class field_entry
return type.obj().accelerated_decay;
}

effect field_effect() const;
bool inside_immune() const;
std::vector<field_effect> field_effects() const;

private:
// The field identifier.
Expand Down
69 changes: 55 additions & 14 deletions src/field_type.cpp
Original file line number Diff line number Diff line change
@@ -1,14 +1,40 @@
#include "field_type.h"

#include <set>

#include "bodypart.h"
#include "debug.h"
#include "enums.h"
#include "generic_factory.h"
#include "json.h"
#include "int_id.h"

namespace io
{

template<>
std::string enum_to_string<game_message_type>( game_message_type data )
{
switch( data ) {
// *INDENT-OFF*
case game_message_type::m_good: return "good";
case game_message_type::m_bad: return "bad";
case game_message_type::m_mixed: return "mixed";
case game_message_type::m_warning: return "warning";
case game_message_type::m_info: return "info";
case game_message_type::m_neutral: return "neutral";
case game_message_type::m_debug: return "debug";
case game_message_type::m_headshot: return "headshot";
case game_message_type::m_critical: return "critical";
case game_message_type::m_grazing: return "grazing";
// *INDENT-ON*
case game_message_type::num_game_message_type:
break;
}
debugmsg( "Invalid side" );
abort();
}

} // namespace io

namespace
{

Expand Down Expand Up @@ -124,18 +150,33 @@ void field_type::load( JsonObject &jo, const std::string & )
fallback_intensity_level.translucency );
optional( jao, was_loaded, "convection_temperature_mod", intensity_level.convection_temperature_mod,
fallback_intensity_level.convection_temperature_mod );
optional( jao, was_loaded, "effect_id", intensity_level.field_effect.id,
fallback_intensity_level.field_effect.id );
optional( jao, was_loaded, "effect_min_duration", intensity_level.field_effect.min_duration,
fallback_intensity_level.field_effect.min_duration );
optional( jao, was_loaded, "effect_max_duration", intensity_level.field_effect.max_duration,
fallback_intensity_level.field_effect.max_duration );
optional( jao, was_loaded, "effect_intensity", intensity_level.field_effect.intensity,
fallback_intensity_level.field_effect.intensity );
optional( jao, was_loaded, "effect_body_part", intensity_level.field_effect.bp,
fallback_intensity_level.field_effect.bp );
optional( jao, was_loaded, "inside_immune", intensity_level.field_effect.inside_immune,
fallback_intensity_level.field_effect.inside_immune );
if( jao.has_array( "effects" ) ) {
JsonArray jae = jao.get_array( "effects" );
for( size_t j = 0; j < jae.size(); ++j ) {
JsonObject joe = jae.next_object();
field_effect fe;
mandatory( joe, was_loaded, "effect_id", fe.id );
optional( joe, was_loaded, "min_duration", fe.min_duration );
optional( joe, was_loaded, "max_duration", fe.max_duration );
optional( joe, was_loaded, "intensity", fe.intensity );
optional( joe, was_loaded, "body_part", fe.bp );
optional( joe, was_loaded, "is_environmental", fe.is_environmental );
optional( joe, was_loaded, "immune_in_vehicle", fe.immune_in_vehicle );
optional( joe, was_loaded, "immune_inside_vehicle", fe.immune_inside_vehicle );
optional( joe, was_loaded, "immune_outside_vehicle", fe.immune_outside_vehicle );
optional( joe, was_loaded, "chance_in_vehicle", fe.chance_in_vehicle );
optional( joe, was_loaded, "chance_inside_vehicle", fe.chance_inside_vehicle );
optional( joe, was_loaded, "chance_outside_vehicle", fe.chance_outside_vehicle );
optional( joe, was_loaded, "message", fe.message );
optional( joe, was_loaded, "message_npc", fe.message_npc );
const auto game_message_type_reader = enum_flags_reader<game_message_type> { "game message types" };
optional( jo, was_loaded, "message_type", fe.env_message_type, game_message_type_reader );
intensity_level.field_effects.emplace_back( fe );
}
} else {
// Use effects from previous intensity level
intensity_level.field_effects = fallback_intensity_level.field_effects;
}
optional( jao, was_loaded, "scent_neutralization", intensity_level.scent_neutralization,
fallback_intensity_level.scent_neutralization );
intensity_levels.emplace_back( intensity_level );
Expand Down
36 changes: 29 additions & 7 deletions src/field_type.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "calendar.h"
#include "catacharset.h"
#include "color.h"
#include "effect.h"
#include "enums.h"
#include "type_id.h"
#include "string_id.h"
Expand All @@ -23,13 +24,34 @@ class JsonObject;
enum phase_id : int;
enum body_part : int;

struct field_effect_data {
struct field_effect {
efftype_id id;
time_duration min_duration;
time_duration max_duration;
int intensity;
body_part bp;
bool inside_immune;
time_duration min_duration = 0_seconds;
time_duration max_duration = 0_seconds;
int intensity = 0;
body_part bp = num_bp;
bool is_environmental = true;
bool immune_in_vehicle = false;
bool immune_inside_vehicle = false;
bool immune_outside_vehicle = false;
int chance_in_vehicle = 0;
int chance_inside_vehicle = 0;
int chance_outside_vehicle = 0;
game_message_type env_message_type = m_neutral;
translation message;
translation message_npc;
time_duration get_duration() const {
return rng( min_duration, max_duration );
}
std::string get_message() const {
return message.translated();
}
std::string get_message_npc() const {
return message_npc.translated();
}
effect get_effect( const time_point &start_time = calendar::turn ) const {
return effect( &id.obj(), get_duration(), bp, false, intensity, start_time );
}
};

struct field_intensity_level {
Expand All @@ -54,7 +76,7 @@ struct field_intensity_level {
float translucency = 0.0f;
int convection_temperature_mod = 0;
int scent_neutralization = 0;
field_effect_data field_effect;
std::vector<field_effect> field_effects;
};

struct field_type {
Expand Down
72 changes: 53 additions & 19 deletions src/map_field.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1694,10 +1694,25 @@ void map::player_in_field( player &u )

void map::creature_in_field( Creature &critter )
{
bool in_vehicle = false;
bool inside_vehicle = false;
player *u = critter.as_player();
if( critter.is_monster() ) {
monster_in_field( *static_cast<monster *>( &critter ) );
} else if( player *p = critter.as_player() ) {
player_in_field( *p );
} else {
if( u ) {
in_vehicle = u->in_vehicle;
// If we are in a vehicle figure out if we are inside (reduces effects usually)
// and what part of the vehicle we need to deal with.
if( in_vehicle ) {
if( const optional_vpart_position vp = veh_at( u->pos() ) ) {
if( vp->is_inside() ) {
inside_vehicle = true;
}
}
}
player_in_field( *u );
}
}

field &curfield = get_field( critter.pos() );
Expand All @@ -1707,25 +1722,44 @@ void map::creature_in_field( Creature &critter )
continue;
}
const field_type_id cur_field_id = cur_field_entry.get_field_type();
const effect field_fx = cur_field_entry.field_effect();
if( field_fx.is_null() ||
critter.is_immune_field( cur_field_id ) || field_fx.get_id().is_empty() ||
critter.is_immune_effect( field_fx.get_id() ) ) {
continue;
}
player *u = critter.as_player();
if( u && cur_field_entry.inside_immune() ) {
// If we are in a vehicle figure out if we are inside (reduces effects usually)
// and what part of the vehicle we need to deal with.
if( u->in_vehicle ) {
if( const optional_vpart_position vp = veh_at( u->pos() ) ) {
if( vp->is_inside() ) {
continue;
}
}

for( const auto &fe : cur_field_entry.field_effects() ) {
if( in_vehicle && fe.immune_in_vehicle ) {
continue;
}
if( inside_vehicle && fe.immune_inside_vehicle ) {
continue;
}
if( !inside_vehicle && fe.immune_outside_vehicle ) {
continue;
}
if( in_vehicle && !one_in( fe.chance_in_vehicle ) ) {
continue;
}
if( inside_vehicle && !one_in( fe.chance_inside_vehicle ) ) {
continue;
}
if( !inside_vehicle && !one_in( fe.chance_outside_vehicle ) ) {
continue;
}

const effect field_fx = fe.get_effect();
if( field_fx.is_null() ||
critter.is_immune_field( cur_field_id ) || field_fx.get_id().is_empty() ||
critter.is_immune_effect( field_fx.get_id() ) ) {
continue;
}
bool effect_added = false;
if( fe.is_environmental ) {
effect_added = critter.add_env_effect( fe.id, fe.bp, fe.intensity, fe.get_duration() );
} else {
effect_added = true;
critter.add_effect( field_fx );
}
if( effect_added ) {
critter.add_msg_player_or_npc( fe.env_message_type, fe.get_message(), fe.get_message_npc() );
}
}
critter.add_effect( field_fx );
}
}

Expand Down

0 comments on commit b518e05

Please sign in to comment.