Something went wrong. Try again.
Perl game server for TLE Community
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745package Lacuna::AI;
use Moose;use utf8;no warnings qw(uninitialized);use Lacuna::Util qw(randint random_element);use Lacuna::Constants qw(FOOD_TYPES ORE_TYPES);use List::Util qw(shuffle);use 5.010;use Module::Find;use Log::Any qw($log);
has empire => ( is => 'ro', lazy => 1, default => sub { my $self = shift; my $empire = Lacuna->db->resultset('Lacuna::DB::Result::Empire')->find($self->empire_id); if (defined $empire) { return $empire; } else { return $self->create_empire; } });
has scratch => ( is => 'ro', lazy => 1, default => sub { my $self = shift; my ($scratch) = Lacuna->db->resultset('Lacuna::DB::Result::AIScratchPad')->search({ ai_empire_id => $self->empire_id, body_id => 0, });
return $scratch; });
sub next_viable_colony { my $self = shift; return $self->viable_colonies->search(undef, { order_by => 'rand()' })->first;}
sub create_empire { my $self = shift; $log->debug('Founding Empire'); my %attributes = ( %{$self->empire_defaults}, id => $self->empire_id, stage => 'founded', date_created => DateTime->now, password => Lacuna::DB::Result::Empire->encrypt_password(rand(99999999)), university_level => 30, ); my $db = Lacuna->db; my $empire = $db->resultset('Lacuna::DB::Result::Empire')->new(\%attributes)->insert;# my $zone = $db->resultset('Lacuna::DB::Result::Map::Body')->get_column('zone')->max;# my $home = $self->viable_colonies->search({zone => $zone})->first; my $home = $self->viable_colonies->search(undef,{ order_by => 'rand()'})->first; my @to_demolish = @{$home->building_cache}; $home->delete_buildings(\@to_demolish); $empire->found($home); $self->build_colony($home); return $empire;}
sub build_colony { my ($self,$body) = @_; $log->debug('Upgrading PCC'); my $pcc = $body->command; $pcc->level(15); $pcc->update; my $decor = [qw( Lacuna::DB::Result::Building::Permanent::Beach1 Lacuna::DB::Result::Building::Permanent::Beach2 Lacuna::DB::Result::Building::Permanent::Beach3 Lacuna::DB::Result::Building::Permanent::Beach4 Lacuna::DB::Result::Building::Permanent::Beach5 Lacuna::DB::Result::Building::Permanent::Beach6 Lacuna::DB::Result::Building::Permanent::Beach7 Lacuna::DB::Result::Building::Permanent::Beach8 Lacuna::DB::Result::Building::Permanent::Beach9 Lacuna::DB::Result::Building::Permanent::Beach10 Lacuna::DB::Result::Building::Permanent::Beach11 Lacuna::DB::Result::Building::Permanent::Beach12 Lacuna::DB::Result::Building::Permanent::Beach13 Lacuna::DB::Result::Building::Permanent::Crater Lacuna::DB::Result::Building::Permanent::Grove Lacuna::DB::Result::Building::Permanent::Lagoon Lacuna::DB::Result::Building::Permanent::Lake Lacuna::DB::Result::Building::Permanent::RockyOutcrop Lacuna::DB::Result::Building::Permanent::Sand Lacuna::DB::Result::Building::PlanetaryCommand )]; foreach my $building (@{$body->building_cache}) { unless ( grep { $building->class eq $_ } @{$decor}) { $building->delete; } }
$log->debug('Placing structures on '.$body->name); my @plans = $self->colony_structures; my $extras = $self->extra_glyph_buildings;
my @findable; if ($extras->{quantity}) { push @findable, @{$extras->{findable}}; foreach (1..$extras->{quantity}) { push @plans, [$findable[rand @findable], randint($extras->{min_level}, $extras->{max_level})]; } } my $plot_use = 0; my $buildings = Lacuna->db->resultset('Lacuna::DB::Result::Building'); foreach my $plan (@plans) { my ($x, $y) = $body->find_free_space; my $building = $buildings->new({ class => $plan->[0], level => $plan->[1] - 1, x => $x, y => $y, body_id => $body->id, body => $body, }); $log->debug($building->name); $body->build_building($building); $building->finish_upgrade; $plot_use++ unless $plan =~ /::Permanent::/; } if ($plot_use > $body->size) { $body->size($plot_use); $body->update; }}
sub run_all_hourly_colony_updates { my $self = shift; my $colonies = $self->empire->planets; while (my $colony = $colonies->next) { $log->debug('###############'); $log->debug('#### UPDATE COLONY : '.$colony->name); $log->debug('###############');
$colony->tick; $self->run_hourly_colony_updates($colony); }}
sub run_all_hourly_empire_updates { my $self = shift; $log->debug('###############'); $log->debug('#### UPDATE EMPIRE '); $log->debug('###############'); $self->run_hourly_empire_updates($self->empire);}
sub add_colonies { my ($self, $add_one) = @_; my $config = Lacuna->config; my $empire = $self->empire; my @all_zones = Lacuna->db->resultset('Map::Star')->search( undef, { distinct => 1 } )->get_column('zone')->all; $log->debug('getting existing colonies'); my $colonies = $empire->planets; my @existing_zones = $colonies->get_column('zone')->all; $log->debug('getting neutral zones'); my $na_param = Lacuna->config->get('neutral_area'); my @neutral_zones = (); if ($na_param->{zone}) { @neutral_zones = @{$na_param->{zone_list}}; } $log->debug('Adding colonies...');ZONE: foreach my $zone (@all_zones) { next unless (grep { $zone eq $_} @all_zones); if (grep { $zone eq $_} @existing_zones) { $log->debug('Colony already exists in '.$zone.'.'); next; } if (grep { $zone eq $_} @neutral_zones) { $log->debug('Skip '.$zone.' because of neutral zone.'); next; } $log->debug($zone); $log->debug('Finding colony in '.$zone.'...');# Need to narrow search if neutral area defined by coordinates. my @bodies = $self->viable_colonies->search({ 'me.zone' => $zone, 'stars.station_id' => undef, },{ join => 'stars', rows => 100, order_by => 'rand()' }); my $body = random_element(\@bodies);
if (defined $body) { $log->debug('Clearing '.$body->name); my @to_demolish = @{$body->building_cache}; $body->delete_buildings(\@to_demolish); $log->debug('Colonizing '.$body->name); $body->found_colony($empire); $self->build_colony($body); $body->happiness(1000000000); $body->update; last ZONE if $add_one; } else { $log->debug('Could not find a colony to occupy in '.$zone.'.'); } }}
sub run_missions { my ($self, $colony) = @_; $log->debug('RUN MISSIONS'); my @missions = $self->spy_missions; my $mission = $missions[rand @missions]; my $infiltrated_spies = Lacuna->db->resultset('Lacuna::DB::Result::Spies')->search({from_body_id => $colony->id, on_body_id => {'!=', $colony->id}}); while (my $spy = $infiltrated_spies->next) { next if $spy->task eq "Sabotage BHG"; if ($spy->is_available) { if ($spy->on_body->id != $spy->from_body->id and $spy->on_body->in_neutral_area ) {# Check if spy is in neutral zone, if it is, send someone to fetch? $log->debug(" Spy ID: ".$spy->id." escaping from neutral zone..."); my $result = eval{$spy->assign("Bugout")}; $log->debug(" ".$result->{result}); } else { $log->debug(" Spy ID: ".$spy->id." running mission..."); my $result = eval{$spy->assign($mission)}; $log->debug(" ".$result->{result}); } } else { $log->debug(" Spy ID: ".$spy->id." not available"); } }}
sub repair_buildings { my ($self, $colony) = @_; $log->debug('REPAIR DAMAGED BUILDINGS'); foreach my $building (@{$colony->building_cache}) { if ($building->efficiency < 100) { $log->debug(" ".$building->name." needs repairing"); my $costs = $building->get_repair_costs; my $can = eval{$building->can_repair($costs)}; my $reason = $@; if ($can) { $building->repair($costs); $log->debug(" repaired"); } else { $log->debug(" ".$reason->[1]); } } }}
sub demolish_bleeders { my ($self, $colony) = @_; $log->debug('DEMOLISH BLEEDERS'); my @bleeders = $colony->get_buildings_of_class('Lacuna::DB::Result::Building::DeployedBleeder'); foreach my $bleeder (@bleeders) { if (randint(0,9) < 5) { $log->debug(' missed bleeder'); } else { $log->debug(' demolish bleeder'); $bleeder->demolish; } }}
sub pod_check { my ($self, $colony, $pod_level) = @_; return if (Lacuna->cache->get('supply_pod_sent',$colony->id)); my $food_stored = 0; my $ore_stored = 0; my @food = map { $_.'_stored' } FOOD_TYPES; my @ore = map { $_.'_stored' } ORE_TYPES; my $attrib; for $attrib (@food) { $food_stored += $colony->$attrib; } for $attrib (@ore) { $ore_stored += $colony->$attrib; } if ($food_stored <= 0 or $ore_stored <= 0 or $colony->water_stored <= 0 or $colony->energy_stored <= 0) { $log->debug('DEPLOY SUPPLY POD'); my ($x, $y) = eval{ $colony->find_free_space };# Check to see if spot found, if not, clear off a crater if found. unless ($@) { my $deployed = Lacuna->db->resultset('Lacuna::DB::Result::Building')->new({ class => 'Lacuna::DB::Result::Building::SupplyPod', x => $x, y => $y, level => $pod_level - 1, body_id => $colony->id, body => $colony, }); $log->debug($deployed->name); $colony->build_building($deployed, 1); $deployed->finish_upgrade; Lacuna->cache->set('supply_pod_sent',$colony->id,1,60*60*24); } else { my @craters = $colony->get_buildings_of_class('Lacuna::DB::Result::Building::Permanent::Crater'); if (@craters) { my $crater = random_element \@craters; $log->debug('DEMOLISH CRATER'); $crater->demolish; } } $colony->recalc_stats; my $add_it = $colony->water_capacity - $colony->water_stored; $log->debug("Adding Water: $add_it"); $colony->add_type("water", $add_it); $add_it = $colony->energy_capacity - $colony->energy_stored; $log->debug("Adding Energy: $add_it"); $colony->add_type("energy", $add_it); my $food_room = $colony->food_capacity - $food_stored; $log->debug("Adding Food: $food_room"); my $ore_room = $colony->ore_capacity - $ore_stored; $log->debug("Adding Ore: $ore_room"); my @foods = shuffle FOOD_TYPES; my @ores = shuffle ORE_TYPES; my @food_type = splice(@foods, 0, 4); my @ore_type = splice(@ores, 0, 4); for my $food (@food_type) { $colony->add_type("$food", int($food_room/4)); } for my $ore (@ore_type) { $colony->add_type("$ore", int($ore_room/4)); } } $colony->update;}
sub train_spies { my ($self, $colony, $chance, $subsidise ) = @_; $log->debug('TRAIN SPIES');
my $intelligence = $colony->get_building_of_class('Lacuna::DB::Result::Building::Intelligence');
return unless defined $intelligence;
my $costs = $intelligence->training_costs; my $spies = Lacuna->db->resultset('Lacuna::DB::Result::Spies')->search({ from_body_id => $colony->id, })->count; my $max_spies = $intelligence->level * 3; my $room_for = $max_spies - $spies; my $train_count = 0; $log->debug(" Training $room_for spies for total of $max_spies with chance of $chance"); if ($subsidise) { $log->debug(" Subsidizing"); my $deception = $colony->empire->effective_deception_affinity * 50; while ($train_count < $room_for) { $train_count++; next if ($chance < rand(100)); # bypass everything and just create the spy my $spy = Lacuna->db->resultset('Lacuna::DB::Result::Spies')->new({ from_body_id => $colony->id, on_body_id => $colony->id, task => 'Idle', date_created => DateTime->now, started_assignment => DateTime->now, available_on => DateTime->now, empire_id => $colony->empire_id, offense => ($intelligence->espionage_level * 75) + $deception, defense => ($intelligence->security_level * 75) + $deception, intel_xp => randint(10,400), mayhem_xp => randint(10,400), politics_xp => randint(10,400), theft_xp => randint(10,400), }) ->update_level ->insert;
$log->debug(" Subsidised spy being trained"); $spies++; } } else { my $can_train = 1;
while ($can_train and $train_count < $room_for) { $train_count++; next if ($chance < rand(100)); my $can = eval{$intelligence->can_train_spy($costs)}; my $reason = $@; if ($can) { $intelligence->spend_resources_to_train_spy($costs); $intelligence->train_spy($costs->{time}); $log->debug(" Spy being trained."); } else { $log->debug(' '.$reason->[1]); $can_train = 0; } } }}
sub build_ships { my ($self, $colony) = @_; $log->debug('BUILD SHIPS'); if ($colony->happiness < -1_000_000) { $log->debug("Too unhappy to build ships."); return; } my @shipyards = sort {$a->work_ends cmp $b->work_ends} $colony->get_buildings_of_class('Lacuna::DB::Result::Building::Shipyard'); my @priorities = $self->ship_building_priorities($colony); my $ships = Lacuna->db->resultset('Lacuna::DB::Result::Ships'); foreach my $priority (@priorities) { $log->debug($priority->[0]); my $count = $ships->search({body_id => $colony->id, type => $priority->[0]})->count; if ($count < $priority->[1]) { my $shipyard = shift @shipyards; $shipyard->body($colony); my $ship = $ships->new({type => $priority->[0]}); my $costs = $shipyard->get_ship_costs($ship); my $can = eval{$shipyard->can_build_ship($ship, $costs)}; my $reason = $@; if ($can) { $log->debug("building ".$ship->type); $shipyard->spend_resources_to_build_ship($costs); $shipyard->build_ship($ship, $costs->{seconds}); } else { $log->debug($reason->[1]); } push @shipyards, $shipyard; } else { $log->debug("have enough"); } }}
# Fill the shipyards as full as they can besub build_ships_max { my ($self, $colony) = @_; $log->debug('BUILD SHIPS'); if ($colony->happiness < -1_000_000) { $log->debug("Too unhappy to build ships."); return; } my @ship_yards = sort {$a->work_ends cmp $b->work_ends} $colony->get_buildings_of_class('Lacuna::DB::Result::Building::Shipyard'); my $ships = Lacuna->db->resultset('Lacuna::DB::Result::Ships'); my $ship_yard = shift @ship_yards; my $free_docks = $ship_yard->level - $ships->search({shipyard_id => $ship_yard->id, task => 'Building'}); my @priorities = $self->ship_building_priorities($colony); SHIP: for my $priority (@priorities) { my ($ship_type,$quota) = @$priority;
my $no_of_ships = $ships->search({body_id => $colony->id, type => $ship_type})->count; my $ships_needed = $quota - $no_of_ships; if ($ships_needed <= 0) { $log->debug(" quota met for $ship_type"); } while ($ships_needed > 0) { # loop around filling shipyards one at a time until either there are no more # shipyards or we need no more ships SHIP_YARD: while ($ships_needed > 0 and $ship_yard) {
while ($free_docks <= 0) { $ship_yard = shift @ship_yards; last SHIP unless $ship_yard; $free_docks = $ship_yard->level - $ships->search({shipyard_id => $ship_yard->id, task => 'Building'}); } my $ship = $ships->new({type => $ship_type}); my $costs = $ship_yard->get_ship_costs($ship); my $can_build = eval{$ship_yard->can_build_ship($ship, $costs)}; my $reason = $@; if ($can_build) { $log->debug(" building ".$ship->type); $ship_yard->spend_resources_to_build_ship($costs); $ship_yard->build_ship($ship, $costs->{seconds}); } else { $log->debug(" ".$reason->[1]); next SHIP; } $ships_needed--; $free_docks--; } } }}
sub set_defenders { my ($self, $colony) = @_; $log->debug('SET DEFENDERS'); my $local_spies = Lacuna->db->resultset('Lacuna::DB::Result::Spies')->search({empire_id => $colony->empire_id, on_body_id => $colony->id}); my $on_sweep = Lacuna->db->resultset('Lacuna::DB::Result::Spies')->search({empire_id => $colony->empire_id, on_body_id => $colony->id, task => "Security Sweep"})->count; my $enemies = Lacuna->db->resultset('Lacuna::DB::Result::Spies')->search({on_body_id => $colony->id, task => { '!=' => 'Captured'}, empire_id => { '!=' => $self->empire_id }})->count; $on_sweep = 10 if ($enemies == 0); while (my $spy = $local_spies->next) { if ($spy->is_available) { if ( $spy->date_created < DateTime->now->subtract(hours => 8) and ($spy->task eq 'Security Sweep' or $on_sweep < 10)) {
$log->debug(" Spy ID: ".$spy->id." sweeping"); my $spy_result = $spy->assign('Security Sweep'); $spy->update; if ($spy_result->{message_id}) { my $message = Lacuna->db->resultset('Lacuna::DB::Result::Message')->find($spy_result->{message_id}); $log->debug("message: ".$message->subject); if ($message && $message->subject =~ /^Spy Report/) { $on_sweep += 10; #No spies to find $log->debug(" spy report, no more sweeps."); } elsif ($message && $message->subject eq "Enemy Captured") { $on_sweep--; $log->debug(" caught someone, more sweeps."); } } $on_sweep++; } elsif ($spy->task ne 'Counter Espionage') { $log->debug(" Spy ID: ".$spy->id." setting to defend"); $spy->task('Counter Espionage'); $spy->update; } } else { $log->debug(" Spy ID: ".$spy->id." is currently unavailable"); } }}
sub kill_prisoners { my ($self, $colony, $when) = @_;#When is in hours from prisoner being released.
$log->debug('KILL PRISONERS'); my $prisoners = Lacuna->db->resultset('Lacuna::DB::Result::Spies')->search({on_body_id => $colony->id, task => 'Captured', empire_id => { '!=' => $self->empire_id }}); my $now = DateTime->now; my $prisoner_cnt = 0; while (my $prisoner = $prisoners->next) { my $sentence = $now->subtract_datetime_absolute($prisoner->available_on); my $hours = int($sentence->seconds/(60*60)); if ($hours < $when) { $prisoner->empire->send_predefined_message( from => $colony->empire, tags => ['Spies','Alert'], filename => 'spy_executed.txt', params => [$prisoner->name, $prisoner->from_body->id, $prisoner->from_body->name, $colony->x, $colony->y, $colony->name, $colony->empire->id, $colony->empire->name], ); $prisoner->delete; $prisoner_cnt++; } } $log->debug($prisoner_cnt." prisoners executed.");}
sub start_attack { my ($self, $attacking_colony, $target_colony, $ship_types) = @_; $log->debug('LOOK FOR PROBES'); my $attack = AnyEvent->condvar; my $db = Lacuna->db; my $seconds = 0; my $count = $db->resultset('Lacuna::DB::Result::Probes')->search({ empire_id => $self->empire_id, star_id => $target_colony->star_id })->count; if ($count) { $log->debug(' Has one at star already...'); $seconds = 1; } my $probe = $db->resultset('Lacuna::DB::Result::Ships')->search({body_id => $attacking_colony->id, type => 'probe', task=>'Docked'})->first; if (defined $probe and $seconds == 0) { $log->debug(' Has a probe to launch for '.$target_colony->name.'...'); $probe->send(target => $target_colony->star); $seconds = $probe->date_available->epoch - time(); $log->debug(' Probe will arrive in '.$seconds.' seconds.'); } if ($seconds) { my $timer; $timer = AnyEvent->timer( after => $seconds, cb => sub { $self->attack_with_ships($attacking_colony, $target_colony, $ship_types); $attack->send; undef $timer; }, ); return $attack; } else { $log->debug(' No probe. Cancel assault.'); $attack->send; return $attack; }}
sub attack_with_ships { my ($self, $attacking_body, $target_body, $ship_types) = @_;
my $arrival = DateTime->now; my $ship_ref; my $ag_chk = 0; my @ag_list = ("sweeper","snark","snark2","snark3", "observatory_seeker","spaceport_seeker","security_ministry_seeker", "scanner","surveyor","detonator","bleeder","thud", "scow","scow_large","scow_fast","scow_mega");STYPE: foreach my $type (@$ship_types) { my $max_berth = $attacking_body->max_berth; unless ($max_berth) { $max_berth = 1; } my $ships_rs = Lacuna->db->resultset('Ships')->search({ body_id => $attacking_body->id, task => 'Docked', type => $type, berth_level => {'<=' => $max_berth }, }); # handle optional parameters my $quantity = $ships_rs->count; next STYPE unless $quantity; if (grep { $type eq $_ } @ag_list) { $ag_chk += $quantity; } my @ships = $ships_rs->all; my $ship = $ships[0]; #Need to grab slowest ship # We only need to check one of the ships $ship->can_send_to_target($target_body);
#Check speed of ship. If it can not make it to the target in time, fail#If time to target is longer than 60 days, fail. my $seconds_to_target = $ship->calculate_travel_time($target_body); my $earliest = DateTime->now->add(seconds=>$seconds_to_target);
my $two_months = DateTime->now->add(days=>60); if ($earliest > $two_months) { $log->debug("$type can't make it in two months."); next STYPE; } if ($earliest > $arrival) { $arrival = $earliest; }
foreach my $ship (@ships) { $ship_ref->{$ship->id} = $ship; } }
# Create attack_group my $cnt = 0; my %ag_hash = map { $_ => $cnt++ } @ag_list; my $attack_group = { speed => 50_000, stealth => 50_000, hold_size => 0, combat => 0, number_of_docks => 0, }; my $payload; $ag_chk = 0 if ($target_body->isa('Lacuna::DB::Result::Map::Star')); foreach my $ship (values %$ship_ref) { if ($ag_chk > 1 and grep { $ship->type eq $_ } @ag_list) { my $sort_val = $ag_hash{$ship->type}; if ($ship->speed < $attack_group->{speed}) { $attack_group->{speed} = $ship->speed; } if ($ship->speed < $attack_group->{stealth}) { $attack_group->{stealth} = $ship->stealth; } $attack_group->{combat} += $ship->combat; $attack_group->{hold_size} += $ship->hold_size; #This really is only good for scows $attack_group->{number_of_docks}++; my $key = sprintf("%02d:%s:%05d:%05d:%05d:%09d", $sort_val, $ship->type, $ship->combat, $ship->speed, $ship->stealth, $ship->hold_size); if ($payload->{fleet}->{$key}) { $payload->{fleet}->{$key}->{quantity}++; } else { $payload->{fleet}->{$key} = { type => $ship->type, name => $ship->name, speed => $ship->speed, combat => $ship->combat, stealth => $ship->stealth, hold_size => $ship->hold_size, target_building => $ship->target_building, damage_taken => 0, quantity => 1, }; } $ship->delete; } else { my $distance = $attacking_body->calculate_distance_to_target($target_body); my $transit_time = $arrival->subtract_datetime_absolute(DateTime->now)->seconds; my $fleet_speed = int( $distance / ($transit_time/3600) + 0.5);
$ship->fleet_speed($fleet_speed); $ship->send(target => $target_body, arrival => $arrival); $attacking_body->add_to_neutral_entry($ship->combat); } } if ($attack_group->{number_of_docks} > 0) { my $distance = $attacking_body->calculate_distance_to_target($target_body); my $transit_time = $arrival->subtract_datetime_absolute(DateTime->now)->seconds; my $fleet_speed = int( $distance / ($transit_time/3600) + 0.5); my $ag = $attacking_body->ships->new({ type => "attack_group", name => "Attack Group TLE", shipyard_id => "17", speed => $attack_group->{speed}, combat => $attack_group->{combat}, stealth => $attack_group->{stealth}, hold_size => $attack_group->{hold_size}, date_available => DateTime->now, date_started => DateTime->now, fleet_speed => $fleet_speed, berth_level => 1, body_id => $attacking_body->id, task => 'Docked', number_of_docks => $attack_group->{number_of_docks}, })->insert; $log->debug("Sending Attack Group from ".$attacking_body->name." to ".$target_body->name); $ag->send(target => $target_body, arrival => $arrival, payload => $payload); $attacking_body->add_to_neutral_entry($attack_group->{combat}); }}
no Moose;__PACKAGE__->meta->make_immutable;