Skip to content

Commit

Permalink
feat(UI): move remaining deactivate and manhack functions to pet menu…
Browse files Browse the repository at this point in the history
…s, sanity-check docile behavior, rework pheromone function into generic monster culling (#4247)

* commit for remote

* commit for remote

* Final fixing up

* Update json_flags.md

* Idea per feedback

* Update monexamine.cpp

* Update game.cpp
  • Loading branch information
chaosvolt committed Mar 2, 2024
1 parent 8f84b48 commit 8c42631
Show file tree
Hide file tree
Showing 12 changed files with 78 additions and 110 deletions.
2 changes: 1 addition & 1 deletion data/json/monsters/drones.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"luminance": 5,
"death_drops": { "subtype": "collection", "groups": [ [ "robots", 80 ] ], "//": "80% chance of an item from group robots" },
"death_function": [ "BROKEN_AMMO" ],
"flags": [ "SEES", "FLIES", "NOHEAD", "ELECTRONIC", "NO_BREATHE", "INTERIOR_AMMO", "BIOPROOF" ]
"flags": [ "SEES", "FLIES", "NOHEAD", "ELECTRONIC", "NO_BREATHE", "INTERIOR_AMMO", "BIOPROOF", "CAN_BE_ORDERED" ]
},
{
"id": "mon_EMP_hack",
Expand Down
1 change: 1 addition & 0 deletions doc/src/content/docs/en/mod/json/reference/json_flags.md
Original file line number Diff line number Diff line change
Expand Up @@ -987,6 +987,7 @@ Multiple death functions can be used. Not all combinations make sense.
- `BLEED` Causes the player to bleed.
- `BONES` May produce bones and sinews when butchered.
- `BORES` Tunnels through just about anything (15x bash multiplier: dark wyrms' bash skill 12->180)
- `CAN_BE_ORDERED` This creature can be directed to not attack enemies, if friendly.
- `CAN_DIG` Can dig _and_ walk.
- `CAN_OPEN_DOORS` Can open doors on its path.
- `CANPLAY` This creature can be played with if it's a pet.
Expand Down
2 changes: 1 addition & 1 deletion src/character.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10961,12 +10961,12 @@ Attitude Character::attitude_to( const Creature &other ) const
switch( m->attitude( const_cast<Character *>( this ) ) ) {
// player probably does not want to harm them, but doesn't care much at all.
case MATT_FOLLOW:
case MATT_FPASSIVE:
case MATT_IGNORE:
case MATT_FLEE:
return Attitude::A_NEUTRAL;
// player does not want to harm those.
case MATT_FRIEND:
case MATT_FPASSIVE:
case MATT_ZLAVE:
// Don't want to harm your zlave!
return Attitude::A_FRIENDLY;
Expand Down
69 changes: 0 additions & 69 deletions src/game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -203,8 +203,6 @@ static constexpr int DANGEROUS_PROXIMITY = 5;
static const activity_id ACT_OPERATION( "ACT_OPERATION" );
static const activity_id ACT_AUTODRIVE( "ACT_AUTODRIVE" );

static const mtype_id mon_manhack( "mon_manhack" );

static const skill_id skill_melee( "melee" );
static const skill_id skill_dodge( "dodge" );
static const skill_id skill_firstaid( "firstaid" );
Expand All @@ -223,7 +221,6 @@ static const efftype_id effect_assisted( "assisted" );
static const efftype_id effect_blind( "blind" );
static const efftype_id effect_bouldering( "bouldering" );
static const efftype_id effect_contacts( "contacts" );
static const efftype_id effect_docile( "docile" );
static const efftype_id effect_downed( "downed" );
static const efftype_id effect_drunk( "drunk" );
static const efftype_id effect_evil( "evil" );
Expand All @@ -235,7 +232,6 @@ static const efftype_id effect_no_sight( "no_sight" );
static const efftype_id effect_npc_suspend( "npc_suspend" );
static const efftype_id effect_onfire( "onfire" );
static const efftype_id effect_pacified( "pacified" );
static const efftype_id effect_paid( "paid" );
static const efftype_id effect_pet( "pet" );
static const efftype_id effect_ridden( "ridden" );
static const efftype_id effect_riding( "riding" );
Expand Down Expand Up @@ -5492,9 +5488,6 @@ static std::string get_fire_fuel_string( const tripoint &examp )

void game::examine( const tripoint &examp )
{
if( disable_robot( examp ) ) {
return;
}

Creature *c = critter_at( examp );
if( c != nullptr ) {
Expand Down Expand Up @@ -8678,68 +8671,6 @@ void game::set_safe_mode( safe_mode_type mode )
safe_mode_warning_logged = false;
}

bool game::disable_robot( const tripoint &p )
{
monster *const mon_ptr = critter_at<monster>( p );
if( !mon_ptr ) {
return false;
}
monster &critter = *mon_ptr;
if( critter.friendly == 0 || critter.has_effect( effect_pet ) ||
critter.has_flag( MF_RIDEABLE_MECH ) ||
( critter.has_flag( MF_PAY_BOT ) && critter.has_effect( effect_paid ) ) ) {
// Can only disable / reprogram friendly monsters
return false;
}
const auto mid = critter.type->id;
const auto mon_item_id = critter.type->revert_to_itype;
if( !mon_item_id.is_empty() &&
query_yn( _( "Deactivate the %s?" ), critter.name() ) ) {

u.moves -= 100;
m.add_item_or_charges( p, critter.to_item() );
if( !critter.has_flag( MF_INTERIOR_AMMO ) ) {
for( auto &ammodef : critter.ammo ) {
if( ammodef.second > 0 ) {
m.spawn_item( p.xy(), ammodef.first, 1, ammodef.second, calendar::turn );
}
}
}
remove_zombie( critter );
return true;
}
// Manhacks are special, they have their own menu here.
if( mid == mon_manhack ) {
int choice = UILIST_CANCEL;
if( critter.has_effect( effect_docile ) ) {
choice = uilist( _( "Reprogram the manhack?" ), { _( "Engage targets." ) } );
} else {
choice = uilist( _( "Reprogram the manhack?" ), { _( "Follow me." ) } );
}
switch( choice ) {
case 0:
if( critter.has_effect( effect_docile ) ) {
critter.remove_effect( effect_docile );
if( one_in( 3 ) ) {
add_msg( _( "The %s hovers momentarily as it surveys the area." ),
critter.name() );
}
} else {
critter.add_effect( effect_docile, 1_turns, num_bp );
if( one_in( 3 ) ) {
add_msg( _( "The %s lets out a whirring noise and starts to follow you." ),
critter.name() );
}
}
u.moves -= 100;
return true;
default:
break;
}
}
return false;
}

bool game::is_dangerous_tile( const tripoint &dest_loc ) const
{
return !( get_dangerous_tile( dest_loc ).empty() );
Expand Down
8 changes: 0 additions & 8 deletions src/game.h
Original file line number Diff line number Diff line change
Expand Up @@ -881,14 +881,6 @@ class game
void win_screen(); // Display our stats, "CONGRATULATIONS!"
void draw_minimap(); // Draw the 5x5 minimap
public:
/**
* If there is a robot (that can be disabled), query the player
* and try to disable it.
* @return true if the robot has been disabled or a similar action has
* been done. false if the player did not choose any action and the function
* has effectively done nothing.
*/
bool disable_robot( const tripoint &p );
// Draws the pixel minimap based on the player's current location
void draw_pixel_minimap( const catacurses::window &w );
private:
Expand Down
8 changes: 4 additions & 4 deletions src/monattack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3119,9 +3119,9 @@ bool mattack::nurse_operate( monster *z )
}
bool mattack::check_money_left( monster *z )
{
if( !z->has_effect( effect_pet ) ) {
if( !z->has_effect( effect_paid ) ) {
if( z->friendly == -1 &&
z->has_effect( effect_paid ) ) { // if the pet effect runs out we're no longer friends
z->has_effect( effect_pet ) ) { // if the pet effect runs out we're no longer friends
z->friendly = 0;

if( !z->get_items().empty() ) {
Expand All @@ -3135,11 +3135,11 @@ bool mattack::check_money_left( monster *z )
const SpeechBubble &speech_no_time = get_speech( "mon_grocerybot_friendship_done" );
sounds::sound( z->pos(), speech_no_time.volume,
sounds::sound_t::electronic_speech, speech_no_time.text );
z->remove_effect( effect_paid );
z->remove_effect( effect_pet );
return true;
}
} else {
const time_duration time_left = z->get_effect_dur( effect_pet );
const time_duration time_left = z->get_effect_dur( effect_paid );
if( time_left < 1_minutes ) {
if( calendar::once_every( 20_seconds ) ) {
const SpeechBubble &speech_time_low = get_speech( "mon_grocerybot_running_out_of_friendship" );
Expand Down
77 changes: 59 additions & 18 deletions src/monexamine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,15 @@


static const quality_id qual_shear( "SHEAR" );
static const quality_id qual_butcher( "BUTCHER" );

static const efftype_id effect_sheared( "sheared" );

static const activity_id ACT_MILK( "ACT_MILK" );
static const activity_id ACT_PLAY_WITH_PET( "ACT_PLAY_WITH_PET" );

static const efftype_id effect_ai_waiting( "ai_waiting" );
static const efftype_id effect_docile( "docile" );
static const efftype_id effect_harnessed( "harnessed" );
static const efftype_id effect_has_bag( "has_bag" );
static const efftype_id effect_monster_armor( "monster_armor" );
Expand Down Expand Up @@ -86,7 +88,7 @@ bool monexamine::pet_menu( monster &z )
leash,
unleash,
play_with_pet,
pheromone,
slaughter,
milk,
shear,
pay,
Expand All @@ -98,13 +100,15 @@ bool monexamine::pet_menu( monster &z )
remove_bat,
insert_bat,
check_bat,
change_orders,
disable_pet,
attack
};

uilist amenu;
std::string pet_name = z.get_name();
bool is_zombie = z.type->in_species( ZOMBIE );
bool can_slaughter = z.type->in_category( "WILDLIFE" );
const auto mon_item_id = z.type->revert_to_itype;
avatar &you = get_avatar();
if( is_zombie ) {
Expand All @@ -122,7 +126,6 @@ bool monexamine::pet_menu( monster &z )
}
}
amenu.addentry( rename, true, 'e', _( "Rename" ) );
amenu.addentry( attack, true, 'A', _( "Attack" ) );
if( z.has_effect( effect_has_bag ) ) {
amenu.addentry( give_items, true, 'g', _( "Place items into bag" ) );
amenu.addentry( remove_bag, true, 'b', _( "Remove bag from %s" ), pet_name );
Expand Down Expand Up @@ -165,10 +168,6 @@ bool monexamine::pet_menu( monster &z )
pet_name );
}
}
if( is_zombie ) {
amenu.addentry( pheromone, true, 'z', _( "Tear out pheromone ball" ) );
}

if( z.has_flag( MF_MILKABLE ) ) {
amenu.addentry( milk, true, 'm', _( "Milk %s" ), pet_name );
}
Expand Down Expand Up @@ -243,14 +242,26 @@ bool monexamine::pet_menu( monster &z )
amenu.addentry( insert_bat, false, 'x', _( "You need a %s to power this mech" ), type.nname( 1 ) );
}
}
if( !mon_item_id.is_empty() && !z.has_flag( MF_RIDEABLE_MECH ) ) {
if( z.has_flag( MF_CAN_BE_ORDERED ) ) {
if( z.has_effect( effect_docile ) ) {
amenu.addentry( change_orders, true, 'O', _( "Order to engage targets" ), pet_name );
} else {
amenu.addentry( change_orders, true, 'O', _( "Order to ignore enemies and follow" ), pet_name );
}
}
if( !mon_item_id.is_empty() && !z.has_flag( MF_RIDEABLE_MECH ) && !z.has_flag( MF_PAY_BOT ) ) {
if( z.has_effect( effect_has_bag ) || z.has_effect( effect_monster_armor ) ||
z.has_effect( effect_leashed ) || z.has_effect( effect_saddled ) ) {
amenu.addentry( disable_pet, true, 'D', _( "Remove items and deactivate the %s" ), pet_name );
} else {
amenu.addentry( disable_pet, true, 'D', _( "Deactivate the %s" ), pet_name );
}
}
if( ( is_zombie || can_slaughter ) && you.has_quality( qual_butcher, 1 ) ) {
amenu.addentry( slaughter, true, 'A', _( "Slaughter %s" ), pet_name );
} else {
amenu.addentry( attack, true, 'A', _( "Attack" ) );
}
amenu.query();
int choice = amenu.ret;

Expand Down Expand Up @@ -294,8 +305,8 @@ bool monexamine::pet_menu( monster &z )
play_with( z );
}
break;
case pheromone:
if( query_yn( _( "Really kill the zombie slave?" ) ) ) {
case slaughter:
if( query_yn( _( "Really kill the %s?" ), pet_name ) ) {
kill_zslave( z );
}
break;
Expand Down Expand Up @@ -335,6 +346,9 @@ bool monexamine::pet_menu( monster &z )
break;
case check_bat:
break;
case change_orders:
toggle_ignore_targets( z );
break;
case disable_pet:
if( query_yn( _( "Really deactivate your %s?" ), pet_name ) ) {
deactivate_pet( z );
Expand Down Expand Up @@ -509,16 +523,29 @@ bool monexamine::mfriend_menu( monster &z )
enum choices {
push_monster = 0,
rename,
change_orders,
disable_pet,
attack
};

uilist amenu;
const std::string pet_name = z.get_name();
const auto mon_item_id = z.type->revert_to_itype;

amenu.text = string_format( _( "What to do with your %s?" ), pet_name );

amenu.addentry( push_monster, true, 'p', _( "Push %s" ), pet_name );
amenu.addentry( rename, true, 'e', _( "Rename" ) );
if( z.has_flag( MF_CAN_BE_ORDERED ) ) {
if( z.has_effect( effect_docile ) ) {
amenu.addentry( change_orders, true, 'O', _( "Order to engage targets" ), pet_name );
} else {
amenu.addentry( change_orders, true, 'O', _( "Order to ignore enemies and follow" ), pet_name );
}
}
if( !mon_item_id.is_empty() && !z.has_flag( MF_RIDEABLE_MECH ) && !z.has_flag( MF_PAY_BOT ) ) {
amenu.addentry( disable_pet, true, 'D', _( "Deactivate the %s" ), pet_name );
}
amenu.addentry( attack, true, 'a', _( "Attack" ) );

amenu.query();
Expand All @@ -531,6 +558,14 @@ bool monexamine::mfriend_menu( monster &z )
case rename:
rename_pet( z );
break;
case change_orders:
toggle_ignore_targets( z );
break;
case disable_pet:
if( query_yn( _( "Really deactivate your %s?" ), pet_name ) ) {
deactivate_pet( z );
}
break;
case attack:
if( query_yn( _( "You may be attacked! Proceed?" ) ) ) {
get_player_character().melee_attack( z, true );
Expand Down Expand Up @@ -791,16 +826,10 @@ void monexamine::play_with( monster &z )
void monexamine::kill_zslave( monster &z )
{
avatar &you = get_avatar();
z.apply_damage( &you, bodypart_id( "torso" ), 100 ); // damage the monster (and its corpse)
z.die( &you ); // and make sure it's really dead
you.add_msg_if_player( _( "With a clean cut you put your %s down." ), z.get_name() );
z.die( &you ); // execute it cleanly without damaging the corpse

you.moves -= 150;

if( !one_in( 3 ) ) {
you.add_msg_if_player( _( "You tear out the pheromone ball from the zombie slave." ) );
item *ball = item::spawn_temporary( "pheromone", calendar::start_of_cataclysm );
iuse::pheromone( &you, ball, true, you.pos() );
}
}

void monexamine::add_leash( monster &z )
Expand Down Expand Up @@ -891,6 +920,19 @@ void monexamine::start_leading( monster &z )
add_msg( _( "You take hold of the %s's leash to make it follow you." ), z.get_name() );
}

void monexamine::toggle_ignore_targets( monster &z )
{
if( z.has_effect( effect_docile ) ) {
z.remove_effect( effect_docile );
add_msg( _( "You order the %s to engage targets." ), z.get_name() );
return;
} else {
z.add_effect( effect_docile, 1_turns );
add_msg( _( "You order the %s to focus on following you." ), z.get_name() );
return;
}
}

void monexamine::stop_leading( monster &z )
{
if( !z.has_effect( effect_led_by_leash ) ) {
Expand All @@ -901,7 +943,6 @@ void monexamine::stop_leading( monster &z )
add_msg( _( "You release the %s's leash." ), z.get_name() );
}


void monexamine::deactivate_pet( monster &z )
{
if( z.has_effect( effect_has_bag ) ) {
Expand Down
1 change: 1 addition & 0 deletions src/monexamine.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ void add_leash( monster &z );
void remove_leash( monster &z );
void start_leading( monster &z );
void stop_leading( monster &z );
void toggle_ignore_targets( monster &z );
void tie_pet( monster &z );
void untie_pet( monster &z );
void shear_animal( monster &z );
Expand Down
Loading

0 comments on commit 8c42631

Please sign in to comment.