File Coverage

blib/lib/Games/Lacuna/Task/Action/StationPlanBuilder.pm
Criterion Covered Total %
statement 4 6 66.6
branch n/a
condition n/a
subroutine 2 2 100.0
pod n/a
total 6 8 75.0


line stmt bran cond sub pod time code
1             package Games::Lacuna::Task::Action::StationPlanBuilder;
2              
3 1     1   1654 use 5.010;
  1         4  
  1         64  
4             our $VERSION = $Games::Lacuna::Task::VERSION;
5              
6 1     1   468 use Moose;
  0            
  0            
7             extends qw(Games::Lacuna::Task::Action);
8             with 'Games::Lacuna::Task::Role::Storage',
9             'Games::Lacuna::Task::Role::CommonAttributes' => { attributes => ['home_planet'] };
10              
11             use Games::Lacuna::Task::Utils qw(parse_date format_date);
12             use List::Util qw(min max);
13              
14             has 'space_station' => (
15             isa => 'Str',
16             is => 'ro',
17             predicate => 'has_space_station',
18             documentation=> q[Space station to be managed],
19             );
20              
21             has 'plans' => (
22             is => 'rw',
23             isa => 'HashRef',
24             required => 1,
25             documentation => 'Plans to be built [Required in config]',
26             default => sub {
27             return {
28             ArtMuseum => { name => 'Art Museum', level => -3, },
29             CulinaryInstitute => { name => 'Culinary Institute', level => -3 },
30             IBS => { name => 'Interstellar Broadcast System', level => -3 },
31             OperaHouse => { name => 'Opera House', level => -3 },
32             Parliament => { skip => 1 },
33             PoliceStation => { name => 'Police Station', level => -3 },
34             StationCommand => { name => 'Station Command Center', skip => 1 },
35             Warehouse => { count => 13, level => 18 },
36             }
37             },
38             );
39              
40             sub description {
41             return q[Build Space Station module plans];
42             }
43              
44             sub run {
45             my ($self) = @_;
46            
47             my $planet_home = $self->home_planet_data();
48             my $timestamp = time();
49            
50             # Get space station lab
51             my $spacestaion_lab = $self->find_building($planet_home->{id},'SSLA');
52             return $self->log('error','Could not find space station labs')
53             unless $spacestaion_lab;
54              
55             if (defined $spacestaion_lab->{work}) {
56             my $work_end = parse_date($spacestaion_lab->{work}{end});
57             if ($work_end > $timestamp) {
58             return $self->log('info','Space station lab is busy until %s',format_date($work_end))
59             }
60             }
61              
62             my $spacestaion_lab_object = $self->build_object($spacestaion_lab);
63            
64             # Get plans on planet
65             my $planet_plans = $self->get_plans_stored($planet_home->{id});
66            
67             # Get plans on space station
68             my ($space_station,$space_station_plans,$space_station_modules);
69             if ($self->has_space_station) {
70             $space_station = $self->my_body_status($self->space_station);
71             return $self->log('error','Could not find space station')
72             unless (defined $space_station);
73             $space_station_plans = $self->get_plans_stored($space_station->{id});
74             $space_station_modules = $self->get_modules_built($space_station->{id});
75             }
76            
77             # TODO: Get plans in transit
78            
79             # Get total plans
80             my $total_plans = _merge_plan_hash($planet_plans,$space_station_plans,$space_station_modules);
81            
82             # Get space station lab details
83             my $spacestaion_lab_data = $self->request(
84             object => $spacestaion_lab_object,
85             method => 'view',
86             );
87            
88             if (defined $spacestaion_lab_data->{building}{work}) {
89             my $work_end = parse_date($spacestaion_lab->{building}{work}{end});
90             return $self->log('info','Space station lab is busy until %s %s',format_date($work_end))
91             }
92            
93             # Get max level
94             my $max_level = min(
95             $spacestaion_lab_data->{building}{level},
96             max(map { keys %{$_} } values %{$total_plans}) + 1
97             );
98            
99             PLAN_LEVEL:
100             foreach my $level (1..$max_level) {
101             last PLAN_LEVEL
102             unless $self->can_afford($planet_home,$spacestaion_lab_data->{make_plan}{level_costs}[$level-1]);
103            
104             PLAN_TYPE:
105             foreach my $plan (keys %{$self->plans}) {
106             my $plan_data = $self->plans->{$plan};
107             my $plan_level = $plan_data->{level} || $max_level;
108             my $plan_name = $plan_data->{name} || $plan;
109             my $plan_skip = $plan_data->{skip} || 0;
110             my $count = $plan_data->{count} // 1;
111             $plan_level = $max_level + $plan_level
112             if ($plan_level < 0);
113            
114             next PLAN_TYPE
115             if $level <= $plan_skip;
116             next PLAN_TYPE
117             if $level > $plan_level;
118            
119             $total_plans->{$plan}{$level} //= 0;
120             if ($total_plans->{$plan}{$level} < $count) {
121             $self->log('notice','Building plan %s (%i) on %s',$plan_name,$level,$planet_home->{name});
122             my ($plan_type) = map { $_->{type} } grep { $_->{name} eq $plan_name } @{$spacestaion_lab_data->{make_plan}{types}};
123            
124             my $response = $self->request(
125             object => $spacestaion_lab_object,
126             method => 'make_plan',
127             params => [$plan_type,$level],
128             );
129             #$response->{building}{work}{end};
130             return;
131             }
132             }
133             }
134             }
135              
136             sub _merge_plan_hash {
137             my (@args) = @_;
138            
139             my $return = {};
140            
141             foreach my $hash (@args) {
142             next
143             unless defined $hash;
144             while (my ($plan,$levels) = each %{$hash}) {
145             $return->{$plan} ||= {};
146             while (my ($level,$count) = each %{$levels}) {
147             $return->{$plan}{$level} ||= 0;
148             $return->{$plan}{$level} += $count;
149             }
150             }
151             }
152            
153             return $return;
154             }
155              
156             sub get_plans_stored {
157             my ($self,$body_id) = @_;
158            
159             my $plans = $self->plans_stored($body_id);
160            
161             my %space_station_plans;
162             while (my ($plan,$data) = each %{$self->plans}) {
163             $space_station_plans{$data->{name} || $plan} = $plan;
164             }
165            
166             my %stored_plans;
167             foreach my $plan (@{$plans}) {
168             my $name = $plan->{name};
169             my $level = $plan->{level};
170            
171             next
172             unless $plan->{extra_build_level} == 0;
173             next
174             unless defined $space_station_plans{$name};
175            
176             my $plan_key = $space_station_plans{$name};
177             $stored_plans{$plan_key} ||= {};
178             $stored_plans{$plan_key}->{$level} ||= 0;
179             $stored_plans{$plan_key}->{$level} ++;
180             }
181            
182             return \%stored_plans;
183             }
184              
185             sub get_modules_built {
186             my ($self,$body_id) = @_;
187            
188             my %modules_built;
189            
190             foreach my $module ($self->buildings_body($body_id)) {
191             my $type = Games::Lacuna::Client::Buildings::type_from_url($module->{url});
192             next
193             unless defined $self->plans->{$type};
194             foreach my $level (1..$module->{level}) {
195             $modules_built{$type} ||= {};
196             $modules_built{$type}->{$level} ||= 0;
197             $modules_built{$type}->{$level} ++;
198             }
199             }
200            
201             return \%modules_built;
202             }
203              
204             __PACKAGE__->meta->make_immutable;
205             no Moose;
206             1;