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