Something went wrong. Try again.
Perl game server for TLE Community
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455package Lacuna::DB::Result::Building::Trade;
use Moose;use List::Util qw(max min);use Carp;use Scalar::Util qw(weaken);
use utf8;use List::Util qw(max);use Data::Dumper;use Lacuna::Constants qw(SHIP_TRADE_TYPES SHIP_WASTE_TYPES);
no warnings qw(uninitialized);extends 'Lacuna::DB::Result::Building';
with 'Lacuna::Role::Trader','Lacuna::Role::Ship::Trade';
around 'build_tags' => sub { my ($orig, $class) = @_; return ($orig->($class), qw(Infrastructure Ships Trade));};
use constant controller_class => 'Lacuna::RPC::Building::Trade';
use constant max_instances_per_planet => 1;
use constant university_prereq => 5;
use constant image => 'trade';
use constant name => 'Trade Ministry';
use constant food_to_build => 75;
use constant energy_to_build => 75;
use constant ore_to_build => 75;
use constant water_to_build => 75;
use constant waste_to_build => 80;
use constant time_to_build => 150;
use constant food_consumption => 5;
use constant energy_consumption => 28;
use constant ore_consumption => 2;
use constant water_consumption => 5;
use constant waste_production => 1;
sub supply_chains { my ($self) = @_;
return Lacuna->db->resultset('Lacuna::DB::Result::SupplyChain')->search({ planet_id => $self->body_id });}
sub waste_chains { my $self = shift;
# If there is no waste chain, then create a default one my $waste_chain = Lacuna->db->resultset('Lacuna::DB::Result::WasteChain')->search({ planet_id => $self->body_id }); if ($waste_chain->count == 0) { Lacuna->db->resultset('Lacuna::DB::Result::WasteChain')->create({ planet_id => $self->body_id, star_id => $self->body->star_id, waste_hour => 0, percent_transferred => 0, }); } return Lacuna->db->resultset('Lacuna::DB::Result::WasteChain')->search({ planet_id => $self->body_id });}
# Ships that are currently in a supply chainsub supply_ships { my ($self) = @_;
return Lacuna->db->resultset('Lacuna::DB::Result::Ships')->search({ body_id => $self->body_id, task => 'Supply Chain', });}
# Ships that are currently in a waste chainsub waste_ships { my ($self) = @_;
return Lacuna->db->resultset('Lacuna::DB::Result::Ships')->search({ body_id => $self->body_id, task => 'Waste Chain', });}
# All ships that are either in a supply chain, or available to be sosub all_supply_ships { my $self = shift; my $body = $self->body; return Lacuna->db->resultset('Lacuna::DB::Result::Ships')->search({ body_id => $self->body_id, -or => { task => 'Supply Chain', -and => [ task => 'Docked', berth_level => {'<=' => $body->max_berth}, type => { '=', [SHIP_TRADE_TYPES]}, ] } },{ order_by => {-desc => [qw(task hold_size)]}, });}
# All ships that are either in a waste chain, or available to be sosub all_waste_ships { my $self = shift; my $body = $self->body; return Lacuna->db->resultset('Lacuna::DB::Result::Ships')->search({ body_id => $self->body_id, -or => { task => 'Waste Chain', -and => [ task => 'Docked', berth_level => {'<=' => $body->max_berth}, type => { '=', [SHIP_WASTE_TYPES]}, ] } },{ order_by => {-desc => [qw(task hold_size)]}, });}
sub max_chains { my $self = shift; return ceil($self->effective_level);}
sub add_waste_ship { my ($self, $ship) = @_; $ship->task('Waste Chain'); $ship->update; $self->recalc_waste_production; return $self;}
sub add_supply_ship { my ($self, $ship) = @_; $ship->task('Supply Chain'); $ship->update; $self->recalc_supply_production; return $self;}
sub send_waste_ship_home { my ($self, $star, $ship) = @_; $ship->send( target => $star, direction => 'in', task => 'Travelling', emptyscow => 1, ); $self->recalc_waste_production; return $self;}
sub send_supply_ship_home { my ($self, $planet, $ship) = @_; $ship->send( target => $planet, direction => 'in', task => 'Travelling', ); $self->recalc_supply_production; return $self;}
sub add_waste_chain { my ($self, $star, $waste_hour) = @_; Lacuna->db->resultset('Lacuna::DB::Result::WasteChain')->new({ planet_id => $self->body_id, star_id => $star->id, waste_hour => $waste_hour, })->insert; $self->recalc_waste_production; return $self;}
sub remove_waste_chain { my ($self, $waste_chain) = @_; if ($self->waste_chains->count == 1) { my $ships = $self->waste_ships; while (my $ship = $ships->next) { $self->send_waste_ship_home($waste_chain->star, $ship); } } $waste_chain->delete; $self->recalc_waste_production; return $self;}
sub remove_supply_chain { my ($self, $supply_chain) = @_; if ($self->supply_chains->count == 1) { my $ships = $self->supply_ships; while (my $ship = $ships->next) { $self->send_supply_ship_home($supply_chain->target, $ship); } } my $target = $supply_chain->target; $supply_chain->delete; $self->recalc_supply_production; $target->needs_recalc(1); $target->update; return $self;}
sub recalc_supply_production { my ($self) = @_; my $body = $self->body;
# Determine the resource/hour/distance for the ship my $ship_rphpd = 0; my $ships = $self->supply_ships; while (my $ship = $ships->next) { $ship_rphpd += $ship->hold_size * $ship->speed; } # Determine the resource/hour for supply chains my $chain_rphpd = 0; my $supply_chains = $self->supply_chains->search({},{prefetch => 'target'}); while (my $supply_chain = $supply_chains->next) { $chain_rphpd += $body->calculate_distance_to_target($supply_chain->target) * 2 * $supply_chain->resource_hour; } my $shipping_capacity = $chain_rphpd ? sprintf('%.0f',($ship_rphpd / $chain_rphpd) * 100) : 0;
$supply_chains->reset; while (my $supply_chain = $supply_chains->next) { $supply_chain->percent_transferred($shipping_capacity); $supply_chain->update; my $target = $supply_chain->target; $target->needs_recalc(1); $target->update; }
$body->needs_recalc(1); $body->update;
return $self;}
sub recalc_waste_production { my ($self) = @_; my $body = $self->body;
# Determine the waste/hour/distance for ship my $ship_wphpd = 0; my $ships = $self->waste_ships; while (my $ship = $ships->next) { $ship_wphpd += $ship->hold_size * $ship->speed; }
# Determine the waste/hour for waste chains my $chain_wphpd = 0; my $waste_chains = $self->waste_chains; while (my $waste_chain = $waste_chains->next) { $chain_wphpd += $body->calculate_distance_to_target($waste_chain->star) * 2 * $waste_chain->waste_hour; } my $shipping_capacity = $chain_wphpd ? int(100 * $ship_wphpd / $chain_wphpd) : 0;
$waste_chains->reset; while (my $waste_chain = $waste_chains->next) { $waste_chain->percent_transferred($shipping_capacity); $waste_chain->update; }
$body->needs_recalc(1); $body->update; return $self;}
before delete => sub { my ($self) = @_; my $market = Lacuna->db->resultset('Lacuna::DB::Result::Market'); my @to_be_deleted = $market->search( { body_id => $self->body_id, transfer_type => 'trade'} )->get_column('id')->all; foreach my $id (@to_be_deleted) { my $trade = $market->find($id); next unless defined $trade; $trade->body->empire->send_predefined_message( filename => 'trade_withdrawn.txt', params => [join("\n",@{$trade->format_description_of_payload}), $trade->ask.' essentia'], tags => ['Trade','Alert'], ); $trade->withdraw; } $self->waste_ships->update({task=>'Docked'}); $self->waste_chains->delete_all; $self->body->needs_recalc(1); $self->body->update;};
before 'can_downgrade' => sub { my $self = shift; if ($self->waste_chains->count >= $self->level) { confess [1013, 'You must cancel one of your supply chains before you can downgrade the Trade Ministry.']; }};
sub add_to_market { my ($self, $offer, $ask, $options, $internal_options) = @_; my $ship = $self->next_available_trade_ship($options->{ship_id}); unless (defined $ship) { confess [1011, "You do not have any ships available that can carry trade goods."]; } unless(Lacuna::Role::Trader::OVERLOAD_ALLOWED()) { $ask = sprintf("%0.1f", $ask); unless ($ask >= 0.1 && $ask <= 100 ) { confess [1009, "You must ask for between 0.1 and 100 essentia to create a trade."]; } unless ($self->effective_level > $self->my_market->count) { confess [1009, "This Trade Ministry can only support ".$self->effective_level." trades at one time."]; } } my $space_used; ($space_used, $offer ) = $self->check_payload($offer, $ship->hold_size, undef, $ship); my ($payload, $meta) = $self->structure_payload($offer, $space_used); $ship->task('Waiting On Trade'); $ship->update; my $body = $self->body; my %trade = ( %{$meta}, payload => $payload, ask => $ask, ship_id => $ship->id, body_id => $self->body_id, transfer_type => $self->transfer_type, x => $body->x, y => $body->y, speed => $ship->speed, trade_range => int(450 + (15 * $self->effective_level)), ); $trade{max_university} = $internal_options->{max_university} if $internal_options; return Lacuna->db->resultset('Market')->new(\%trade)->insert;}
sub transfer_type { my $self = shift; return 'trade';}
# all trades within range (including those on this colony)sub local_market { my ($self, $args) = @_;
my $minus_x = -$self->body->x; my $minus_y = -$self->body->y;
return $self->market->search({ %$args, -and => [ \[ "transfer_type = ? and ceil(pow(pow(me.x + $minus_x, 2) + pow(me.y + $minus_y, 2), 0.5)) < trade_range", [transfer_type => $self->transfer_type]], ] },{ '+select' => [ { ceil => \"pow(pow(me.x + $minus_x,2) + pow(me.y + $minus_y,2), 0.5)", '-as' => 'distance' }, ], '+as' => [ 'distance', ], join => 'body', });}
# available market. All trades within range that are not our ownsub available_market { my ($self) = @_; return $self->local_market({ body_id => {'!=' => $self->body_id}, });}
sub trade_ships { my $self = shift; my $body = $self->body; return Lacuna->db->resultset('Lacuna::DB::Result::Ships')->search({ task => 'Docked', type => { 'in' => [SHIP_TRADE_TYPES] }, body_id => $self->body_id, berth_level => {'<=' => $body->max_berth } }, { order_by=> {-desc => ['hold_size']} });}
sub next_available_trade_ship { my ($self, $ship_id) = @_; if ($ship_id) { return $self->trade_ships->find($ship_id); } else { return $self->trade_ships->search(undef)->first; }}
sub push_items { my ($self, $target, $items, $options) = @_; my $ship = $self->next_available_trade_ship($options->{ship_id}); unless (defined $ship) { confess [1011, 'You do not have a ship available to transport cargo.']; }
my $space_used; ($space_used, $items) = $self->check_payload($items, $ship->hold_size, undef, $ship); $self->check_payload_ships($items, $target, $options->{stay});
my ($payload, $meta) = $self->structure_payload($items, $space_used); foreach my $item (@{$items}) { if ( $item->{type} eq 'ship' ) { my $pship = Lacuna->db->resultset('Lacuna::DB::Result::Ships')->find($item->{ship_id}); next unless defined $pship; $pship->body_id($target->id); $pship->update; } }
if ($options->{stay}) { $ship->body_id($target->id); $ship->body($target); weaken($ship->{_relationship_data}{body}); $ship->send( target => $self->body, direction => 'in', payload => $payload, ); } else { $ship->send( target => $target, payload => $payload, ); } return $ship;}
no Moose;__PACKAGE__->meta->make_immutable(inline_constructor => 0);