From 8cf4a3be9fd6eb64f33827b0d2bc339cf8b66d7d Mon Sep 17 00:00:00 2001 From: Ian Docherty Date: Wed, 5 Dec 2012 06:28:51 -0500 Subject: [PATCH] Started to modify Trade Ministry for fleets --- docs/Trade.pod | 250 +++++++++++------ lib/Lacuna/DB/Result/Building/Trade.pm | 2 +- lib/Lacuna/RPC/Building/Trade.pm | 353 ++++++++++++++++--------- lib/Lacuna/Role/Fleet/Trade.pm | 43 +++ 4 files changed, 432 insertions(+), 216 deletions(-) create mode 100644 lib/Lacuna/Role/Fleet/Trade.pm diff --git a/docs/Trade.pod b/docs/Trade.pod index 1e46b831..12583856 100644 --- a/docs/Trade.pod +++ b/docs/Trade.pod @@ -5,39 +5,133 @@ The Trade Ministry is accessible via the URL C. It allows you to send ca The list of methods below represents changes and additions to the methods that all L share. + + +=head2 accept_from_market + +Accept a trade offer from the list of available trades. See C. + +Accepts either fixed arguments or a hash of named parameters + + ( session_id, building_id, trade_id) + ( parameter_hash ) + +=head3 session_id (required) + +A session ID. + +=head3 building_id (required) + +This building's ID + +=head3 trade_id (required) + +The unique ID of the trade being accepted. + +=head3 RESPONSE + +Returns the same as C + + +=head2 add_fleet_to_supply_duty + +Take a fleet from your space port and put them on duty supporting your supply chains. + +Accepts either fixed arguments or a hash of named parameters + + ( session_id, building_id, fleet_id ) + ( parameter_hash ) + +Throws 1009. + +=head3 session_id (required) + +A Session ID. + +=head3 building_id (required) + +The unique ID of the Trade Ministry. + +=head3 fleet_id (required) + +The unique ID of the ship you want to add to the fleet. + +=head3 quantity (optional) + +Only available in the named argument call method. The number of ships to put on duty. +Defaults to 1 ship. + +=head3 RESPONSE + +Returns the same as C + + +=head2 add_fleet_to_waste_duty + +Take a fleet from your space port and put them on duty supporting your waste chains. + +Accepts either fixed arguments or a hash of named parameters + + ( session_id, building_id, fleet_id ) + ( parameter_hash ) + +Throws 1009. + +=head3 session_id (required) + +A Session ID. + +=head3 building_id (required) + +The unique ID of the Trade Ministry. + +=head3 fleet_id (required) + +The unique ID of the ship you want to add to the fleet. + +=head3 quantity (optional) + +Only available in the named argument call method. The number of ships to put on duty. +Defaults to 1 ship. + +=head3 RESPONSE + +Returns the same as C + =head2 add_to_market ( session_id, building_id, offer, ask, options ) -Queues a trade for others to see. Returns: +Adds a trade to the market for others to see. - { - "trade_id" : "id-goes-here", - "status" : { ... }, - } +Accepts either fixed arguments or a hash of named parameters -=head3 session_id + ( session_id, building_id, offer, ask, options ) + ( parameter_hash ) -A session id. +=head3 session_id (required) -=head3 building_id +A Session ID. -The unique id of the trade ministry. +=head3 building_id (required) + +The unique ID of the Trade Ministry. -=head3 offer +=head3 offer (required) -An array reference of hash references of items you wish to trade. There are five types of items that can be traded via this mechanism. They are resources, glyphs, plans, prisoners, and ships. +An array reference of hash references of items you wish to trade. +There are five types of items you can trade via this mechanism. +They are C C C C and C [ - { - "type" : "bauxite", - "quantity" : 10000 - }, - { - "type" : "prisoner", - "prisoner_id" : "id-goes-here" - } + { + "type" : "bauxite", + "quantity" : 10000 + }, + { + "type" : "prisoner", + "prisoner_id" : "id-goes-here" + } ] - =over =item resources @@ -45,8 +139,8 @@ An array reference of hash references of items you wish to trade. There are five The hash reference for resources looks like: { - "type" : "bauxite", - "quantity" : 10000 + "type" : "bauxite", + "quantity" : 10000 } =over @@ -61,14 +155,15 @@ The amount of the resource that you want to trade. =back + =item glyphs The hash reference for glyphs looks like this: { - "type" : "glyph", - "name : "bauxite", - "quantity" : 3 + "type" : "glyph", + "name : "bauxite", + "quantity" : 3 } =over @@ -93,14 +188,13 @@ The number of glyphs of type C that you want to trade The hash reference for plans looks like this: { - "type" : "plan", - "plan_type" : "Permanent_AlgaePond", - "level" : 1, - "extra_build_level" : 5, - "quantity" : 4, + "type" : "plan", + "plan_type" : "Permanent_AlgaePond", + "level" : 1, + "extra_build_level" : 5, + "quantity" : 4, } - =over =item type @@ -117,7 +211,7 @@ Level of the plan being added. =item extra_build_level -Level of plus to plan. Note this will be 0 except possibly when the base level is 1. +Extra level of plan to build to. Note this will be 0 except possibly where the level is 1. =item quantity @@ -131,8 +225,8 @@ Number of plans to add. The hash reference for prisoners looks like: { - "type" : "prisoner", - "prisoner_id" : "id-goes-here" + "type" : "prisoner", + "prisoner_id" : "id-goes-here" } =over @@ -148,24 +242,25 @@ The unique id of the spy that you want to trade. See the C method =back -=item ships +=item fleets The hash reference for ships looks like: { - "type" : "ship", - "ship_id" : "id-goes-here" + "type" : "fleet", + "fleet_id" : "id-goes-here", + "quantity" : 3 } =over =item type -Must be exactly C. +Must be exactly C. -=item ship_id +=item fleet_id -The unique id of the ship that you want to trade. See the C method for a list of your prisoners. +The unique id of the fleet that you want to trade. See the C method for a list of your fleets. =back @@ -173,21 +268,44 @@ The unique id of the ship that you want to trade. See the C metho =head3 ask -An integer representing the amount of essentia you are asking for in this trade. Must be between 1 and 99. +A number representing the amount of essentia you are asking for this trade. Must be a number between 0.1 and 99.9. -=head3 options +=head3 options (optional) A hash reference of options to modify the trade. =over -=item ship_id +=item fleet_id + +The ID of the fleet you want to use to transport this trade. See C for details. + +If you don't specify a fleet_id then it will take the first available fleet for the trade. -The specific id of a ship you want to use for this trade. See C for details. +The quantity of ships to send will be based on the number of ships in the fleet and the cargo capacity +of each ship in the fleet. =back + + + + + + + + + + + + + + + + + + =head2 get_ships ( session_id, building_id ) Returns a list of ships that may be traded. Used with the C method. @@ -665,50 +783,6 @@ Note, there is no B because all planets have a waste chain b You may set the B to zero if you want to stop transferring waste. -=head2 add_supply_ship_to_fleet (session_id, building_id, ship_id ) - -Take a ship from your space port and add it to the ships servicing the supply chains. - - { - "status" : { ... }, - } - -Throws 1009. - -=head3 session_id - -A Session ID. - -=head3 building_id - -The unique ID of the Trade Ministry. - -=head3 ship_id - -The unique ID of the ship you want to add to the fleet. - - -=head2 add_waste_ship_to_fleet (session_id, building_id, ship_id ) - -Take a scow from your space port and add it to the ships servicing the waste pushes. - - { - "status" : { ... }, - } - -Throws 1009. - -=head3 session_id - -A Session ID. - -=head3 building_id - -The unique ID of the Trade Ministry. - -=head3 ship_id - -The unique ID of the ship you want to add to the fleet. =head2 remove_supply_ship_from_fleet (session_id, building_id, ship_id ) diff --git a/lib/Lacuna/DB/Result/Building/Trade.pm b/lib/Lacuna/DB/Result/Building/Trade.pm index 9df24aeb..2e437a7b 100644 --- a/lib/Lacuna/DB/Result/Building/Trade.pm +++ b/lib/Lacuna/DB/Result/Building/Trade.pm @@ -409,7 +409,7 @@ sub push_items { my $space_used; ($space_used, $items) = $self->check_payload($items, $ship->hold_size, undef, $ship); - $self->check_payload_ships($items, $target, $options->{stay}); + $self->check_payload_fleet_size($items, $target, $options->{stay}); my ($payload, $meta) = $self->structure_payload($items, $space_used); foreach my $item (@{$items}) { diff --git a/lib/Lacuna/RPC/Building/Trade.pm b/lib/Lacuna/RPC/Building/Trade.pm index a53cf7f2..8d64f82e 100644 --- a/lib/Lacuna/RPC/Building/Trade.pm +++ b/lib/Lacuna/RPC/Building/Trade.pm @@ -9,7 +9,7 @@ use Guard; use List::Util qw(first); use Lacuna::Constants qw(FOOD_TYPES ORE_TYPES SHIP_WASTE_TYPES SHIP_TRADE_TYPES); -with 'Lacuna::Role::TraderRpc','Lacuna::Role::Ship::Trade'; +with 'Lacuna::Role::TraderRpc','Lacuna::Role::Fleet::Trade'; sub app_url { return '/trade'; @@ -19,91 +19,239 @@ sub model_class { return 'Lacuna::DB::Result::Building::Trade'; } -sub get_trade_ships { - my ($self, $session_id, $building_id, $target_id) = @_; - my $empire = $self->get_empire_by_session($session_id); - my $building = $self->get_building($empire, $building_id); - my $target = Lacuna->db->resultset('Lacuna::DB::Result::Map::Body')->find($target_id) if $target_id; - my @ships; - my $ships = $building->trade_ships; - while (my $ship = $ships->next) { +sub accept_from_market { + my $self = shift; + my $args = shift; - push @ships, $ship->get_status($target); + if (ref($args) ne "HASH") { + $args = { + session_id => $args, + building_id => shift, + trade_id => shift, + }; + } + + my $empire = $self->get_empire_by_session($args->{session_id}); + my $building = $self->get_building($empire, $args->{building_id}); + my $trade_id = $args->{trade_id}; + + if (not $trade_id) { + confess [1002, 'You have not specified a trade to accept.']; + } + my $cache = Lacuna->cache; + if (! $cache->add('trade_lock', $trade_id, 1, 5)) { + confess [1013, 'Another buyer has placed an offer on this trade. Please wait a few moments and try again.']; + } + my $guard = guard { + $cache->delete('trade_lock',$trade_id); + }; + + if ($building->level < 1) { + confess [1013, 'You cannot use a trade ministry that has not yet been built.']; + } + + $empire->current_session->check_captcha; + + my $trade = $building->market->find($trade_id); + if (not defined $trade) { + confess [1002, 'Could not find that trade. Perhaps it has already been accepted.',$trade_id]; } + my $offer_fleet = Lacuna->db->resultset('Fleet')->find($trade->fleet_id); + if (not defined $offer_fleet) { + $trade->withdraw; + confess [1009, 'Trade no longer available.']; + } + + my $body = $building->body; + if ($empire->essentia < $trade->ask) { + confess [1011, 'You need at least '.$trade->ask.' essentia to make this trade.'] + } + + $self->check_payload_fleet_id($trade->payload->{fleets}, $body); + + $guard->cancel; + + $empire->spend_essentia($trade->ask, 'Trade Price', 0, $trade->body->empire->id, $trade->body->empire->name )->update; + $trade->body->empire->add_essentia($trade->ask, 'Trade Income', 0, $empire->id, $empire->name)->update; + + $offer_fleet->send( + target => $body, + payload => $trade->payload, + ); + + $trade->body->empire->send_predefined_message( + tags => ['Trade','Alert'], + filename => 'trade_accepted.txt', + params => [join("; ",@{$trade->format_description_of_payload}), $trade->ask.' essentia', $empire->id, $empire->name], + ); + $trade->delete; + return { status => $self->format_status($empire, $building->body), - ships => \@ships, }; } -sub add_supply_ship_to_fleet { - my ($self, $session_id, $building_id, $ship_id) = @_; - my $empire = $self->get_empire_by_session($session_id); - my $building = $self->get_building($empire, $building_id); - unless (defined $building) { + +sub add_fleet_to_supply_duty { + my $self = shift; + my $args = shift; + + if (ref($args) ne "HASH") { + $args = { + session_id => $args, + building_id => shift, + fleet_id => shift, + }; + } + + my $empire = $self->get_empire_by_session($args->{session_id}); + my $building = $self->get_building($empire, $args->{building_id}); + my $fleet_id = $args->{fleet_id}; + my $quantity = $args->{quantity} || 1; + + if (not defined $building) { confess [1002, "Building not found."]; } - my $ship = Lacuna->db->resultset('Lacuna::DB::Result::Ships')->find($ship_id); - unless (defined $ship) { - confess [1002, "Ship not found."]; + my $fleet = Lacune->db->resultset('Fleet')->find($fleet_id); + if (not defined $fleet) { + confess [1002, "Fleet not found."]; } - unless ($ship->task eq 'Docked') { - confess [1009, "That ship is not available."]; + if ($fleet->task ne 'Docked') { + confess [1009, "That fleet is not available."]; } - unless ($ship->hold_size > 0) { - confess [1009, 'That ship has no cargo hold.']; + if ($fleet->hold_size <= 0) { + confess [1009, 'That fleet has no cargo hold.']; } - unless ($ship->body_id eq $building->body_id) { - confess [1013, "You can't manage a ship that is not yours."]; + if ($fleet->body_id != $building->body_id) { + confess [1013, "You can't manage a fleet that is not yours."]; } - unless (first {$ship->type eq $_} (SHIP_TRADE_TYPES)) { + if (not first {$fleet->type eq $_} (SHIP_TRADE_TYPES)) { confess [1009, 'You can only add transport ships to a supply chain.']; } my $max_berth = $building->body->max_berth; - unless ($ship->berth_level <= $max_berth) { - confess [1009, "You don't have a high enough berth for this ship."]; + if ($fleet->berth_level > $max_berth) { + confess [1009, "You don't have a high enough berth for this fleet."]; } - $building->add_supply_ship($ship); + $fleet = $fleet->split($quantity); + + $building->add_fleet_to_supply_duty($fleet); return { status =>$self->format_status($empire, $building->body), }; } -sub add_waste_ship_to_fleet { - my ($self, $session_id, $building_id, $ship_id) = @_; - my $empire = $self->get_empire_by_session($session_id); - my $building = $self->get_building($empire, $building_id); - unless (defined $building) { +sub add_fleet_to_waste_duty { + my $self = shift; + my $args = shift; + + if (ref($args) ne "HASH") { + $args = { + session_id => $args, + building_id => shift, + fleet_id => shift, + }; + } + + my $empire = $self->get_empire_by_session($args->{session_id}); + my $building = $self->get_building($empire, $args->{building_id}); + my $fleet_id = $args->{fleet_id}; + my $quantity = $args->{quantity} || 1; + + if (not defined $building) { confess [1002, "Building not found."]; } - my $ship = Lacuna->db->resultset('Lacuna::DB::Result::Ships')->find($ship_id); - unless (defined $ship) { - confess [1002, "Ship not found."]; + my $fleet = Lacune->db->resultset('Fleet')->find($fleet_id); + if (not defined $fleet) { + confess [1002, "Fleet not found."]; } - unless ($ship->task eq 'Docked') { - confess [1009, "That ship is not available."]; + if ($fleet->task ne 'Docked') { + confess [1009, "That fleet is not available."]; } - unless ($ship->hold_size > 0) { - confess [1009, 'That ship has no cargo hold.']; + if ($fleet->hold_size <= 0) { + confess [1009, 'That fleet has no cargo hold.']; } - unless ($ship->body_id eq $building->body_id) { - confess [1013, "You can't manage a ship that is not yours."]; + if ($fleet->body_id != $building->body_id) { + confess [1013, "You can't manage a fleet that is not yours."]; } - unless ($ship->type =~ m/^scow/) { - confess [1009, 'You can only add scows to a waste chain.']; + if ($fleet->type !~ m/^scow/) { + confess [1009, 'You can only add scows to a supply chain.']; } my $max_berth = $building->body->max_berth; - unless ($ship->berth_level <= $max_berth) { - confess [1009, "You don't have a high enough berth for this ship."]; + if ($fleet->berth_level > $max_berth) { + confess [1009, "You don't have a high enough berth for this fleet."]; } - $building->add_waste_ship($ship); + $fleet = $fleet->split($quantity); + $building->add_fleet_to_waste_duty($fleet); return { status =>$self->format_status($empire, $building->body), }; } +sub add_to_market { + my $self = shift; + my $args = shift; + + if (ref($args) ne "HASH") { + $args = { + session_id => $args, + building_id => shift, + fleet_id => shift, + }; + } + + my $empire = $self->get_empire_by_session($args->{session_id}); + my $building = $self->get_building($empire, $args->{building_id}); + + + + + + my ($self, $session_id, $building_id, $offer, $ask, $options) = @_; + my $empire = $self->get_empire_by_session($session_id); + my $building = $self->get_building($empire, $building_id); + confess [1013, 'You cannot use a trade ministry that has not yet been built.'] unless $building->level > 0; + my $cache = Lacuna->cache; + if (! $cache->add('trade_add_lock', $building_id, 1, 5)) { + confess [1013, 'You have a trade setup in progress. Please wait a few moments and try again.']; + } + my $guard = guard { + $cache->delete('trade_add_lock',$building_id); + }; + my $trade = $building->add_to_market($offer, $ask, $options); + return { + trade_id => $trade->id, + status => $self->format_status($empire, $building->body), + }; +} + + +#------------------------------------------------------------------------------ + + + + + + + +sub get_trade_ships { + my ($self, $session_id, $building_id, $target_id) = @_; + my $empire = $self->get_empire_by_session($session_id); + my $building = $self->get_building($empire, $building_id); + my $target = Lacuna->db->resultset('Lacuna::DB::Result::Map::Body')->find($target_id) if $target_id; + my @ships; + my $ships = $building->trade_ships; + while (my $ship = $ships->next) { + + push @ships, $ship->get_status($target); + } + return { + status => $self->format_status($empire, $building->body), + ships => \@ships, + }; +} + sub remove_supply_ship_from_fleet { my ($self, $session_id, $building_id, $ship_id) = @_; my $empire = $self->get_empire_by_session($session_id); @@ -456,87 +604,38 @@ sub withdraw_from_market { } -sub accept_from_market { - my ($self, $session_id, $building_id, $trade_id) = @_; - unless ($trade_id) { - confess [1002, 'You have not specified a trade to accept.']; - } - my $cache = Lacuna->cache; - if (! $cache->add('trade_lock', $trade_id, 1, 5)) { - confess [1013, 'Another buyer has placed an offer on this trade. Please wait a few moments and try again.']; - } - my $guard = guard { - $cache->delete('trade_lock',$trade_id); - }; - - my $empire = $self->get_empire_by_session($session_id); - my $building = $self->get_building($empire, $building_id); - confess [1013, 'You cannot use a trade ministry that has not yet been built.'] unless $building->level > 0; - - $empire->current_session->check_captcha; - - my $trade = $building->market->find($trade_id); - unless (defined $trade) { - confess [1002, 'Could not find that trade. Perhaps it has already been accepted.',$trade_id]; - } - my $offer_ship = Lacuna->db->resultset('Lacuna::DB::Result::Ships')->find($trade->ship_id); - unless (defined $offer_ship) { - $trade->withdraw; - confess [1009, 'Trade no longer available.']; - } - - my $body = $building->body; - unless ($empire->essentia >= $trade->ask) { - confess [1011, 'You need at least '.$trade->ask.' essentia to make this trade.'] - } - - $self->check_payload_ships_id($trade->payload->{ships}, $body); - - $guard->cancel; - - $empire->spend_essentia($trade->ask, 'Trade Price', 0, $trade->body->empire->id, $trade->body->empire->name )->update; - $trade->body->empire->add_essentia($trade->ask, 'Trade Income', 0, $empire->id, $empire->name)->update; - - $offer_ship->send( - target => $body, - payload => $trade->payload, - ); - - $trade->body->empire->send_predefined_message( - tags => ['Trade','Alert'], - filename => 'trade_accepted.txt', - params => [join("; ",@{$trade->format_description_of_payload}), $trade->ask.' essentia', $empire->id, $empire->name], - ); - $trade->delete; - - return { - status => $self->format_status($empire, $building->body), - }; -} - -sub add_to_market { - my ($self, $session_id, $building_id, $offer, $ask, $options) = @_; - my $empire = $self->get_empire_by_session($session_id); - my $building = $self->get_building($empire, $building_id); - confess [1013, 'You cannot use a trade ministry that has not yet been built.'] unless $building->level > 0; - my $cache = Lacuna->cache; - if (! $cache->add('trade_add_lock', $building_id, 1, 5)) { - confess [1013, 'You have a trade setup in progress. Please wait a few moments and try again.']; - } - my $guard = guard { - $cache->delete('trade_add_lock',$building_id); - }; - my $trade = $building->add_to_market($offer, $ask, $options); - return { - trade_id => $trade->id, - status => $self->format_status($empire, $building->body), - }; -} - - -__PACKAGE__->register_rpc_method_names(qw(get_supply_ships view_supply_chains add_supply_ship_to_fleet remove_supply_ship_from_fleet create_supply_chain delete_supply_chain update_supply_chain get_waste_ships view_waste_chains add_waste_ship_to_fleet remove_waste_ship_from_fleet update_waste_chain report_abuse view_my_market view_market accept_from_market withdraw_from_market add_to_market push_items get_trade_ships get_stored_resources get_ships get_ship_summary get_prisoners get_plans get_plan_summary get_glyphs get_glyph_summary)); +__PACKAGE__->register_rpc_method_names(qw( + accept_from_market + add_fleet_to_supply_duty + add_fleet_to_waste_duty + add_to_market + create_supply_chain + delete_supply_chain + get_glyph_summary + get_glyphs + get_plan_summary + get_plans + get_ship_summary + get_ships + get_stored_resources + get_supply_ships + get_prisoners + get_trade_ships + get_waste_ships + push_items + remove_supply_ship_from_fleet + remove_waste_ship_from_fleet + report_abuse + update_supply_chains + update_waste_chains + view_market + view_my_market + view_supply_chains + view_waste_chains + withdraw_from_market +)); no Moose; __PACKAGE__->meta->make_immutable; diff --git a/lib/Lacuna/Role/Fleet/Trade.pm b/lib/Lacuna/Role/Fleet/Trade.pm new file mode 100644 index 00000000..3886f26a --- /dev/null +++ b/lib/Lacuna/Role/Fleet/Trade.pm @@ -0,0 +1,43 @@ +package Lacuna::Role::Fleet::Trade; + +use Moose::Role; +use feature "switch"; + +my $no_docks_exception = [1011, 'There are not enough docks available to receive the ships.']; +my $no_spaceport_exception = [1011, 'There is no space port available to receive the ships.']; + +# Check if the payload has ships and if so if the target has room for them +# +sub check_payload_fleet_size { + my ($self, $items, $target, $fleet_stay) = @_; + + return if not $items; + + my $ship_count = $fleet_stay ? $fleet->quantity : 0; + my @fleets; + + if (ref $items eq 'HASH') { + my $f = $items->{fleet} + if ($f) { + @fleets = @$f; + } + } + if (ref $items eq 'ARRAY') { + @fleets = grep {$_->{type} eq 'fleet'} @$items; + } + for my $fleet (@fleets) { + $ship_count += $fleet->{quantity}; + } + if ($ship_count) { + my $spaceport = $target->spaceport; + if (not defined $spaceport) { + confess $no_spaceport_exception; + } + if ($spaceport->docs_available < $ship_count) { + confess $no_docks_exception; + } + } +} + +1; + -- 2.51.2