File Coverage

lib/Traveller/System.pm
Criterion Covered Total %
statement 193 193 100.0
branch 161 166 96.9
condition 179 186 96.2
subroutine 21 21 100.0
pod 0 17 0.0
total 554 583 95.0


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   1054 use Mojo::Base -base;
  2         4  
  2         13  
19 2     2   387 use List::Util qw(any);
  2         3  
  2         4012  
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 1484     1484 0 2196 my $self = shift;
46 1484         2060 my $digraphs = shift;
47 1484         3265 my $max = scalar(@$digraphs);
48 1484         2501 my $length = 3 + rand(3); # length of name before adding one more
49 1484         2262 my $name = '';
50 1484         3655 while (length($name) < $length) {
51 3593         5990 my $i = 2*int(rand($max/2));
52 3593         5337 $name .= $digraphs->[$i];
53 3593         9413 $name .= $digraphs->[$i+1];
54             }
55 1484         3198 $name =~ s/\.//g;
56 1484         5274 return ucfirst($name);
57             }
58              
59             sub roll1d6 {
60 17941     17941 0 45139 return 1+int(rand(6));
61             }
62              
63             sub roll2d6 {
64 8631     8631 0 12279 my $self = shift;
65 8631         14210 return $self->roll1d6() + $self->roll1d6();
66             }
67              
68             sub compute_starport {
69 679     679 0 1169 my $self = shift;
70 679         7284 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 679         1429 return $map{$self->roll2d6()};
73             }
74              
75             sub compute_bases {
76 679     679 0 965 my $self = shift;
77 679 100       1221 if ($self->starport eq 'A') {
    100          
    100          
    100          
    100          
78 50         283 $self->naval($self->roll2d6() >= 8);
79 50         336 $self->scout($self->roll2d6() >= 10);
80 50         307 $self->research($self->roll2d6() >= 8);
81 50         415 $self->TAS($self->roll2d6() >= 4);
82 50         331 $self->consulate($self->roll2d6() >= 6);
83             } elsif ($self->starport eq 'B') {
84 131         996 $self->naval($self->roll2d6() >= 8);
85 131         845 $self->scout($self->roll2d6() >= 8);
86 131         779 $self->research($self->roll2d6() >= 10);
87 131         995 $self->TAS($self->roll2d6() >= 6);
88 131         753 $self->consulate($self->roll2d6() >= 8);
89 131         769 $self->pirate($self->roll2d6() >= 12);
90             } elsif ($self->starport eq 'C') {
91 208         2142 $self->scout($self->roll2d6() >= 8);
92 208         1197 $self->research($self->roll2d6() >= 10);
93 208         1721 $self->TAS($self->roll2d6() >= 10);
94 208         1190 $self->consulate($self->roll2d6() >= 10);
95 208         1209 $self->pirate($self->roll2d6() >= 10);
96             } elsif ($self->starport eq 'D') {
97 174         2370 $self->scout($self->roll2d6() >= 7);
98 174         1120 $self->pirate($self->roll2d6() >= 12);
99             } elsif ($self->starport eq 'E') {
100 96         1530 $self->pirate($self->roll2d6() >= 12);
101             }
102 679         4652 $self->gasgiant($self->roll2d6() < 10);
103             }
104              
105             sub compute_atmosphere {
106 679     679 0 1016 my $self = shift;
107 679         1272 my $atmosphere = $self->roll2d6() -7 + $self->size;
108 679 100       3059 $atmosphere = 0 if $atmosphere < 0;
109 679         2049 return $atmosphere;
110             }
111              
112             sub compute_temperature {
113 679     679 0 980 my $self = shift;
114 679         1183 my $temperature = $self->roll2d6();
115 679         1340 my $atmosphere = $self->atmosphere;
116 679 100 100     4060 $temperature -= 2
117             if $atmosphere == 2
118             or $atmosphere == 3;
119 679 100 100     3018 $temperature -= 1
      100        
120             if $atmosphere == 3
121             or $atmosphere == 4
122             or $atmosphere == 14; # E
123 679 100 100     2241 $temperature += 1
124             if $atmosphere == 8
125             or $atmosphere == 9;
126 679 100 100     2831 $temperature += 2
      100        
127             if $atmosphere == 10 # A
128             or $atmosphere == 13 # D
129             or $atmosphere == 15; # F
130 679 100 100     2262 $temperature += 6
131             if $atmosphere == 11 # B
132             or $atmosphere == 12; # C
133 679         1976 return $temperature;
134             }
135              
136             sub compute_hydro {
137 679     679 0 1028 my $self = shift;
138 679         1399 my $hydro = $self->roll2d6() - 7 + $self->size;
139 679 100 100     2821 $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 679 100 100     11278 $hydro -= 2
      100        
146             if $self->atmosphere != 13 # D
147             and $self->temperature >= 10
148             and $self->temperature <= 11;
149 679 100 100     6080 $hydro -= 6
150             if $self->atmosphere != 13 # D
151             and $self->temperature >= 12;
152 679 100 100     5379 $hydro = 0
153             if $self->size <= 1
154             or $hydro < 0;
155 679 100       3739 $hydro = 10 if $hydro > 10;
156 679         2015 return $hydro;
157             }
158              
159             sub compute_government {
160 679     679 0 1009 my $self = shift;
161 679         1442 my $government = $self->roll2d6() - 7 + $self->population; # max 15
162 679 100 100     3265 $government = 0
163             if $government < 0
164             or $self->population == 0;
165 679         3869 return $government;
166             }
167              
168             sub compute_law {
169 679     679 0 1063 my $self = shift;
170 679         1204 my $law = $self->roll2d6()-7+$self->government; # max 20!
171 679 100 100     3257 $law = 0
172             if $law < 0
173             or $self->population == 0;
174 679         3719 return $law;
175             }
176              
177             sub compute_tech {
178 679     679 0 1000 my $self = shift;
179 679         1309 my $tech = $self->roll1d6();
180 679 100       1372 $tech += 6 if $self->starport eq 'A';
181 679 100       3358 $tech += 4 if $self->starport eq 'B';
182 679 100       2940 $tech += 2 if $self->starport eq 'C';
183 679 100       3029 $tech -= 4 if $self->starport eq 'X';
184 679 100       3008 $tech += 2 if $self->size <= 1;
185 679 100 100     3038 $tech += 1 if $self->size >= 2 and $self->size <= 4;
186 679 100 100     5352 $tech += 1 if $self->atmosphere <= 3 or $self->atmosphere >= 10;
187 679 100 100     4914 $tech += 1 if $self->hydro == 0 or $self->hydro == 9;
188 679 100       4832 $tech += 2 if $self->hydro == 10;
189 679 100 100     2902 $tech += 1 if $self->population >= 1 and $self->population <= 5;
190 679 100       5389 $tech += 1 if $self->population == 9;
191 679 100       2790 $tech += 2 if $self->population == 10;
192 679 50       2742 $tech += 3 if $self->population == 11; # impossible?
193 679 50       2695 $tech += 4 if $self->population == 12; # impossible?
194 679 100 100     2738 $tech += 1 if $self->government == 0 or $self->government == 5;
195 679 100       4861 $tech += 2 if $self->government == 7;
196 679 100 100     2730 $tech -= 2 if $self->government == 13 or $self->government == 14;
197 679 100       4870 $tech = 0 if $self->population == 0;
198 679 100       2725 $tech = 15 if $tech > 15;
199 679         1969 return $tech;
200             }
201              
202             sub check_doom {
203 679     679 0 976 my $self = shift;
204 679         966 my $doomed = 0;
205 679 100 100     1344 $doomed = 1 if $self->atmosphere <= 1 and $self->tech < 8;
206 679 100 100     3500 $doomed = 1 if $self->atmosphere <= 3 and $self->tech < 5;
207 679 100 100     3833 $doomed = 1 if ($self->atmosphere == 4
      100        
208             or $self->atmosphere == 7
209             or $self->atmosphere == 9) and $self->tech < 3;
210 679 100 100     7848 $doomed = 1 if $self->atmosphere == 10 and $self->tech < 8;
211 679 100 100     3018 $doomed = 1 if $self->atmosphere == 11 and $self->tech < 9;
212 679 100 100     3012 $doomed = 1 if $self->atmosphere == 12 and $self->tech < 10;
213 679 50 66     3683 $doomed = 1 if ($self->atmosphere == 13
      33        
214             and $self->atmosphere == 14) and $self->tech < 5;
215 679 50 66     2863 $doomed = 1 if $self->atmosphere == 15 and $self->tech < 8;
216 679 100       2952 if ($doomed) {
217 78         245 $self->population(0);
218 78         495 $self->government(0);
219 78         488 $self->law(0);
220 78         417 $self->tech(0);
221             }
222             }
223              
224             sub compute_tradecodes {
225 679     679 0 1152 my $self = shift;
226 679         1082 my $tradecodes = '';
227 679 100 100     1247 $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 679 100 100     8403 $tradecodes .= " As" if $self->size == 0 and $self->atmosphere == 0 and $self->hydro == 0;
      66        
231 679 50 66     3368 $tradecodes .= " Ba" if $self->population == 0 and $self->government == 0 and $self->law == 0;
      66        
232 679 100 100     3715 $tradecodes .= " De" if $self->atmosphere >= 2 and $self->hydro == 0;
233 679 100 100     4789 $tradecodes .= " Fl" if $self->atmosphere >= 10 and $self->hydro >= 1;
234 679 100 100     3503 $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 679 100       7207 $tradecodes .= " Hi" if $self->population >= 9;
238 679 100       3016 $tradecodes .= " Ht" if $self->tech >= 12;
239 679 100 100     2880 $tradecodes .= " Ic" if $self->atmosphere <= 1 and $self->hydro >= 1;
240 679 100 100 293   3190 $tradecodes .= " In" if $self->population >= 9 and any { $_ == $self->atmosphere } qw(0 1 2 4 7 9);
  293         1372  
241 679 100 100     3210 $tradecodes .= " Lo" if $self->population >= 1 and $self->population <= 3;
242 679 100 100     4800 $tradecodes .= " Lt" if $self->tech >= 1 and $self->tech <= 5;
243 679 100 100     4798 $tradecodes .= " Na" if $self->atmosphere <= 3 and $self->hydro <= 3 and $self->population >= 6;
      100        
244 679 100 100     4792 $tradecodes .= " Ni" if $self->population >= 4 and $self->population <= 6;
245 679 100 100     4668 $tradecodes .= " Po" if $self->atmosphere >= 2 and $self->atmosphere <= 5 and $self->hydro <= 3;
      100        
246 679 100 100 411   5909 $tradecodes .= " Ri" if $self->population >= 6 and $self->population <= 8 and any { $_ == $self->atmosphere } qw(6 8);
  411   100     4062  
247 679 100       4156 $tradecodes .= " Wa" if $self->hydro >= 10;
248 679 100       2830 $tradecodes .= " Va" if $self->atmosphere == 0;
249 679         3946 return $tradecodes;
250             }
251              
252             sub compute_travelzone {
253 679     679 0 1091 my $self = shift;
254 679         1116 my $danger = 0;
255 679 100       1262 $danger++ if $self->atmosphere >= 10;
256 679 100 100     2967 $danger++ if $self->population and $self->government == 0;
257 679 100       4993 $danger++ if $self->government == 7;
258 679 100       2804 $danger++ if $self->government == 10;
259 679 100 100     2745 $danger++ if $self->population and $self->law == 0;
260 679 100       4928 $danger++ if $self->law >= 9;
261 679 100 100     3242 return 'R' if $danger and $self->pirate;
262 657 100       3341 return 'A' if $danger;
263             }
264              
265             sub init {
266 679     679 0 1008 my $self = shift;
267 679         2162 $self->x(shift);
268 679         5115 $self->y(shift);
269 679         4149 $self->name($self->compute_name(shift));
270 679         4911 $self->starport($self->compute_starport);
271 679         4682 $self->compute_bases;
272 679         4186 $self->size($self->roll2d6()-2);
273 679         5225 $self->atmosphere($self->compute_atmosphere);
274 679         3779 $self->temperature($self->compute_temperature);
275 679         4077 $self->hydro($self->compute_hydro);
276 679         3929 $self->population($self->roll2d6()-2); # How to get to B and C in the table?
277 679         4436 $self->government($self->compute_government);
278 679         4106 $self->law($self->compute_law);
279 679         3965 $self->tech($self->compute_tech);
280 679         4417 $self->check_doom;
281 679         1730 $self->tradecodes($self->compute_tradecodes);
282 679         4854 $self->travelzone($self->compute_travelzone);
283 679         5308 return $self;
284             }
285              
286             sub code {
287 4074     4074 0 13524 my $num = shift;
288 4074 100       9352 return $num if $num < 10;
289 316         782 return chr(65-10+$num);
290             }
291              
292             sub str {
293 679     679 0 1017 my $self = shift;
294 679         1612 my $uwp = sprintf("%-16s %02d%02d ", $self->name, $self->x, $self->y);
295 679         7750 $uwp .= $self->starport;
296 679         2951 $uwp .= code($self->size);
297 679         1520 $uwp .= code($self->atmosphere);
298 679         1566 $uwp .= code($self->hydro);
299 679         1612 $uwp .= code($self->population);
300 679         1554 $uwp .= code($self->government);
301 679         1488 $uwp .= code($self->law);
302 679         1214 $uwp .= '-';
303 679         1471 $uwp .= sprintf("%-2d", $self->tech);
304 679         2898 my $bases = '';
305 679 100       1502 $bases .= 'N' if $self->naval;
306 679 100       4641 $bases .= 'S' if $self->scout;
307 679 100       3069 $bases .= 'R' if $self->research;
308 679 100       3099 $bases .= 'T' if $self->TAS;
309 679 100       3162 $bases .= 'C' if $self->consulate;
310 679 100       3138 $bases .= 'P' if $self->pirate;
311 679 100       3082 $bases .= 'G' if $self->gasgiant;
312 679         3040 $uwp .= sprintf("%7s", $bases);
313 679         1417 $uwp .= ' ' . $self->tradecodes;
314 679 100       3498 $uwp .= ' ' . $self->travelzone if $self->travelzone;
315 679 100       4046 if ($self->culture) {
316 549         2721 my $spaces = 20 - length($self->tradecodes);
317 549 100       2170 $spaces -= 1 + length($self->travelzone) if $self->travelzone;
318 549         2984 $uwp .= ' ' x $spaces;
319 549         1135 $uwp .= '[' . $self->culture . ']';
320             }
321 679         4144 return $uwp;
322             }
323              
324             1;