forked from CleverRaven/Cataclysm-DDA
-
Notifications
You must be signed in to change notification settings - Fork 0
/
teleport.cpp
179 lines (173 loc) · 6.87 KB
/
teleport.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
#include "teleport.h"
#include <cmath>
#include <memory>
#include <string>
#include "avatar.h"
#include "calendar.h"
#include "character.h"
#include "creature.h"
#include "creature_tracker.h"
#include "debug.h"
#include "enums.h"
#include "event.h"
#include "event_bus.h"
#include "game.h"
#include "map.h"
#include "messages.h"
#include "point.h"
#include "rng.h"
#include "translations.h"
#include "type_id.h"
#include "viewer.h"
#include "map_iterator.h"
static const efftype_id effect_grabbed( "grabbed" );
static const efftype_id effect_teleglow( "teleglow" );
static const flag_id json_flag_DIMENSIONAL_ANCHOR( "DIMENSIONAL_ANCHOR" );
bool teleport::teleport( Creature &critter, int min_distance, int max_distance, bool safe,
bool add_teleglow )
{
if( min_distance > max_distance ) {
debugmsg( "ERROR: Function teleport::teleport called with invalid arguments." );
return false;
}
int tries = 0;
tripoint origin = critter.pos();
tripoint new_pos = origin;
map &here = get_map();
do {
int rangle = rng( 0, 360 );
int rdistance = rng( min_distance, max_distance );
new_pos.x = origin.x + rdistance * std::cos( rangle );
new_pos.y = origin.y + rdistance * std::sin( rangle );
tries++;
} while( here.impassable( new_pos ) && tries < 20 );
return teleport_to_point( critter, new_pos, safe, add_teleglow );
}
bool teleport::teleport_to_point( Creature &critter, tripoint target, bool safe,
bool add_teleglow, bool display_message, bool force )
{
if( critter.pos() == target ) {
return false;
}
Character *const p = critter.as_character();
const bool c_is_u = p != nullptr && p->is_avatar();
map &here = get_map();
//The teleportee is dimensionally anchored so nothing happens
if( !force && p && ( p->worn_with_flag( json_flag_DIMENSIONAL_ANCHOR ) ||
p->has_effect_with_flag( json_flag_DIMENSIONAL_ANCHOR ) ) ) {
if( display_message ) {
p->add_msg_if_player( m_warning, _( "You feel a strange, inwards force." ) );
}
return false;
}
tripoint_abs_ms avatar_pos = get_avatar().get_location();
bool shifted = false;
if( !here.inbounds( target ) ) {
const tripoint_abs_ms abs_ms( here.getabs( target ) );
g->place_player_overmap( project_to<coords::omt>( abs_ms ), false );
shifted = true;
target = here.getlocal( abs_ms );
}
//handles teleporting into solids.
if( here.impassable( target ) ) {
if( force ) {
const cata::optional<tripoint> nt =
random_point( points_in_radius( target, 5 ),
[]( const tripoint & el ) {
return get_map().passable( el );
} );
target = nt ? *nt : target;
} else {
if( safe ) {
if( c_is_u && display_message ) {
add_msg( m_bad, _( "You cannot teleport safely." ) );
}
if( shifted ) {
g->place_player_overmap( project_to<coords::omt>( avatar_pos ), false );
}
return false;
}
critter.apply_damage( nullptr, bodypart_id( "torso" ), 9999 );
if( c_is_u ) {
get_event_bus().send<event_type::teleports_into_wall>( p->getID(), here.obstacle_name( target ) );
if( display_message ) {
add_msg( m_bad, _( "You die after teleporting into a solid." ) );
}
}
critter.check_dead_state();
}
}
//handles telefragging other creatures
int tfrag_attempts = 5;
while( Creature *const poor_soul = get_creature_tracker().creature_at<Creature>( target ) ) {
//Fail if we run out of telefrag attempts
if( tfrag_attempts-- < 1 ) {
if( p && display_message ) {
p->add_msg_player_or_npc( m_warning, _( "You flicker." ), _( "<npcname> flickers." ) );
} else if( get_player_view().sees( critter ) && display_message ) {
add_msg( _( "%1$s flickers." ), critter.disp_name() );
}
return false;
}
Character *const poor_player = dynamic_cast<Character *>( poor_soul );
if( force ) {
poor_soul->apply_damage( nullptr, bodypart_id( "torso" ), 9999 );
poor_soul->check_dead_state();
} else if( safe ) {
if( c_is_u && display_message ) {
add_msg( m_bad, _( "You cannot teleport safely." ) );
}
if( shifted ) {
g->place_player_overmap( project_to<coords::omt>( avatar_pos ), false );
}
return false;
} else if( poor_player && ( poor_player->worn_with_flag( json_flag_DIMENSIONAL_ANCHOR ) ||
poor_player->has_flag( json_flag_DIMENSIONAL_ANCHOR ) ) ) {
if( display_message ) {
poor_player->add_msg_if_player( m_warning, _( "You feel disjointed." ) );
}
if( shifted ) {
g->place_player_overmap( project_to<coords::omt>( avatar_pos ), false );
}
return false;
} else {
const bool poor_soul_is_u = poor_soul->is_avatar();
if( poor_soul_is_u && display_message ) {
add_msg( m_bad, _( "…" ) );
add_msg( m_bad, _( "You explode into thousands of fragments." ) );
}
if( p ) {
if( display_message ) {
p->add_msg_player_or_npc( m_warning,
_( "You teleport into %s, and they explode into thousands of fragments." ),
_( "<npcname> teleports into %s, and they explode into thousands of fragments." ),
poor_soul->disp_name() );
}
get_event_bus().send<event_type::telefrags_creature>( p->getID(), poor_soul->get_name() );
} else {
if( get_player_view().sees( *poor_soul ) ) {
if( display_message ) {
add_msg( m_good, _( "%1$s teleports into %2$s, killing them!" ),
critter.disp_name(), poor_soul->disp_name() );
}
}
}
//Splatter real nice.
poor_soul->apply_damage( nullptr, bodypart_id( "torso" ), 9999 );
poor_soul->check_dead_state();
}
}
critter.setpos( target );
//player and npc exclusive teleporting effects
if( p ) {
g->place_player( p->pos() );
if( add_teleglow ) {
p->add_effect( effect_teleglow, 30_minutes );
}
}
if( c_is_u ) {
g->update_map( *p );
}
critter.remove_effect( effect_grabbed );
return true;
}