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

[WIP] Rebalancing of the control laptop, give robots a chance #30892

Closed
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
6 changes: 6 additions & 0 deletions data/json/effects.json
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,12 @@
"name": [ "Pushed" ],
"desc": [ "AI tag used for monsters pushing each other. This is a bug if you have it." ]
},
{
"type": "effect_type",
"id": "not_receiving",
"name": [ "Not Accepting Remote Connections" ],
"desc": [ "AI tag used for robots not accepting remote connections. This is a bug if you have it." ]
},
{
"//": "ACTUAL PLAYER EFFECTS START HERE",
"type": "effect_type",
Expand Down
7 changes: 4 additions & 3 deletions data/json/monsters.json
Original file line number Diff line number Diff line change
Expand Up @@ -654,7 +654,8 @@
"STUMBLES",
"HUMAN",
"PATH_AVOID_DANGER_2",
"PRIORITIZE_TARGETS"
"PRIORITIZE_TARGETS",
"HACK_IMMUNE"
]
},
{
Expand Down Expand Up @@ -720,7 +721,7 @@
"special_attacks": [ [ "CHICKENBOT", 4 ] ],
"death_drops": { "groups": [ [ "robots", 4 ], [ "chickenbot", 1 ] ] },
"death_function": [ "EXPLODE" ],
"flags": [ "SEES", "HEARS", "BASHES", "NO_BREATHE", "ELECTRONIC", "PRIORITIZE_TARGETS" ]
"flags": [ "SEES", "HEARS", "BASHES", "NO_BREATHE", "ELECTRONIC", "PRIORITIZE_TARGETS", "HACK_DEFENSE" ]
},
{
"id": "mon_chud",
Expand Down Expand Up @@ -784,7 +785,7 @@
"special_attacks": [ [ "COPBOT", 3 ] ],
"death_drops": { "groups": [ [ "robots", 4 ], [ "copbot", 1 ] ] },
"death_function": [ "BROKEN" ],
"flags": [ "SEES", "HEARS", "BASHES", "ELECTRONIC", "NO_BREATHE", "PRIORITIZE_TARGETS", "PATH_AVOID_DANGER_1" ]
"flags": [ "SEES", "HEARS", "BASHES", "ELECTRONIC", "NO_BREATHE", "PRIORITIZE_TARGETS", "PATH_AVOID_DANGER_1", "HACK_DEFENSE" ]
},
{
"id": "mon_crawler",
Expand Down
6 changes: 3 additions & 3 deletions data/json/monsters/defense_bot.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"special_attacks": [ { "type": "gun", "cooldown": 2, "gun_type": "hk_mp5", "ranges": [ [ 0, 6, "AUTO" ], [ 7, 12, "DEFAULT" ] ] } ],
"death_drops": { "groups": [ [ "robots", 4 ], [ "secubot", 1 ] ] },
"death_function": [ "EXPLODE" ],
"flags": [ "SEES", "HEARS", "BASHES", "ELECTRONIC", "NO_BREATHE", "PATH_AVOID_DANGER_1", "LOUDMOVES" ]
"flags": [ "SEES", "HEARS", "BASHES", "ELECTRONIC", "NO_BREATHE", "PATH_AVOID_DANGER_1", "LOUDMOVES", "HACK_DEFENSE" ]
},
{
"id": "mon_turret",
Expand Down Expand Up @@ -189,7 +189,7 @@
"special_attacks": [ [ "GRENADIER", 10 ] ],
"death_drops": { "groups": [ [ "robots", 1 ] ] },
"death_function": [ "BROKEN" ],
"flags": [ "SEES", "HEARS", "ELECTRONIC", "NO_BREATHE", "PRIORITIZE_TARGETS", "PATH_AVOID_DANGER_2", "LOUDMOVES" ]
"flags": [ "SEES", "HEARS", "ELECTRONIC", "NO_BREATHE", "PRIORITIZE_TARGETS", "PATH_AVOID_DANGER_2", "LOUDMOVES", "HACK_DEFENSE" ]
},
{
"id": "mon_dispatch_military",
Expand Down Expand Up @@ -222,6 +222,6 @@
"special_attacks": [ [ "GRENADIER_ELITE", 10 ] ],
"death_drops": { "groups": [ [ "robots", 1 ] ] },
"death_function": [ "BROKEN" ],
"flags": [ "SEES", "HEARS", "ELECTRONIC", "NO_BREATHE", "PRIORITIZE_TARGETS", "PATH_AVOID_DANGER_2", "LOUDMOVES" ]
"flags": [ "SEES", "HEARS", "ELECTRONIC", "NO_BREATHE", "PRIORITIZE_TARGETS", "PATH_AVOID_DANGER_2", "LOUDMOVES", "HACK_DEFENSE" ]
}
]
3 changes: 2 additions & 1 deletion data/json/player_activities.json
Original file line number Diff line number Diff line change
Expand Up @@ -543,7 +543,8 @@
"stop_phrase": "Stop programming override?",
"suspendable": false,
"based_on": "time",
"no_resume": true
"no_resume": true,
"rooted": true
},
{
"id": "ACT_WEAR",
Expand Down
50 changes: 38 additions & 12 deletions src/activity_handlers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,11 @@ const skill_id skill_firstaid( "firstaid" );
const skill_id skill_electronics( "electronics" );

const species_id HUMAN( "HUMAN" );
const species_id ROBOT( "ROBOT" );
const species_id ZOMBIE( "ZOMBIE" );

const efftype_id effect_milked( "milked" );
const efftype_id effect_not_receiving( "not_receiving" );
const efftype_id effect_sleep( "sleep" );

using namespace activity_handlers;
Expand Down Expand Up @@ -3441,10 +3443,32 @@ void activity_handlers::robot_control_do_turn( player_activity *act, player *p )
return;
}

