diff --git a/docs/Shipyard.pod b/docs/Shipyard.pod index 6fe73955..34c8136b 100644 --- a/docs/Shipyard.pod +++ b/docs/Shipyard.pod @@ -61,8 +61,25 @@ A session id. The unique id of the Shipyard. - - +=head2 subsidize_ship ( session_id, building_id, ship_id ) + +Will spend 1 essentia to complete the build of the specified ship immediately. Returns C. + +Throws 1011. + +=head3 session_id + +A session id. + +=head3 building_id + +The unique id of the Shipyard. + +=head3 ship_id + +The unique id of the Ship, as returned in C + + =head2 get_buildable ( session_id, building_id, [ tag ] ) Returns a list of buildable ships and their costs, and if they're not buildable, gives a reason why not in the form of an exception. diff --git a/lib/Lacuna/DB/Result/Building.pm b/lib/Lacuna/DB/Result/Building.pm index 6d684f05..3560097b 100755 --- a/lib/Lacuna/DB/Result/Building.pm +++ b/lib/Lacuna/DB/Result/Building.pm @@ -879,7 +879,6 @@ sub finish_upgrade { $body->needs_recalc(1); $body->needs_surface_refresh(1); -# $body->tick; $body->update; $empire->add_medal($type); diff --git a/lib/Lacuna/DB/Result/Ships.pm b/lib/Lacuna/DB/Result/Ships.pm index 08a5886d..43a008b7 100644 --- a/lib/Lacuna/DB/Result/Ships.pm +++ b/lib/Lacuna/DB/Result/Ships.pm @@ -434,6 +434,69 @@ sub finish_construction { return $self; } + +# Remove one ship from the build queue, reschedule all other following ships +# +sub reschedule_queue { + my ($self) = @_; + + my $start_time = DateTime->now; + my $ship_end_time; # when the current ship completes + my $building_time; # The end time of the building working + + my @ships_queue = Lacuna->db->resultset('Ships')->search({ + task => 'Building', + shipyard_id => $self->shipyard_id, + },{ + order_by => { -asc => 'date_available'}, + })->all; + + my $ship; + $building_time = DateTime->now; + BUILD: + while ($ship = shift @ships_queue) { + $ship_end_time = $ship->date_available; + if ($ship->id == $self->id) { + last BUILD; + } + # Start time of the next ship is the end time of this one + $start_time = $ship_end_time; + } + if ($ship) { + # Remove this scheduled event + my $duration = $ship_end_time->epoch - $start_time->epoch; + # Don't bother to reschedule if it is a small period + if ($duration > 5) { + my ($schedule) = Lacuna->db->resultset('Schedule')->search({ + parent_table => 'Ships', + parent_id => $self->id, + task => 'finish_construction', + }); + $schedule->delete if defined $schedule; + $building_time = $start_time; + + # Change the scheduled time for all subsequent builds (if any) + while (my $ship = shift @ships_queue) { + my $construction_ends = $ship->date_available->clone->subtract(seconds => $duration); + $building_time = $construction_ends; + + $ship->date_available($construction_ends); + $ship->update; + Lacuna->db->resultset('Schedule')->reschedule({ + parent_table => 'Ships', + parent_id => $ship->id, + task => 'finish_construction', + delivery => $construction_ends, + }); + } + } + } + # Set shipyard end time + my $shipyard = Lacuna->db->resultset('Building')->find({ id => $self->shipyard_id }); + $shipyard->reschedule_work($building_time); +} + + sub orbit { my ($self) = @_; $self->task('Orbiting'); diff --git a/lib/Lacuna/RPC/Building/Development.pm b/lib/Lacuna/RPC/Building/Development.pm index 2add1790..1c0a43f0 100644 --- a/lib/Lacuna/RPC/Building/Development.pm +++ b/lib/Lacuna/RPC/Building/Development.pm @@ -60,6 +60,9 @@ sub subsidize_one_build { confess [1003, "You must have a functional development ministry!"]; } my $scheduled_building = Lacuna->db->resultset('Building')->find({id => $args->{scheduled_id}}); + if (not $scheduled_building) { + confess [1003, "Cannot find that building."]; + } if ($scheduled_building->body_id != $building->body_id) { confess [1003, "That building is not on the same planet as your development ministry."]; } diff --git a/lib/Lacuna/RPC/Building/Shipyard.pm b/lib/Lacuna/RPC/Building/Shipyard.pm index 0a6ebd65..2695030d 100644 --- a/lib/Lacuna/RPC/Building/Shipyard.pm +++ b/lib/Lacuna/RPC/Building/Shipyard.pm @@ -78,6 +78,44 @@ sub subsidize_build_queue { } +sub subsidize_ship { + my ($self, $args) = @_; + + if (ref($args) ne "HASH") { + confess [1000, "You have not supplied a hash reference"]; + } + my $empire = $self->get_empire_by_session($args->{session_id}); + my $building = $self->get_building($empire, $args->{building_id}); + unless ($building->level > 0 and $building->efficiency == 100) { + confess [1003, "You must have a functional Space Port!"]; + } + my $scheduled_ship = Lacuna->db->resultset('Ships')->find({id => $args->{ship_id}}); + + if (not $scheduled_ship) { + confess [1003, "Cannot find that ship!"]; + } + if ($scheduled_ship->shipyard_id != $building->id or $scheduled_ship->task ne 'Building') { + confess [1003, "That ship is not in construction at this shipyard!"]; + } + + my $cost = 1; + unless ($empire->essentia >= $cost) { + confess [1011, "Not enough essentia."]; + } + $empire->spend_essentia({ + amount => $cost, + reason => 'ship build subsidy after the fact', + }); + $empire->update; + + $scheduled_ship->reschedule_queue; + $scheduled_ship->finish_construction; + + return $self->view_build_queue($empire, $building); + +} + + sub build_ship { my ($self, $session_id, $building_id, $type, $quantity) = @_; $quantity = defined $quantity ? $quantity : 1; @@ -159,6 +197,7 @@ __PACKAGE__->register_rpc_method_names(qw( build_ship view_build_queue subsidize_build_queue + subsidize_ship )); diff --git a/t/520_shipyard_subsidize.t b/t/520_shipyard_subsidize.t new file mode 100644 index 00000000..48a9acff --- /dev/null +++ b/t/520_shipyard_subsidize.t @@ -0,0 +1,20 @@ +use lib '../lib'; +use Test::More tests => 14; +use Test::Deep; +use Data::Dumper; +use 5.010; +use DateTime; + +use TestHelper; + +my $tester = TestHelper->new({empire_name => 'icydee'}); + +$tester->use_existing_test_empire; +diag("tester = [$tester]"); + +my $session_id = $tester->session->id; +my $empire = $tester->empire; +my $home = $empire->home_planet; + +$result = $tester->post('shipyard', 'subsidize_ship', [{session_id => $session_id, building_id => 131851, ship_id => 83668}]); + diff --git a/t/TestHelper.pm b/t/TestHelper.pm index f5279364..d345f512 100644 --- a/t/TestHelper.pm +++ b/t/TestHelper.pm @@ -35,7 +35,7 @@ has empire => ( has session => ( is => 'rw', -); + ); has x => ( is => 'rw', @@ -61,7 +61,9 @@ sub clear_all_test_empires { name => {like => $name}, }); while (my $empire = $empires->next) { - $empire->essentia(0); + $empire->essentia_game(0); + $empire->essentia_free(0); + $empire->essentia_paid(0); $empire->update; my $planets = $empire->planets; diff --git a/var/www/public/changes.txt b/var/www/public/changes.txt index 3496c60b..0cfa8148 100644 --- a/var/www/public/changes.txt +++ b/var/www/public/changes.txt @@ -7,6 +7,7 @@ - Fix: Make sure body condition current when spies arrive. - Fix: Use proper planet names for incoming on Spy Travel report. - Fix: resources.json water-reclamation-facility + - Add: Ability to subsidize individual ships in the shipyard build queue 3.0880: - Fix: Glyphs should now show in alpha order in the TM and SST