forked from CleverRaven/Cataclysm-DDA
-
Notifications
You must be signed in to change notification settings - Fork 0
/
character_escape.cpp
376 lines (345 loc) · 14.8 KB
/
character_escape.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
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
#include "character.h"
#include "creature_tracker.h"
#include "flag.h"
#include "map.h"
#include "map_iterator.h"
#include "messages.h"
#include "monster.h"
#include "mtype.h"
#include "output.h"
static const efftype_id effect_beartrap( "beartrap" );
static const efftype_id effect_crushed( "crushed" );
static const efftype_id effect_downed( "downed" );
static const efftype_id effect_grabbed( "grabbed" );
static const efftype_id effect_grabbing( "grabbing" );
static const efftype_id effect_heavysnare( "heavysnare" );
static const efftype_id effect_in_pit( "in_pit" );
static const efftype_id effect_lightsnare( "lightsnare" );
static const efftype_id effect_stunned( "stunned" );
static const efftype_id effect_webbed( "webbed" );
static const itype_id itype_rope_6( "rope_6" );
static const itype_id itype_snare_trigger( "snare_trigger" );
static const itype_id itype_string_36( "string_36" );
void Character::try_remove_downed()
{
/** @EFFECT_DEX increases chance to stand up when knocked down */
/** @EFFECT_STR increases chance to stand up when knocked down, slightly */
if( rng( 0, 40 ) > get_dex() + get_str() / 2 ) {
add_msg_if_player( _( "You struggle to stand." ) );
} else {
add_msg_player_or_npc( m_good, _( "You stand up." ),
_( "<npcname> stands up." ) );
remove_effect( effect_downed );
}
}
void Character::try_remove_bear_trap()
{
/* Real bear traps can't be removed without the proper tools or immense strength; eventually this should
allow normal players two options: removal of the limb or removal of the trap from the ground
(at which point the player could later remove it from the leg with the right tools).
As such we are currently making it a bit easier for players and NPC's to get out of bear traps.
*/
/** @EFFECT_STR increases chance to escape bear trap */
// If is riding, then despite the character having the effect, it is the mounted creature that escapes.
if( is_avatar() && is_mounted() ) {
auto *mon = mounted_creature.get();
if( mon->type->melee_dice * mon->type->melee_sides >= 18 ) {
if( x_in_y( mon->type->melee_dice * mon->type->melee_sides, 200 ) ) {
mon->remove_effect( effect_beartrap );
remove_effect( effect_beartrap );
add_msg( _( "The %s escapes the bear trap!" ), mon->get_name() );
} else {
add_msg_if_player( m_bad,
_( "Your %s tries to free itself from the bear trap, but can't get loose!" ), mon->get_name() );
}
}
} else {
if( x_in_y( get_str(), 100 ) ) {
remove_effect( effect_beartrap );
add_msg_player_or_npc( m_good, _( "You free yourself from the bear trap!" ),
_( "<npcname> frees themselves from the bear trap!" ) );
} else {
add_msg_if_player( m_bad,
_( "You try to free yourself from the bear trap, but can't get loose!" ) );
}
}
}
void Character::try_remove_lightsnare()
{
map &here = get_map();
if( is_mounted() ) {
auto *mon = mounted_creature.get();
if( x_in_y( mon->type->melee_dice * mon->type->melee_sides, 12 ) ) {
mon->remove_effect( effect_lightsnare );
remove_effect( effect_lightsnare );
here.spawn_item( pos(), itype_string_36 );
here.spawn_item( pos(), itype_snare_trigger );
add_msg( _( "The %s escapes the light snare!" ), mon->get_name() );
}
} else {
/** @EFFECT_STR increases chance to escape light snare */
/** @EFFECT_DEX increases chance to escape light snare */
if( x_in_y( get_str(), 12 ) || x_in_y( get_dex(), 8 ) ) {
remove_effect( effect_lightsnare );
add_msg_player_or_npc( m_good, _( "You free yourself from the light snare!" ),
_( "<npcname> frees themselves from the light snare!" ) );
item string( "string_36", calendar::turn );
item snare( "snare_trigger", calendar::turn );
here.add_item_or_charges( pos(), string );
here.add_item_or_charges( pos(), snare );
} else {
add_msg_if_player( m_bad,
_( "You try to free yourself from the light snare, but can't get loose!" ) );
}
}
}
void Character::try_remove_heavysnare()
{
map &here = get_map();
if( is_mounted() ) {
auto *mon = mounted_creature.get();
if( mon->type->melee_dice * mon->type->melee_sides >= 7 ) {
if( x_in_y( mon->type->melee_dice * mon->type->melee_sides, 32 ) ) {
mon->remove_effect( effect_heavysnare );
remove_effect( effect_heavysnare );
here.spawn_item( pos(), itype_rope_6 );
here.spawn_item( pos(), itype_snare_trigger );
add_msg( _( "The %s escapes the heavy snare!" ), mon->get_name() );
}
}
} else {
/** @EFFECT_STR increases chance to escape heavy snare, slightly */
/** @EFFECT_DEX increases chance to escape light snare */
if( x_in_y( get_str(), 32 ) || x_in_y( get_dex(), 16 ) ) {
remove_effect( effect_heavysnare );
add_msg_player_or_npc( m_good, _( "You free yourself from the heavy snare!" ),
_( "<npcname> frees themselves from the heavy snare!" ) );
item rope( "rope_6", calendar::turn );
item snare( "snare_trigger", calendar::turn );
here.add_item_or_charges( pos(), rope );
here.add_item_or_charges( pos(), snare );
} else {
add_msg_if_player( m_bad,
_( "You try to free yourself from the heavy snare, but can't get loose!" ) );
}
}
}
void Character::try_remove_crushed()
{
/** @EFFECT_STR increases chance to escape crushing rubble */
/** @EFFECT_DEX increases chance to escape crushing rubble, slightly */
if( x_in_y( get_str() + get_dex() / 4.0, 100 ) ) {
remove_effect( effect_crushed );
add_msg_player_or_npc( m_good, _( "You free yourself from the rubble!" ),
_( "<npcname> frees themselves from the rubble!" ) );
} else {
add_msg_if_player( m_bad, _( "You try to free yourself from the rubble, but can't get loose!" ) );
}
}
bool Character::try_remove_grab()
{
int zed_number = 0;
if( is_mounted() ) {
auto *mon = mounted_creature.get();
if( mon->has_effect( effect_grabbed ) ) {
if( ( dice( mon->type->melee_dice + mon->type->melee_sides,
3 ) < get_effect_int( effect_grabbed ) ) ||
!one_in( 4 ) ) {
add_msg( m_bad, _( "Your %s tries to break free, but fails!" ), mon->get_name() );
return false;
} else {
add_msg( m_good, _( "Your %s breaks free from the grab!" ), mon->get_name() );
remove_effect( effect_grabbed );
mon->remove_effect( effect_grabbed );
}
} else {
if( one_in( 4 ) ) {
add_msg( m_bad, _( "You are pulled from your %s!" ), mon->get_name() );
remove_effect( effect_grabbed );
forced_dismount();
}
}
} else {
map &here = get_map();
creature_tracker &creatures = get_creature_tracker();
for( auto&& dest : here.points_in_radius( pos(), 1, 0 ) ) { // *NOPAD*
const monster *const mon = creatures.creature_at<monster>( dest );
if( mon && mon->has_effect( effect_grabbing ) ) {
zed_number += mon->get_grab_strength();
}
}
/** @EFFECT_STR increases chance to escape grab */
/** @EFFECT_DEX increases chance to escape grab */
int defender_check = rng( 0, std::max( get_str(), get_dex() ) );
int attacker_check = rng( get_effect_int( effect_grabbed, body_part_torso ), 8 );
if( has_grab_break_tec() ) {
defender_check = defender_check + 2;
}
if( is_throw_immune() ) {
defender_check = defender_check + 2;
}
if( get_effect_int( effect_stunned ) ) {
defender_check = defender_check - 2;
}
if( get_effect_int( effect_downed ) ) {
defender_check = defender_check - 2;
}
if( zed_number == 0 ) {
add_msg_player_or_npc( m_good, _( "You find yourself no longer grabbed." ),
_( "<npcname> finds themselves no longer grabbed." ) );
remove_effect( effect_grabbed );
/** @EFFECT_STR increases chance to escape grab */
} else if( defender_check < attacker_check ) {
add_msg_player_or_npc( m_bad, _( "You try to break out of the grab, but fail!" ),
_( "<npcname> tries to break out of the grab, but fails!" ) );
return false;
} else {
std::vector<item_pocket *> pd = worn.grab_drop_pockets();
// if we have items that can be pulled off
if( !pd.empty() ) {
// choose an item to be ripped off
int index = rng( 0, pd.size() - 1 );
int chance = rng( 0, get_effect_int( effect_grabbed, body_part_torso ) );
int sturdiness = rng( 0, pd[index]->get_pocket_data()->ripoff );
// the item is ripped off your character
if( sturdiness < chance ) {
pd[index]->spill_contents( adjacent_tile() );
add_msg_player_or_npc( m_bad,
_( "As you escape the grab something comes loose and falls to the ground!" ),
_( "<npcname> escapes the grab something comes loose and falls to the ground!" ) );
if( is_avatar() ) {
popup( _( "As you escape the grab something comes loose and falls to the ground!" ) );
}
}
}
add_msg_player_or_npc( m_good, _( "You break out of the grab!" ),
_( "<npcname> breaks out of the grab!" ) );
remove_effect( effect_grabbed );
for( auto&& dest : here.points_in_radius( pos(), 1, 0 ) ) { // *NOPAD*
monster *mon = creatures.creature_at<monster>( dest );
if( mon && mon->has_effect( effect_grabbing ) ) {
mon->remove_effect( effect_grabbing );
}
}
}
}
return true;
}
void Character::try_remove_webs()
{
if( is_mounted() ) {
auto *mon = mounted_creature.get();
if( x_in_y( mon->type->melee_dice * mon->type->melee_sides,
6 * get_effect_int( effect_webbed ) ) ) {
add_msg( _( "The %s breaks free of the webs!" ), mon->get_name() );
mon->remove_effect( effect_webbed );
remove_effect( effect_webbed );
}
/** @EFFECT_STR increases chance to escape webs */
} else if( x_in_y( get_str(), 6 * get_effect_int( effect_webbed ) ) ) {
add_msg_player_or_npc( m_good, _( "You free yourself from the webs!" ),
_( "<npcname> frees themselves from the webs!" ) );
remove_effect( effect_webbed );
} else {
add_msg_if_player( _( "You try to free yourself from the webs, but can't get loose!" ) );
}
}
void Character::try_remove_impeding_effect()
{
for( const effect &eff : get_effects_with_flag( flag_EFFECT_IMPEDING ) ) {
const efftype_id &eff_id = eff.get_id();
if( is_mounted() ) {
auto *mon = mounted_creature.get();
if( x_in_y( mon->type->melee_dice * mon->type->melee_sides,
6 * get_effect_int( eff_id ) ) ) {
add_msg( _( "The %s breaks free!" ), mon->get_name() );
mon->remove_effect( eff_id );
remove_effect( eff_id );
}
/** @EFFECT_STR increases chance to escape webs */
} else if( x_in_y( get_str(), 6 * get_effect_int( eff_id ) ) ) {
add_msg_player_or_npc( m_good, _( "You free yourself!" ),
_( "<npcname> frees themselves!" ) );
remove_effect( eff_id );
} else {
add_msg_if_player( _( "You try to free yourself, but can't!" ) );
}
}
}
bool Character::move_effects( bool attacking )
{
if( has_effect( effect_downed ) ) {
try_remove_downed();
return false;
}
if( has_effect( effect_webbed ) ) {
try_remove_webs();
return false;
}
if( has_effect( effect_lightsnare ) ) {
try_remove_lightsnare();
return false;
}
if( has_effect( effect_heavysnare ) ) {
try_remove_heavysnare();
return false;
}
if( has_effect( effect_beartrap ) ) {
try_remove_bear_trap();
return false;
}
if( has_effect( effect_crushed ) ) {
try_remove_crushed();
return false;
}
if( has_effect_with_flag( flag_EFFECT_IMPEDING ) ) {
try_remove_impeding_effect();
return false;
}
// Below this point are things that allow for movement if they succeed
// Currently we only have one thing that forces movement if you succeed, should we get more
// than this will need to be reworked to only have success effects if /all/ checks succeed
if( has_effect( effect_in_pit ) ) {
/** @EFFECT_STR increases chance to escape pit */
/** @EFFECT_DEX increases chance to escape pit, slightly */
if( rng( 0, 40 ) > get_str() + get_dex() / 2 ) {
add_msg_if_player( m_bad, _( "You try to escape the pit, but slip back in." ) );
return false;
} else {
add_msg_player_or_npc( m_good, _( "You escape the pit!" ),
_( "<npcname> escapes the pit!" ) );
remove_effect( effect_in_pit );
}
}
return !has_effect( effect_grabbed ) || attacking || try_remove_grab();
}
void Character::wait_effects( bool attacking )
{
if( has_effect( effect_downed ) ) {
try_remove_downed();
return;
}
if( has_effect( effect_beartrap ) ) {
try_remove_bear_trap();
return;
}
if( has_effect( effect_lightsnare ) ) {
try_remove_lightsnare();
return;
}
if( has_effect( effect_heavysnare ) ) {
try_remove_heavysnare();
return;
}
if( has_effect( effect_webbed ) ) {
try_remove_webs();
return;
}
if( has_effect_with_flag( flag_EFFECT_IMPEDING ) ) {
try_remove_impeding_effect();
return;
}
if( has_effect( effect_grabbed ) && !attacking && !try_remove_grab() ) {
return;
}
}