File Coverage

lib/BalanceOfPower/Role/Diplomat.pm
Criterion Covered Total %
statement 225 258 87.2
branch 41 50 82.0
condition 18 42 42.8
subroutine 35 39 89.7
pod 0 30 0.0
total 319 419 76.1


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