// TODO: Add some kind of chance of getting the target's attention

// Allow time to pass
p->pause();
// robot can detect hacking attempt
// 1. roll against hacking attempt
// 2. if failure, then robot will
// 3. sound alarm, say "Remote intrusion detected! Notifying network."
// 4. All robots within 10 tiles that are receiving will be notified, set not_receiving
// 5. This robot sets not_receiving
/** @EFFECT_INT increases chance of successful robot reprogramming, vs difficulty */
/** @EFFECT_COMPUTER increases chance of successful robot reprogramming, vs difficulty */
const float success = p->get_skill_level( skill_id( "computer" ) ) - 1.5 * ( z->type->difficulty ) /
( ( rng( 2, p->int_cur ) / 2 ) + ( p->get_skill_level( skill_id( "computer" ) ) / 2 ) );
Copy link
Member

@anothersimulacrum anothersimulacrum May 27, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While I'm not against this change, I think the real issue here is this formula.
This formula puts too much emphasis on the difficulty value. Here's a table of the min and max for hacking of a security bot and tank drone by intelligence and computer skill.
Values are (min,max) - even though they aren't that way for low intelligence.
Calculated from

const float success_min = p->get_skill_level( skill_id( "computer" ) ) - 1.5 *
                              ( z->type->difficulty ) /
                              ( ( 2 / 2 ) + ( p->get_skill_level( skill_id( "computer" ) ) / 2 ) );
const float success_max = p->get_skill_level( skill_id( "computer" ) ) - 1.5 *
                              ( z->type->difficulty ) /
                              ( ( p->int_cur / 2 ) + ( p->get_skill_level( skill_id( "computer" ) ) / 2 ) );

Security Bot - difficulty 14

0 1 5 10
1 -20,-inf -2,-5.5 6.5,5.8
2 -20,-20 -2,-2 6.5,6.5
3 -20,-20 -2,-2 6.5,6.5
4 -20,-9.5 -2,-0.25 6.5,7
5 -20,-9.5 -2,-0.25 6.5,7
6 -20,-6 -2,0.8 6.5,7.375
7 -20,-6 -2,0.8 6.5,7.375
8 -20,-4.25 -2,1.5 6.5,7.667
9 -20,-4.25 -2,1.5 6.5,7.667
10 -20,-3.2 -2,2 6.5,7.9
12 -20,-2.5 -2,2.375 6.5,8.0909
14 -20,-2 -2,-2.667 6.5,8.25
16 -20,-1.625 -2,2.9 6.5,8.384615

Tank Drone - difficulty 126

