Skip to content

Commit

Permalink
Port complete leash and lead system (#1905)
Browse files Browse the repository at this point in the history
* add complete leash and lead system!

* remove old code

* remove debug code

* remove unused variable

* fix and improve keybindings
  • Loading branch information
leoCottret authored Oct 5, 2022
1 parent 2133ebf commit c4994df
Show file tree
Hide file tree
Showing 5 changed files with 178 additions and 47 deletions.
12 changes: 12 additions & 0 deletions data/json/effects.json
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,18 @@
"desc": [ "AI tag used for critters holding your bags. This is a bug if you have it." ],
"permanent": true
},
{
"type": "effect_type",
"id": "leashed",
"name": [ "Has Leash" ],
"desc": [ "AI tag used for critters wearing a leash. This is a bug if you have it." ]
},
{
"type": "effect_type",
"id": "led_by_leash",
"name": [ "Being Led By Leash" ],
"desc": [ "AI tag used for critters forced to follow using a leash. This is a bug if you have it." ]
},
{
"type": "effect_type",
"id": "monster_armor",
Expand Down
184 changes: 140 additions & 44 deletions src/monexamine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#include "units.h"
#include "value_ptr.h"


static const quality_id qual_shear( "SHEAR" );

static const efftype_id effect_sheared( "sheared" );
Expand All @@ -53,6 +54,8 @@ 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_saddled( "monster_saddled" );
static const efftype_id effect_leashed( "leashed" );
static const efftype_id effect_led_by_leash( "led_by_leash" );
static const efftype_id effect_tied( "tied" );

static const itype_id itype_cash_card( "cash_card" );
Expand All @@ -66,6 +69,8 @@ bool monexamine::pet_menu( monster &z )
enum choices {
swap_pos = 0,
push_zlave,
lead,
stop_lead,
rename,
attach_bag,
remove_bag,
Expand All @@ -74,6 +79,8 @@ bool monexamine::pet_menu( monster &z )
mon_armor_add,
mon_harness_remove,
mon_armor_remove,
leash,
unleash,
play_with_pet,
pheromone,
milk,
Expand All @@ -82,7 +89,8 @@ bool monexamine::pet_menu( monster &z )
attach_saddle,
remove_saddle,
mount,
rope,
tie,
untie,
remove_bat,
insert_bat,
check_bat,
Expand All @@ -100,6 +108,13 @@ bool monexamine::pet_menu( monster &z )

amenu.addentry( swap_pos, true, 's', _( "Swap positions" ) );
amenu.addentry( push_zlave, true, 'p', _( "Push %s" ), pet_name );
if( z.has_effect( effect_leashed ) ) {
if( z.has_effect( effect_led_by_leash ) ) {
amenu.addentry( stop_lead, true, 'p', _( "Stop leading %s" ), pet_name );
} else {
amenu.addentry( lead, true, 'p', _( "Lead %s by the leash" ), pet_name );
}
}
amenu.addentry( rename, true, 'e', _( "Rename" ) );
amenu.addentry( attack, true, 'A', _( "Attack" ) );
if( z.has_effect( effect_has_bag ) ) {
Expand All @@ -124,15 +139,21 @@ bool monexamine::pet_menu( monster &z )
amenu.addentry( play_with_pet, true, 'y', _( "Play with %s" ), pet_name );
}
if( z.has_effect( effect_tied ) ) {
amenu.addentry( rope, true, 't', _( "Untie" ) );
} else if( !z.has_flag( MF_RIDEABLE_MECH ) ) {
std::vector<item *> rope_inv = g->u.items_with( []( const item & itm ) {
return itm.has_flag( "TIE_UP" );
amenu.addentry( untie, true, 'u', _( "Untie" ) );
}
if( z.has_effect( effect_leashed ) && !z.has_effect( effect_tied ) ) {
amenu.addentry( tie, true, 't', _( "Tie" ) );
amenu.addentry( unleash, true, 'T', _( "Remove leash from %s" ), pet_name );
}
if( !z.has_effect( effect_leashed ) && !z.has_flag( MF_RIDEABLE_MECH ) ) {
Character &player_character = g->u;
std::vector<item *> rope_inv = player_character.items_with( []( const item & it ) {
return it.has_flag( "TIE_UP" );
} );
if( !rope_inv.empty() ) {
amenu.addentry( rope, true, 't', _( "Tie" ) );
amenu.addentry( leash, true, 'l', _( "Attach leash to %s" ), pet_name );
} else {
amenu.addentry( rope, false, 't', _( "You need any type of rope to tie %s in place" ),
amenu.addentry( leash, false, 'l', _( "You need any type of rope to tie %s in place" ),
pet_name );
}
}
Expand Down Expand Up @@ -173,6 +194,7 @@ bool monexamine::pet_menu( monster &z )
if( z.has_flag( MF_PAY_BOT ) ) {
amenu.addentry( pay, true, 'f', _( "Manage your friendship with %s" ), pet_name );
}

if( !z.has_flag( MF_RIDEABLE_MECH ) ) {
if( z.has_flag( MF_PET_MOUNTABLE ) && g->u.can_mount( z ) ) {
amenu.addentry( mount, true, 'r', _( "Mount %s" ), pet_name );
Expand Down Expand Up @@ -223,6 +245,12 @@ bool monexamine::pet_menu( monster &z )
case push_zlave:
push( z );
break;
case lead:
start_leading( z );
break;
case stop_lead:
stop_leading( z );
break;
case rename:
rename_pet( z );
break;
Expand Down Expand Up @@ -255,8 +283,11 @@ bool monexamine::pet_menu( monster &z )
kill_zslave( z );
}
break;
case rope:
tie_or_untie( z );
case leash:
add_leash( z );
break;
case unleash:
remove_leash( z );
break;
case attach_saddle:
case remove_saddle:
Expand All @@ -265,6 +296,12 @@ bool monexamine::pet_menu( monster &z )
case mount:
mount_pet( z );
break;
case tie:
tie_pet( z );
break;
case untie:
untie_pet( z );
break;
case milk:
milk_source( z );
break;
Expand Down Expand Up @@ -302,7 +339,7 @@ void monexamine::shear_animal( monster &z )
g->u.activity.coords.push_back( g->m.getabs( z.pos() ) );
// pin the sheep in place if it isn't already
if( !z.has_effect( effect_tied ) ) {
z.add_effect( effect_tied, 1_turns, num_bp );
z.add_effect( effect_tied, 1_turns );
g->u.activity.str_values.push_back( "temp_tie" );
}
g->u.activity.targets.push_back( item_location( g->u, g->u.best_quality_item( qual_shear ) ) );
Expand Down Expand Up @@ -742,43 +779,102 @@ void monexamine::kill_zslave( monster &z )
}
}

void monexamine::tie_or_untie( monster &z )
void monexamine::add_leash( monster &z )
{
if( z.has_effect( effect_leashed ) ) {
return;
}
Character &player = get_player_character();
std::vector<item *> rope_inv = player.items_with( []( const item & it ) {
return it.has_flag( "TIE_UP" );
} );

if( rope_inv.empty() ) {
return;
}
int i = 0;
uilist selection_menu;
selection_menu.text = string_format( _( "Select an item to leash your %s with." ), z.get_name() );
selection_menu.addentry( i++, true, MENU_AUTOASSIGN, _( "Cancel" ) );
for( const item *iter : rope_inv ) {
selection_menu.addentry( i++, true, MENU_AUTOASSIGN, _( "Use %s" ), iter->tname() );
}
selection_menu.selected = 1;
selection_menu.query();
int index = selection_menu.ret;
if( index == 0 || index == UILIST_CANCEL || index < 0 ||
index > static_cast<int>( rope_inv.size() ) ) {
return;
}
item *rope_item = rope_inv[index - 1];
z.tied_item = cata::make_value<item>( *rope_item );
player.i_rem( rope_item );
z.add_effect( effect_leashed, 1_turns );
z.get_effect( effect_leashed ).set_permanent();
add_msg( _( "You add a leash to your %s." ), z.get_name() );
}

void monexamine::remove_leash( monster &z )
{
if( !z.has_effect( effect_leashed ) ) {
return;
}
z.remove_effect( effect_led_by_leash );
z.remove_effect( effect_leashed );

if( z.tied_item ) {
get_player_character().i_add( *z.tied_item );
z.tied_item.reset();
}
add_msg( _( "You remove the leash from your %s." ), z.get_name() );
}

void monexamine::tie_pet( monster &z )
{
if( z.has_effect( effect_tied ) ) {
z.remove_effect( effect_tied );
if( z.tied_item ) {
g->u.i_add( *z.tied_item );
z.tied_item.reset();
}
} else {
std::vector<item *> rope_inv = g->u.items_with( []( const item & itm ) {
return itm.has_flag( "TIE_UP" );
} );
if( rope_inv.empty() ) {
return;
}
int i = 0;
uilist selection_menu;
selection_menu.text = string_format( _( "Select an item to tie your %s with." ), z.get_name() );
selection_menu.addentry( i++, true, MENU_AUTOASSIGN, _( "Cancel" ) );
for( auto iter : rope_inv ) {
selection_menu.addentry( i++, true, MENU_AUTOASSIGN, _( "Use %s" ), iter->tname() );
}
selection_menu.selected = 1;
selection_menu.query();
auto index = selection_menu.ret;
if( index == 0 || index == UILIST_CANCEL || index < 0 ||
index > static_cast<int>( rope_inv.size() ) ) {
return;
}
item *rope_item = rope_inv[index - 1];
int item_pos = g->u.get_item_position( rope_item );
if( item_pos != INT_MIN ) {
z.tied_item = cata::make_value<item>( *rope_item );
g->u.i_rem( item_pos );
z.add_effect( effect_tied, 1_turns, num_bp );
}
return;
}
z.add_effect( effect_tied, 1_turns );
z.get_effect( effect_tied ).set_permanent();
add_msg( _( "You tie your %s." ), z.get_name() );
}

void monexamine::untie_pet( monster &z )
{
if( !z.has_effect( effect_tied ) ) {
return;
}
z.remove_effect( effect_tied );
if( !z.has_effect( effect_leashed ) ) {
// migration code dealing with animals tied before leashing was introduced
z.add_effect( effect_leashed, 1_turns );
z.get_effect( effect_leashed ).set_permanent();
}
add_msg( _( "You untie your %s." ), z.get_name() );
}

void monexamine::start_leading( monster &z )
{
if( z.has_effect( effect_led_by_leash ) ) {
return;
}
if( z.has_effect( effect_tied ) ) {
monexamine::untie_pet( z );
}
z.add_effect( effect_led_by_leash, 1_turns );
z.get_effect( effect_led_by_leash ).set_permanent();

add_msg( _( "You take hold of the %s's leash to make it follow you." ), z.get_name() );
}

void monexamine::stop_leading( monster &z )
{
if( !z.has_effect( effect_led_by_leash ) ) {
return;
}
z.remove_effect( effect_led_by_leash );
// The pet may or may not stop following so don't print that here
add_msg( _( "You release the %s's leash." ), z.get_name() );
}

void monexamine::milk_source( monster &source_mon )
Expand Down
8 changes: 7 additions & 1 deletion src/monexamine.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,16 @@ void remove_armor( monster &z );
void remove_harness( monster &z );
void play_with( monster &z );
void kill_zslave( monster &z );
void tie_or_untie( monster &z );
void add_leash( monster &z );
void remove_leash( monster &z );
void start_leading( monster &z );
void stop_leading( monster &z );
void tie_pet( monster &z );
void untie_pet( monster &z );
void shear_animal( monster &z );
void mount_pet( monster &z );
void attach_or_remove_saddle( monster &z );

/*
*Manages the milking and milking cool down of monsters.
*Milked item uses starting_ammo, where ammo type is the milked item
Expand Down
20 changes: 18 additions & 2 deletions src/monmove.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "cata_utility.h"
#include "creature_tracker.h"
#include "debug.h"
#include "effect.h"
#include "field.h"
#include "field_type.h"
#include "game.h"
Expand Down Expand Up @@ -60,6 +61,7 @@ static const efftype_id effect_operating( "operating" );
static const efftype_id effect_pacified( "pacified" );
static const efftype_id effect_pushed( "pushed" );
static const efftype_id effect_stunned( "stunned" );
static const efftype_id effect_led_by_leash( "led_by_leash" );

static const itype_id itype_pressurized_tank( "pressurized_tank" );

Expand Down Expand Up @@ -336,7 +338,7 @@ void monster::plan()
auto mood = attitude();

// If we can see the player, move toward them or flee, simpleminded animals are too dumb to follow the player.
if( friendly == 0 && sees( g->u ) && !has_flag( MF_PET_WONT_FOLLOW ) && !waiting ) {
if( friendly == 0 && sees( g->u ) && !waiting ) {
dist = rate_target( g->u, dist, smart_planning );
fleeing = fleeing || is_fleeing( g->u );
target = &g->u;
Expand Down Expand Up @@ -579,7 +581,14 @@ void monster::plan()
} else if( friendly > 0 && one_in( 3 ) ) {
// Grow restless with no targets
friendly--;
} else if( friendly < 0 && sees( g->u ) ) {
} else if( friendly != 0 && has_effect( effect_led_by_leash ) ) {
// visibility doesn't matter, we're getting pulled by a leash
if( rl_dist( pos(), g->u.pos() ) > 1 ) {
set_dest( g->u.pos() );
} else {
unset_dest();
}
} else if( friendly < 0 && sees( g->u ) && !has_flag( MF_PET_WONT_FOLLOW ) ) {
if( rl_dist( pos(), g->u.pos() ) > 2 ) {
set_dest( g->u.pos() );
} else {
Expand Down Expand Up @@ -1035,6 +1044,13 @@ void monster::move()
moves -= 100;
stumble();
path.clear();
if( has_effect( effect_led_by_leash ) ) {
if( rl_dist( pos(), g->u.pos() ) > 6 ) {
// Either failed to keep up with the player or moved away
remove_effect( effect_led_by_leash );
add_msg( m_info, _( "You lose hold of a leash." ) );
}
}
}
}

Expand Down
1 change: 1 addition & 0 deletions src/monster.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "creature.h"
#include "cursesdef.h"
#include "damage.h"
#include "effect.h"
#include "enums.h"
#include "optional.h"
#include "pldata.h"
Expand Down

0 comments on commit c4994df

Please sign in to comment.