Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add reproduce area options in debug-map menu #4311

Merged
merged 3 commits into from
Mar 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading