@@ -210,6 +210,7 @@ static const ter_str_id ter_t_door_glass_frosted_c( "t_door_glass_frosted_c" );
210
210
static const ter_str_id ter_t_door_metal_c ( " t_door_metal_c" );
211
211
static const ter_str_id ter_t_door_metal_locked ( " t_door_metal_locked" );
212
212
static const ter_str_id ter_t_floor ( " t_floor" );
213
+ static const ter_str_id ter_t_floor_burnt ( " t_floor_burnt" );
213
214
static const ter_str_id ter_t_fungus_floor_in ( " t_fungus_floor_in" );
214
215
static const ter_str_id ter_t_fungus_wall ( " t_fungus_wall" );
215
216
static const ter_str_id ter_t_grass ( " t_grass" );
@@ -225,6 +226,7 @@ static const ter_str_id ter_t_strconc_floor( "t_strconc_floor" );
225
226
static const ter_str_id ter_t_thconc_floor ( " t_thconc_floor" );
226
227
static const ter_str_id ter_t_thconc_floor_olight ( " t_thconc_floor_olight" );
227
228
static const ter_str_id ter_t_vat ( " t_vat" );
229
+ static const ter_str_id ter_t_wall_burnt ( " t_wall_burnt" );
228
230
static const ter_str_id ter_t_water_sh ( " t_water_sh" );
229
231
230
232
static const trait_id trait_NPC_STATIC_NPC ( " NPC_STATIC_NPC" );
@@ -419,38 +421,62 @@ static void place_bool_pools( map &md, const tripoint_bub_ms ¤t_tile,
419
421
}
420
422
}
421
423
422
- static void GENERATOR_riot_damage ( map &md, const tripoint_abs_omt &p )
423
- {
424
- std::list<tripoint_bub_ms> all_points_in_map;
425
-
424
+ struct generator_vars {
425
+ int scaling_days_start;
426
+ int scaling_days_end;
427
+ int num_attempts;
428
+ int percent_chance;
429
+ int min_intensity;
430
+ int max_intensity;
431
+ };
426
432
427
- int days_since_cataclysm = to_days<int >( calendar::turn - calendar::start_of_cataclysm );
433
+ static void GENERATOR_bash_damage ( map &md,
434
+ std::list<tripoint_bub_ms> &all_points_in_map,
435
+ int days_since_cataclysm )
436
+ {
437
+ // Later, this will be loaded from json.
438
+ generator_vars bash_vars{};
439
+ bash_vars.scaling_days_start = 0 ; // irrelevant for this one
440
+ bash_vars.scaling_days_end = days_since_cataclysm; // irrelevant for this one
441
+ bash_vars.num_attempts = 250 ; // Roughly half as many attempts as old version, may need tweaking
442
+ bash_vars.percent_chance = 10 ;
443
+ bash_vars.min_intensity = 6 ; // For this generator: Bash damage
444
+ bash_vars.max_intensity = 60 ; // For this generator: Bash damage
428
445
429
- // Placeholder / FIXME
430
- // This assumes that we're only dealing with regular 24x24 OMTs. That is likely not the case.
431
- for ( int i = 0 ; i < SEEX * 2 ; i++ ) {
432
- for ( int n = 0 ; n < SEEY * 2 ; n++ ) {
433
- tripoint_bub_ms current_tile ( i, n, p.z () );
434
- all_points_in_map.push_back ( current_tile );
446
+ for ( int i = 0 ; i < bash_vars.num_attempts ; i++ ) {
447
+ if ( !x_in_y ( bash_vars.percent_chance , 100 ) ) {
448
+ continue ; // failed roll
435
449
}
436
- }
437
- for ( size_t i = 0 ; i < all_points_in_map.size (); i++ ) {
438
- // Pick a tile at random!
439
- tripoint_bub_ms current_tile = random_entry ( all_points_in_map );
440
-
441
- // Do nothing at random!;
442
- if ( x_in_y ( 10 , 100 ) ) {
450
+ const tripoint_bub_ms current_tile = random_entry ( all_points_in_map );
451
+ if ( md.has_flag_ter ( ter_furn_flag::TFLAG_NATURAL_UNDERGROUND, current_tile ) ) {
443
452
continue ;
444
453
}
445
- // Skip naturally occuring underground wall tiles
454
+ md.bash ( current_tile, rng ( bash_vars.min_intensity , bash_vars.max_intensity ) );
455
+ }
456
+ }
457
+
458
+ static void GENERATOR_move_items ( map &md,
459
+ std::list<tripoint_bub_ms> &all_points_in_map,
460
+ int days_since_cataclysm )
461
+ {
462
+ // Later, this will be loaded from json.
463
+ generator_vars mover_vars{};
464
+ mover_vars.scaling_days_start = 0 ; // irrelevant for this one, currently.
465
+ mover_vars.scaling_days_end = days_since_cataclysm; // irrelevant for this one
466
+
467
+ // NOTE: Each tile of items is fully iterated over, to eliminate the effects of stack ordering.
468
+ // Otherwise we would be biased towards the front of the stack
469
+ mover_vars.num_attempts = 250 ; // Roughly half as many attempts as old version, may need tweaking
470
+
471
+ mover_vars.percent_chance = 10 ;
472
+ mover_vars.min_intensity = 0 ; // For this generator: Min distance moved. Note: NOT IMPLEMENTED
473
+ mover_vars.max_intensity = 3 ; // For this generator: Max distance moved
474
+
475
+ for ( int i = 0 ; i < mover_vars.num_attempts ; i++ ) {
476
+ const tripoint_bub_ms current_tile = random_entry ( all_points_in_map );
446
477
if ( md.has_flag_ter ( ter_furn_flag::TFLAG_NATURAL_UNDERGROUND, current_tile ) ) {
447
478
continue ;
448
479
}
449
- // Bash stuff at random!
450
- if ( x_in_y ( 20 , 100 ) ) {
451
- md.bash ( current_tile, rng ( 6 , 60 ) );
452
- }
453
- // Move stuff at random!
454
480
auto item_iterator = md.i_at ( current_tile.xy () ).begin ();
455
481
while ( item_iterator != md.i_at ( current_tile.xy () ).end () ) {
456
482
// Some items must not be moved out of SEALED CONTAINER
@@ -463,11 +489,13 @@ static void GENERATOR_riot_damage( map &md, const tripoint_abs_omt &p )
463
489
continue ;
464
490
}
465
491
}
466
- if ( x_in_y ( 10 , 100 ) ) {
492
+
493
+ if ( x_in_y ( mover_vars.percent_chance , 100 ) ) {
467
494
// pick a new spot...
468
- tripoint_bub_ms destination_tile ( current_tile.x () + rng ( -3 , 3 ),
469
- current_tile.y () + rng ( -3 , 3 ),
470
- current_tile.z () );
495
+ tripoint_bub_ms destination_tile (
496
+ current_tile.x () + rng ( -mover_vars.max_intensity , mover_vars.max_intensity ),
497
+ current_tile.y () + rng ( -mover_vars.max_intensity , mover_vars.max_intensity ),
498
+ current_tile.z () );
471
499
// oops, don't place out of bounds. just skip moving
472
500
const bool outbounds_X = destination_tile.x () < 0 || destination_tile.x () >= SEEX * 2 ;
473
501
const bool outbounds_Y = destination_tile.y () < 0 || destination_tile.y () >= SEEY * 2 ;
@@ -486,6 +514,155 @@ static void GENERATOR_riot_damage( map &md, const tripoint_abs_omt &p )
486
514
} else {
487
515
item_iterator++;
488
516
}
517
+
518
+ }
519
+ }
520
+
521
+ }
522
+
523
+ static void GENERATOR_add_fire ( map &md,
524
+ std::list<tripoint_bub_ms> &all_points_in_map,
525
+ int days_since_cataclysm )
526
+ {
527
+ // Later, this will be loaded from json.
528
+ generator_vars fire_vars{};
529
+ fire_vars.scaling_days_start = 0 ;
530
+ fire_vars.scaling_days_end = 14 ;
531
+
532
+ // Placeholder. Number selected so that the # of fires is close to the old implementation.
533
+ fire_vars.num_attempts = 2 ;
534
+
535
+ // FIXME? I'm concerned by the fact that the initial chance scales higher the later the last scaling day is.
536
+ // This is not great, but it ramps down linearly without relying on magic numbers.
537
+ fire_vars.percent_chance = std::max ( fire_vars.scaling_days_end - days_since_cataclysm, 0 );
538
+
539
+ fire_vars.min_intensity = 1 ; // For this generator: field intensity
540
+ fire_vars.max_intensity = 3 ; // For this generator: field intensity
541
+
542
+ for ( int i = 0 ; i < fire_vars.num_attempts ; i++ ) {
543
+ if ( !x_in_y ( fire_vars.percent_chance , 100 ) ) {
544
+ continue ; // failed roll
545
+ }
546
+ const tripoint_bub_ms current_tile = random_entry ( all_points_in_map );
547
+ if ( md.has_flag_ter ( ter_furn_flag::TFLAG_NATURAL_UNDERGROUND, current_tile ) ) {
548
+ continue ;
549
+ }
550
+
551
+ if ( x_in_y ( fire_vars.percent_chance , 100 ) ) {
552
+ // FIXME: Magic number 3. Replace with some value loaded into generator_vars?
553
+ if ( md.has_flag_ter_or_furn ( ter_furn_flag::TFLAG_FLAMMABLE, current_tile ) ||
554
+ md.has_flag_ter_or_furn ( ter_furn_flag::TFLAG_FLAMMABLE_ASH, current_tile ) ||
555
+ md.has_flag_ter_or_furn ( ter_furn_flag::TFLAG_FLAMMABLE_HARD, current_tile ) ||
556
+ days_since_cataclysm < 3 ) {
557
+ // Only place fire on flammable surfaces unless the cataclysm started very recently
558
+ // Note that most floors are FLAMMABLE_HARD, this is fine. This check is primarily geared
559
+ // at preventing fire in the middle of roads or parking lots.
560
+ md.add_field ( current_tile, field_fd_fire,
561
+ rng ( fire_vars.min_intensity , fire_vars.max_intensity ) );
562
+ }
563
+ }
564
+
565
+ }
566
+
567
+ }
568
+
569
+ static void GENERATOR_pre_burn ( map &md,
570
+ std::list<tripoint_bub_ms> &all_points_in_map,
571
+ int days_since_cataclysm )
572
+ {
573
+ // Later, this will be loaded from json.
574
+ generator_vars burnt_vars{};
575
+ // Fires are still raging around this time, but some start appearing
576
+ // Never appears before this date
577
+ burnt_vars.scaling_days_start = 3 ;
578
+
579
+ burnt_vars.scaling_days_end = 14 ; // Continues appearing at maximum appearance rate after this day
580
+ burnt_vars.num_attempts = 1 ; // Currently only applied to the whole map, so one pass.
581
+
582
+ burnt_vars.min_intensity = 6 ; // For this generator: % chance at start day
583
+ burnt_vars.max_intensity = 28 ; // For this generator: % chance at end day
584
+
585
+ // between start and end day we linearly interpolate.
586
+ double lerp_scalar = static_cast <double >(
587
+ static_cast <double >( days_since_cataclysm - burnt_vars.scaling_days_start ) /
588
+ static_cast <double >( burnt_vars.scaling_days_end - burnt_vars.scaling_days_start ) );
589
+ burnt_vars.percent_chance = lerp ( burnt_vars.min_intensity , burnt_vars.max_intensity , lerp_scalar );
590
+ // static values outside that range. Note we do not use std::clamp because the chance is *0* until the start day is reached
591
+ if ( days_since_cataclysm < burnt_vars.scaling_days_start ) {
592
+ burnt_vars.percent_chance = 0 ;
593
+ } else if ( days_since_cataclysm >= burnt_vars.scaling_days_end ) {
594
+ burnt_vars.percent_chance = burnt_vars.max_intensity ;
595
+ }
596
+
597
+ for ( int i = 0 ; i < burnt_vars.num_attempts ; i++ ) {
598
+ if ( !x_in_y ( burnt_vars.percent_chance , 100 ) ) {
599
+ continue ; // failed roll
600
+ }
601
+ for ( tripoint_bub_ms current_tile : all_points_in_map ) {
602
+ if ( md.has_flag_ter ( ter_furn_flag::TFLAG_NATURAL_UNDERGROUND, current_tile ) ) {
603
+ continue ;
604
+ }
605
+ if ( md.has_flag_ter ( ter_furn_flag::TFLAG_WALL, current_tile ) ) {
606
+ // burnt wall
607
+ md.ter_set ( current_tile.xy (), ter_t_wall_burnt );
608
+ } else if ( md.has_flag_ter ( ter_furn_flag::TFLAG_INDOORS, current_tile ) ||
609
+ md.has_flag_ter ( ter_furn_flag::TFLAG_DOOR, current_tile ) ) {
610
+ // if we're indoors but we're not a wall, then we must be a floor.
611
+ // doorways also get burned to the ground.
612
+ md.ter_set ( current_tile.xy (), ter_t_floor_burnt );
613
+ } else if ( !md.has_flag_ter ( ter_furn_flag::TFLAG_INDOORS, current_tile ) ) {
614
+ // if we're outside on ground level, burn it to dirt.
615
+ if ( current_tile.z () == 0 ) {
616
+ md.ter_set ( current_tile.xy (), ter_t_dirt );
617
+ }
618
+ }
619
+
620
+ // destroy any furniture that is in the tile. it's been burned, after all.
621
+ md.furn_set ( current_tile.xy (), furn_str_id::NULL_ID () );
622
+
623
+ // destroy all items in the tile.
624
+ md.i_clear ( current_tile.xy () );
625
+ }
626
+ }
627
+ }
628
+
629
+ static void GENERATOR_riot_damage ( map &md, const tripoint_abs_omt &p, bool is_a_road )
630
+ {
631
+ std::list<tripoint_bub_ms> all_points_in_map;
632
+
633
+
634
+ int days_since_cataclysm = to_days<int >( calendar::turn - calendar::start_of_cataclysm );
635
+
636
+ // Placeholder / FIXME
637
+ // This assumes that we're only dealing with regular 24x24 OMTs. That is likely not the case.
638
+ for ( int i = 0 ; i < SEEX * 2 ; i++ ) {
639
+ for ( int n = 0 ; n < SEEY * 2 ; n++ ) {
640
+ tripoint_bub_ms current_tile ( i, n, p.z () );
641
+ all_points_in_map.push_back ( current_tile );
642
+ }
643
+ }
644
+
645
+ // Run sub generators associated with this generator. Currently hardcoded.
646
+ GENERATOR_bash_damage ( md, all_points_in_map, days_since_cataclysm );
647
+ GENERATOR_move_items ( md, all_points_in_map, days_since_cataclysm );
648
+ GENERATOR_add_fire ( md, all_points_in_map, days_since_cataclysm );
649
+ // HACK: Don't burn roads to the ground! This should be resolved when the system is moved to json
650
+ if ( !is_a_road ) {
651
+ GENERATOR_pre_burn ( md, all_points_in_map, days_since_cataclysm );
652
+ }
653
+
654
+ // NOTE: Below currently only runs for bloodstains.
655
+ for ( size_t i = 0 ; i < all_points_in_map.size (); i++ ) {
656
+ // Pick a tile at random!
657
+ tripoint_bub_ms current_tile = random_entry ( all_points_in_map );
658
+
659
+ // Do nothing at random!;
660
+ if ( x_in_y ( 10 , 100 ) ) {
661
+ continue ;
662
+ }
663
+ // Skip naturally occuring underground wall tiles
664
+ if ( md.has_flag_ter ( ter_furn_flag::TFLAG_NATURAL_UNDERGROUND, current_tile ) ) {
665
+ continue ;
489
666
}
490
667
// Set some fields at random!
491
668
if ( x_in_y ( 15 , 1000 ) ) {
@@ -502,20 +679,6 @@ static void GENERATOR_riot_damage( map &md, const tripoint_abs_omt &p )
502
679
place_bool_pools ( md, current_tile, days_since_cataclysm );
503
680
}
504
681
}
505
-
506
- // Randomly spawn fires, with the chance decreasing from 1 in 2000 to 1 in 10,000 over the
507
- // course of 14 days
508
- if ( x_in_y ( 1 , std::min ( 2000 + 571 * days_since_cataclysm, 10000 ) ) ) {
509
- if ( md.has_flag_ter_or_furn ( ter_furn_flag::TFLAG_FLAMMABLE, current_tile ) ||
510
- md.has_flag_ter_or_furn ( ter_furn_flag::TFLAG_FLAMMABLE_ASH, current_tile ) ||
511
- md.has_flag_ter_or_furn ( ter_furn_flag::TFLAG_FLAMMABLE_HARD, current_tile ) ||
512
- days_since_cataclysm < 3 ) {
513
- // Only place fire on flammable surfaces unless the cataclysm started very recently
514
- // Note that most floors are FLAMMABLE_HARD, this is fine. This check is primarily geared
515
- // at preventing fire in the middle of roads or parking lots.
516
- md.add_field ( current_tile, field_fd_fire );
517
- }
518
- }
519
682
}
520
683
}
521
684
@@ -693,10 +856,11 @@ void map::generate( const tripoint_abs_omt &p, const time_point &when, bool save
693
856
if ( any_missing || !save_results ) {
694
857
const tripoint_abs_omt omt_point = { p.x (), p.y (), gridz };
695
858
oter_id omt = overmap_buffer.ter ( omt_point );
696
- if ( omt->has_flag (
697
- oter_flags::pp_generate_riot_damage ) || ( omt->has_flag ( oter_flags::road ) &&
698
- overmap_buffer.is_in_city ( omt_point ) ) ) {
699
- GENERATOR_riot_damage ( *this , omt_point );
859
+ if ( omt->has_flag ( oter_flags::pp_generate_riot_damage ) && !omt->has_flag ( oter_flags::road ) ) {
860
+ GENERATOR_riot_damage ( *this , omt_point, false );
861
+ } else if ( omt->has_flag ( oter_flags::road ) && overmap_buffer.is_in_city ( omt_point ) ) {
862
+ // HACK: Hardcode running only certain sub-generators on roads
863
+ GENERATOR_riot_damage ( *this , omt_point, true );
700
864
}
701
865
}
702
866
}
0 commit comments