File Coverage

lib/BalanceOfPower/Role/Diplomat.pm
Criterion Covered Total %
statement 225 258 87.2
branch 42 50 84.0
condition 19 42 45.2
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.400110';
3 13     13   4711 use strict;
  13         19  
  13         300  
4 13     13   166 use v5.10;
  13         31  
5 13     13   38 use Moo::Role;
  13         13  
  13         64  
6              
7 13     13   2569 use BalanceOfPower::Constants ':all';
  13         15  
  13         5326  
8              
9 13     13   3647 use BalanceOfPower::Relations::Friendship;
  13         24  
  13         334  
10 13     13   3622 use BalanceOfPower::Relations::Treaty;
  13         26  
  13         301  
11 13     13   59 use BalanceOfPower::Relations::RelPack;
  13         13  
  13         240  
12 13     13   41 use BalanceOfPower::Utils qw( as_main_title as_html_box br);
  13         15  
  13         23980  
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 28 my $self = shift;
41 16         22 my @nations = @{$self->nation_names};
  16         72  
42 16         35 foreach my $n1 (@nations)
43             {
44 72         86 foreach my $n2 (@nations)
45             {
46 354 100 100     2479 if($n1 ne $n2 && ! $self->_diplomacy_exists($n1, $n2))
47             {
48 141         135 my $minimum_friendship = 0;
49 141         244 my $rel = BalanceOfPower::Relations::Friendship->new( node1 => $n1,
50             node2 => $n2,
51             factor => $self->calculate_random_friendship($n1, $n2));
52 141         11127 $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 129 my $self = shift;
62 141         96 my $nation1 = shift;
63 141         93 my $nation2 = shift;
64 141         297 my $distance = $self->distance($nation1, $nation2);
65 141 100       239 $distance = 3 if $distance > 3;
66              
67 141         91 my $middle = 50;
68              
69 141         150 my $polar_factor = ( 4 - $distance ) * 5;
70 141         132 my $random_floor = ( ( 3 - $distance ) * 5 ) + 25;
71              
72 141         2151 my $side = $self->random(0, 1, "Side for friendship between $nation1 and $nation2");
73 141 100       270 $side = $side == 0 ? -1 : 1;
74 141         2715 my $random_factor = $self->random(0, $random_floor, "Random factor for friendship between $nation1 and $nation2 [floor: $random_floor]");
75              
76 141         214 my $friendship = $middle + ( $side * ( $polar_factor + $random_factor ) );
77 141         2781 return $friendship;
78             }
79              
80              
81             sub init_random_alliances
82             {
83 1     1 0 3 my $self = shift;
84 1         3 my @nations = @{$self->nation_names};
  1         8  
85 1         9 for(my $i = 0; $i < STARTING_ALLIANCES; $i++)
86             {
87 7         142 my $n1 = $nations[$self->random(0, $#nations, "Nation1 for random alliance")];
88 7         137 my $n2 = $nations[$self->random(0, $#nations, "Nation2 for random alliance")];
89 7 100       20 if($n1 ne $n2)
90             {
91 4         11 $self->add_alliance($n1, $n2);
92 4         21 $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         2 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 1027     1027 0 2438 my $self = shift;
110 1027         756 my $n1 = shift;
111 1027         675 my $n2 = shift;
112 1027         1666 my $r = $self->_diplomacy_exists($n1, $n2);
113 1027 50       1533 if(! defined $r)
114             {
115 0         0 say "ERROR! No diplomacy between $n1, $n2";
116             }
117 1027         1004 return $r;
118             }
119              
120             sub get_hates
121             {
122 49     49 0 49 my $self = shift;
123 49         44 my $nation = shift;
124 49     377   205 my @hates = $self->diplomatic_relations->query( sub { my $rel = shift; return $rel->status eq 'HATE' });
  377         248  
  377         427  
125 49         109 my @out = ();
126 49         57 foreach my $r (@hates)
127             {
128 121 100 100     447 if(($nation && $r->has_node($nation)) || (! $nation))
      100        
129             {
130 115 100 66     241 if(! $self->is_under_influence($r->node1) && ! $self->is_under_influence($r->node2))
131             {
132 109         140 push @out, $r;
133             }
134             }
135             }
136 49         100 return @out;
137             }
138             sub get_nations_with_status
139             {
140 19     19 0 16 my $self = shift;
141 19         17 my $nation = shift;
142 19         18 my $status = shift;
143 19         21 my @st_array = @{$status};
  19         26  
144 19         43 my @relations = $self->get_diplomatic_relations($nation);
145 19         25 my @out = ();
146 19         26 for(@relations)
147             {
148 76         56 my $r = $_;
149 76 100       60 if(grep{ $_ eq $r->status } @st_array)
  188         237  
150             {
151 29         61 push @out, $r->destination($nation);
152             }
153             }
154 19         262 return @out;
155             }
156              
157             sub get_friends
158             {
159 14     14 0 14 my $self = shift;
160 14         17 my $nation = shift;
161 14         41 return $self->get_nations_with_status($nation, ['FRIENDSHIP', 'ALLIANCE', 'INFLUENCE PRESENT']);
162             }
163             sub set_diplomacy
164             {
165 32     32 0 61 my $self = shift;
166 32         31 my $node1 = shift;
167 32         28 my $node2 = shift;
168 32         25 my $new_factor = shift;
169 32         47 my $r = $self->diplomacy_exists($node1, $node2);
170 32 50       53 return undef if(!$r ); #Should never happen
171 32         47 $r->factor($new_factor);
172 32         44 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         2 my $nation_to = shift;
179 3         7 my @relations = $self->get_diplomatic_relations($nation_from);
180 3         5 for(@relations)
181             {
182 9         7 my $r = $_;
183 9         18 my $other = $r->destination($nation_from);
184 9 100       15 if($other ne $nation_to)
185             {
186 6         12 $self->set_diplomacy($nation_to, $other, $r->factor);
187             }
188             }
189              
190              
191             }
192              
193             sub change_diplomacy
194             {
195 51     51 0 106 my $self = shift;
196 51         53 my $node1 = shift;
197 51         47 my $node2 = shift;
198 51         46 my $dipl = shift;
199 51         41 my $reason = shift;
200 51         84 my $r = $self->diplomacy_exists($node1, $node2);
201 51 50       95 return if(!$r ); #Should never happen
202 51 100 66     116 return if $r->status eq 'ALLIANCE' || $r->status eq 'INFLUENCE PRESENT';
203 48         93 my $present_status = $r->status;
204 48         113 $r->change_factor($dipl);
205 48         67 my $actual_status = $r->status;
206 48 100       73 my $trend = $dipl > 0 ? 'up' : 'down';
207 48 100       73 if($present_status ne $actual_status)
208             {
209 14         39 my $event_text = "RELATIONS BETWEEN $node1 AND $node2 CHANGED FROM $present_status TO $actual_status";
210 14 50       17 if($reason)
211             {
212 0         0 $event_text = $event_text . " " . $reason;
213             }
214             else
215             {
216 14         16 $reason = "";
217             }
218 14         68 $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 14 100       43 if($actual_status eq 'HATE')
224             {
225 3         8 $self->diplomatic_breakdown($node1, $node2);
226             }
227             }
228             else
229             {
230 34         32 my $event_text;
231 34 100       52 if($dipl > 0)
232             {
233 19         53 $event_text = "RELATIONS BETWEEN $node1 AND $node2 ARE BETTER";
234             }
235             else
236             {
237 15         43 $event_text = "RELATIONS BETWEEN $node1 AND $node2 ARE WORSE";
238             }
239 34 100       64 if($reason)
240             {
241 29         64 $event_text = $event_text . " " . $reason;
242             }
243 34         194 $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 57     57 0 44 my $self = shift;
253 57         45 my $n1 = shift;
254 57         44 my $n2 = shift;
255 57         73 my $r = $self->diplomacy_exists($n1, $n2);
256 57         108 return $r->status;
257             }
258              
259             sub diplomatic_breakdown
260             {
261 3     3 0 2 my $self = shift;
262 3         4 my $n1 = shift;
263 3         3 my $n2 = shift;
264 3         7 my $treaty = $self->exists_treaty($n1, $n2);
265 3 50       7 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 3         7 $self->stop_military_support($self->get_nation($n1), $self->get_nation($n2), 1);
274 3         4 $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 146 my $self = shift;
280 177         138 my $node = shift;
281 177         139 my %relations;
282 177         133 foreach my $n (@{$self->nation_names})
  177         317  
283             {
284 841 100       1164 if($n ne $node)
285             {
286 664         747 my $real_r = $self->diplomacy_exists($node, $n);
287 664         1113 $relations{$n} = $real_r->factor;
288             }
289             }
290 177         674 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 4     4 0 4 my $self = shift;
311 4         4 my $nation1 = shift;
312 4         7 my $nation2 = shift;
313 4         10 my @friends = $self->get_friends($nation1);
314 4         20 $self->change_diplomacy($nation1, $nation2, DIPLOMATIC_PRESSURE_FACTOR, "DIPLOMATIC PRESSURE OF $nation1 ON $nation2");
315 4         33 $self->broadcast_event({ code => 'pressure',
316             text => "DIPLOMATIC PRESSURE OF $nation1 ON $nation2",
317             involved => [$nation1, $nation2] }, $nation1, $nation2);
318 4         13 for(@friends)
319             {
320 2         3 my $f = $_;
321 2         7 $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 17     17 0 350 my $self = shift;
330 17         22 my $nation1 = shift;
331 17         20 my $nation2 = shift;
332 17         34 my $rel = $self->diplomacy_exists($nation1, $nation2);
333 17 100       51 if($rel->get_crisis_level == 0)
334             {
335 15         46 $rel->escalate_crisis();
336             }
337             }
338             sub delete_crisis
339             {
340 11     11 0 24 my $self = shift;
341 11         15 my $nation1 = shift;
342 11         9 my $nation2 = shift;
343 11         23 my $rel = $self->diplomacy_exists($nation1, $nation2);
344 11         32 $rel->crisis_level(0);
345             }
346             sub crisis_exists
347             {
348 180     180 0 168 my $self = shift;
349 180   50     261 my $nation1 = shift || "";
350 180   50     246 my $nation2 = shift || "";
351 180         242 my $rel = $self->diplomacy_exists($nation1, $nation2);
352 180 50       257 if(! $rel)
353             {
354 0         0 say "ERROR: no diplomacy between $nation1, $nation2";
355 0         0 return undef;
356             }
357 180 100       312 if($rel->get_crisis_level > 0)
358             {
359 64         166 return $rel;
360             }
361             else
362             {
363 116         301 return undef;
364             }
365             }
366             sub get_crises
367             {
368 31     31 0 33 my $self = shift;
369 31         29 my $nation = shift;
370 31         68 my @crises = $self->get_diplomatic_relations($nation);
371 31         42 @crises = grep { $_->get_crisis_level > 0 } @crises;
  124         174  
372 31         60 return @crises;
373             }
374             sub get_all_crises
375             {
376 91     91 0 80 my $self = shift;
377 91         255 my @rels = $self->diplomatic_relations->all();
378 91         131 return grep { $_->is_crisis() } @rels;
  679         849  
379             }
380             sub reset_crises
381             {
382 5     5 0 8 my $self = shift;
383 5         5 my $nation = shift;
384 5         14 my @rels = $self->get_diplomatic_relations($nation);
385 5         12 for(@rels)
386             {
387 9         16 $_->crisis_level(0);
388             }
389             }
390              
391             #Functions to manage treaties
392             sub create_treaty
393             {
394 13     13 0 15 my $self = shift;
395 13         12 my $nation1 = shift;
396 13         13 my $nation2 = shift;
397 13         12 my $type = shift;
398 13         218 $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 103     103 0 95 my $self = shift;
406 103         76 my $nation1 = shift;
407 103         75 my $nation2 = shift;
408 103         79 my $type = shift;
409 103         221 my $rel = $self->exists_treaty($nation1, $nation2);
410 103 100 66     276 if( $rel && ($rel->type eq $type || $rel->type eq 'alliance')) #Alliance means both treaties are active
      66        
411             {
412 14         42 return $rel;
413             }
414             else
415             {
416 89         182 return undef;
417             }
418             }
419             sub get_treaties_for_nation_by_type
420             {
421 22     22 0 20 my $self = shift;
422 22         16 my $nation = shift;
423 22         23 my $type = shift;
424 22         51 my @treaties = $self->get_treaties_for_nation($nation);
425 22         42 return grep { $_->type eq $type } @treaties;
  10         39  
426             }
427              
428             #Functions to manage alliances
429             sub add_alliance
430             {
431 6     6 0 11 my $self = shift;
432 6         8 my $nation1 = shift;
433 6         5 my $nation2 = shift;
434 6         15 $self->create_treaty($nation1, $nation2, 'alliance');
435 6         14 $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 22     22 0 20 my $self = shift;
478 22         24 my $nation = shift;
479 22         41 return $self->get_treaties_for_nation_by_type($nation, 'alliance');
480             }
481              
482              
483             1;