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(UI): move remaining deactivate and manhack functions to pet menus, sanity-check docile behavior, rework pheromone function into generic monster culling #4247

Merged
merged 8 commits into from
Mar 2, 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
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 @@ -8668,68 +8661,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
Loading