1 #include "mission.h" // IWYU pragma: associated
2
3 #include <memory>
4 #include <new>
5 #include <vector>
6
7 #include "character.h"
8 #include "computer.h"
9 #include "coordinates.h"
10 #include "debug.h"
11 #include "enum_traits.h"
12 #include "game.h"
13 #include "game_constants.h"
14 #include "item.h"
15 #include "line.h"
16 #include "map.h"
17 #include "map_iterator.h"
18 #include "mapdata.h"
19 #include "messages.h"
20 #include "name.h"
21 #include "npc.h"
22 #include "npc_class.h"
23 #include "omdata.h"
24 #include "optional.h"
25 #include "overmap.h"
26 #include "overmapbuffer.h"
27 #include "point.h"
28 #include "rng.h"
29 #include "string_formatter.h"
30 #include "translations.h"
31 #include "units.h"
32
33 static const itype_id itype_software_hacking( "software_hacking" );
34 static const itype_id itype_software_math( "software_math" );
35 static const itype_id itype_software_medical( "software_medical" );
36 static const itype_id itype_software_useless( "software_useless" );
37
38 static const mtype_id mon_dog( "mon_dog" );
39 static const mtype_id mon_zombie( "mon_zombie" );
40 static const mtype_id mon_zombie_brute( "mon_zombie_brute" );
41 static const mtype_id mon_zombie_dog( "mon_zombie_dog" );
42 static const mtype_id mon_zombie_hulk( "mon_zombie_hulk" );
43 static const mtype_id mon_zombie_master( "mon_zombie_master" );
44 static const mtype_id mon_zombie_necro( "mon_zombie_necro" );
45
46 /* These functions are responsible for making changes to the game at the moment
47 * the mission is accepted by the player. They are also responsible for
48 * updating *miss with the target and any other important information.
49 */
50
standard(mission *)51 void mission_start::standard( mission * )
52 {
53 }
54
place_dog(mission * miss)55 void mission_start::place_dog( mission *miss )
56 {
57 const tripoint_abs_omt house = mission_util::random_house_in_closest_city();
58 npc *dev = g->find_npc( miss->npc_id );
59 if( dev == nullptr ) {
60 debugmsg( "Couldn't find NPC! %d", miss->npc_id.get_value() );
61 return;
62 }
63 get_player_character().i_add( item( "dog_whistle", calendar::turn_zero ) );
64 add_msg( _( "%s gave you a dog whistle." ), dev->name );
65
66 miss->target = house;
67 overmap_buffer.reveal( house, 6 );
68
69 tinymap doghouse;
70 doghouse.load( project_to<coords::sm>( house ), false );
71 doghouse.add_spawn( mon_dog, 1, { SEEX, SEEY, house.z() }, true, -1, miss->uid );
72 doghouse.save();
73 }
74
place_zombie_mom(mission * miss)75 void mission_start::place_zombie_mom( mission *miss )
76 {
77 const tripoint_abs_omt house = mission_util::random_house_in_closest_city();
78
79 miss->target = house;
80 overmap_buffer.reveal( house, 6 );
81
82 tinymap zomhouse;
83 zomhouse.load( project_to<coords::sm>( house ), false );
84 zomhouse.add_spawn( mon_zombie, 1, { SEEX, SEEY, house.z() }, false, -1, miss->uid,
85 Name::get( nameFlags::IsFemaleName | nameFlags::IsGivenName ) );
86 zomhouse.save();
87 }
88
kill_horde_master(mission * miss)89 void mission_start::kill_horde_master( mission *miss )
90 {
91 npc *p = g->find_npc( miss->npc_id );
92 if( p == nullptr ) {
93 debugmsg( "could not find mission NPC %d", miss->npc_id.get_value() );
94 return;
95 }
96 // Npc joins you
97 p->set_attitude( NPCATT_FOLLOW );
98 // Pick one of the below locations for the horde to haunt
99 const tripoint_abs_omt center = p->global_omt_location();
100 tripoint_abs_omt site = overmap_buffer.find_closest( center, "office_tower_1", 0, false );
101 if( site == overmap::invalid_tripoint ) {
102 site = overmap_buffer.find_closest( center, "hotel_tower_1_8", 0, false );
103 }
104 if( site == overmap::invalid_tripoint ) {
105 site = overmap_buffer.find_closest( center, "school_5", 0, false );
106 }
107 if( site == overmap::invalid_tripoint ) {
108 site = overmap_buffer.find_closest( center, "forest_thick", 0, false );
109 }
110 miss->target = site;
111 overmap_buffer.reveal( site, 6 );
112 tinymap tile;
113 tile.load( project_to<coords::sm>( site ), false );
114 tile.add_spawn( mon_zombie_master, 1, { SEEX, SEEY, site.z() }, false, -1, miss->uid,
115 _( "Demonic Soul" ) );
116 tile.add_spawn( mon_zombie_brute, 3, { SEEX, SEEY, site.z() } );
117 tile.add_spawn( mon_zombie_dog, 3, { SEEX, SEEY, site.z() } );
118
119 for( int x = SEEX - 1; x <= SEEX + 1; x++ ) {
120 for( int y = SEEY - 1; y <= SEEY + 1; y++ ) {
121 tile.add_spawn( mon_zombie, rng( 3, 10 ), { x, y, site.z() } );
122 }
123 tile.add_spawn( mon_zombie_dog, rng( 0, 2 ), { SEEX, SEEY, site.z() } );
124 }
125 tile.add_spawn( mon_zombie_necro, 2, { SEEX, SEEY, site.z() } );
126 tile.add_spawn( mon_zombie_hulk, 1, { SEEX, SEEY, site.z() } );
127 tile.save();
128 }
129
130 /*
131 * Find a location to place a computer. In order, prefer:
132 * 1) Broken consoles.
133 * 2) Corners or coords adjacent to a bed/dresser? (this logic may be flawed, dates from Whales in 2011)
134 * 3) A spot near the center of the tile that is not a console
135 * 4) A random spot near the center of the tile.
136 */
find_potential_computer_point(const tinymap & compmap)137 static tripoint find_potential_computer_point( const tinymap &compmap )
138 {
139 constexpr int rng_x_min = 10;
140 constexpr int rng_x_max = SEEX * 2 - 11;
141 constexpr int rng_y_min = 10;
142 constexpr int rng_y_max = SEEY * 2 - 11;
143 static_assert( rng_x_min <= rng_x_max && rng_y_min <= rng_y_max, "invalid randomization range" );
144 std::vector<tripoint> broken;
145 std::vector<tripoint> potential;
146 std::vector<tripoint> last_resort;
147 for( const tripoint &p : compmap.points_on_zlevel() ) {
148 if( compmap.furn( p ) == f_console_broken ) {
149 broken.emplace_back( p );
150 } else if( broken.empty() && compmap.ter( p ) == t_floor && compmap.furn( p ) == f_null ) {
151 for( const tripoint &p2 : compmap.points_in_radius( p, 1 ) ) {
152 if( compmap.furn( p2 ) == f_bed || compmap.furn( p2 ) == f_dresser ) {
153 potential.emplace_back( p );
154 break;
155 }
156 }
157 int wall = 0;
158 for( const tripoint &p2 : compmap.points_in_radius( p, 1 ) ) {
159 if( compmap.has_flag_ter( "WALL", p2 ) ) {
160 wall++;
161 }
162 }
163 if( wall == 5 ) {
164 if( compmap.is_last_ter_wall( true, p.xy(), point( SEEX * 2, SEEY * 2 ), direction::NORTH ) &&
165 compmap.is_last_ter_wall( true, p.xy(), point( SEEX * 2, SEEY * 2 ), direction::SOUTH ) &&
166 compmap.is_last_ter_wall( true, p.xy(), point( SEEX * 2, SEEY * 2 ), direction::WEST ) &&
167 compmap.is_last_ter_wall( true, p.xy(), point( SEEX * 2, SEEY * 2 ), direction::EAST ) ) {
168 potential.emplace_back( p );
169 }
170 }
171 } else if( broken.empty() && potential.empty() && p.x >= rng_x_min && p.x <= rng_x_max
172 && p.y >= rng_y_min && p.y <= rng_y_max && compmap.furn( p ) != f_console ) {
173 last_resort.emplace_back( p );
174 }
175 }
176 std::vector<tripoint> *used = &broken;
177 if( used->empty() ) {
178 used = &potential;
179 }
180 if( used->empty() ) {
181 used = &last_resort;
182 }
183 // if there's no possible location, then we have to overwrite an existing console...
184 const tripoint fallback( rng( rng_x_min, rng_x_max ), rng( rng_y_min, rng_y_max ),
185 compmap.get_abs_sub().z );
186 return random_entry( *used, fallback );
187 }
188
place_npc_software(mission * miss)189 void mission_start::place_npc_software( mission *miss )
190 {
191 npc *dev = g->find_npc( miss->npc_id );
192 if( dev == nullptr ) {
193 debugmsg( "Couldn't find NPC! %d", miss->npc_id.get_value() );
194 return;
195 }
196 get_player_character().i_add( item( "usb_drive", calendar::turn_zero ) );
197 add_msg( _( "%s gave you a USB drive." ), dev->name );
198
199 std::string type = "house";
200
201 if( dev->myclass == NC_HACKER ) {
202 miss->item_id = itype_software_hacking;
203 } else if( dev->myclass == NC_DOCTOR ) {
204 miss->item_id = itype_software_medical;
205 static const std::set<std::string> pharmacies = { "s_pharm", "s_pharm_1" };
206 type = random_entry( pharmacies );
207 miss->follow_up = mission_type_id( "MISSION_GET_ZOMBIE_BLOOD_ANAL" );
208 } else if( dev->myclass == NC_SCIENTIST ) {
209 miss->item_id = itype_software_math;
210 } else {
211 miss->item_id = itype_software_useless;
212 }
213
214 tripoint_abs_omt place;
215 if( type == "house" ) {
216 place = mission_util::random_house_in_closest_city();
217 } else {
218 place = overmap_buffer.find_closest( dev->global_omt_location(), type, 0, false );
219 }
220 miss->target = place;
221 overmap_buffer.reveal( place, 6 );
222
223 tinymap compmap;
224 compmap.load( project_to<coords::sm>( place ), false );
225 tripoint comppoint;
226
227 oter_id oter = overmap_buffer.ter( place );
228 if( is_ot_match( "house", oter, ot_match_type::prefix ) ||
229 is_ot_match( "s_pharm", oter, ot_match_type::prefix ) || oter == "" ) {
230 comppoint = find_potential_computer_point( compmap );
231 }
232
233 compmap.i_clear( comppoint );
234 compmap.furn_set( comppoint, f_console );
235 computer *tmpcomp = compmap.add_computer( comppoint, string_format( _( "%s's Terminal" ),
236 dev->name ), 0 );
237 tmpcomp->set_mission( miss->get_id() );
238 tmpcomp->add_option( _( "Download Software" ), COMPACT_DOWNLOAD_SOFTWARE, 0 );
239 compmap.save();
240 }
241
place_priest_diary(mission * miss)242 void mission_start::place_priest_diary( mission *miss )
243 {
244 const tripoint_abs_omt place = mission_util::random_house_in_closest_city();
245 miss->target = place;
246 overmap_buffer.reveal( place, 2 );
247 tinymap compmap;
248 compmap.load( project_to<coords::sm>( place ), false );
249
250 std::vector<tripoint> valid;
251 for( const tripoint &p : compmap.points_on_zlevel() ) {
252 if( compmap.furn( p ) == f_bed || compmap.furn( p ) == f_dresser ||
253 compmap.furn( p ) == f_indoor_plant || compmap.furn( p ) == f_cupboard ) {
254 valid.push_back( p );
255 }
256 }
257 const tripoint fallback( rng( 6, SEEX * 2 - 7 ), rng( 6, SEEY * 2 - 7 ), place.z() );
258 const tripoint comppoint = random_entry( valid, fallback );
259 compmap.spawn_item( comppoint, "priest_diary" );
260 compmap.save();
261 }
262
place_deposit_box(mission * miss)263 void mission_start::place_deposit_box( mission *miss )
264 {
265 npc *p = g->find_npc( miss->npc_id );
266 if( p == nullptr ) {
267 debugmsg( "could not find mission NPC %d", miss->npc_id.get_value() );
268 return;
269 }
270 // Npc joins you
271 p->set_attitude( NPCATT_FOLLOW );
272 tripoint_abs_omt site =
273 overmap_buffer.find_closest( p->global_omt_location(), "bank", 0, false );
274 if( site == overmap::invalid_tripoint ) {
275 site = overmap_buffer.find_closest( p->global_omt_location(), "office_tower_1", 0, false );
276 }
277
278 if( site == overmap::invalid_tripoint ) {
279 site = p->global_omt_location();
280 debugmsg( "Couldn't find a place for deposit box" );
281 }
282
283 miss->target = site;
284 overmap_buffer.reveal( site, 2 );
285
286 tinymap compmap;
287 compmap.load( project_to<coords::sm>( site ), false );
288 std::vector<tripoint> valid;
289 for( const tripoint &p : compmap.points_on_zlevel() ) {
290 if( compmap.ter( p ) == t_floor ) {
291 for( const tripoint &p2 : compmap.points_in_radius( p, 1 ) ) {
292 if( compmap.ter( p2 ) == t_wall_metal ) {
293 valid.push_back( p );
294 break;
295 }
296 }
297 }
298 }
299 const tripoint fallback( rng( 6, SEEX * 2 - 7 ), rng( 6, SEEY * 2 - 7 ), site.z() );
300 const tripoint comppoint = random_entry( valid, fallback );
301 compmap.spawn_item( comppoint, "safe_box" );
302 compmap.save();
303 }
304
find_safety(mission * miss)305 void mission_start::find_safety( mission *miss )
306 {
307 const tripoint_abs_omt place = get_player_character().global_omt_location();
308 for( int radius = 0; radius <= 20; radius++ ) {
309 for( int dist = 0 - radius; dist <= radius; dist++ ) {
310 int offset = rng( 0, 3 ); // Randomizes the direction we check first
311 for( int i = 0; i <= 3; i++ ) { // Which direction?
312 tripoint_abs_omt check = place;
313 switch( ( offset + i ) % 4 ) {
314 case 0:
315 check.x() += dist;
316 check.y() -= radius;
317 break;
318 case 1:
319 check.x() += dist;
320 check.y() += radius;
321 break;
322 case 2:
323 check.y() += dist;
324 check.x() -= radius;
325 break;
326 case 3:
327 check.y() += dist;
328 check.x() += radius;
329 break;
330 }
331 if( overmap_buffer.is_safe( check ) ) {
332 miss->target = check;
333 return;
334 }
335 }
336 }
337 }
338 // Couldn't find safety; so just set the target to far away
339 switch( rng( 0, 3 ) ) {
340 case 0:
341 miss->target = place + point( -20, -20 );
342 break;
343 case 1:
344 miss->target = place + point( -20, 20 );
345 break;
346 case 2:
347 miss->target = place + point( 20, -20 );
348 break;
349 case 3:
350 miss->target = place + point( 20, 20 );
351 break;
352 }
353 }
354
355 static const int RANCH_SIZE = 5;
356
ranch_nurse_1(mission * miss)357 void mission_start::ranch_nurse_1( mission *miss )
358 {
359 //Improvements to clinic...
360 tripoint_abs_omt site = mission_util::target_om_ter_random(
361 "ranch_camp_59", 1, miss, false, RANCH_SIZE );
362 tinymap bay;
363 bay.load( project_to<coords::sm>( site ), false );
364 bay.draw_square_furn( f_rack, point( 16, 9 ), point( 17, 9 ) );
365 bay.spawn_item( point( 16, 9 ), "bandages", rng( 1, 3 ) );
366 bay.spawn_item( point( 17, 9 ), "aspirin", rng( 1, 2 ) );
367 bay.save();
368 }
369
ranch_nurse_2(mission * miss)370 void mission_start::ranch_nurse_2( mission *miss )
371 {
372 //Improvements to clinic...
373 tripoint_abs_omt site = mission_util::target_om_ter_random(
374 "ranch_camp_59", 1, miss, false, RANCH_SIZE );
375 tinymap bay;
376 bay.load( project_to<coords::sm>( site ), false );
377 bay.draw_square_furn( f_counter, point( 3, 7 ), point( 5, 7 ) );
378 bay.draw_square_furn( f_rack, point( 8, 4 ), point( 8, 5 ) );
379 bay.spawn_item( point( 8, 4 ), "manual_first_aid" );
380 bay.save();
381 }
382
ranch_nurse_3(mission * miss)383 void mission_start::ranch_nurse_3( mission *miss )
384 {
385 //Improvements to clinic...
386 tripoint_abs_omt site = mission_util::target_om_ter_random(
387 "ranch_camp_50", 1, miss, false, RANCH_SIZE );
388 tinymap bay;
389 bay.load( project_to<coords::sm>( site ), false );
390 bay.draw_square_ter( t_dirt, point( 2, 16 ), point( 9, 23 ) );
391 bay.draw_square_ter( t_dirt, point( 13, 16 ), point( 20, 23 ) );
392 bay.draw_square_ter( t_dirt, point( 10, 17 ), point( 12, 23 ) );
393 bay.save();
394
395 site = mission_util::target_om_ter_random( "ranch_camp_59", 1, miss, false, RANCH_SIZE );
396 bay.load( project_to<coords::sm>( site ), false );
397 bay.draw_square_ter( t_dirt, point( 2, 0 ), point( 20, 2 ) );
398 bay.draw_square_ter( t_dirt, point( 10, 3 ), point( 12, 4 ) );
399 bay.save();
400 }
401
ranch_nurse_4(mission * miss)402 void mission_start::ranch_nurse_4( mission *miss )
403 {
404 //Improvements to clinic...
405 tripoint_abs_omt site = mission_util::target_om_ter_random(
406 "ranch_camp_50", 1, miss, false, RANCH_SIZE );
407 tinymap bay;
408 bay.load( project_to<coords::sm>( site ), false );
409 bay.draw_square_ter( t_wall_half, point( 2, 16 ), point( 9, 23 ) );
410 bay.draw_square_ter( t_dirt, point( 3, 17 ), point( 8, 22 ) );
411 bay.draw_square_ter( t_wall_half, point( 13, 16 ), point( 20, 23 ) );
412 bay.draw_square_ter( t_dirt, point( 14, 17 ), point( 19, 22 ) );
413 bay.draw_square_ter( t_wall_half, point( 10, 17 ), point( 12, 23 ) );
414 bay.draw_square_ter( t_dirt, point( 10, 18 ), point( 12, 23 ) );
415 bay.ter_set( point( 9, 19 ), t_door_frame );
416 bay.ter_set( point( 13, 19 ), t_door_frame );
417 bay.save();
418
419 site = mission_util::target_om_ter_random( "ranch_camp_59", 1, miss, false, RANCH_SIZE );
420 bay.load( project_to<coords::sm>( site ), false );
421 bay.draw_square_ter( t_wall_half, point( 4, 0 ), point( 18, 2 ) );
422 bay.draw_square_ter( t_wall_half, point( 10, 3 ), point( 12, 4 ) );
423 bay.draw_square_ter( t_dirt, point( 5, 0 ), point( 8, 2 ) );
424 bay.draw_square_ter( t_dirt, point( 10, 0 ), point( 12, 4 ) );
425 bay.draw_square_ter( t_dirt, point( 14, 0 ), point( 17, 2 ) );
426 bay.ter_set( point( 9, 1 ), t_door_frame );
427 bay.ter_set( point( 13, 1 ), t_door_frame );
428 bay.save();
429 }
430
ranch_nurse_5(mission * miss)431 void mission_start::ranch_nurse_5( mission *miss )
432 {
433 //Improvements to clinic...
434 tripoint_abs_omt site = mission_util::target_om_ter_random(
435 "ranch_camp_50", 1, miss, false, RANCH_SIZE );
436 tinymap bay;
437 bay.load( project_to<coords::sm>( site ), false );
438 bay.translate( t_wall_half, t_wall_wood );
439 bay.ter_set( point( 2, 21 ), t_window_frame );
440 bay.ter_set( point( 2, 18 ), t_window_frame );
441 bay.ter_set( point( 20, 18 ), t_window_frame );
442 bay.ter_set( point( 20, 21 ), t_window_frame );
443 bay.ter_set( point( 11, 17 ), t_window_frame );
444 bay.save();
445
446 site = mission_util::target_om_ter_random( "ranch_camp_59", 1, miss, false, RANCH_SIZE );
447 bay.load( project_to<coords::sm>( site ), false );
448 bay.translate( t_wall_half, t_wall_wood );
449 bay.draw_square_ter( t_dirt, point( 10, 0 ), point( 12, 4 ) );
450 bay.save();
451 }
452
ranch_nurse_6(mission * miss)453 void mission_start::ranch_nurse_6( mission *miss )
454 {
455 //Improvements to clinic...
456 tripoint_abs_omt site = mission_util::target_om_ter_random(
457 "ranch_camp_50", 1, miss, false, RANCH_SIZE );
458 tinymap bay;
459 bay.load( project_to<coords::sm>( site ), false );
460 bay.translate( t_window_frame, t_window_boarded_noglass );
461 bay.translate( t_door_frame, t_door_c );
462 bay.draw_square_ter( t_dirtfloor, point( 3, 17 ), point( 8, 22 ) );
463 bay.draw_square_ter( t_dirtfloor, point( 14, 17 ), point( 19, 22 ) );
464 bay.draw_square_ter( t_dirtfloor, point( 10, 18 ), point( 12, 23 ) );
465 bay.save();
466
467 site = mission_util::target_om_ter_random( "ranch_camp_59", 1, miss, false, RANCH_SIZE );
468 bay.load( project_to<coords::sm>( site ), false );
469 bay.translate( t_door_frame, t_door_c );
470 bay.draw_square_ter( t_dirtfloor, point( 5, 0 ), point( 8, 2 ) );
471 bay.draw_square_ter( t_dirtfloor, point( 10, 0 ), point( 12, 4 ) );
472 bay.draw_square_ter( t_dirtfloor, point( 14, 0 ), point( 17, 2 ) );
473 bay.save();
474 }
475
ranch_nurse_7(mission * miss)476 void mission_start::ranch_nurse_7( mission *miss )
477 {
478 //Improvements to clinic...
479 tripoint_abs_omt site = mission_util::target_om_ter_random(
480 "ranch_camp_50", 1, miss, false, RANCH_SIZE );
481 tinymap bay;
482 bay.load( project_to<coords::sm>( site ), false );
483 bay.translate( t_dirtfloor, t_floor );
484 bay.save();
485
486 site = mission_util::target_om_ter_random( "ranch_camp_59", 1, miss, false, RANCH_SIZE );
487 bay.load( project_to<coords::sm>( site ), false );
488 bay.translate( t_dirtfloor, t_floor );
489 bay.draw_square_ter( t_floor, point( 10, 5 ), point( 12, 5 ) );
490 bay.draw_square_furn( f_rack, point( 17, 0 ), point( 17, 2 ) );
491 bay.save();
492 }
493
ranch_nurse_8(mission * miss)494 void mission_start::ranch_nurse_8( mission *miss )
495 {
496 //Improvements to clinic...
497 tripoint_abs_omt site = mission_util::target_om_ter_random(
498 "ranch_camp_50", 1, miss, false, RANCH_SIZE );
499 tinymap bay;
500 bay.load( project_to<coords::sm>( site ), false );
501 bay.draw_square_furn( f_makeshift_bed, point( 4, 21 ), point( 4, 22 ) );
502 bay.draw_square_furn( f_makeshift_bed, point( 7, 21 ), point( 7, 22 ) );
503 bay.draw_square_furn( f_makeshift_bed, point( 15, 21 ), point( 15, 22 ) );
504 bay.draw_square_furn( f_makeshift_bed, point( 18, 21 ), point( 18, 22 ) );
505 bay.draw_square_furn( f_makeshift_bed, point( 4, 17 ), point( 4, 18 ) );
506 bay.draw_square_furn( f_makeshift_bed, point( 7, 17 ), point( 7, 18 ) );
507 bay.draw_square_furn( f_makeshift_bed, point( 15, 17 ), point( 15, 18 ) );
508 bay.draw_square_furn( f_makeshift_bed, point( 18, 17 ), point( 18, 18 ) );
509 bay.save();
510
511 site = mission_util::target_om_ter_random( "ranch_camp_59", 1, miss, false, RANCH_SIZE );
512 bay.load( project_to<coords::sm>( site ), false );
513 bay.translate( t_dirtfloor, t_floor );
514 bay.place_items( item_group_id( "cleaning" ), 75, point( 17, 0 ), point( 17, 2 ), true,
515 calendar::start_of_cataclysm );
516 bay.place_items( item_group_id( "surgery" ), 75, point( 15, 4 ), point( 18, 4 ), true,
517 calendar::start_of_cataclysm );
518 bay.save();
519 }
520
ranch_nurse_9(mission * miss)521 void mission_start::ranch_nurse_9( mission *miss )
522 {
523 //Improvements to clinic...
524 tripoint_abs_omt site = mission_util::target_om_ter_random(
525 "ranch_camp_50", 1, miss, false, RANCH_SIZE );
526 tinymap bay;
527 bay.load( project_to<coords::sm>( site ), false );
528 bay.furn_set( point( 3, 22 ), f_dresser );
529 bay.furn_set( point( 8, 22 ), f_dresser );
530 bay.furn_set( point( 14, 22 ), f_dresser );
531 bay.furn_set( point( 19, 22 ), f_dresser );
532 bay.furn_set( point( 3, 17 ), f_dresser );
533 bay.furn_set( point( 8, 17 ), f_dresser );
534 bay.furn_set( point( 14, 17 ), f_dresser );
535 bay.furn_set( point( 19, 17 ), f_dresser );
536 bay.place_npc( point( 16, 19 ), string_id<npc_template>( "ranch_doctor" ) );
537 bay.save();
538
539 mission_util::target_om_ter_random( "ranch_camp_59", 1, miss, false, RANCH_SIZE );
540 }
541
ranch_scavenger_1(mission * miss)542 void mission_start::ranch_scavenger_1( mission *miss )
543 {
544 tripoint_abs_omt site = mission_util::target_om_ter_random(
545 "ranch_camp_48", 1, miss, false, RANCH_SIZE );
546 tinymap bay;
547 bay.load( project_to<coords::sm>( site ), false );
548 bay.draw_square_ter( t_chainfence, point( 15, 13 ), point( 15, 22 ) );
549 bay.draw_square_ter( t_chainfence, point( 16, 13 ), point( 23, 13 ) );
550 bay.draw_square_ter( t_chainfence, point( 16, 22 ), point( 23, 22 ) );
551 bay.save();
552
553 site = mission_util::target_om_ter_random( "ranch_camp_49", 1, miss, false, RANCH_SIZE );
554 bay.load( project_to<coords::sm>( site ), false );
555 bay.place_items( item_group_id( "mechanics" ), 65, point( 9, 13 ), point( 10, 16 ), true,
556 calendar::turn_zero );
557 bay.draw_square_ter( t_chainfence, point( 0, 22 ), point( 7, 22 ) );
558 bay.draw_square_ter( t_dirt, point( 2, 22 ), point( 3, 22 ) );
559 bay.spawn_item( point( 7, 19 ), "30gal_drum" );
560 bay.save();
561 }
562
ranch_scavenger_2(mission * miss)563 void mission_start::ranch_scavenger_2( mission *miss )
564 {
565 tripoint_abs_omt site = mission_util::target_om_ter_random(
566 "ranch_camp_48", 1, miss, false, RANCH_SIZE );
567 tinymap bay;
568 bay.load( project_to<coords::sm>( site ), false );
569 bay.add_vehicle( vproto_id( "car_chassis" ), point( 20, 15 ), 0_degrees );
570 bay.draw_square_ter( t_wall_half, point( 18, 19 ), point( 21, 22 ) );
571 bay.draw_square_ter( t_dirt, point( 19, 20 ), point( 20, 21 ) );
572 bay.ter_set( point( 19, 19 ), t_door_frame );
573 bay.save();
574
575 site = mission_util::target_om_ter_random( "ranch_camp_49", 1, miss, false, RANCH_SIZE );
576 bay.load( project_to<coords::sm>( site ), false );
577 bay.place_items( item_group_id( "mischw" ), 65, point( 12, 13 ), point( 13, 16 ), true,
578 calendar::start_of_cataclysm );
579 bay.draw_square_ter( t_chaingate_l, point( 2, 22 ), point( 3, 22 ) );
580 bay.spawn_item( point( 7, 20 ), "30gal_drum" );
581 bay.save();
582 }
583
ranch_scavenger_3(mission * miss)584 void mission_start::ranch_scavenger_3( mission *miss )
585 {
586 tripoint_abs_omt site = mission_util::target_om_ter_random(
587 "ranch_camp_48", 1, miss, false, RANCH_SIZE );
588 tinymap bay;
589 bay.load( project_to<coords::sm>( site ), false );
590 bay.translate( t_door_frame, t_door_locked );
591 bay.translate( t_wall_half, t_wall_wood );
592 bay.draw_square_ter( t_dirtfloor, point( 19, 20 ), point( 20, 21 ) );
593 bay.spawn_item( point( 16, 21 ), "wheel_wide" );
594 bay.spawn_item( point( 17, 21 ), "wheel_wide" );
595 bay.spawn_item( point( 23, 18 ), "v8_combustion" );
596 bay.furn_set( point( 23, 17 ), furn_str_id( "f_arcade_machine" ) );
597 bay.ter_set( point( 23, 16 ), ter_str_id( "t_machinery_light" ) );
598 bay.furn_set( point( 20, 21 ), f_woodstove );
599 bay.save();
600
601 site = mission_util::target_om_ter_random( "ranch_camp_49", 1, miss, false, RANCH_SIZE );
602 bay.load( project_to<coords::sm>( site ), false );
603 bay.place_items( item_group_id( "mischw" ), 65, point( 2, 10 ), point( 4, 10 ), true,
604 calendar::start_of_cataclysm );
605 bay.place_items( item_group_id( "mischw" ), 65, point( 2, 13 ), point( 4, 13 ), true,
606 calendar::start_of_cataclysm );
607 bay.furn_set( point( 1, 15 ), f_fridge );
608 bay.spawn_item( point( 2, 15 ), "hdframe" );
609 bay.furn_set( point( 3, 15 ), f_washer );
610 bay.save();
611 }
612
place_book(mission *)613 void mission_start::place_book( mission * )
614 {
615 }
616
reveal_refugee_center(mission * miss)617 void mission_start::reveal_refugee_center( mission *miss )
618 {
619 mission_target_params t;
620 t.overmap_terrain = "refctr_S3e";
621 t.overmap_special = overmap_special_id( "evac_center" );
622 t.mission_pointer = miss;
623 t.search_range = 0;
624 t.reveal_radius = 3;
625
626 const cata::optional<tripoint_abs_omt> target_pos = mission_util::assign_mission_target( t );
627
628 if( !target_pos ) {
629 add_msg( _( "You don't know where the address could be…" ) );
630 return;
631 }
632
633 const tripoint_abs_omt source_road = overmap_buffer.find_closest(
634 get_player_character().global_omt_location(), "road",
635 3, false );
636 const tripoint_abs_omt dest_road = overmap_buffer.find_closest( *target_pos, "road", 3, false );
637
638 if( overmap_buffer.reveal_route( source_road, dest_road, 1, true ) ) {
639 add_msg( _( "You mark the refugee center and the road that leads to it…" ) );
640 } else {
641 add_msg( _( "You mark the refugee center, but you have no idea how to get there by road…" ) );
642 }
643 }
644
645 // Creates multiple lab consoles near tripoint place, which must have its z-level set to where consoles should go.
create_lab_consoles(mission * miss,const tripoint_abs_omt & place,const std::string & otype,int security,const std::string & comp_name,const std::string & download_name)646 void static create_lab_consoles(
647 mission *miss, const tripoint_abs_omt &place, const std::string &otype, int security,
648 const std::string &comp_name, const std::string &download_name )
649 {
650 // Drop four computers in nearby lab spaces so the player can stumble upon one of them.
651 for( int i = 0; i < 4; ++i ) {
652 tripoint_abs_omt om_place = mission_util::target_om_ter_random(
653 otype, -1, miss, false, 4, place );
654
655 tinymap compmap;
656 compmap.load( project_to<coords::sm>( om_place ), false );
657
658 tripoint comppoint = find_potential_computer_point( compmap );
659
660 computer *tmpcomp = compmap.add_computer( comppoint, comp_name, security );
661 tmpcomp->set_mission( miss->get_id() );
662 tmpcomp->add_option( download_name, COMPACT_DOWNLOAD_SOFTWARE, security );
663 tmpcomp->add_failure( COMPFAIL_ALARM );
664 tmpcomp->add_failure( COMPFAIL_DAMAGE );
665 tmpcomp->add_failure( COMPFAIL_MANHACKS );
666
667 compmap.save();
668 }
669 }
670
create_lab_console(mission * miss)671 void mission_start::create_lab_console( mission *miss )
672 {
673 Character &player_character = get_player_character();
674 // Pick a lab that has spaces on z = -1: e.g., in hidden labs.
675 tripoint_abs_omt loc = player_character.global_omt_location();
676 loc.z() = -1;
677 const tripoint_abs_omt place = overmap_buffer.find_closest( loc, "lab", 0, false );
678
679 create_lab_consoles( miss, place, "lab", 2, _( "Workstation" ),
680 _( "Download Memory Contents" ) );
681
682 // Target the lab entrance.
683 const tripoint_abs_omt target = mission_util::target_closest_lab_entrance( place, 2, miss );
684 mission_util::reveal_road( player_character.global_omt_location(), target, overmap_buffer );
685 }
686
create_hidden_lab_console(mission * miss)687 void mission_start::create_hidden_lab_console( mission *miss )
688 {
689 Character &player_character = get_player_character();
690 // Pick a hidden lab entrance.
691 tripoint_abs_omt loc = player_character.global_omt_location();
692 loc.z() = -1;
693 tripoint_abs_omt place =
694 mission_util::target_om_ter_random( "basement_hidden_lab_stairs", -1, miss, false, 0, loc );
695 place.z() = -2; // then go down 1 z-level to place consoles.
696
697 create_lab_consoles( miss, place, "lab", 3, _( "Workstation" ),
698 _( "Download Encryption Routines" ) );
699
700 // Target the lab entrance.
701 const tripoint_abs_omt target = mission_util::target_closest_lab_entrance( place, 2, miss );
702 mission_util::reveal_road( player_character.global_omt_location(), target, overmap_buffer );
703 }
704
create_ice_lab_console(mission * miss)705 void mission_start::create_ice_lab_console( mission *miss )
706 {
707 Character &player_character = get_player_character();
708 // Pick an ice lab with spaces on z = -4.
709 tripoint_abs_omt loc = player_character.global_omt_location();
710 loc.z() = -4;
711 const tripoint_abs_omt place = overmap_buffer.find_closest( loc, "ice_lab", 0, false );
712
713 create_lab_consoles( miss, place, "ice_lab", 3, _( "Durable Storage Archive" ),
714 _( "Download Archives" ) );
715
716 // Target the lab entrance.
717 const tripoint_abs_omt target = mission_util::target_closest_lab_entrance( place, 2, miss );
718 mission_util::reveal_road( player_character.global_omt_location(), target, overmap_buffer );
719 }
720
has_console(const tripoint_abs_omt & location,const int mission_id)721 static bool has_console( const tripoint_abs_omt &location, const int mission_id )
722 {
723 tinymap compmap;
724 compmap.load( project_to<coords::sm>( location ), false );
725 cata::optional<tripoint> comppoint;
726
727 for( const tripoint &point : compmap.points_on_zlevel() ) {
728 if( compmap.ter( point ) == t_console ) {
729 comppoint = point;
730 break;
731 }
732 }
733
734 if( !comppoint ) {
735 return false;
736 }
737
738 computer *tmpcomp = compmap.computer_at( *comppoint );
739 tmpcomp->set_mission( mission_id );
740 tmpcomp->add_option( _( "Download Routing Software" ), COMPACT_DOWNLOAD_SOFTWARE, 0 );
741
742 compmap.save();
743 return true;
744 }
745
reveal_lab_train_depot(mission * miss)746 void mission_start::reveal_lab_train_depot( mission *miss )
747 {
748 Character &player_character = get_player_character();
749 // Find and prepare lab location.
750 tripoint_abs_omt loc = player_character.global_omt_location();
751 loc.z() = -4; // tunnels are at z = -4
752 tripoint_abs_omt place;
753 const int mission_id = miss->get_id();
754
755 omt_find_params params = {{ {{ std::make_pair( "lab_train_depot", ot_match_type::type ) }} }};
756 const std::vector<tripoint_abs_omt> all_omts_near = overmap_buffer.find_all( loc, params );
757 // sort it by range
758 std::multimap<int, tripoint_abs_omt> omts_by_range;
759 for( const tripoint_abs_omt &location : all_omts_near ) {
760 omts_by_range.emplace( rl_dist( loc, location ), location );
761 }
762 for( const std::pair<const int, tripoint_abs_omt> &location : omts_by_range ) {
763 if( has_console( location.second, mission_id ) ) {
764 place = location.second;
765 break;
766 }
767 }
768
769 // Target the lab entrance.
770 const tripoint_abs_omt target = mission_util::target_closest_lab_entrance( place, 2, miss );
771 mission_util::reveal_road( player_character.global_omt_location(), target, overmap_buffer );
772 }
773