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