Int Comp 1 Comp 5 Comp 10
1 -188,-inf -58,-89.5 -21.5,-27.8
5 -188,-93.5 -58,-42.25 -21.5,-17
10 -188,-36.8 -58,-22 -21.5,-8.9
20 -188,-17.9 -58,-10.75 -21.5,-2.6
100 -188,-2.78 -58,1.365385 -21.5,6.563636

To me, it seems as though this formula cares too much about difficulty. It's probably like the electrohack formula #29898 - old and not making a huge amount of sense.
If the goal of this PR is to address the way that the control laptop trivializes things, I think the root of the problem is here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree about the formula, it is likely the root of the problems.

I see now that I had not dug into difficulty so my odds were off a bit (I assumed it was just from the json, but its a calculation itself).

debugmsg( "In robot_control_do_turn success is %s", success);
if( success >= -2 ) {
act->index++; // how many times checked
act->position+=success; // cumulative successes
return; // good so far, continue hacking
} else { // critical failure! we were detected
sounds::sound( z->pos(), 20, sounds::sound_t::speech, _( "a loud robotic voice say, \"Remote intrusion detected! Notifying network. Shutting down transmitter.\"" ));
for( monster &candidate : g->all_monsters() ) {
if( !candidate.is_dead() && candidate.type->in_species( ROBOT ) && candidate.friendly == 0 && rl_dist( z->pos(), candidate.pos() ) <= 10 ) {
candidate.add_effect( effect_not_receiving, 1_turns, num_bp, true );
}
}
z->add_effect( effect_not_receiving, 1_turns, num_bp, true );
act->set_to_null();
return;
}
}

void activity_handlers::robot_control_finish( player_activity *act, player *p )
Expand All @@ -3456,6 +3480,11 @@ void activity_handlers::robot_control_finish( player_activity *act, player *p )
return;
}

if( act->index <= 0 ) {
debugmsg( "robot_control_do_turn not called in ACT_ROBOT_CONTROL" );
return;
}

std::shared_ptr<monster> z = act->monsters[0].lock();
act->monsters.clear();

Expand All @@ -3466,15 +3495,14 @@ void activity_handlers::robot_control_finish( player_activity *act, player *p )

p->add_msg_if_player( _( "You unleash your override attack on the %s." ), z->name() );

/** @EFFECT_INT increases chance of successful robot reprogramming, vs difficulty */
/** @EFFECT_COMPUTER increases chance of successful robot reprogramming, vs difficulty */
const float success = p->get_skill_level( skill_id( "computer" ) ) - 1.5 * ( z->type->difficulty ) /
( ( rng( 2, p->int_cur ) / 2 ) + ( p->get_skill_level( skill_id( "computer" ) ) / 2 ) );
if( success >= 0 ) {
const float avg_success = act->position / act->index;
debugmsg( "In finish with avg_success: %s", avg_success );

if( avg_success >= 0 ) {
p->add_msg_if_player( _( "You successfully override the %s's IFF protocols!" ),
z->name() );
z->friendly = -1;
} else if( success >= -2 ) { //A near success
} else if( avg_success >= -2 ) { //A near success
p->add_msg_if_player( _( "The %s short circuits as you attempt to reprogram it!" ),
z->name() );
z->apply_damage( p, bp_torso, rng( 1, 10 ) ); //damage it a little
Expand All @@ -3490,8 +3518,6 @@ void activity_handlers::robot_control_finish( player_activity *act, player *p )
z->friendly = rng( 5, 40 ); // it didn't
}
}
} else {
p->add_msg_if_player( _( "...but the robot refuses to acknowledge you as an ally!" ) );
}
p->practice( skill_id( "computer" ), 10 );
}
Expand Down
25 changes: 15 additions & 10 deletions src/iuse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ const efftype_id effect_infected( "infected" );
const efftype_id effect_jetinjector( "jetinjector" );
const efftype_id effect_meth( "meth" );
const efftype_id effect_music( "music" );
const efftype_id effect_not_receiving( "not_receiving" );
const efftype_id effect_paincysts( "paincysts" );
const efftype_id effect_panacea( "panacea" );
const efftype_id effect_pet( "pet" );
Expand Down Expand Up @@ -5751,6 +5752,8 @@ bool iuse::robotcontrol_can_target( player *p, const monster &m )
return !m.is_dead()
&& m.type->in_species( ROBOT )
&& m.friendly == 0
&& !m.has_flag(MF_HACK_IMMUNE)
&& !m.has_effect( effect_not_receiving, num_bp )
&& rl_dist( p->pos(), m.pos() ) <= 10;
}

