1 #include "projectile.h"
2 
3 #include <algorithm>
4 #include <memory>
5 #include <string>
6 #include <type_traits>
7 #include <vector>
8 
9 #include "ammo_effect.h"
10 #include "debug.h"
11 #include "enums.h"
12 #include "explosion.h"
13 #include "item.h"
14 #include "map.h"
15 #include "map_iterator.h"
16 #include "mapdata.h"
17 #include "messages.h"
18 #include "rng.h"
19 #include "translations.h"
20 #include "type_id.h"
21 
projectile()22 projectile::projectile() :
23     critical_multiplier( 2.0 ), drop( nullptr ), custom_explosion( nullptr )
24 { }
25 
26 projectile::~projectile() = default;
27 
28 projectile::projectile( projectile && ) = default;
29 
projectile(const projectile & other)30 projectile::projectile( const projectile &other )
31 {
32     *this = other;
33 }
34 
operator =(const projectile & other)35 projectile &projectile::operator=( const projectile &other )
36 {
37     impact = other.impact;
38     speed = other.speed;
39     range = other.range;
40     proj_effects = other.proj_effects;
41     critical_multiplier = other.critical_multiplier;
42     set_drop( other.get_drop() );
43     set_custom_explosion( other.get_custom_explosion() );
44 
45     return *this;
46 }
47 
get_drop() const48 const item &projectile::get_drop() const
49 {
50     if( drop != nullptr ) {
51         return *drop;
52     }
53 
54     static const item null_drop;
55     return null_drop;
56 }
57 
set_drop(const item & it)58 void projectile::set_drop( const item &it )
59 {
60     if( it.is_null() ) {
61         unset_drop();
62     } else {
63         drop = std::make_unique<item>( it );
64     }
65 }
66 
set_drop(item && it)67 void projectile::set_drop( item &&it )
68 {
69     if( it.is_null() ) {
70         unset_drop();
71     } else {
72         drop = std::make_unique<item>( std::move( it ) );
73     }
74 }
75 
unset_drop()76 void projectile::unset_drop()
77 {
78     drop.reset( nullptr );
79 }
80 
get_custom_explosion() const81 const explosion_data &projectile::get_custom_explosion() const
82 {
83     if( custom_explosion != nullptr ) {
84         return *custom_explosion;
85     }
86 
87     static const explosion_data null_explosion{};
88     return null_explosion;
89 }
90 
set_custom_explosion(const explosion_data & ex)91 void projectile::set_custom_explosion( const explosion_data &ex )
92 {
93     custom_explosion = std::make_unique<explosion_data>( ex );
94 }
95 
unset_custom_explosion()96 void projectile::unset_custom_explosion()
97 {
98     custom_explosion.reset();
99 }
100 
foamcrete_build(const tripoint & p)101 static void foamcrete_build( const tripoint &p )
102 {
103     map &here = get_map();
104     const ter_str_id floor = ter_str_id( "t_foamcrete_floor" );
105     const ter_str_id wall = ter_str_id( "t_foamcrete_wall" );
106     const field_type_str_id field_fd_foamcrete( "fd_foamcrete" );
107 
108     if( !( wall.is_valid() && floor.is_valid() && field_fd_foamcrete.is_valid() ) ) {
109         debugmsg( "Foamcrete terrains or fields are missing" );
110         return;
111     }
112 
113     if( here.has_flag_ter( TFLAG_NO_FLOOR, p ) ) {
114         for( const tripoint &ep : here.points_in_radius( p, 1 ) ) {
115             if( here.has_flag_ter( TFLAG_SUPPORTS_ROOF, ep ) ) {
116                 here.ter_set( p, floor );
117                 here.add_field( p, field_fd_foamcrete, 1 );
118                 return;
119             }
120         }
121         add_msg( m_bad, _( "The foamcrete falls without a wall to anchor against." ) );
122     } else if( here.get_field_intensity( p, field_fd_foamcrete ) >= 2 ) {
123         here.bash( p, 9001, false, true, false );
124         here.ter_set( p, wall );
125     } else {
126         here.add_field( p, field_fd_foamcrete, 1 );
127     }
128 }
129 
apply_ammo_effects(const tripoint & p,const std::set<std::string> & effects)130 void apply_ammo_effects( const tripoint &p, const std::set<std::string> &effects )
131 {
132     map &here = get_map();
133     for( const ammo_effect &ae : ammo_effects::get_all() ) {
134         if( effects.count( ae.id.str() ) > 0 ) {
135             for( const tripoint &pt : here.points_in_radius( p, ae.aoe_radius, ae.aoe_radius_z ) ) {
136                 if( x_in_y( ae.aoe_chance, 100 ) ) {
137                     const bool check_sees = !ae.aoe_check_sees || here.sees( p, pt, ae.aoe_check_sees_radius );
138                     const bool check_passable = !ae.aoe_check_passable || here.passable( pt );
139                     if( check_sees && check_passable ) {
140                         here.add_field( pt, ae.aoe_field_type, rng( ae.aoe_intensity_min, ae.aoe_intensity_max ) );
141                     }
142                 }
143             }
144             if( ae.aoe_explosion_data.power > 0 ) {
145                 explosion_handler::explosion( p, ae.aoe_explosion_data );
146             }
147             if( ae.do_flashbang ) {
148                 explosion_handler::flashbang( p );
149             }
150             if( ae.do_emp_blast ) {
151                 explosion_handler::emp_blast( p );
152             }
153             if( ae.foamcrete_build ) {
154                 foamcrete_build( p );
155             }
156         }
157     }
158 }
159 
max_aoe_size(const std::set<std::string> & tags)160 int max_aoe_size( const std::set<std::string> &tags )
161 {
162     int aoe_size = 0;
163     for( const ammo_effect &aed : ammo_effects::get_all() ) {
164         if( tags.count( aed.id.str() ) > 0 ) {
165             aoe_size = std::max( aoe_size,  aed.aoe_size ) ;
166         }
167     }
168     return aoe_size;
169 }
170