File Coverage

lib/BalanceOfPower/Role/Diplomat.pm
Criterion Covered Total %
statement 226 258 87.6
branch 42 50 84.0
condition 18 42 42.8
subroutine 35 39 89.7
pod 0 30 0.0
total 321 419 76.6


line stmt bran cond sub pod time code
1             package BalanceOfPower::Role::Diplomat;
2             $BalanceOfPower::Role::Diplomat::VERSION = '0.400105';
3 13     13   4803 use strict;
  13         18  
  13         314  
4 13     13   101 use v5.10;
  13         33  
5 13     13   40 use Moo::Role;
  13         14  
  13         68  
6              
7 13     13   2689 use BalanceOfPower::Constants ':all';
  13         20  
  13         5314  
8              
9 13     13   3696 use BalanceOfPower::Relations::Friendship;
  13         23  
  13         330  
10 13     13   3491 use BalanceOfPower::Relations::Treaty;
  13         23  
  13         287  
11 13     13   60 use BalanceOfPower::Relations::RelPack;
  13         14  
  13         266  
12 13     13   40 use BalanceOfPower::Utils qw( as_main_title as_html_box br);
  13         16  
  13         23372  
13              
14             has diplomatic_relations => (
15             is => 'ro',
16             default => sub { BalanceOfPower::Relations::RelPack->new() },
17             handles => { add_diplomacy => 'add_link',
18             _diplomacy_exists => 'exists_link',
19             update_diplomacy => 'update_link',
20             get_diplomatic_relations => 'links_for_node' }
21             );
22             has treaties => (
23             is => 'ro',
24             default => sub { BalanceOfPower::Relations::RelPack->new() },
25             handles => { add_treaty => 'add_link',
26             exists_treaty => 'exists_link',
27             get_treaties_for_nation => 'links_for_node',
28             reset_treaties => 'delete_link_for_node',
29             delete_treaty => 'delete_link', }
30             );
31              
32             requires 'random';
33             requires 'distance';
34             requires 'border_exists';
35             requires 'broadcast_event';
36             requires 'is_under_influence';
37              
38             sub init_diplomacy
39             {
40 16     16 0 33 my $self = shift;
41 16         24 my @nations = @{$self->nation_names};
  16         77  
42 16         39 foreach my $n1 (@nations)
43             {
44 72         93 foreach my $n2 (@nations)
45             {
46 354 100 100     1018 if($n1 ne $n2 && ! $self->_diplomacy_exists($n1, $n2))
47             {
48 141         124 my $minimum_friendship = 0;
49 141         262 my $rel = BalanceOfPower::Relations::Friendship->new( node1 => $n1,
50             node2 => $n2,
51             factor => $self->calculate_random_friendship($n1, $n2));
52 141         11708 $self->add_diplomacy($rel);
53             }
54             }
55             }
56             }
57              
58             #Random friendship is function of the distance
59             sub calculate_random_friendship
60             {
61 141     141 0 118 my $self = shift;
62 141         110 my $nation1 = shift;
63 141         106 my $nation2 = shift;
64 141         309 my $distance = $self->distance($nation1, $nation2);
65 141 100       260 $distance = 3 if $distance > 3;
66              
67 141         103 my $middle = 50;
68              
69 141         161 my $polar_factor = ( 4 - $distance ) * 5;
70 141         150 my $random_floor = ( ( 3 - $distance ) * 5 ) + 25;
71              
72 141         2314 my $side = $self->random(0, 1, "Side for friendship between $nation1 and $nation2");
73 141 100       273 $side = $side == 0 ? -1 : 1;
74 141         2871 my $random_factor = $self->random(0, $random_floor, "Random factor for friendship between $nation1 and $nation2 [floor: $random_floor]");
75              
76 141         224 my $friendship = $middle + ( $side * ( $polar_factor + $random_factor ) );
77 141         2871 return $friendship;
78             }
79              
80              
81             sub init_random_alliances
82             {
83 1     1 0 2 my $self = shift;
84 1         2 my @nations = @{$self->nation_names};
  1         8  
85 1         7 for(my $i = 0; $i < STARTING_ALLIANCES; $i++)
86             {
87 7         166 my $n1 = $nations[$self->random(0, $#nations, "Nation1 for random alliance")];
88 7         141 my $n2 = $nations[$self->random(0, $#nations, "Nation2 for random alliance")];
89 7 100       33 if($n1 ne $n2)
90             {
91 5         17 $self->add_alliance($n1, $n2);
92 5         24 $self->broadcast_event("ALLIANCE BETWEEN $n1 AND $n2 CREATED", $n1, $n2);
93             }
94             }
95             }
96             sub reroll_diplomacy
97             {
98 2     2 0 4 my $self = shift;
99 2         5 my $nation = shift;
100 2         9 my @rels = $self->get_diplomatic_relations($nation);
101 2         8 for(@rels)
102             {
103 0         0 $_->factor($self->random(0 ,100, "Reroll diplomacy for " . $_->node1 . ", " . $_->node2));
104             }
105             }
106              
107             sub diplomacy_exists
108             {
109 987     987 0 2466 my $self = shift;
110 987         728 my $n1 = shift;
111 987         653 my $n2 = shift;
112 987         1656 my $r = $self->_diplomacy_exists($n1, $n2);
113 987 50       1482 if(! defined $r)
114             {
115 0         0 say "ERROR! No diplomacy between $n1, $n2";
116             }
117 987         1011 return $r;
118             }
119              
120             sub get_hates
121             {
122 47     47 0 56 my $self = shift;
123 47         87 my $nation = shift;
124 47     357   223 my @hates = $self->diplomatic_relations->query( sub { my $rel = shift; return $rel->status eq 'HATE' });
  357         239  
  357         451  
125 47         105 my @out = ();
126 47         64 foreach my $r (@hates)
127             {
128 76 100 100     316 if(($nation && $r->has_node($nation)) || (! $nation))
      100        
129             {
130 75 50 33     223 if(! $self->is_under_influence($r->node1) && ! $self->is_under_influence($r->node2))
131             {
132 75         103 push @out, $r;
133             }
134             }
135             }
136 47         113 return @out;
137             }
138             sub get_nations_with_status
139             {
140 19     19 0 16 my $self = shift;
141 19         16 my $nation = shift;
142 19         17 my $status = shift;
143 19         21 my @st_array = @{$status};
  19         26  
144 19         47 my @relations = $self->get_diplomatic_relations($nation);
145 19         21 my @out = ();
146 19         32 for(@relations)
147             {
148 76         55 my $r = $_;
149 76 100       53 if(grep{ $_ eq $r->status } @st_array)
  180         228  
150             {
151 32         73 push @out, $r->destination($nation);
152             }
153             }
154 19         212 return @out;
155             }
156              
157             sub get_friends
158             {
159 13     13 0 21 my $self = shift;
160 13         12 my $nation = shift;
161 13         48 return $self->get_nations_with_status($nation, ['FRIENDSHIP', 'ALLIANCE', 'INFLUENCE PRESENT']);
162             }
163             sub set_diplomacy
164             {
165 33     33 0 69 my $self = shift;
166 33         34 my $node1 = shift;
167 33         32 my $node2 = shift;
168 33         33 my $new_factor = shift;
169 33         59 my $r = $self->diplomacy_exists($node1, $node2);
170 33 50       60 return undef if(!$r ); #Should never happen
171 33         60 $r->factor($new_factor);
172 33         39 return $r;
173             }
174             sub copy_diplomacy
175             {
176 3     3 0 3 my $self = shift;
177 3         3 my $nation_from = shift;
178 3         4 my $nation_to = shift;
179 3         6 my @relations = $self->get_diplomatic_relations($nation_from);
180 3         8 for(@relations)
181             {
182 9         9 my $r = $_;
183 9         18 my $other = $r->destination($nation_from);
184 9 100       16 if($other ne $nation_to)
185             {
186 6         19 $self->set_diplomacy($nation_to, $other, $r->factor);
187             }
188             }
189              
190              
191             }
192              
193             sub change_diplomacy
194             {
195 58     58 0 132 my $self = shift;
196 58         60 my $node1 = shift;
197 58         50 my $node2 = shift;
198 58         57 my $dipl = shift;
199 58         58 my $reason = shift;
200 58         104 my $r = $self->diplomacy_exists($node1, $node2);
201 58 50       112 return if(!$r ); #Should never happen
202 58 100 66     142 return if $r->status eq 'ALLIANCE' || $r->status eq 'INFLUENCE PRESENT';
203 56         101 my $present_status = $r->status;
204 56         141 $r->change_factor($dipl);
205 56         88 my $actual_status = $r->status;
206 56 100       90 my $trend = $dipl > 0 ? 'up' : 'down';
207 56 100       99 if($present_status ne $actual_status)
208             {
209 13         40 my $event_text = "RELATIONS BETWEEN $node1 AND $node2 CHANGED FROM $present_status TO $actual_status";
210 13 100       21 if($reason)
211             {
212 1         3 $event_text = $event_text . " " . $reason;
213             }
214             else
215             {
216 12         24 $reason = "";
217             }
218 13         142 $self->broadcast_event({ code => "relchange",
219             text => $event_text,
220             involved => [$node1, $node2],
221             values => [$trend, $present_status, $actual_status, $reason]},
222             $node1, $node2);
223 13 100       42 if($actual_status eq 'HATE')
224             {
225 4         17 $self->diplomatic_breakdown($node1, $node2);
226             }
227             }
228             else
229             {
230 43         49 my $event_text;
231 43 100       74 if($dipl > 0)
232             {
233 20         65 $event_text = "RELATIONS BETWEEN $node1 AND $node2 ARE BETTER";
234             }
235             else
236             {
237 23         50 $event_text = "RELATIONS BETWEEN $node1 AND $node2 ARE WORSE";
238             }
239 43 100       89 if($reason)
240             {
241 36         72 $event_text = $event_text . " " . $reason;
242             }
243 43         259 $self->broadcast_event({ code => "relchange",
244             text => $event_text,
245             involved => [$node1, $node2],
246             values => [$trend, $actual_status, $actual_status, $reason]},
247             $node1, $node2);
248             }
249             }
250             sub diplomacy_status
251             {
252 62     62 0 61 my $self = shift;
253 62         57 my $n1 = shift;
254 62         47 my $n2 = shift;
255 62         90 my $r = $self->diplomacy_exists($n1, $n2);
256 62         141 return $r->status;
257             }
258              
259             sub diplomatic_breakdown
260             {
261 4     4 0 8 my $self = shift;
262 4         5 my $n1 = shift;
263 4         7 my $n2 = shift;
264 4         14 my $treaty = $self->exists_treaty($n1, $n2);
265 4 50       13 if($treaty)
266             {
267 0         0 $self->delete_treaty($n1, $n2);
268 0         0 $self->broadcast_event({ code => lc($treaty->short_tag) . "treatybroken",
269             text => $treaty->short_tag . " TREATY BETWEEN $n1 AND $n2 BROKEN",
270             involved => [$n1, $n2] },
271             $n1, $n2);
272             }
273 4         13 $self->stop_military_support($self->get_nation($n1), $self->get_nation($n2), 1);
274 4         11 $self->stop_military_support($self->get_nation($n2), $self->get_nation($n1), 1);
275             }
276              
277             sub diplomacy_for_node
278             {
279 177     177 0 141 my $self = shift;
280 177         144 my $node = shift;
281 177         154 my %relations;
282 177         135 foreach my $n (@{$self->nation_names})
  177         455  
283             {
284 841 100       1216 if($n ne $node)
285             {
286 664         848 my $real_r = $self->diplomacy_exists($node, $n);
287 664         1270 $relations{$n} = $real_r->factor;
288             }
289             }
290 177         698 return %relations;;
291             }
292              
293             sub print_diplomacy
294             {
295 0     0 0 0 my $self = shift;
296 0         0 my $n = shift;
297 0   0     0 my $mode = shift || "print";
298 0         0 my $out;
299 0         0 my @outnodes = sort { $a->factor <=> $b->factor} $self->get_diplomatic_relations($n);
  0         0  
300 0         0 return BalanceOfPower::Printer::print($mode, $self, 'print_diplomacy',
301             { nation => $n,
302             relationships => \@outnodes,
303             } );
304              
305             }
306              
307              
308             sub diplomatic_pressure
309             {
310 6     6 0 7 my $self = shift;
311 6         5 my $nation1 = shift;
312 6         7 my $nation2 = shift;
313 6         11 my @friends = $self->get_friends($nation1);
314 6         25 $self->change_diplomacy($nation1, $nation2, DIPLOMATIC_PRESSURE_FACTOR, "DIPLOMATIC PRESSURE OF $nation1 ON $nation2");
315 6         39 $self->broadcast_event({ code => 'pressure',
316             text => "DIPLOMATIC PRESSURE OF $nation1 ON $nation2",
317             involved => [$nation1, $nation2] }, $nation1, $nation2);
318 6         12 for(@friends)
319             {
320 9         11 my $f = $_;
321 9         34 $self->change_diplomacy($f, $nation2, DIPLOMATIC_PRESSURE_FACTOR, "DIPLOMATIC PRESSURE OF $nation1 ON $nation2");
322             }
323             }
324              
325              
326             #Functions to manage relationships as crises
327             sub add_crisis
328             {
329 18     18 0 380 my $self = shift;
330 18         51 my $nation1 = shift;
331 18         23 my $nation2 = shift;
332 18         51 my $rel = $self->diplomacy_exists($nation1, $nation2);
333 18 100       68 if($rel->get_crisis_level == 0)
334             {
335 17         96 $rel->escalate_crisis();
336             }
337             }
338             sub delete_crisis
339             {
340 7     7 0 19 my $self = shift;
341 7         11 my $nation1 = shift;
342 7         10 my $nation2 = shift;
343 7         18 my $rel = $self->diplomacy_exists($nation1, $nation2);
344 7         27 $rel->crisis_level(0);
345             }
346             sub crisis_exists
347             {
348 130     130 0 121 my $self = shift;
349 130   50     221 my $nation1 = shift || "";
350 130   50     196 my $nation2 = shift || "";
351 130         212 my $rel = $self->diplomacy_exists($nation1, $nation2);
352 130 50       212 if(! $rel)
353             {
354 0         0 say "ERROR: no diplomacy between $nation1, $nation2";
355 0         0 return undef;
356             }
357 130 100       258 if($rel->get_crisis_level > 0)
358             {
359 41         114 return $rel;
360             }
361             else
362             {
363 89         267 return undef;
364             }
365             }
366             sub get_crises
367             {
368 29     29 0 41 my $self = shift;
369 29         33 my $nation = shift;
370 29         77 my @crises = $self->get_diplomatic_relations($nation);
371 29         44 @crises = grep { $_->get_crisis_level > 0 } @crises;
  116         174  
372 29         66 return @crises;
373             }
374             sub get_all_crises
375             {
376 91     91 0 93 my $self = shift;
377 91         587 my @rels = $self->diplomatic_relations->all();
378 91         155 return grep { $_->is_crisis() } @rels;
  679         888  
379             }
380             sub reset_crises
381             {
382 5     5 0 8 my $self = shift;
383 5         8 my $nation = shift;
384 5         19 my @rels = $self->get_diplomatic_relations($nation);
385 5         13 for(@rels)
386             {
387 9         18 $_->crisis_level(0);
388             }
389             }
390              
391             #Functions to manage treaties
392             sub create_treaty
393             {
394 15     15 0 19 my $self = shift;
395 15         18 my $nation1 = shift;
396 15         14 my $nation2 = shift;
397 15         15 my $type = shift;
398 15         388 $self->add_treaty(BalanceOfPower::Relations::Treaty->new(
399             node1 => $nation1,
400             node2 => $nation2,
401             type => $type ));
402             }
403             sub exists_treaty_by_type
404             {
405 111     111 0 96 my $self = shift;
406 111         92 my $nation1 = shift;
407 111         78 my $nation2 = shift;
408 111         90 my $type = shift;
409 111         244 my $rel = $self->exists_treaty($nation1, $nation2);
410 111 100 66     348 if( $rel && ($rel->type eq $type || $rel->type eq 'alliance')) #Alliance means both treaties are active
      66        
411             {
412 24         75 return $rel;
413             }
414             else
415             {
416 87         179 return undef;
417             }
418             }
419             sub get_treaties_for_nation_by_type
420             {
421 23     23 0 20 my $self = shift;
422 23         27 my $nation = shift;
423 23         20 my $type = shift;
424 23         52 my @treaties = $self->get_treaties_for_nation($nation);
425 23         44 return grep { $_->type eq $type } @treaties;
  13         45  
426             }
427              
428             #Functions to manage alliances
429             sub add_alliance
430             {
431 7     7 0 15 my $self = shift;
432 7         9 my $nation1 = shift;
433 7         7 my $nation2 = shift;
434 7         23 $self->create_treaty($nation1, $nation2, 'alliance');
435 7         33 $self->set_diplomacy($nation1, $nation2, ALLIANCE_FRIENDSHIP_FACTOR);
436             }
437             sub print_allies
438             {
439 0     0 0 0 my $self = shift;
440 0         0 my $nation = shift;
441 0         0 my $mode = shift;
442 0         0 return $self->print_treaties($nation, "ALLIANCES", 'alliance', $mode);
443             }
444             sub print_treaties
445             {
446 0     0 0 0 my $self = shift;
447 0         0 my $nation = shift;
448 0   0     0 my $title = shift || "TREATIES";
449 0   0     0 my $treaty = shift || undef;
450 0   0     0 my $mode = shift || 'print';
451 0         0 my @treaties = $self->treaties->all();
452 0         0 my @to_print;
453 0         0 for(@treaties)
454             {
455 0 0 0     0 if((($treaty && $_->type eq $treaty) || ! $treaty) &&
      0        
      0        
456             (($nation && $_->involve($nation)) || ! $nation))
457             {
458 0         0 push @to_print, $_;
459             }
460             }
461 0         0 return BalanceOfPower::Printer::print($mode, $self, 'print_treaties',
462             { title => $title,
463             treaties => \@to_print,
464             } );
465             }
466              
467             sub exists_alliance
468             {
469 0     0 0 0 my $self = shift;
470 0         0 my $nation1 = shift;
471 0         0 my $nation2 = shift;
472 0         0 return $self->exists_treaty_by_type($nation1, $nation2, 'alliance');
473             }
474              
475             sub get_allies
476             {
477 23     23 0 28 my $self = shift;
478 23         24 my $nation = shift;
479 23         53 return $self->get_treaties_for_nation_by_type($nation, 'alliance');
480             }
481              
482              
483             1;