Expand All @@ -5766,16 +5769,21 @@ int iuse::robotcontrol( player *p, item *it, bool, const tripoint & )
return 0;
}

int choice = uilist( _( "Welcome to hackPRO!:" ), {
_( "Prepare IFF protocol override" ),
_( "Set friendly robots to passive mode" ),
_( "Set friendly robots to combat mode" )
} );
/** @EFFECT_INT speeds up hacking preperation */
/** @EFFECT_COMPUTER speeds up hacking preperation */
int deliver_move_cost = std::max( 100, 1000 - p->int_cur * 10 - p->get_skill_level( skill_computer ) * 10 );
const int mode_move_cost = 100;

int choice = uilist(_("Welcome to hackPRO!:"),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
int choice = uilist(_("Welcome to hackPRO!:"),
int choice = uilist(_("Welcome to hackPRO!"),

{{ uilist_entry( 0, true, -1, _("Scan for broadcasting robots"), _("Scan for nearby robots that are accepting connections"), std::to_string(deliver_move_cost))},
{ uilist_entry( 1, true, -1, _("Set friendly robots to passive mode"), _("Robots will stop pursuing all targets for attack"), std::to_string(mode_move_cost))},
{ uilist_entry( 2, true, -1, _("Set friendly robots to combat mode"), _("Robots will pursue all targets for attack"), std::to_string(mode_move_cost))}
});
switch( choice ) {
case 0: { // attempt to make a robot friendly
uilist pick_robot;
pick_robot.text = _( "Choose an endpoint to hack." );
// Build a list of all unfriendly robots in range.
// Build a list of all unfriendly robots in range, that are accepting connections
std::vector< std::shared_ptr< monster> > mons; // TODO: change into vector<Creature*>
std::vector< tripoint > locations;
int entry_num = 0;
Expand Down Expand Up @@ -5808,10 +5816,7 @@ int iuse::robotcontrol( player *p, item *it, bool, const tripoint & )
std::shared_ptr< monster > z = mons[mondex];
p->add_msg_if_player( _( "You start reprogramming the %s into an ally." ), z->name() );

/** @EFFECT_INT speeds up hacking preperation */
/** @EFFECT_COMPUTER speeds up hacking preperation */
int move_cost = std::max( 100, 1000 - p->int_cur * 10 - p->get_skill_level( skill_computer ) * 10 );
player_activity act( activity_id( "ACT_ROBOT_CONTROL" ), move_cost );
player_activity act( activity_id( "ACT_ROBOT_CONTROL" ), deliver_move_cost );
act.monsters.emplace_back( z );

p->assign_activity( act );
Expand Down
4 changes: 3 additions & 1 deletion src/monstergenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,9 @@ const std::map<std::string, m_flag> flag_map = {
{ "DRIPS_NAPALM", MF_DRIPS_NAPALM },
{ "DRIPS_GASOLINE", MF_DRIPS_GASOLINE },
{ "ELECTRIC_FIELD", MF_ELECTRIC_FIELD },
{ "LOUDMOVES", MF_LOUDMOVES }
{ "LOUDMOVES", MF_LOUDMOVES },
{ "HACK_IMMUNE", MF_HACK_IMMUNE },
{ "HACK_DEFENSE", MF_HACK_DEFENSE }
};

}
Expand Down
2 changes: 2 additions & 0 deletions src/mtype.h
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,8 @@ enum m_flag : int {
MF_ELECTRIC_FIELD, // This monster is surrounded by an electrical field that ignites flammable liquids near it
MF_LOUDMOVES, // This monster makes move noises as if ~2 sizes louder, even if flying.
MF_CAN_OPEN_DOORS, // This monster can open doors.
MF_HACK_IMMUNE, // This monster cannot be hacked (with e.g. the control laptop)
MF_HACK_DEFENSE, // This monster has defenses against hacking (with e.g. the control laptop)
MF_MAX // Sets the length of the flags - obviously must be LAST
};

Expand Down