Skip to content

Commit

Permalink
feat: add reproduce area options in debug-map menu (cataclysmbnteam#4311
Browse files Browse the repository at this point in the history
)

* feat: add reproduce area options in debug-map menu

Extends the map submenu of the debug menu with an option to force
monsters in a rectangular area to reproduce.

cow goes moo, sheep goes bah

* refactor: separate reproduce check and execution

---------

Co-authored-by: scarf <greenscarf005@gmail.com>
  • Loading branch information
ekaratzas and scarf005 authored Mar 8, 2024
1 parent b86d593 commit c8d4601
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 35 deletions.
63 changes: 46 additions & 17 deletions src/debug_menu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ enum debug_menu_index {
DEBUG_SPAWN_NPC,
DEBUG_SPAWN_MON,
DEBUG_GAME_STATE,
DEBUG_REPRODUCE_AREA,
DEBUG_KILL_AREA,
DEBUG_KILL_NPCS,
DEBUG_MUTATE,
Expand Down Expand Up @@ -295,6 +296,7 @@ static int map_uilist()
{
const std::vector<uilist_entry> uilist_initializer = {
{ uilist_entry( DEBUG_REVEAL_MAP, true, 'r', _( "Reveal map" ) ) },
{ uilist_entry( DEBUG_REPRODUCE_AREA, true, 'R', _( "Reproduce in Area" ) ) },
{ uilist_entry( DEBUG_KILL_AREA, true, 'a', _( "Kill in Area" ) ) },
{ uilist_entry( DEBUG_KILL_NPCS, true, 'k', _( "Kill NPCs" ) ) },
{ uilist_entry( DEBUG_MAP_EDITOR, true, 'M', _( "Map editor" ) ) },
Expand Down Expand Up @@ -1381,6 +1383,33 @@ void benchmark( const int max_difference, bench_kind kind )
difference / 1000.0, 1000.0 * draw_counter / static_cast<double>( difference ) );
}

// prompts player to select 2 points that will form a rectangular area
static std::optional<tripoint_range<tripoint>> select_area()
{
static_popup popup;
popup.on_top( true );
popup.message( "%s", _( "Select first point." ) );

tripoint initial_pos = g->u.pos();
const look_around_result first = g->look_around( false, initial_pos, initial_pos,
false, true, false, false, tripoint_zero, true );

if( !first.position ) {
return std::nullopt;
}

popup.message( "%s", _( "Select second point." ) );
const look_around_result second = g->look_around( false, initial_pos, *first.position,
true, true, false, false, tripoint_zero, true );

if( !second.position ) {
return std::nullopt;
}

return get_map().points_in_rectangle(
first.position.value(), second.position.value() );
}

void debug()
{
bool debug_menu_has_hotkey = hotkey_for_action( ACTION_DEBUG, false ) != -1;
Expand Down Expand Up @@ -1484,30 +1513,30 @@ void debug()
g->disp_NPCs();
break;
}
case DEBUG_KILL_AREA: {
static_popup popup;
popup.on_top( true );
popup.message( "%s", _( "Select first point." ) );

tripoint initial_pos = g->u.pos();
const look_around_result first = g->look_around( false, initial_pos, initial_pos,
false, true, false, false, tripoint_zero, true );

if( !first.position ) {
case DEBUG_REPRODUCE_AREA: {
const std::optional<tripoint_range<tripoint>> points_opt = select_area();
if( !points_opt.has_value() ) {
break;
}

popup.message( "%s", _( "Select second point." ) );
const look_around_result second = g->look_around( false, initial_pos, *first.position,
true, true, false, false, tripoint_zero, true );
const tripoint_range<tripoint> points = points_opt.value();
std::vector<Creature *> creatures = g->get_creatures_if(
[&points]( const Creature & critter ) -> bool {
return !critter.is_avatar() && critter.is_monster() && points.is_point_inside( critter.pos() );
} );

if( !second.position ) {
for( Creature *critter : creatures ) {
static_cast<monster *>( critter )->reproduce();
}
}
break;
case DEBUG_KILL_AREA: {
const std::optional<tripoint_range<tripoint>> points_opt = select_area();
if( !points_opt.has_value() ) {
break;
}

const tripoint_range<tripoint> points = get_map().points_in_rectangle(
first.position.value(), second.position.value() );

const tripoint_range<tripoint> points = points_opt.value();
std::vector<Creature *> creatures = g->get_creatures_if(
[&points]( const Creature & critter ) -> bool {
return !critter.is_avatar() && points.is_point_inside( critter.pos() );
Expand Down
47 changes: 29 additions & 18 deletions src/monster.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -465,9 +465,6 @@ void monster::try_upgrade( bool pin_time )

void monster::try_reproduce()
{
if( !reproduces ) {
return;
}
// This can happen if the monster type has changed (from reproducing to non-reproducing monster)
if( !type->baby_timer ) {
return;
Expand Down Expand Up @@ -510,26 +507,40 @@ void monster::try_reproduce()

chance += 2;

// wildlife creatures that are pets of the player will spawn pet offspring
const spawn_disposition disposition = is_pet() ? spawn_disposition::SpawnDisp_Pet :
spawn_disposition::SpawnDisp_Default;
if( season_match && female && one_in( chance ) ) {
int spawn_cnt = rng( 1, type->baby_count );
if( type->baby_monster ) {
g->m.add_spawn( type->baby_monster, spawn_cnt, pos(), disposition );
} else {
detached_ptr<item> item_to_spawn = item::spawn( type->baby_egg, *baby_timer, spawn_cnt );
if( disposition == spawn_disposition::SpawnDisp_Pet ) {
item_to_spawn->set_flag( flag_SPAWN_FRIENDLY );
}
g->m.add_item_or_charges( pos(), std::move( item_to_spawn ), true );
}
if( ( season_match && female && one_in( chance ) ) ) {
reproduce();
}

*baby_timer += *type->baby_timer;
}
}

void monster::reproduce()
{
if( !reproduces ) {
return;
}

const int spawn_cnt = rng( 1, type->baby_count );
const auto birth = baby_timer ? *baby_timer : calendar::turn;

// wildlife creatures that are pets of the player will spawn pet offspring
const spawn_disposition disposition = is_pet()
? spawn_disposition::SpawnDisp_Pet
: spawn_disposition::SpawnDisp_Default;

if( type->baby_monster ) {
g->m.add_spawn( type->baby_monster, spawn_cnt, pos(), disposition );
} else {
detached_ptr<item> item_to_spawn = item::spawn( type->baby_egg, birth, spawn_cnt );

if( disposition == spawn_disposition::SpawnDisp_Pet ) {
item_to_spawn->set_flag( flag_SPAWN_FRIENDLY );
}

g->m.add_item_or_charges( pos(), std::move( item_to_spawn ), true );
}
}

void monster::refill_udders()
{
if( type->starting_ammo.empty() ) {
Expand Down
3 changes: 3 additions & 0 deletions src/monster.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,10 @@ class monster : public Creature, public location_visitable<monster>
int get_upgrade_time() const;
void allow_upgrade();
void try_upgrade( bool pin_time );
/// Check if monster is ready to reproduce and do so if possible, refreshing baby timer.
void try_reproduce();
/// Immediatly spawn an offspring without mutating baby timer.
void reproduce();
void refill_udders();
void spawn( const tripoint &p );
m_size get_size() const override;
Expand Down

0 comments on commit c8d4601

Please sign in to comment.