Skip to content

Commit 72a5b8a

Browse files
authored
Merge pull request CleverRaven#76269 from RenechCDDA/debug_menu_hordes
[DEBUG] Modify hordes through overmap editor
2 parents 574a3ce + 7bf6ca4 commit 72a5b8a

File tree

8 files changed

+217
-12
lines changed

8 files changed

+217
-12
lines changed

data/raw/keybindings.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1241,6 +1241,13 @@
12411241
"name": "Teleport to cursor",
12421242
"bindings": [ { "input_method": "keyboard_any", "key": "d" } ]
12431243
},
1244+
{
1245+
"type": "keybinding",
1246+
"id": "MODIFY_HORDE",
1247+
"category": "OVERMAP",
1248+
"name": "Modify existing horde or place new one",
1249+
"bindings": [ { "input_method": "keyboard_any", "key": "p" } ]
1250+
},
12441251
{
12451252
"type": "keybinding",
12461253
"name": "View missions",

src/debug_menu.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
class Character;
1414
class Creature;
15+
struct mongroup;
1516
struct tripoint;
1617

1718
template <typename E> struct enum_traits;
@@ -121,6 +122,8 @@ void wishitem( Character *you = nullptr );
121122
void wishitem( Character *you, const tripoint & );
122123
void wishitem( Character *you, const tripoint_bub_ms & );
123124
void wishmonster( const std::optional<tripoint> &p );
125+
void wishmonstergroup( tripoint_abs_omt &loc );
126+
void wishmonstergroup_mon_selection( mongroup &group );
124127
void wishmutate( Character *you );
125128
void wishbionics( Character *you );
126129
/*

src/mongroup.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,11 @@ void MonsterGroupManager::FinalizeMonsterGroups()
449449
}
450450
}
451451

452+
std::map<mongroup_id, MonsterGroup> &MonsterGroupManager::Get_all_Groups()
453+
{
454+
return MonsterGroupManager::monsterGroupMap;
455+
}
456+
452457
void MonsterGroupManager::LoadMonsterGroup( const JsonObject &jo )
453458
{
454459
float mon_upgrade_factor = get_option<float>( "MONSTER_UPGRADE_FACTOR" );

src/mongroup.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,9 @@ class MonsterGroupManager
224224

225225
static bool is_animal( const mongroup_id &group );
226226

227+
// Public getter for private monsterGroupMap, do not use if you don't know what you're doing.
228+
static std::map<mongroup_id, MonsterGroup> &Get_all_Groups();
229+
227230
private:
228231
static std::map<mongroup_id, MonsterGroup> monsterGroupMap;
229232
using t_string_set = std::set<std::string>;

src/overmap.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7553,6 +7553,23 @@ void overmap::debug_force_add_group( const mongroup &group )
75537553
add_mon_group( group, 1 );
75547554
}
75557555

7556+
std::vector<std::reference_wrapper<mongroup>> overmap::debug_unsafe_get_groups_at(
7557+
tripoint_abs_omt &loc )
7558+
{
7559+
point_abs_om overmap;
7560+
tripoint_om_omt omt_within_overmap;
7561+
std::tie( overmap, omt_within_overmap ) = project_remain<coords::om>( loc );
7562+
tripoint_om_sm om_sm_pos = project_to<coords::sm>( omt_within_overmap );
7563+
7564+
std::vector<std::reference_wrapper <mongroup>> groups_at;
7565+
for( std::pair<const tripoint_om_sm, mongroup> &pair : zg ) {
7566+
if( pair.first == om_sm_pos ) {
7567+
groups_at.emplace_back( pair.second );
7568+
}
7569+
}
7570+
return groups_at;
7571+
}
7572+
75567573
void overmap::add_mon_group( const mongroup &group )
75577574
{
75587575
zg.emplace( group.rel_pos(), group );

src/overmap.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -540,6 +540,7 @@ class overmap
540540

541541
// DEBUG ONLY!
542542
void debug_force_add_group( const mongroup &group );
543+
std::vector<std::reference_wrapper<mongroup>> debug_unsafe_get_groups_at( tripoint_abs_omt &loc );
543544
private:
544545
/**
545546
* Iterate over the overmap and place the quota of specials.

src/overmap_ui.cpp

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#include "cuboid_rectangle.h"
3636
#include "cursesdef.h"
3737
#include "display.h"
38+
#include "debug_menu.h"
3839
#include "game.h"
3940
#include "game_constants.h"
4041
#include "game_ui.h"
@@ -1151,6 +1152,7 @@ static void draw_om_sidebar( ui_adaptor &ui,
11511152
print_hint( "PLACE_SPECIAL", c_light_blue );
11521153
print_hint( "SET_SPECIAL_ARGS", c_light_blue );
11531154
print_hint( "LONG_TELEPORT", c_light_blue );
1155+
print_hint( "MODIFY_HORDE", c_light_blue );
11541156
++y;
11551157
}
11561158

@@ -1628,6 +1630,92 @@ static void set_special_args( tripoint_abs_omt &curs )
16281630
*maybe_args = args;
16291631
}
16301632

1633+
static void modify_horde_func( tripoint_abs_omt &curs )
1634+
{
1635+
overmap &map_at_cursor = overmap_buffer.get( project_to<coords::om>( curs ).xy() );
1636+
std::vector<std::reference_wrapper<mongroup>> hordes =
1637+
map_at_cursor.debug_unsafe_get_groups_at( curs );
1638+
if( hordes.empty() ) {
1639+
if( !query_yn( _( "No hordes there. Would you like to make a new horde?" ) ) ) {
1640+
return;
1641+
} else {
1642+
debug_menu::wishmonstergroup( curs );
1643+
return;
1644+
}
1645+
}
1646+
uilist horde_list;
1647+
int entry_num = 0;
1648+
for( auto &horde_wrapper : hordes ) {
1649+
mongroup &mg = horde_wrapper.get();
1650+
// We do some special handling here to provide the information in as simple a way as possible
1651+
// emulates horde behavior
1652+
int displayed_monster_num = mg.monsters.empty() ? mg.population : mg.monsters.size();
1653+
std::string horde_description = string_format( _( "group(type: %s) with %d monsters" ),
1654+
mg.type.c_str(), displayed_monster_num );
1655+
horde_list.addentry( entry_num, true, -1, horde_description );
1656+
}
1657+
horde_list.query();
1658+
int &selected_group = horde_list.ret;
1659+
if( selected_group < 0 || static_cast<size_t>( selected_group ) > hordes.size() ) {
1660+
return;
1661+
}
1662+
mongroup &chosen_group = hordes[selected_group];
1663+
1664+
uilist smenu;
1665+
smenu.addentry( 0, true, 'I', _( "Set horde's interest (in %%)" ) );
1666+
smenu.addentry( 1, true, 'D', _( "Set horde's destination" ) );
1667+
smenu.addentry( 2, true, 'P', _( "Modify horde's population" ) );
1668+
smenu.addentry( 3, true, 'M', _( "Add a new monster to the horde" ) );
1669+
smenu.addentry( 4, true, 'B', _( "Set horde behavior" ) );
1670+
smenu.addentry( 5, true, 'T', _( "Set horde's boolean values" ) );
1671+
smenu.addentry( 6, true, 'A', _( "Add another horde to this location" ) );
1672+
smenu.query();
1673+
int new_value = 0;
1674+
tripoint_abs_omt horde_destination = tripoint_abs_omt_zero;
1675+
switch( smenu.ret ) {
1676+
case 0:
1677+
query_int( new_value, _( "Set interest to what value? Currently %d" ), chosen_group.interest );
1678+
chosen_group.set_interest( new_value );
1679+
break;
1680+
case 1:
1681+
popup( _( "Select a target destination for the horde." ) );
1682+
horde_destination = ui::omap::choose_point( true );
1683+
if( horde_destination == overmap::invalid_tripoint || horde_destination == tripoint_abs_omt_zero ) {
1684+
break;
1685+
}
1686+
chosen_group.target = project_to<coords::sm>( horde_destination ).xy();
1687+
break;
1688+
case 2:
1689+
query_int( new_value, _( "Set population to what value? Currently %d" ), chosen_group.population );
1690+
chosen_group.population = new_value;
1691+
break;
1692+
case 3:
1693+
debug_menu::wishmonstergroup_mon_selection( chosen_group );
1694+
break;
1695+
case 4:
1696+
// Screw it we hardcode a popup, if you really want to use this you're welcome to improve it
1697+
popup( _( "Set behavior to which enum value? Currently %d. \nAccepted values:\n0 = none,\n1 = city,\n2=roam,\n3=nemesis" ),
1698+
static_cast<int>( chosen_group.behaviour ) );
1699+
query_int( new_value, "" );
1700+
chosen_group.behaviour = static_cast<mongroup::horde_behaviour>( new_value );
1701+
break;
1702+
case 5:
1703+
// One day we'll be able to simply convert booleans to strings...
1704+
chosen_group.horde = query_yn(
1705+
_( "Set group's \"horde\" value to true? (Select no to set to false) \nCurrently %s" ),
1706+
chosen_group.horde ? _( "true" ) : _( "false" ) );
1707+
chosen_group.dying = query_yn(
1708+
_( "Set group's \"dying\" value to true? (Select no to set to false) \nCurrently %s" ),
1709+
chosen_group.dying ? _( "true" ) : _( "false" ) );
1710+
break;
1711+
case 6:
1712+
debug_menu::wishmonstergroup( curs );
1713+
break;
1714+
default:
1715+
break;
1716+
}
1717+
}
1718+
16311719
static std::vector<tripoint_abs_omt> get_overmap_path_to( const tripoint_abs_omt &dest,
16321720
bool driving )
16331721
{
@@ -1809,6 +1897,7 @@ static tripoint_abs_omt display()
18091897
ictxt.register_action( "PLACE_SPECIAL" );
18101898
ictxt.register_action( "SET_SPECIAL_ARGS" );
18111899
ictxt.register_action( "LONG_TELEPORT" );
1900+
ictxt.register_action( "MODIFY_HORDE" );
18121901
}
18131902
ictxt.register_action( "QUIT" );
18141903
std::string action;
@@ -2022,6 +2111,9 @@ static tripoint_abs_omt display()
20222111
g->place_player_overmap( curs );
20232112
add_msg( _( "You teleport to submap %s." ), curs.to_string() );
20242113
action = "QUIT";
2114+
} else if( action == "MODIFY_HORDE" ) {
2115+
modify_horde_func( curs );
2116+
action = "QUIT";
20252117
} else if( action == "MISSIONS" ) {
20262118
g->list_missions();
20272119
}
@@ -2289,6 +2381,7 @@ void ui::omap::display()
22892381
{
22902382
g->overmap_data = overmap_ui::overmap_draw_data_t(); //reset data
22912383
g->overmap_data.origin_pos = get_player_character().global_omt_location();
2384+
g->overmap_data.debug_editor = debug_mode; // always display debug editor if game is in debug mode
22922385
overmap_ui::display();
22932386
}
22942387

src/wish.cpp

Lines changed: 88 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,10 @@
2929
#include "item_factory.h"
3030
#include "itype.h"
3131
#include "localized_comparator.h"
32+
#include "overmap.h"
33+
#include "overmapbuffer.h"
3234
#include "map.h"
35+
#include "mongroup.h"
3336
#include "monster.h"
3437
#include "monstergenerator.h"
3538
#include "mtype.h"
@@ -49,6 +52,8 @@
4952

5053
static const efftype_id effect_pet( "pet" );
5154

55+
static const mongroup_id GROUP_ZOMBIE( "GROUP_ZOMBIE" );
56+
5257
class ui_adaptor;
5358

5459
class wish_mutate_callback: public uilist_callback
@@ -713,26 +718,97 @@ class wish_monster_callback: public uilist_callback
713718
~wish_monster_callback() override = default;
714719
};
715720

721+
static void setup_wishmonster( uilist &pick_a_monster, std::vector<const mtype *> &mtypes )
722+
{
723+
pick_a_monster.desired_bounds = { -1.0, -1.0, 1.0, 1.0 };
724+
pick_a_monster.selected = uistate.wishmonster_selected;
725+
int i = 0;
726+
for( const mtype &montype : MonsterGenerator::generator().get_all_mtypes() ) {
727+
pick_a_monster.addentry( i, true, 0, montype.nname() );
728+
pick_a_monster.entries[i].extratxt.txt = montype.sym;
729+
pick_a_monster.entries[i].extratxt.color = montype.color;
730+
pick_a_monster.entries[i].extratxt.left = 1;
731+
++i;
732+
mtypes.push_back( &montype );
733+
}
734+
}
735+
736+
void debug_menu::wishmonstergroup( tripoint_abs_omt &loc )
737+
{
738+
bool population_group = query_yn(
739+
_( "Is this a population-based horde, based on an existing monster group? Select \"No\" to manually assign monsters." ) );
740+
mongroup new_group;
741+
// Just in case, we manually set some values
742+
new_group.abs_pos = project_to<coords::sm>( loc );
743+
new_group.target = new_group.abs_pos.xy();
744+
new_group.population = 1; // overwritten if population_group
745+
new_group.horde = true;
746+
new_group.type = GROUP_ZOMBIE; // overwritten if population_group
747+
if( population_group ) {
748+
uilist type_selection;
749+
std::vector<mongroup_id> possible_groups;
750+
int i = 0;
751+
for( auto &group_pair : MonsterGroupManager::Get_all_Groups() ) {
752+
possible_groups.emplace_back( group_pair.first );
753+
type_selection.addentry( i, true, -1, group_pair.first.c_str() );
754+
i++;
755+
}
756+
type_selection.query();
757+
int &selected = type_selection.ret;
758+
if( selected < 0 || static_cast<size_t>( selected ) >= possible_groups.size() ) {
759+
return;
760+
}
761+
const mongroup_id selected_group( possible_groups[selected] );
762+
new_group.type = selected_group;
763+
int new_value = 0;
764+
query_int( new_value, _( "Set population to what value? Currently %d" ), new_group.population );
765+
overmap &there = overmap_buffer.get( project_to<coords::om>( loc ).xy() );
766+
there.debug_force_add_group( new_group );
767+
return; // Don't go to adding individual monsters, they'll override the values we just set
768+
}
769+
770+
771+
wishmonstergroup_mon_selection( new_group );
772+
overmap &there = overmap_buffer.get( project_to<coords::om>( loc ).xy() );
773+
there.debug_force_add_group( new_group );
774+
}
775+
776+
void debug_menu::wishmonstergroup_mon_selection( mongroup &group )
777+
{
778+
779+
std::vector<const mtype *> mtypes;
780+
uilist new_mon_selection;
781+
setup_wishmonster( new_mon_selection, mtypes );
782+
wish_monster_callback cb( mtypes );
783+
new_mon_selection.callback = &cb;
784+
new_mon_selection.query();
785+
int &selected = new_mon_selection.ret;
786+
if( selected < 0 || static_cast<size_t>( selected ) >= mtypes.size() ) {
787+
return;
788+
}
789+
const mtype_id &mon_type = mtypes[ selected ]->id;
790+
for( int i = 0; i < cb.group; i++ ) {
791+
monster new_mon( mon_type );
792+
if( cb.friendly ) {
793+
new_mon.friendly = -1;
794+
new_mon.add_effect( effect_pet, 1_turns, true );
795+
}
796+
if( cb.hallucination ) {
797+
new_mon.hallucination = true;
798+
}
799+
group.monsters.emplace_back( new_mon );
800+
}
801+
}
802+
716803
void debug_menu::wishmonster( const std::optional<tripoint> &p )
717804
{
718805
std::vector<const mtype *> mtypes;
719806

720807
uilist wmenu;
721-
wmenu.desired_bounds = { -1.0, -1.0, 1.0, 1.0 };
722-
wmenu.selected = uistate.wishmonster_selected;
808+
setup_wishmonster( wmenu, mtypes );
723809
wish_monster_callback cb( mtypes );
724810
wmenu.callback = &cb;
725811

726-
int i = 0;
727-
for( const mtype &montype : MonsterGenerator::generator().get_all_mtypes() ) {
728-
wmenu.addentry( i, true, 0, montype.nname() );
729-
wmenu.entries[i].extratxt.txt = montype.sym;
730-
wmenu.entries[i].extratxt.color = montype.color;
731-
wmenu.entries[i].extratxt.left = 1;
732-
++i;
733-
mtypes.push_back( &montype );
734-
}
735-
736812
do {
737813
wmenu.query();
738814
if( wmenu.ret >= 0 ) {

0 commit comments

Comments
 (0)