File Coverage

blib/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   960 use Mojo::Base -base;
  2         3  
  2         15  
19 2     2   277 use List::Util qw(any);
  2         5  
  2         4072  
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 2782     2782 0 3621 my $self = shift;
46 2782         3339 my $digraphs = shift;
47 2782         3724 my $max = scalar(@$digraphs);
48 2782         4249 my $length = 3 + rand(3); # length of name before adding one more
49 2782         3700 my $name = '';
50 2782         5788 while (length($name) < $length) {
51 6575         9933 my $i = 2*int(rand($max/2));
52 6575         9210 $name .= $digraphs->[$i];
53 6575         11941 $name .= $digraphs->[$i+1];
54             }
55 2782         5855 $name =~ s/\.//g;
56 2782         8364 return ucfirst($name);
57             }
58              
59             sub roll1d6 {
60 33795     33795 0 67574 return 1+int(rand(6));
61             }
62              
63             sub roll2d6 {
64 16256     16256 0 19366 my $self = shift;
65 16256         20938 return $self->roll1d6() + $self->roll1d6();
66             }
67              
68             sub compute_starport {
69 1283     1283 0 1812 my $self = shift;
70 1283         8195 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 1283         2650 return $map{$self->roll2d6()};
73             }
74              
75             sub compute_bases {
76 1283     1283 0 1664 my $self = shift;
77 1283 100       2111 if ($self->starport eq 'A') {
    100          
    100          
    100          
    100          
78 107         432 $self->naval($self->roll2d6() >= 8);
79 107         569 $self->scout($self->roll2d6() >= 10);
80 107         565 $self->research($self->roll2d6() >= 8);
81 107         538 $self->TAS($self->roll2d6() >= 4);
82 107         679 $self->consulate($self->roll2d6() >= 6);
83             } elsif ($self->starport eq 'B') {
84 219         1402 $self->naval($self->roll2d6() >= 8);
85 219         1102 $self->scout($self->roll2d6() >= 8);
86 219         1123 $self->research($self->roll2d6() >= 10);
87 219         1148 $self->TAS($self->roll2d6() >= 6);
88 219         1347 $self->consulate($self->roll2d6() >= 8);
89 219         1123 $self->pirate($self->roll2d6() >= 12);
90             } elsif ($self->starport eq 'C') {
91 398         3498 $self->scout($self->roll2d6() >= 8);
92 398         2167 $self->research($self->roll2d6() >= 10);
93 398         2123 $self->TAS($self->roll2d6() >= 10);
94 398         2135 $self->consulate($self->roll2d6() >= 10);
95 398         2538 $self->pirate($self->roll2d6() >= 10);
96             } elsif ($self->starport eq 'D') {
97 346         3837 $self->scout($self->roll2d6() >= 7);
98 346         1798 $self->pirate($self->roll2d6() >= 12);
99             } elsif ($self->starport eq 'E') {
100 178         2467 $self->pirate($self->roll2d6() >= 12);
101             }
102 1283         7350 $self->gasgiant($self->roll2d6() < 10);
103             }
104              
105             sub compute_atmosphere {
106 1283     1283 0 1671 my $self = shift;
107 1283         2020 my $atmosphere = $self->roll2d6() -7 + $self->size;
108 1283 100       4983 $atmosphere = 0 if $atmosphere < 0;
109 1283         3034 return $atmosphere;
110             }
111              
112             sub compute_temperature {
113 1283     1283 0 1666 my $self = shift;
114 1283         1909 my $temperature = $self->roll2d6();
115 1283         2114 my $atmosphere = $self->atmosphere;
116 1283 100 100     6290 $temperature -= 2
117             if $atmosphere == 2
118             or $atmosphere == 3;
119 1283 100 100     4303 $temperature -= 1
      100        
120             if $atmosphere == 3
121             or $atmosphere == 4
122             or $atmosphere == 14; # E
123 1283 100 100     3251 $temperature += 1
124             if $atmosphere == 8
125             or $atmosphere == 9;
126 1283 100 100     4384 $temperature += 2
      100        
127             if $atmosphere == 10 # A
128             or $atmosphere == 13 # D
129             or $atmosphere == 15; # F
130 1283 100 100     3265 $temperature += 6
131             if $atmosphere == 11 # B
132             or $atmosphere == 12; # C
133 1283         3066 return $temperature;
134             }
135              
136             sub compute_hydro {
137 1283     1283 0 1592 my $self = shift;
138 1283         1959 my $hydro = $self->roll2d6() - 7 + $self->size;
139 1283 100 100     4487 $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 1283 100 100     18005 $hydro -= 2
      100        
146             if $self->atmosphere != 13 # D
147             and $self->temperature >= 10
148             and $self->temperature <= 11;
149 1283 100 100     9936 $hydro -= 6
150             if $self->atmosphere != 13 # D
151             and $self->temperature >= 12;
152 1283 100 100     8419 $hydro = 0
153             if $self->size <= 1
154             or $hydro < 0;
155 1283 100       6040 $hydro = 10 if $hydro > 10;
156 1283         2905 return $hydro;
157             }
158              
159             sub compute_government {
160 1283     1283 0 1623 my $self = shift;
161 1283         1955 my $government = $self->roll2d6() - 7 + $self->population; # max 15
162 1283 100 100     5300 $government = 0
163             if $government < 0
164             or $self->population == 0;
165 1283         6131 return $government;
166             }
167              
168             sub compute_law {
169 1283     1283 0 1644 my $self = shift;
170 1283         1937 my $law = $self->roll2d6()-7+$self->government; # max 20!
171 1283 100 100     5094 $law = 0
172             if $law < 0
173             or $self->population == 0;
174 1283         5945 return $law;
175             }
176              
177             sub compute_tech {
178 1283     1283 0 1625 my $self = shift;
179 1283         1874 my $tech = $self->roll1d6();
180 1283 100       2254 $tech += 6 if $self->starport eq 'A';
181 1283 100       5159 $tech += 4 if $self->starport eq 'B';
182 1283 100       4969 $tech += 2 if $self->starport eq 'C';
183 1283 100       4828 $tech -= 4 if $self->starport eq 'X';
184 1283 100       4770 $tech += 2 if $self->size <= 1;
185 1283 100 100     4797 $tech += 1 if $self->size >= 2 and $self->size <= 4;
186 1283 100 100     8481 $tech += 1 if $self->atmosphere <= 3 or $self->atmosphere >= 10;
187 1283 100 100     7467 $tech += 1 if $self->hydro == 0 or $self->hydro == 9;
188 1283 100       7537 $tech += 2 if $self->hydro == 10;
189 1283 100 100     4597 $tech += 1 if $self->population >= 1 and $self->population <= 5;
190 1283 100       8401 $tech += 1 if $self->population == 9;
191 1283 100       4572 $tech += 2 if $self->population == 10;
192 1283 50       4512 $tech += 3 if $self->population == 11; # impossible?
193 1283 50       4487 $tech += 4 if $self->population == 12; # impossible?
194 1283 100 100     4460 $tech += 1 if $self->government == 0 or $self->government == 5;
195 1283 100       7720 $tech += 2 if $self->government == 7;
196 1283 100 100     4468 $tech -= 2 if $self->government == 13 or $self->government == 14;
197 1283 100       8283 $tech = 0 if $self->population == 0;
198 1283 100       4522 $tech = 15 if $tech > 15;
199 1283         2924 return $tech;
200             }
201              
202             sub check_doom {
203 1283     1283 0 1619 my $self = shift;
204 1283         1511 my $doomed = 0;
205 1283 100 100     2102 $doomed = 1 if $self->atmosphere <= 1 and $self->tech < 8;
206 1283 100 100     5633 $doomed = 1 if $self->atmosphere <= 3 and $self->tech < 5;
207 1283 100 100     6358 $doomed = 1 if ($self->atmosphere == 4
      100        
208             or $self->atmosphere == 7
209             or $self->atmosphere == 9) and $self->tech < 3;
210 1283 100 100     12737 $doomed = 1 if $self->atmosphere == 10 and $self->tech < 8;
211 1283 100 100     4920 $doomed = 1 if $self->atmosphere == 11 and $self->tech < 9;
212 1283 100 100     4939 $doomed = 1 if $self->atmosphere == 12 and $self->tech < 10;
213 1283 50 66     4781 $doomed = 1 if ($self->atmosphere == 13
      33        
214             and $self->atmosphere == 14) and $self->tech < 5;
215 1283 50 66     4818 $doomed = 1 if $self->atmosphere == 15 and $self->tech < 8;
216 1283 100       5301 if ($doomed) {
217 179         384 $self->population(0);
218 179         896 $self->government(0);
219 179         893 $self->law(0);
220 179         829 $self->tech(0);
221             }
222             }
223              
224             sub compute_tradecodes {
225 1283     1283 0 1602 my $self = shift;
226 1283         1757 my $tradecodes = '';
227 1283 100 100     2189 $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 1283 100 100     13703 $tradecodes .= " As" if $self->size == 0 and $self->atmosphere == 0 and $self->hydro == 0;
      66        
231 1283 50 66     5200 $tradecodes .= " Ba" if $self->population == 0 and $self->government == 0 and $self->law == 0;
      66        
232 1283 100 100     6014 $tradecodes .= " De" if $self->atmosphere >= 2 and $self->hydro == 0;
233 1283 100 100     7948 $tradecodes .= " Fl" if $self->atmosphere >= 10 and $self->hydro >= 1;
234 1283 100 100     5097 $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 1283 100       12207 $tradecodes .= " Hi" if $self->population >= 9;
238 1283 100       4596 $tradecodes .= " Ht" if $self->tech >= 12;
239 1283 100 100     4542 $tradecodes .= " Ic" if $self->atmosphere <= 1 and $self->hydro >= 1;
240 1283 100 100 436   5397 $tradecodes .= " In" if $self->population >= 9 and any { $_ == $self->atmosphere } qw(0 1 2 4 7 9);
  436         1874  
241 1283 100 100     5269 $tradecodes .= " Lo" if $self->population >= 1 and $self->population <= 3;
242 1283 100 100     7929 $tradecodes .= " Lt" if $self->tech >= 1 and $self->tech <= 5;
243 1283 100 100     7892 $tradecodes .= " Na" if $self->atmosphere <= 3 and $self->hydro <= 3 and $self->population >= 6;
      100        
244 1283 100 100     7240 $tradecodes .= " Ni" if $self->population >= 4 and $self->population <= 6;
245 1283 100 100     7139 $tradecodes .= " Po" if $self->atmosphere >= 2 and $self->atmosphere <= 5 and $self->hydro <= 3;
      100        
246 1283 100 100 633   9732 $tradecodes .= " Ri" if $self->population >= 6 and $self->population <= 8 and any { $_ == $self->atmosphere } qw(6 8);
  633   100     4913  
247 1283 100       5976 $tradecodes .= " Wa" if $self->hydro >= 10;
248 1283 100       4716 $tradecodes .= " Va" if $self->atmosphere == 0;
249 1283         6429 return $tradecodes;
250             }
251              
252             sub compute_travelzone {
253 1283     1283 0 1707 my $self = shift;
254 1283         1507 my $danger = 0;
255 1283 100       2185 $danger++ if $self->atmosphere >= 10;
256 1283 100 100     4703 $danger++ if $self->population and $self->government == 0;
257 1283 100       8397 $danger++ if $self->government == 7;
258 1283 100       4689 $danger++ if $self->government == 10;
259 1283 100 100     4400 $danger++ if $self->population and $self->law == 0;
260 1283 100       8081 $danger++ if $self->law >= 9;
261 1283 100 100     5132 return 'R' if $danger and $self->pirate;
262 1245 100       5534 return 'A' if $danger;
263             }
264              
265             sub init {
266 1283     1283 0 1703 my $self = shift;
267 1283         3066 $self->x(shift);
268 1283         7527 $self->y(shift);
269 1283         6822 $self->name($self->compute_name(shift));
270 1283         7288 $self->starport($self->compute_starport);
271 1283         7138 $self->compute_bases;
272 1283         6893 $self->size($self->roll2d6()-2);
273 1283         7186 $self->atmosphere($self->compute_atmosphere);
274 1283         6628 $self->temperature($self->compute_temperature);
275 1283         6618 $self->hydro($self->compute_hydro);
276 1283         6248 $self->population($self->roll2d6()-2); # How to get to B and C in the table?
277 1283         7228 $self->government($self->compute_government);
278 1283         7326 $self->law($self->compute_law);
279 1283         6308 $self->tech($self->compute_tech);
280 1283         6921 $self->check_doom;
281 1283         2785 $self->tradecodes($self->compute_tradecodes);
282 1283         7670 $self->travelzone($self->compute_travelzone);
283 1283         8098 return $self;
284             }
285              
286             sub code {
287 7698     7698 0 24559 my $num = shift;
288 7698 100       14828 return $num if $num < 10;
289 537         1031 return chr(65-10+$num);
290             }
291              
292             sub str {
293 1283     1283 0 1828 my $self = shift;
294 1283         2309 my $uwp = sprintf("%-16s %02d%02d ", $self->name, $self->x, $self->y);
295 1283         11344 $uwp .= $self->starport;
296 1283         5552 $uwp .= code($self->size);
297 1283         2477 $uwp .= code($self->atmosphere);
298 1283         2545 $uwp .= code($self->hydro);
299 1283         2541 $uwp .= code($self->population);
300 1283         2411 $uwp .= code($self->government);
301 1283         2406 $uwp .= code($self->law);
302 1283         1775 $uwp .= '-';
303 1283         2399 $uwp .= sprintf("%-2d", $self->tech);
304 1283         4911 my $bases = '';
305 1283 100       2260 $bases .= 'N' if $self->naval;
306 1283 100       5254 $bases .= 'S' if $self->scout;
307 1283 100       5385 $bases .= 'R' if $self->research;
308 1283 100       5190 $bases .= 'T' if $self->TAS;
309 1283 100       5230 $bases .= 'C' if $self->consulate;
310 1283 100       5057 $bases .= 'P' if $self->pirate;
311 1283 100       5272 $bases .= 'G' if $self->gasgiant;
312 1283         5752 $uwp .= sprintf("%7s", $bases);
313 1283         2489 $uwp .= ' ' . $self->tradecodes;
314 1283 100       5616 $uwp .= ' ' . $self->travelzone if $self->travelzone;
315 1283 100       6687 if ($self->culture) {
316 944         4125 my $spaces = 20 - length($self->tradecodes);
317 944 100       3539 $spaces -= 1 + length($self->travelzone) if $self->travelzone;
318 944         4882 $uwp .= ' ' x $spaces;
319 944         1709 $uwp .= '[' . $self->culture . ']';
320             }
321 1283         6751 return $uwp;
322             }
323              
324             1;