File Coverage

blib/lib/Traveller/System.pm
Criterion Covered Total %
statement 193 193 100.0
branch 161 166 96.9
condition 177 186 95.1
subroutine 21 21 100.0
pod 0 17 0.0
total 552 583 94.6


line stmt bran cond sub pod time code
1             #!/usr/bin/perl
2             # Copyright (C) 2009-2021 Alex Schroeder
3             # Copyright (C) 2020 Christian Carey
4             #
5             # This program is free software: you can redistribute it and/or modify it under
6             # the terms of the GNU General Public License as published by the Free Software
7             # Foundation, either version 3 of the License, or (at your option) any later
8             # version.
9             #
10             # This program is distributed in the hope that it will be useful, but WITHOUT
11             # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12             # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
13             #
14             # You should have received a copy of the GNU General Public License along with
15             # this program. If not, see .
16              
17             package Traveller::System;
18 2     2   1218 use Mojo::Base -base;
  2         4  
  2         18  
19 2     2   341 use List::Util qw(any);
  2         5  
  2         4757  
20              
21             has 'name';
22             has 'x';
23             has 'y';
24             has 'starport';
25             has 'size';
26             has 'atmosphere';
27             has 'temperature';
28             has 'hydro';
29             has 'population';
30             has 'government';
31             has 'law';
32             has 'tech';
33             has 'consulate';
34             has 'pirate';
35             has 'TAS';
36             has 'research';
37             has 'naval';
38             has 'scout';
39             has 'gasgiant';
40             has 'tradecodes';
41             has 'travelzone';
42             has 'culture';
43              
44             sub compute_name {
45 2708     2708 0 3772 my $self = shift;
46 2708         3422 my $digraphs = shift;
47 2708         3797 my $max = scalar(@$digraphs);
48 2708         4466 my $length = 3 + rand(3); # length of name before adding one more
49 2708         3916 my $name = '';
50 2708         6059 while (length($name) < $length) {
51 6509         10546 my $i = 2*int(rand($max/2));
52 6509         9339 $name .= $digraphs->[$i];
53 6509         12893 $name .= $digraphs->[$i+1];
54             }
55 2708         6278 $name =~ s/\.//g;
56 2708         9059 return ucfirst($name);
57             }
58              
59             sub roll1d6 {
60 35071     35071 0 76057 return 1+int(rand(6));
61             }
62              
63             sub roll2d6 {
64 16875     16875 0 21532 my $self = shift;
65 16875         24189 return $self->roll1d6() + $self->roll1d6();
66             }
67              
68             sub compute_starport {
69 1321     1321 0 1931 my $self = shift;
70 1321         9559 my %map = ( 2=>'X', 3=>'E', 4=>'E', 5=>'D', 6=>'D', 7=>'C',
71             8=>'C', 9=>'B', 10=>'B', 11=>'A', 12=>'A' );
72 1321         2771 return $map{$self->roll2d6()};
73             }
74              
75             sub compute_bases {
76 1321     1321 0 1930 my $self = shift;
77 1321 100       2205 if ($self->starport eq 'A') {
    100          
    100          
    100          
    100          
78 119         548 $self->naval($self->roll2d6() >= 8);
79 119         681 $self->scout($self->roll2d6() >= 10);
80 119         691 $self->research($self->roll2d6() >= 8);
81 119         673 $self->TAS($self->roll2d6() >= 4);
82 119         820 $self->consulate($self->roll2d6() >= 6);
83             } elsif ($self->starport eq 'B') {
84 243         2071 $self->naval($self->roll2d6() >= 8);
85 243         1409 $self->scout($self->roll2d6() >= 8);
86 243         1387 $self->research($self->roll2d6() >= 10);
87 243         1330 $self->TAS($self->roll2d6() >= 6);
88 243         1732 $self->consulate($self->roll2d6() >= 8);
89 243         1387 $self->pirate($self->roll2d6() >= 12);
90             } elsif ($self->starport eq 'C') {
91 422         4072 $self->scout($self->roll2d6() >= 8);
92 422         2450 $self->research($self->roll2d6() >= 10);
93 422         2359 $self->TAS($self->roll2d6() >= 10);
94 422         2359 $self->consulate($self->roll2d6() >= 10);
95 422         3097 $self->pirate($self->roll2d6() >= 10);
96             } elsif ($self->starport eq 'D') {
97 325         3959 $self->scout($self->roll2d6() >= 7);
98 325         1891 $self->pirate($self->roll2d6() >= 12);
99             } elsif ($self->starport eq 'E') {
100 173         2547 $self->pirate($self->roll2d6() >= 12);
101             }
102 1321         8702 $self->gasgiant($self->roll2d6() < 10);
103             }
104              
105             sub compute_atmosphere {
106 1321     1321 0 1939 my $self = shift;
107 1321         2297 my $atmosphere = $self->roll2d6() -7 + $self->size;
108 1321 100       5234 $atmosphere = 0 if $atmosphere < 0;
109 1321         3376 return $atmosphere;
110             }
111              
112             sub compute_temperature {
113 1321     1321 0 1896 my $self = shift;
114 1321         2078 my $temperature = $self->roll2d6();
115 1321         2362 my $atmosphere = $self->atmosphere;
116 1321 100 100     7024 $temperature -= 2
117             if $atmosphere == 2
118             or $atmosphere == 3;
119 1321 100 100     4906 $temperature -= 1
      100        
120             if $atmosphere == 3
121             or $atmosphere == 4
122             or $atmosphere == 14; # E
123 1321 100 100     3684 $temperature += 1
124             if $atmosphere == 8
125             or $atmosphere == 9;
126 1321 100 100     5020 $temperature += 2
      66        
127             if $atmosphere == 10 # A
128             or $atmosphere == 13 # D
129             or $atmosphere == 15; # F
130 1321 100 100     3776 $temperature += 6
131             if $atmosphere == 11 # B
132             or $atmosphere == 12; # C
133 1321         3589 return $temperature;
134             }
135              
136             sub compute_hydro {
137 1321     1321 0 1805 my $self = shift;
138 1321         2106 my $hydro = $self->roll2d6() - 7 + $self->size;
139 1321 100 100     5038 $hydro -= 4
      100        
      100        
      100        
140             if $self->atmosphere == 0
141             or $self->atmosphere == 1
142             or $self->atmosphere == 10 # A
143             or $self->atmosphere == 11 # B
144             or $self->atmosphere == 12; # C
145 1321 100 100     20551 $hydro -= 2
      100        
146             if $self->atmosphere != 13 # D
147             and $self->temperature >= 10
148             and $self->temperature <= 11;
149 1321 100 100     11010 $hydro -= 6
150             if $self->atmosphere != 13 # D
151             and $self->temperature >= 12;
152 1321 100 100     9461 $hydro = 0
153             if $self->size <= 1
154             or $hydro < 0;
155 1321 100       6715 $hydro = 10 if $hydro > 10;
156 1321         3742 return $hydro;
157             }
158              
159             sub compute_government {
160 1321     1321 0 1909 my $self = shift;
161 1321         2201 my $government = $self->roll2d6() - 7 + $self->population; # max 15
162 1321 100 100     5728 $government = 0
163             if $government < 0
164             or $self->population == 0;
165 1321         6824 return $government;
166             }
167              
168             sub compute_law {
169 1321     1321 0 1924 my $self = shift;
170 1321         2147 my $law = $self->roll2d6()-7+$self->government; # max 20!
171 1321 100 100     5808 $law = 0
172             if $law < 0
173             or $self->population == 0;
174 1321         6619 return $law;
175             }
176              
177             sub compute_tech {
178 1321     1321 0 1952 my $self = shift;
179 1321         2253 my $tech = $self->roll1d6();
180 1321 100       2412 $tech += 6 if $self->starport eq 'A';
181 1321 100       6011 $tech += 4 if $self->starport eq 'B';
182 1321 100       5176 $tech += 2 if $self->starport eq 'C';
183 1321 100       5235 $tech -= 4 if $self->starport eq 'X';
184 1321 100       5245 $tech += 2 if $self->size <= 1;
185 1321 100 100     5056 $tech += 1 if $self->size >= 2 and $self->size <= 4;
186 1321 100 100     9496 $tech += 1 if $self->atmosphere <= 3 or $self->atmosphere >= 10;
187 1321 100 100     8424 $tech += 1 if $self->hydro == 0 or $self->hydro == 9;
188 1321 100       8464 $tech += 2 if $self->hydro == 10;
189 1321 100 100     5121 $tech += 1 if $self->population >= 1 and $self->population <= 5;
190 1321 100       9552 $tech += 1 if $self->population == 9;
191 1321 100       5434 $tech += 2 if $self->population == 10;
192 1321 50       5005 $tech += 3 if $self->population == 11; # impossible?
193 1321 50       5009 $tech += 4 if $self->population == 12; # impossible?
194 1321 100 100     4905 $tech += 1 if $self->government == 0 or $self->government == 5;
195 1321 100       9148 $tech += 2 if $self->government == 7;
196 1321 100 100     5154 $tech -= 2 if $self->government == 13 or $self->government == 14;
197 1321 100       9130 $tech = 0 if $self->population == 0;
198 1321 100       5042 $tech = 15 if $tech > 15;
199 1321         3175 return $tech;
200             }
201              
202             sub check_doom {
203 1321     1321 0 1818 my $self = shift;
204 1321         1713 my $doomed = 0;
205 1321 100 100     2284 $doomed = 1 if $self->atmosphere <= 1 and $self->tech < 8;
206 1321 100 100     6201 $doomed = 1 if $self->atmosphere <= 3 and $self->tech < 5;
207 1321 100 100     6794 $doomed = 1 if ($self->atmosphere == 4
      100        
208             or $self->atmosphere == 7
209             or $self->atmosphere == 9) and $self->tech < 3;
210 1321 100 100     14480 $doomed = 1 if $self->atmosphere == 10 and $self->tech < 8;
211 1321 100 100     5615 $doomed = 1 if $self->atmosphere == 11 and $self->tech < 9;
212 1321 100 100     5384 $doomed = 1 if $self->atmosphere == 12 and $self->tech < 10;
213 1321 50 66     5249 $doomed = 1 if ($self->atmosphere == 13
      33        
214             and $self->atmosphere == 14) and $self->tech < 5;
215 1321 50 33     5345 $doomed = 1 if $self->atmosphere == 15 and $self->tech < 8;
216 1321 100       5739 if ($doomed) {
217 174         419 $self->population(0);
218 174         987 $self->government(0);
219 174         936 $self->law(0);
220 174         897 $self->tech(0);
221             }
222             }
223              
224             sub compute_tradecodes {
225 1321     1321 0 1869 my $self = shift;
226 1321         2018 my $tradecodes = '';
227 1321 100 100     2301 $tradecodes .= " Ag" if $self->atmosphere >= 4 and $self->atmosphere <= 9
      100        
      100        
      100        
      100        
228             and $self->hydro >= 4 and $self->hydro <= 8
229             and $self->population >= 5 and $self->population <= 7;
230 1321 100 100     15466 $tradecodes .= " As" if $self->size == 0 and $self->atmosphere == 0 and $self->hydro == 0;
      66        
231 1321 50 66     6113 $tradecodes .= " Ba" if $self->population == 0 and $self->government == 0 and $self->law == 0;
      66        
232 1321 100 100     6787 $tradecodes .= " De" if $self->atmosphere >= 2 and $self->hydro == 0;
233 1321 100 100     8903 $tradecodes .= " Fl" if $self->atmosphere >= 10 and $self->hydro >= 1;
234 1321 100 100     5832 $tradecodes .= " Ga" if $self->size >= 5
      100        
      100        
      100        
235             and $self->atmosphere >= 4 and $self->atmosphere <= 9
236             and $self->hydro >= 4 and $self->hydro <= 8;
237 1321 100       13130 $tradecodes .= " Hi" if $self->population >= 9;
238 1321 100       5338 $tradecodes .= " Ht" if $self->tech >= 12;
239 1321 100 100     5178 $tradecodes .= " Ic" if $self->atmosphere <= 1 and $self->hydro >= 1;
240 1321 100 100 482   6263 $tradecodes .= " In" if $self->population >= 9 and any { $_ == $self->atmosphere } qw(0 1 2 4 7 9);
  482         2254  
241 1321 100 100     5667 $tradecodes .= " Lo" if $self->population >= 1 and $self->population <= 3;
242 1321 100 100     9101 $tradecodes .= " Lt" if $self->tech >= 1 and $self->tech <= 5;
243 1321 100 100     8821 $tradecodes .= " Na" if $self->atmosphere <= 3 and $self->hydro <= 3 and $self->population >= 6;
      100        
244 1321 100 100     7916 $tradecodes .= " Ni" if $self->population >= 4 and $self->population <= 6;
245 1321 100 100     8179 $tradecodes .= " Po" if $self->atmosphere >= 2 and $self->atmosphere <= 5 and $self->hydro <= 3;
      100        
246 1321 100 100 692   11166 $tradecodes .= " Ri" if $self->population >= 6 and $self->population <= 8 and any { $_ == $self->atmosphere } qw(6 8);
  692   100     5875  
247 1321 100       6699 $tradecodes .= " Wa" if $self->hydro >= 10;
248 1321 100       5162 $tradecodes .= " Va" if $self->atmosphere == 0;
249 1321         6926 return $tradecodes;
250             }
251              
252             sub compute_travelzone {
253 1321     1321 0 2079 my $self = shift;
254 1321         1703 my $danger = 0;
255 1321 100       2315 $danger++ if $self->atmosphere >= 10;
256 1321 100 100     5214 $danger++ if $self->population and $self->government == 0;
257 1321 100       9464 $danger++ if $self->government == 7;
258 1321 100       5144 $danger++ if $self->government == 10;
259 1321 100 100     5120 $danger++ if $self->population and $self->law == 0;
260 1321 100       8804 $danger++ if $self->law >= 9;
261 1321 100 100     5772 return 'R' if $danger and $self->pirate;
262 1282 100       5991 return 'A' if $danger;
263             }
264              
265             sub init {
266 1321     1321 0 1828 my $self = shift;
267 1321         3291 $self->x(shift);
268 1321         8556 $self->y(shift);
269 1321         7154 $self->name($self->compute_name(shift));
270 1321         8363 $self->starport($self->compute_starport);
271 1321         8337 $self->compute_bases;
272 1321         7862 $self->size($self->roll2d6()-2);
273 1321         7853 $self->atmosphere($self->compute_atmosphere);
274 1321         7360 $self->temperature($self->compute_temperature);
275 1321         7446 $self->hydro($self->compute_hydro);
276 1321         6962 $self->population($self->roll2d6()-2); # How to get to B and C in the table?
277 1321         7653 $self->government($self->compute_government);
278 1321         8136 $self->law($self->compute_law);
279 1321         7147 $self->tech($self->compute_tech);
280 1321         7685 $self->check_doom;
281 1321         3036 $self->tradecodes($self->compute_tradecodes);
282 1321         8565 $self->travelzone($self->compute_travelzone);
283 1321         9457 return $self;
284             }
285              
286             sub code {
287 7926     7926 0 25081 my $num = shift;
288 7926 100       15625 return $num if $num < 10;
289 542         1029 return chr(65-10+$num);
290             }
291              
292             sub str {
293 1321     1321 0 1825 my $self = shift;
294 1321         2390 my $uwp = sprintf("%-16s %02d%02d ", $self->name, $self->x, $self->y);
295 1321         11600 $uwp .= $self->starport;
296 1321         5724 $uwp .= code($self->size);
297 1321         2693 $uwp .= code($self->atmosphere);
298 1321         2569 $uwp .= code($self->hydro);
299 1321         2497 $uwp .= code($self->population);
300 1321         2478 $uwp .= code($self->government);
301 1321         2879 $uwp .= code($self->law);
302 1321         2131 $uwp .= '-';
303 1321         2497 $uwp .= sprintf("%-2d", $self->tech);
304 1321         5385 my $bases = '';
305 1321 100       2304 $bases .= 'N' if $self->naval;
306 1321 100       5464 $bases .= 'S' if $self->scout;
307 1321 100       5645 $bases .= 'R' if $self->research;
308 1321 100       5331 $bases .= 'T' if $self->TAS;
309 1321 100       5255 $bases .= 'C' if $self->consulate;
310 1321 100       5339 $bases .= 'P' if $self->pirate;
311 1321 100       5422 $bases .= 'G' if $self->gasgiant;
312 1321         6073 $uwp .= sprintf("%7s", $bases);
313 1321         2490 $uwp .= ' ' . $self->tradecodes;
314 1321 100       5478 $uwp .= ' ' . $self->travelzone if $self->travelzone;
315 1321 100       6743 if ($self->culture) {
316 968         4561 my $spaces = 20 - length($self->tradecodes);
317 968 100       3620 $spaces -= 1 + length($self->travelzone) if $self->travelzone;
318 968         5209 $uwp .= ' ' x $spaces;
319 968         1856 $uwp .= '[' . $self->culture . ']';
320             }
321 1321         6991 return $uwp;
322             }
323              
324             1;