From e43e22bfe3d8de447120e0ac2f21661b59dc497e Mon Sep 17 00:00:00 2001 From: JT Smith Date: Fri, 17 Dec 2010 23:29:53 -0600 Subject: [PATCH] added combat rating to ships --- lib/Lacuna/DB/Result/Building/Shipyard.pm | 42 +++++++++++--- lib/Lacuna/DB/Result/Mission.pm | 7 ++- lib/Lacuna/DB/Result/Ships.pm | 3 + lib/Lacuna/DB/Result/Ships/Drone.pm | 1 + lib/Lacuna/DB/Result/Ships/Fighter.pm | 2 + .../DB/Result/Ships/ObservatorySeeker.pm | 3 +- lib/Lacuna/DB/Result/Ships/Scanner.pm | 1 + lib/Lacuna/DB/Result/Ships/Scow.pm | 1 + .../DB/Result/Ships/SecurityMinistrySeeker.pm | 3 +- lib/Lacuna/DB/Result/Ships/Snark.pm | 1 + lib/Lacuna/DB/Result/Ships/SpacePortSeeker.pm | 3 +- lib/Lacuna/RPC/Building/Shipyard.pm | 7 ++- lib/Lacuna/Role/Ship/Arrive/TriggerDefense.pm | 55 ++++++++++++------- var/upgrades/2.4000.sql | 10 ++++ var/www/public/changes.txt | 12 ++++ 15 files changed, 114 insertions(+), 37 deletions(-) create mode 100644 var/upgrades/2.4000.sql diff --git a/lib/Lacuna/DB/Result/Building/Shipyard.pm b/lib/Lacuna/DB/Result/Building/Shipyard.pm index 17cb560e..bbefa15c 100644 --- a/lib/Lacuna/DB/Result/Building/Shipyard.pm +++ b/lib/Lacuna/DB/Result/Building/Shipyard.pm @@ -23,6 +23,12 @@ sub get_ship_costs { $percentage_of_cost += $trade->level * 3; } } + if ($ship->base_combat) { + my $munitions = $self->munitions_lab; + if (defined $munitions) { + $percentage_of_cost += $munitions->level * 3; + } + } if ($ship->base_stealth) { my $cloak = $self->cloaking_lab; if (defined $cloak) { @@ -127,6 +133,7 @@ sub build_ship { $ship->body_id($self->body_id); $ship->shipyard_id($self->id); $self->set_ship_speed($ship); + $self->set_ship_combat($ship); $self->set_ship_hold_size($ship); $self->set_ship_stealth($ship); $time ||= $self->get_ship_costs($ship)->{seconds}; @@ -224,25 +231,42 @@ has trade_ministry => ( }, ); +has munitions_lab => ( + is => 'rw', + lazy => 1, + default => sub { + my $self = shift; + return $self->body->get_building_of_class('Lacuna::DB::Result::Building::MunitionsLab'); + }, +); + sub set_ship_speed { my ($self, $ship) = @_; my $propulsion_level = (defined $self->propulsion_factory) ? $self->propulsion_factory->level : 0; my $css_level = (defined $self->crashed_ship_site) ? $self->crashed_ship_site->level : 0; my $ptf = ($ship->pilotable && defined $self->pilot_training_facility) ? $self->pilot_training_facility->level : 0; - my $speed_improvement = 1 + ($ptf * 0.03) + ($propulsion_level * 0.05) + ($css_level * 0.05) + ($self->body->empire->science_affinity * 0.03); - $ship->speed(sprintf('%.0f', $ship->base_speed * $speed_improvement)); + my $improvement = 1 + ($self->level * 0.01) + ($ptf * 0.03) + ($propulsion_level * 0.05) + ($css_level * 0.05) + ($self->body->empire->science_affinity * 0.03); + $ship->speed(sprintf('%.0f', $ship->base_speed * $improvement)); return $ship->speed; } +sub set_ship_combat { + my ($self, $ship) = @_; + my $css_level = (defined $self->crashed_ship_site) ? $self->crashed_ship_site->level : 0; + my $munitions = (defined $self->munitions_lab) ? $self->munitions_lab->level : 0; + my $ptf = ($ship->pilotable && defined $self->pilot_training_facility) ? $self->pilot_training_facility->level : 0; + my $improvement = 1 + ($self->level * 0.01) + ($ptf * 0.03) + ($munitions * 0.05) + ($css_level * 0.05) + ($self->body->empire->deception_affinity * 0.03) + ($self->body->empire->science_affinity * 0.03); + $ship->combat(sprintf('%.0f', $ship->base_combat * $improvement)); + return $ship->combat; +} + sub set_ship_hold_size { my ($self, $ship) = @_; my $trade_ministry_level = (defined $self->trade_ministry) ? $self->trade_ministry->level : 0; my $css_level = (defined $self->crashed_ship_site) ? $self->crashed_ship_site->level : 0; - my $bonus = $self->body->empire->trade_affinity * $trade_ministry_level; - my $css_bonus = (defined $self->crashed_ship_site) ? 1 + ($self->crashed_ship_site->level * 0.05) : 1; - my $hold_size = $ship->base_hold_size * $bonus; - $hold_size *= $css_bonus; - $ship->hold_size(sprintf('%.0f', $hold_size)); + my $improvement = 1 + ($self->level * 0.01) + ($css_level * 0.05); + my $trade_bonus = $self->body->empire->trade_affinity * ( $trade_ministry_level || 0.1 ); + $ship->hold_size(sprintf('%.0f', $ship->base_hold_size * $trade_bonus * $improvement)); return $ship->hold_size; } @@ -251,8 +275,8 @@ sub set_ship_stealth { my $cloaking_level = (defined $self->cloaking_lab) ? $self->cloaking_lab->level : 1; my $ptf = ($ship->pilotable && defined $self->pilot_training_facility) ? $self->pilot_training_facility->level : 1; my $css_level = (defined $self->crashed_ship_site) ? $self->crashed_ship_site->level : 0; - my $stealth_improvement = 1 + ($ptf * 0.03) + ($cloaking_level * 0.05) + ($css_level * 0.05) + ($self->body->empire->deception_affinity * 0.03); - $ship->stealth(sprintf('%.0f', $ship->base_stealth * $stealth_improvement )); + my $improvement = 1 + ($self->level * 0.01) + ($ptf * 0.03) + ($cloaking_level * 0.05) + ($css_level * 0.05) + ($self->body->empire->deception_affinity * 0.03); + $ship->stealth(sprintf('%.0f', $ship->base_stealth * $improvement )); return $ship->stealth; } diff --git a/lib/Lacuna/DB/Result/Mission.pm b/lib/Lacuna/DB/Result/Mission.pm index c0f7a327..19138352 100644 --- a/lib/Lacuna/DB/Result/Mission.pm +++ b/lib/Lacuna/DB/Result/Mission.pm @@ -122,6 +122,7 @@ sub add_rewards { type => $ship->{type}, name => $ship->{type}, speed => $ship->{speed}, + combat => $ship->{combat}, stealth => $ship->{stealth}, hold_size => $ship->{hold_size}, body_id => $body->id, @@ -173,6 +174,7 @@ sub spend_objectives { { task => 'Docked', type => $ship->{type}, + combat => {'>=' => $ship->{combat}}, speed => {'>=' => $ship->{speed}}, stealth => {'>=' => $ship->{stealth}}, hold_size => {'>=' => $ship->{hold_size}}, @@ -240,6 +242,7 @@ sub check_objectives { foreach my $ship (@{$objectives->{ships}}) { my $this = $body->ships->search({ type => $ship->{type}, + combat => {'>=' => $ship->{combat}}, speed => {'>=' => $ship->{speed}}, stealth => {'>=' => $ship->{stealth}}, hold_size => {'>=' => $ship->{hold_size}}, @@ -336,8 +339,8 @@ sub format_items { my $ships = Lacuna->db->resultset('Lacuna::DB::Result::Ships'); foreach my $stats (@{ $items->{ships}}) { my $ship = $ships->new({type=>$stats->{type}}); - my $pattern = $is_objective ? '%s (speed >= %s, stealth >= %s, hold size >= %s)' : '%s (speed: %s, stealth: %s, hold size: %s)' ; - push @items, sprintf($pattern, $ship->type_formatted, commify($stats->{speed}), commify($stats->{stealth}), commify($stats->{hold_size})); + my $pattern = $is_objective ? '%s (speed >= %s, stealth >= %s, hold size >= %s, combat >= %s)' : '%s (speed: %s, stealth: %s, hold size: %s, combat: %s)' ; + push @items, sprintf($pattern, $ship->type_formatted, commify($stats->{speed}), commify($stats->{stealth}), commify($stats->{hold_size}), commify($stats->{combat})); } # fleet movement diff --git a/lib/Lacuna/DB/Result/Ships.pm b/lib/Lacuna/DB/Result/Ships.pm index 73c95ca3..43186842 100644 --- a/lib/Lacuna/DB/Result/Ships.pm +++ b/lib/Lacuna/DB/Result/Ships.pm @@ -20,6 +20,7 @@ __PACKAGE__->add_columns( name => { data_type => 'varchar', size => 30, is_nullable => 0 }, speed => { data_type => 'int', size => 11, is_nullable => 0 }, stealth => { data_type => 'int', size => 11, is_nullable => 0 }, + combat => { data_type => 'int', size => 11, is_nullable => 0 }, hold_size => { data_type => 'int', size => 11, is_nullable => 0 }, payload => { data_type => 'mediumblob', is_nullable => 1, 'serializer_class' => 'JSON' }, roundtrip => { data_type => 'bit', default_value => 0 }, @@ -67,6 +68,7 @@ use constant base_ore_cost => 1; use constant base_time_cost => 1; use constant base_waste_cost => 1; use constant base_speed => 1; +use constant base_combat => 0; use constant base_stealth => 0; use constant base_hold_size => 0; use constant pilotable => 0; @@ -151,6 +153,7 @@ sub get_status { task => $self->task, speed => $self->speed, stealth => $self->stealth, + combat => $self->combat, hold_size => $self->hold_size, date_started => $self->date_started_formatted, date_available => $self->date_available_formatted, diff --git a/lib/Lacuna/DB/Result/Ships/Drone.pm b/lib/Lacuna/DB/Result/Ships/Drone.pm index 7ba3137f..20155291 100644 --- a/lib/Lacuna/DB/Result/Ships/Drone.pm +++ b/lib/Lacuna/DB/Result/Ships/Drone.pm @@ -13,6 +13,7 @@ use constant base_ore_cost => 3550; use constant base_time_cost => 3650; use constant base_waste_cost => 1050; use constant base_speed => 0; +use constant base_combat => 6000; use constant base_stealth => 0; use constant base_hold_size => 0; use constant build_tags => ['War']; diff --git a/lib/Lacuna/DB/Result/Ships/Fighter.pm b/lib/Lacuna/DB/Result/Ships/Fighter.pm index 87aacc47..56598c0a 100644 --- a/lib/Lacuna/DB/Result/Ships/Fighter.pm +++ b/lib/Lacuna/DB/Result/Ships/Fighter.pm @@ -12,6 +12,8 @@ use constant base_energy_cost => 16200; use constant base_ore_cost => 14200; use constant base_time_cost => 14600; use constant base_waste_cost => 4200; +use constant base_combat => 4000; +use constant base_speed => 2000; use constant pilotable => 1; use constant build_tags => ['War']; diff --git a/lib/Lacuna/DB/Result/Ships/ObservatorySeeker.pm b/lib/Lacuna/DB/Result/Ships/ObservatorySeeker.pm index fe117fa5..378054b1 100644 --- a/lib/Lacuna/DB/Result/Ships/ObservatorySeeker.pm +++ b/lib/Lacuna/DB/Result/Ships/ObservatorySeeker.pm @@ -8,11 +8,12 @@ extends 'Lacuna::DB::Result::Ships'; use constant prereq => { class=> 'Lacuna::DB::Result::Building::MunitionsLab', level => 10 }; use constant base_food_cost => 20000; use constant base_water_cost => 50000; -use constant base_energy_cost => 150000; +use constant base_energy_cost => 170000; use constant base_ore_cost => 200000; use constant base_time_cost => 58500; use constant base_waste_cost => 40000; use constant base_speed => 1000; +use constant base_combat => 2500; use constant base_stealth => 4000; use constant target_building => 'Lacuna::DB::Result::Building::Observatory'; use constant build_tags => ['War']; diff --git a/lib/Lacuna/DB/Result/Ships/Scanner.pm b/lib/Lacuna/DB/Result/Ships/Scanner.pm index 3d6e0356..19e81bce 100644 --- a/lib/Lacuna/DB/Result/Ships/Scanner.pm +++ b/lib/Lacuna/DB/Result/Ships/Scanner.pm @@ -13,6 +13,7 @@ use constant base_ore_cost => 2900; use constant base_time_cost => 3600; use constant base_waste_cost => 520; use constant base_speed => 3000; +use constant base_combat => 200; use constant base_stealth => 3700; use constant base_hold_size => 0; use constant build_tags => [qw(Exploration Intelligence)]; diff --git a/lib/Lacuna/DB/Result/Ships/Scow.pm b/lib/Lacuna/DB/Result/Ships/Scow.pm index 6258371d..788d7a2f 100644 --- a/lib/Lacuna/DB/Result/Ships/Scow.pm +++ b/lib/Lacuna/DB/Result/Ships/Scow.pm @@ -13,6 +13,7 @@ use constant base_ore_cost => 28400; use constant base_time_cost => 14600; use constant base_waste_cost => 8400; use constant base_speed => 400; +use constant base_combat => 500; use constant base_stealth => 1000; use constant base_hold_size => 2100; use constant build_tags => [qw(War Trade)]; diff --git a/lib/Lacuna/DB/Result/Ships/SecurityMinistrySeeker.pm b/lib/Lacuna/DB/Result/Ships/SecurityMinistrySeeker.pm index f9e5fd3c..2d97a2f4 100644 --- a/lib/Lacuna/DB/Result/Ships/SecurityMinistrySeeker.pm +++ b/lib/Lacuna/DB/Result/Ships/SecurityMinistrySeeker.pm @@ -8,11 +8,12 @@ extends 'Lacuna::DB::Result::Ships'; use constant prereq => { class=> 'Lacuna::DB::Result::Building::MunitionsLab', level => 20 }; use constant base_food_cost => 20000; use constant base_water_cost => 50000; -use constant base_energy_cost => 150000; +use constant base_energy_cost => 180000; use constant base_ore_cost => 200000; use constant base_time_cost => 58500; use constant base_waste_cost => 40000; use constant base_speed => 1000; +use constant base_combat => 3500; use constant base_stealth => 6000; use constant target_building => 'Lacuna::DB::Result::Building::Security'; use constant build_tags => ['War']; diff --git a/lib/Lacuna/DB/Result/Ships/Snark.pm b/lib/Lacuna/DB/Result/Ships/Snark.pm index 2f06b700..a2be89d7 100644 --- a/lib/Lacuna/DB/Result/Ships/Snark.pm +++ b/lib/Lacuna/DB/Result/Ships/Snark.pm @@ -14,6 +14,7 @@ use constant base_time_cost => 58400; use constant base_waste_cost => 39600; use constant base_speed => 1000; use constant base_stealth => 3000; +use constant base_combat => 2000; use constant base_hold_size => 0; use constant build_tags => ['War']; diff --git a/lib/Lacuna/DB/Result/Ships/SpacePortSeeker.pm b/lib/Lacuna/DB/Result/Ships/SpacePortSeeker.pm index a0b01642..73dd48c0 100644 --- a/lib/Lacuna/DB/Result/Ships/SpacePortSeeker.pm +++ b/lib/Lacuna/DB/Result/Ships/SpacePortSeeker.pm @@ -8,11 +8,12 @@ extends 'Lacuna::DB::Result::Ships'; use constant prereq => { class=> 'Lacuna::DB::Result::Building::MunitionsLab', level => 15 }; use constant base_food_cost => 20000; use constant base_water_cost => 50000; -use constant base_energy_cost => 150000; +use constant base_energy_cost => 160000; use constant base_ore_cost => 200000; use constant base_time_cost => 58500; use constant base_waste_cost => 40000; use constant base_speed => 1000; +use constant base_combat => 3000; use constant base_stealth => 5000; use constant target_building => 'Lacuna::DB::Result::Building::SpacePort'; use constant build_tags => ['War']; diff --git a/lib/Lacuna/RPC/Building/Shipyard.pm b/lib/Lacuna/RPC/Building/Shipyard.pm index d026c22b..16df0e8c 100644 --- a/lib/Lacuna/RPC/Building/Shipyard.pm +++ b/lib/Lacuna/RPC/Building/Shipyard.pm @@ -103,9 +103,10 @@ sub get_buildable { my $can = eval{$building->can_build_ship($ship)}; $buildable{$type} = { attributes => { - speed => $building->set_ship_speed($ship), - stealth => $building->set_ship_stealth($ship), - hold_size => $building->set_ship_hold_size($ship), + speed => $building->set_ship_speed($ship), + stealth => $building->set_ship_stealth($ship), + hold_size => $building->set_ship_hold_size($ship), + combat => $building->set_ship_combat($ship), }, tags => \@tags, cost => $building->get_ship_costs($ship), diff --git a/lib/Lacuna/Role/Ship/Arrive/TriggerDefense.pm b/lib/Lacuna/Role/Ship/Arrive/TriggerDefense.pm index 43bc832d..d127986d 100644 --- a/lib/Lacuna/Role/Ship/Arrive/TriggerDefense.pm +++ b/lib/Lacuna/Role/Ship/Arrive/TriggerDefense.pm @@ -17,33 +17,48 @@ after handle_arrival_procedures => sub { return if $body_attacked->empire_id == $self->body->empire_id; # get defensive ships - my $defense = Lacuna->db->resultset('Lacuna::DB::Result::Ships')->search( + my $defense_ships = Lacuna->db->resultset('Lacuna::DB::Result::Ships')->search( { body_id => $self->foreign_body_id, type => { in => [qw(drone fighter)]}, task=>'Docked'}, - { rows => 1 } - )->single; + ); # if there are defensive ships let's duke it out - if (defined $defense) { - $self->body->empire->send_predefined_message( - tags => ['Alert'], - filename => 'ship_shot_down.txt', - params => [$self->type_formatted, $body_attacked->x, $body_attacked->y, $body_attacked->name, $self->body->id, $self->body->name], - ); - $body_attacked->empire->send_predefined_message( - tags => ['Alert'], - filename => 'we_shot_down_a_ship.txt', - params => [$self->type_formatted, $body_attacked->id, $body_attacked->name, $self->body->empire_id, $self->body->empire->name], - ); - $body_attacked->add_news(20, sprintf('An amateur astronomer witnessed an explosion in the sky today over %s.',$body_attacked->name)); - $self->delete; - if ($defense->type eq 'fighter' && randint(1,100) > 50) { - # fighter lives + while (my $defender = $defense_ships->next) { + my $damage = $defender->combat; + if ($defender->type eq 'drone') { + $defender->delete; } else { - $defense->delete; + $defender->combat( $defender->combat - $damage ); + if ($defender->combat < 1) { + $defender->delete; + } + else { + $defender->send(target => $body_attacked->star); + } } - confess [-1] + $self->damage_in_combat($damage); } }; + +sub damage_in_combat { + my ($self, $damage) = @_; + $self->combat( $self->combat - $damage ); + return unless $self->combat < 1; + my $body_attacked = $self->foreign_body; + $self->body->empire->send_predefined_message( + tags => ['Alert'], + filename => 'ship_shot_down.txt', + params => [$self->type_formatted, $body_attacked->x, $body_attacked->y, $body_attacked->name, $self->body->id, $self->body->name], + ); + $body_attacked->empire->send_predefined_message( + tags => ['Alert'], + filename => 'we_shot_down_a_ship.txt', + params => [$self->type_formatted, $body_attacked->id, $body_attacked->name, $self->body->empire_id, $self->body->empire->name], + ); + $body_attacked->add_news(20, sprintf('An amateur astronomer witnessed an explosion in the sky today over %s.',$body_attacked->name)); + $self->destroy; + confess [-1] +} + 1; diff --git a/var/upgrades/2.4000.sql b/var/upgrades/2.4000.sql new file mode 100644 index 00000000..b78c45bb --- /dev/null +++ b/var/upgrades/2.4000.sql @@ -0,0 +1,10 @@ +alter table ships add column combat int not null default 0; +update ships set combat=2000 where type='snark'; +update ships set combat=200 where type='scanner'; +update ships set combat=2500 where type='observatory_seeker'; +update ships set combat=3500 where type='security_ministry_seeker'; +update ships set combat=3000 where type='spaceport_seeker'; +update ships set combat=6000 where type='drone'; +update ships set combat=4000 where type='fighter'; +update ships set combat=500 where type='scow'; +update ships set speed=2000 where type='fighter' and speed < 2000; diff --git a/var/www/public/changes.txt b/var/www/public/changes.txt index 49963905..fea48bad 100644 --- a/var/www/public/changes.txt +++ b/var/www/public/changes.txt @@ -1,8 +1,20 @@ 2.4000 - Refactored ship classes. - Scows are no longer expendable if used to dump waste into a star. + - Scows no longer have a 0 hold size if you have no Trade Ministry, however the Trade Ministry helps them greatly. - Excavators now work on inhabited planets. - All ships now return max_occupants in their status. + - Ships now have a combat rating, which is used in ship-to-ship combat calculations. + - Munitions lab gives a 5% bonus to combat rating, but increases ship cost by 3%. + - Deception and Science affinities each give a 3% bonus to combat rating. + - The Crashed Ship Site gives a 5% bonus to combat rating. + - All ships, except drones, can now survive ship-to-ship combat if their combat rating is higher than the ship going against them. + - Ships lose combat rating equal to the amount of the combat rating of the ships they fight. + - Fighters now die based upon their combat rating going to zero, rather than a random roll of the dice. + - Fighters no longer instantly reset after combat. Their speed determines how quickly they get back into a reset position. + - If you have existing fighters, and they had a speed lower than 2000, it is now 2000. + - The level of the Shipyard building the ship now adds a 1% bonus per level to all attributes of the ship, without raising its cost. + 2.3902 - Halls of Vrbansk now also returns building URL. -- 2.54.0