diff --git a/lib/Lacuna/DB/Result/Ships/SpyPod.pm b/lib/Lacuna/DB/Result/Ships/SpyPod.pm index b0a1c1f1..b192db80 100644 --- a/lib/Lacuna/DB/Result/Ships/SpyPod.pm +++ b/lib/Lacuna/DB/Result/Ships/SpyPod.pm @@ -26,6 +26,7 @@ with "Lacuna::Role::Ship::Send::NotIsolationist"; with "Lacuna::Role::Ship::Send::LoadWithSpies"; with "Lacuna::Role::Ship::Send::IsHostile"; with "Lacuna::Role::Ship::Arrive::CaptureWithSpies"; +with "Lacuna::Role::Ship::Arrive::PickUpSpies"; with "Lacuna::Role::Ship::Arrive::CargoExchange"; with "Lacuna::Role::Ship::Arrive::Scuttle"; diff --git a/lib/Lacuna/DB/Result/Ships/SpyShuttle.pm b/lib/Lacuna/DB/Result/Ships/SpyShuttle.pm index a32487dd..76336f0e 100644 --- a/lib/Lacuna/DB/Result/Ships/SpyShuttle.pm +++ b/lib/Lacuna/DB/Result/Ships/SpyShuttle.pm @@ -27,6 +27,7 @@ with "Lacuna::Role::Ship::Send::LoadWithSpies"; with "Lacuna::Role::Ship::Send::IsHostile"; with "Lacuna::Role::Ship::Arrive::CaptureWithSpies"; with "Lacuna::Role::Ship::Arrive::Orbit"; +with "Lacuna::Role::Ship::Arrive::PickUpSpies"; with "Lacuna::Role::Ship::Arrive::CargoExchange"; no Moose; diff --git a/lib/Lacuna/DB/Result/Spies.pm b/lib/Lacuna/DB/Result/Spies.pm index 1f5a82ac..5c9d0028 100644 --- a/lib/Lacuna/DB/Result/Spies.pm +++ b/lib/Lacuna/DB/Result/Spies.pm @@ -171,6 +171,11 @@ sub offensive_assignments { recovery => $self->recovery_time(60 * 60 * 8), skill => 'mayhem', }, + { + task =>'Sabotage Defenses', + recovery => $self->recovery_time(60 * 60 * 10), + skill => 'mayhem', + }, { task =>'Sabotage BHG', recovery => 0, @@ -262,13 +267,23 @@ sub defensive_assignments { sub neutral_assignments { my $self = shift; - return ( + my @assignments = ( { task => 'Idle', recovery => 0, skill => 'none', }, ); + if ($self->on_body->id ne $self->from_body_id) { + push @assignments, ( + { + task =>'Bugout', + recovery => 0, + skill => '*', + }, + ); + } + return @assignments; } sub get_possible_assignments { @@ -531,6 +546,7 @@ use constant assignments => ( 'Rescue Comrades', 'Sabotage Resources', 'Appropriate Resources', + 'Sabotage Defenses', 'Sabotage Infrastructure', 'Sabotage BHG', 'Assassinate Operatives', @@ -539,6 +555,7 @@ use constant assignments => ( 'Incite Rebellion', 'Appropriate Technology', 'Incite Insurrection', + 'Bugout', 'Intel Training', 'Mayhem Training', 'Politics Training', @@ -620,6 +637,9 @@ sub assign { elsif ($assignment eq 'Security Sweep') { return $self->run_security_sweep($mission); } + elsif ($assignment eq 'Bugout') { + return $self->bugout($mission); + } else { return $self->run_mission($mission); } @@ -684,6 +704,7 @@ my %outcomes = ( 'Appropriate Technology' => 'appropriate_tech', 'Sabotage Probes' => 'sabotage_probes', 'Rescue Comrades' => 'rescue_comrades', + 'Sabotage Defenses' => 'sabotage_defenses', 'Sabotage Resources' => 'sabotage_resources', 'Appropriate Resources' => 'appropriate_resources', 'Assassinate Operatives' => 'assassinate_operatives', @@ -943,6 +964,88 @@ sub run_security_sweep { return $out; } +sub bugout { + my ($self, $mission) = @_; + + if (!$self->empire->alliance_id || $self->empire->alliance_id != $self->on_body->empire->alliance_id ) { + my $power = $self->offense + $self->intel_xp; + my $toughness = 0; + my $defender = $self->get_defender; + my $hfa = 0; + if (defined $defender) { + $toughness = $defender->defense + $defender->intel_xp; + $hfa = $defender->home_field_advantage; + } + my $breakthru = ($power - $toughness - $hfa) + $self->luck; + + $breakthru = ( randint(0,99) < 5) ? $breakthru * -1 : $breakthru; + if ($breakthru < -2000) { + $self->on_body->add_news(50, + 'An enemy agent narrowly got away from the security forces of %s.', + $self->on_body->name); + $self->on_body->empire->send_predefined_message( + tags => ['Spies','Alert'], + filename => 'unauthorized_launch_tracked.txt', + params => [$self->on_body->id, $self->on_body->name, + $self->from_body->x, $self->from_body->y, $self->from_body->name], + ); +#Narrow escape home + } + elsif ($breakthru > 500) { +#Clean escape + $self->on_body->add_news(10, + 'An unauthorized ship launching happened on %s.', + $self->on_body->name); + } + else { + $self->on_body->add_news(50, + 'An unauthorized ship launching happened on %s.', + $self->on_body->name); + $self->on_body->empire->send_predefined_message( + tags => ['Spies','Alert'], + filename => 'unauthorized_launch.txt', + params => [$self->on_body->id, $self->on_body->name], + ); + } + $self->empire->send_predefined_message( + tags => ['Intelligence'], + filename => 'on_way_home.txt', + params => [ + $self->on_body->empire->id, + $self->on_body->empire->name, + $self->on_body->x, + $self->on_body->y, + $self->on_body->name, + $self->name, + $self->from_body->id, + $self->from_body->name], + ); + } + my $spy_pod = Lacuna->db->resultset('Ships')->new({ + body_id => $self->from_body_id, + type => 'spy_pod', + name => "Bugout", + })->insert; + $spy_pod->date_available(DateTime->now); + $spy_pod->speed(1000+ ($self->level*100)); + $spy_pod->send( + target => $self->on_body, + direction => 'in', + payload => { spies => [ $self->id ] } + ); + $self->available_on($spy_pod->date_available); + $self->on_body_id($self->from_body_id); + $self->task('Travelling'); + $self->started_assignment(DateTime->now); + $self->update; + my $out = { result => 'Success', +# message_id => $message_id, + reason => random_element(['Mom would have been proud.', + 'Done.', + 'That is why you pay me the big bucks.']) }; + return $out; +} + sub get_defender { my ($self, $mission) = @_; @@ -1546,6 +1649,26 @@ sub abduct_operatives_loss { } } +sub sabotage_defenses { + my $self = shift; + given (randint(1,4)) { + when (1) { return $self->knock_defender_unconscious(@_) } + when (2) { return $self->shut_down_defenses(@_) } + when (3) { return $self->shut_down_defenses(@_) } + when (4) { return $self->destroy_defense_ship(@_) } +# when (5) { return $self->destroy_incoming_supply(@_) } + } +} + +sub sabotage_defenses_loss { + my $self = shift; + given (randint(1,3)) { + when (1) { return $self->capture_saboteur(@_) } + when (2) { return $self->thwart_saboteur(@_) } + when (3) { return $self->knock_attacker_unconscious(@_) } + } +} + sub sabotage_resources { my $self = shift; given (randint(1,9)) { @@ -2269,6 +2392,44 @@ sub destroy_infrastructure { )->id; } +sub destroy_defense_ship { + my ($self, $defender) = @_; + my $ship = $self->on_body->ships->search( + {task => 'Docked', + type => {'in' => ['sweeper', + 'fighter', + 'drone', + ]}, + }, + {rows => 1, order_by => 'rand()' } + )->single; + + return $self->ship_not_found->id unless (defined $ship); + $self->things_destroyed( $self->things_destroyed + 1 ); + $self->on_body->empire->send_predefined_message( + tags => ['Spies','Alert'], + filename => 'ship_blew_up_at_port.txt', + params => [$ship->type_formatted, $self->on_body->id, $self->on_body->name], + ); + my $message = $self->empire->send_predefined_message( + tags => ['Intelligence'], + filename => 'sabotage_report.txt', + params => [$ship->type_formatted, + $self->on_body->x, + $self->on_body->y, + $self->on_body->name, + $self->name, + $self->from_body->id, + $self->from_body->name], + ); + $self->on_body->add_news(90, + 'Today officials on %s are investigating the explosion of a %s at the Space Port.', + $self->on_body->name, + $ship->type_formatted); + $ship->delete; + return $message->id; +} + sub destroy_ship { my ($self, $defender) = @_; my $ship = $self->on_body->ships->search( @@ -2788,6 +2949,46 @@ sub thwart_thief { return $defender->thwart_a_spy($self)->id; } +sub shut_down_defenses { + my ($self, $defender) = @_; + + my ($building) = sort { + rand() <=> rand() + } + grep { + ($_->efficiency > 0) and ( + $_->class eq 'Lacuna::DB::Result::Building::SAW' or + $_->class eq 'Lacuna::DB::Result::Building::Shipyard' or + $_->class eq 'Lacuna::DB::Result::Building::Intelligence' or + $_->class eq 'Lacuna::DB::Result::Building::Security' or + $_->class eq 'Lacuna::DB::Result::Building::Module::PoliceStation' or + $_->class eq 'Lacuna::DB::Result::Building::Permanent::GratchsGauntlet' or + $_->class eq 'Lacuna::DB::Result::Building::Permanent::CitadelOfKnope' ) + } + @{$self->on_body->building_cache}; + + return $self->building_not_found->id unless defined $building; + $self->on_body->empire->send_predefined_message( + tags => ['Spies','Alert'], + filename => 'building_loss_of_power.txt', + params => [$building->name, $self->on_body->id, $self->on_body->name], + ); + $building->spend_efficiency(2 * $self->level)->update; + $self->on_body->add_news(25, + 'Employees at the %s on %s were left in the dark today during a power outage.', + $building->name, + $self->on_body->name); + return $self->empire->send_predefined_message( + tags => ['Intelligence'], + filename => 'we_disabled_a_building.txt', + params => [$building->name, + $self->on_body->x, + $self->on_body->y, + $self->on_body->name, + $self->format_from], + )->id; +} + sub shut_down_building { my ($self, $defender) = @_; diff --git a/lib/Lacuna/Role/Ship/Arrive/Orbit.pm b/lib/Lacuna/Role/Ship/Arrive/Orbit.pm index f44e6cd9..bff33ede 100644 --- a/lib/Lacuna/Role/Ship/Arrive/Orbit.pm +++ b/lib/Lacuna/Role/Ship/Arrive/Orbit.pm @@ -12,6 +12,7 @@ after handle_arrival_procedures => sub { # only orbit on arrival to the foreign body return if $self->direction eq 'in'; + return if ( $self->payload->{fetch_spies} ); # Don't orbit if we're fetching $self->orbit->update; confess [-1]; diff --git a/lib/Lacuna/Role/Ship/Send/LoadWithSpies.pm b/lib/Lacuna/Role/Ship/Send/LoadWithSpies.pm index 1e91e2e7..f2859fef 100644 --- a/lib/Lacuna/Role/Ship/Send/LoadWithSpies.pm +++ b/lib/Lacuna/Role/Ship/Send/LoadWithSpies.pm @@ -8,6 +8,7 @@ after send => sub { return if ( $self->direction eq 'in' && $self->type ne 'spy_shuttle' ); # load outbound ships and inbound spy shuttles return if ( $self->payload->{mercenary} ); # Mercenary already loaded return if ( $self->payload->{spies} ); # Spies already loaded + return if ( $self->payload->{fetch_spies} ); # Don't send spies if we are fetching my $arrives = DateTime->now->add(seconds=>$self->calculate_travel_time($self->foreign_body)); my @spies; my $to_body = $self->direction eq 'out' ? $self->foreign_body : $self->body; diff --git a/var/messages/on_way_home.txt b/var/messages/on_way_home.txt new file mode 100644 index 00000000..af63d8f9 --- /dev/null +++ b/var/messages/on_way_home.txt @@ -0,0 +1,7 @@ +On Way Home +~~~ +I managed to give {Empire %s %s}'s goons the slip and am heading away from {Starmap %s %s %s}. I'll be home soon. + +Regards, + +%s of {Planet %s %s} diff --git a/var/messages/unauthorized_launch.txt b/var/messages/unauthorized_launch.txt new file mode 100644 index 00000000..0ee9c69c --- /dev/null +++ b/var/messages/unauthorized_launch.txt @@ -0,0 +1,8 @@ +Unauthorized Launch +~~~ +A launch was seen leaving the atmosphere just now from {Planet %s %s}. + +Regards, + +Your Humble Assistant + diff --git a/var/messages/unauthorized_launch_tracked.txt b/var/messages/unauthorized_launch_tracked.txt new file mode 100644 index 00000000..6e4ca9a3 --- /dev/null +++ b/var/messages/unauthorized_launch_tracked.txt @@ -0,0 +1,9 @@ +Launch Tracked +~~~ +A launch was seen leaving the atmosphere just now from {Planet %s %s}. +We managed to track it long enough to see that it is headed for {Starmap %s %s %s}. + +Regards, + +Your Humble Assistant + diff --git a/var/www/public/changes.txt b/var/www/public/changes.txt index a2b231a1..c0df7045 100644 --- a/var/www/public/changes.txt +++ b/var/www/public/changes.txt @@ -1,6 +1,9 @@ 3.0907: - Add: Timer added to colony object preventing passage into Neutral Zone. - Add: colonies and stations added to empire stat. planets kept to maintain backwards compatibility + - Fix: Fetching Spies no longer will send more spies. + - Add: Sabotage Defenses task added for spies. + - Add: Bugout task for spies added to get spies home. 3.0906: - Fix: Some fixes to the send_ship_types API call.