license changed GPL2 -> AGPL3
[aymargeddon/current.git] / src / Aymargeddon.pm
1 ##########################################################################
2 #
3 #   Copyright (c) 2003-2012 Aymargeddon Development Team
4 #
5 #   This file is part of "Last days of Aymargeddon" - a massive multi player
6 #   onine game of strategy      
7 #   
8 #        This program is free software: you can redistribute it and/or modify
9 #        it under the terms of the GNU Affero General Public License as
10 #        published by the Free Software Foundation, either version 3 of the
11 #        License, or (at your option) any later version.
12 #    
13 #        This program is distributed in the hope that it will be useful,
14 #        but WITHOUT ANY WARRANTY; without even the implied warranty of
15 #        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16 #
17 #    See the GNU Affero General Public License for more details.
18 #    
19 #    You should have received a copy of the GNU Affero General Public License
20 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 #    
22 ###########################################################################
23 #
24
25 # generell Aymargeddon-specific functions
26 #
27
28
29 # TODO: move color calculation from map.epl in this module
30
31
32 use strict;
33 use FROGS::Game;
34 use FROGS::HexTorus;
35
36 package Aymargeddon;
37 use Data::Dumper;
38 @Aymargeddon::ISA = qw(Game);
39
40 sub new{
41   my ($class,$game,$user,$db,$lang) = @_;
42
43   my $self = Game->new($game,$user,$db);
44
45   bless($self,$class);
46 }
47
48 sub get_map{
49   my $self = shift;
50
51   unless (exists $self->{-map}){
52     $self->{-map} = $self->read_map("TERRAIN,HOME,OCCUPANT,TEMPLE,PLAGUE,HOME");
53   }
54   return $self->{-map};
55 }
56
57 sub get_size{
58   my $self = shift;
59
60   unless ($self->{-size}){
61     my @size = $self->{-db}->read_game($self->{-game},'SIZE');
62     $self->{-size} = $size[0] ? $size[0] : die "could not find size";
63   }
64   return $self->{-size};
65 }
66
67 sub get_relation{
68   my ($self, $other) = @_;
69
70   unless ($self->{-rel}){
71     # print "bindrin\n";
72     #    $self->{-rel} = $self->read_player_relations($self->{-game}, $self->{-user});
73     $self->{-rel} = $self->read_player_relations($self->{-user});
74   }
75   #  print Dumper $self->{-rel};
76   my $stat = $self->{-rel}->{$other}->{'STATUS'};
77   return $stat ? $stat : 'NEUTRAL';
78 }
79
80 # FRIEND, ALLIED => FRIEND ; FOE, BETRAY => FOE
81 sub simplyfied_single_relation{
82   my ($self,$me,$you) = @_;
83   my $rel = $self->read_single_relation($me,$you);
84
85   return 'FRIEND' if Util::is_in($rel,'FRIEND','ALLIED');
86   return 'FOE' if Util::is_in($rel,'FOE','BETRAY');
87   return 'NEUTRAL';
88 }
89
90
91 sub god_fight{
92   my ($self,$loc_str) = @_;
93   my @ret = $self->read_field('GOD_ATTACKER',$loc_str);
94   return $ret[0] ? 1 : 0;
95 }
96
97 sub earthling_fight{
98   my ($self,$loc_str) = @_;
99   my @ret = $self->read_field('ATTACKER',$loc_str);
100   return $ret[0] ? 1 : 0;
101 }
102
103 sub arc_present{
104   my ($self,$loc_str) = @_;
105   my $arks_ref = $self->read_mobile('ID','ARK',$loc_str,1);
106   my @arks = @$arks_ref;
107   return $#arks+1;
108 }
109
110 sub avatar_present{
111   my ($self,$loc_str) = @_;
112   return $self->read_mobile('OWNER','AVATAR',$loc_str,1);
113 }
114
115 sub mobiles_available{
116   my ($self,$loc_str,$avail) = @_;
117   $avail = 1 unless defined $avail;
118   my $fields = 'ID, TYPE, OWNER, ADORING, COUNT, STATUS, MOVE_WITH';
119   return $self->read_mobile($fields,'',$loc_str, $avail);
120 }
121
122
123 #
124 # sight stuff
125 #
126 # TODO: maybe the generell sight-stuff could go to Game.pm
127
128 # ATTENTION: this function generates the whole sight-matrix, if necessary.
129 # it could be very time-consuming
130 sub player_see_field{
131   my ($self,$loc) = @_;
132
133   my @players = $self->get_all_roles();
134
135   my @ret = ();
136   for my $player (@players){
137     # ($player) = @$player;
138     my $players_aym = new Aymargeddon($self->{-game},$player,
139                                       $self->{-db},$self->{-lang});
140     if ($players_aym->sight_of_field($loc)){
141       push @ret, $player;
142       # print "$player sees $loc.\n";
143     }
144   }
145   return @ret;
146 }
147
148 # this two functions reads sight directly from database
149 sub sight_of_field{
150   my ($self,$loc) = @_;
151
152   return 1 if $self->role($self->{-user}) eq 'OBSERVER'; # admin sees all
153
154   my $player = $self->{-user};
155   my $map = HexTorus->new($self->get_size());
156   return 1 if $self->sight_of_field_of_player($loc,$player,$map);
157
158   # read all players, which give us informations
159   my $rel = $self->reverse_player_relations();
160   for my $friend (keys %$rel){
161     my $status = $rel->{$friend}->{'STATUS'};
162     if($status eq 'ALLIED' or $status eq 'BETRAY'){
163       if($self->is_earthling($friend) or $::conf->{-GODS_SHOW_EARTHLINGS}){
164         return 1 if $self->sight_of_field_of_player($loc,$friend,$map);
165       }
166     }
167   }
168   return 0;
169 }
170
171 sub sight_of_field_of_player{
172   my ($self,$loc,$player,$map) = @_;
173
174   my ($ter,$own,$occ,$temple) = $self->read_field('TERRAIN,HOME,OCCUPANT,TEMPLE',$loc);
175
176   return 1 if($own == $player or $occ == $player);
177   return 1 if @{$self->own_in_mobile($loc,$player)};
178
179   my $location = Location->from_string($loc);
180   my $dist = 2;
181   my @neighbours = $map->distant_neighbours($location,$dist);
182   # Util::log("neighbours: ",-2);
183   for my $l (@neighbours){
184     my $d = $map->distance($location,$l);
185     my $locstring = $l->to_string();
186     # Util::log(" $locstring ($d),",-2);
187
188     my ($neighbour_ter,$neighbour_home) = $self->read_field('TERRAIN,HOME',$locstring);
189     next if ($d > 1 && $neighbour_ter ne 'MOUNTAIN');
190     return 1 if $neighbour_home == $player;
191     return 1 if $neighbour_ter eq 'MOUNTAIN' and
192       $neighbour_home <= 0 and $self->is_god($player);
193     return 1 if @{$self->own_in_mobile($locstring,$player)};
194   }
195   # Util::log("",2);
196   return 0;
197 }
198
199 # this function generates the whole sight if called
200 sub sight{
201   my ($self,$loc_str) = @_;
202
203   return 1 if $self->role($self->{-user}) eq 'OBSERVER'; # admin sees all
204
205   $self->generate_sight() unless $self->{-sight_map};
206
207   return 1 if $self->{-sight_map}->{$loc_str};
208 }
209
210 # overloads the function from Game-Class
211 sub seen_locations{
212   my $self = shift;
213
214   # TODO-PERFORMANCE: make map a self-constructing member of class (like size)
215   my $map = HexTorus->new($self->get_size());
216
217   my @ret = ();
218   for my $loc ($map->get_all()){
219     my $ls = $loc->to_string();
220     push @ret, $ls if $self->sight($ls);
221   }
222   return @ret;
223 }
224
225 sub generate_sight{
226   my ($self) = @_;
227
228   delete $self->{-sight_map};
229
230   my $rel = $self->reverse_player_relations();
231
232   $self->sight_of_player($self->{-user});
233   for my $player (keys %$rel){
234     my $status = $rel->{$player}->{'STATUS'};
235     if($status eq 'ALLIED' or $status eq 'BETRAY'){
236       if($self->is_earthling($player) or $::conf->{-GODS_SHOW_EARTHLINGS}){
237         $self->sight_of_player($player);
238       }
239     }
240   }
241
242   # print Dumper $self->{-sight_map};
243 }
244
245 sub sight_of_player{
246   my ($self,$player) = @_;
247
248   my $map = HexTorus->new($self->get_size());
249
250   my $selfmap = $self->get_map();
251
252   for my $row (@$selfmap){
253     my ($loc,$ter,$own,$occ,$temple,$plague,$home) = @$row;
254
255     if($own == $player or $occ == $player
256        or @{$self->own_in_mobile($loc,$player)}
257        or ($self->is_god($player) and $ter eq 'MOUNTAIN' and $home <= 0)){
258       $self->{-sight_map}->{$loc} = 1;
259       my $location = Location->from_string($loc);
260       my $dist = 1;
261       $dist = 2 if $ter eq 'MOUNTAIN';
262       my @neighbours = $map->distant_neighbours($location,$dist);
263       for my $l (@neighbours){
264         $self->{-sight_map}->{$l->to_string()} = 1;
265       }
266     }
267   }
268 }
269
270 sub is_coast{
271   my ($self,$loc_str) = @_;
272   my ($ter) = $self->read_field('TERRAIN',$loc_str);
273   return 0 if($ter ne 'PLAIN' and $ter ne 'CITY' and $ter ne 'MOUNTAIN');
274
275   my $map = HexTorus->new($self->get_size());
276   my @neighbours = $map->neighbours(Location->from_string($loc_str));
277   for my $loc (@neighbours){
278     ($ter) = $self->read_field('TERRAIN',$loc->to_string());
279     return 1 if($ter eq 'ISLE' or $ter eq 'WATER');
280   }
281   return 0;
282 }
283
284 sub is_arrival{
285   my ($self, $loc_str) = @_;
286
287   return 1 if $loc_str eq $self->incarnation_place();
288
289   return 0;
290 }
291
292 sub is_god{
293   my ($self,$player) = @_;
294   $player = $self->{-user} unless defined $player;
295   return ($self->role($player) eq 'GOD');
296 }
297
298 sub is_earthling{
299   my ($self,$player) = @_;
300   $player = $self->{-user} unless defined $player;
301   return ($self->role($player) eq 'EARTHLING');
302 }
303
304 sub gods{
305   my ($self) = @_;
306   return $self->get_all_roles('GOD');
307 }
308
309 sub earthlings{
310   my ($self) = @_;
311   return $self->get_all_roles('EARTHLING');
312 }
313
314 sub get_mana{
315   my ($self,$player) = @_;
316   $player = $self->{-user} unless defined $player;
317   return 0 if $player < 1;
318
319   my $stmt = "SELECT MANA from GOD where GAME=$self->{-game} AND PLAYER=$player";
320   my ($mana) = $self->{-db}->single_select($stmt);
321   return $mana ? $mana : 0;
322 }
323
324 sub gender{
325   my ($self,$player) = @_;
326   return 0 if $player < 1;
327   my @gen = $self->read_role($player, 'GENDER');
328   return $gen[0];
329 }
330
331
332 sub field_string{
333   my ($self, $type) = @_;
334   return $self->{-db}->loc('FIELD_'.$type);
335 }
336
337 sub relation_string{
338   my ($self, $other) = @_;
339   my $rel = $self->get_relation($other);
340   # print Dumper $rel;
341   $rel = 'NEUTRAL' if not $rel;
342   return $self->{-db}->loc('STAT_'.$rel);
343 }
344
345 sub mobile_string{
346   my ($self, $type, $num) = @_;
347   my $tag = 'MOBILE_'.$type;
348   $tag .= '_PL' if $num != 1;
349   return $self->{-db}->loc($tag);
350 }
351
352 sub mobile_extended_string{
353   # count + localised type + adored god if any
354   my ($self, $type, $num, $adoring) = @_;
355   my $out = $num.' '.$self->mobile_string($type, $num);
356   if($type eq 'PRIEST' or $type eq 'PROPHET' or $type eq 'HERO'){
357     $out .= ' '.$self->{-db}->loc('ADJ_ADORING').' '.$self->charname($adoring);
358   }
359   return $out;
360 }
361
362 sub role_string{
363   my ($self, $player) = @_;
364   my $role = $self->role($player);
365   $role = 'UNDEFINED' unless defined $role;
366   my $tag = "ROLE_$role";
367   return $self->{-db}->loc($tag);
368 }
369
370
371 sub new_role{
372   my($self,$role,$name,$gender,$desc) = @_;
373   $desc = 'none' unless defined $desc;
374   my $db = $self->{-db};
375
376 #  my ($qname, $qgender, $qdesc, $qrole)
377 #    = $db->quote_all($name, $gender, $desc, $role);
378
379   my $cond = 'GAME='.$self->{-game}." AND NICKNAME=$name";
380   return 0 if @{$db->select_array('ROLE','GAME',$cond)}; # error: dublicate name
381
382   my @homes; # all possible homes for this role
383   if($role ne 'OBSERVER'){
384     @homes = $self->open_homes($role);
385     return 0 if $#homes<0; # error: no home free
386   }
387
388   # dont allow names only in uppercase
389   return 0 if $name =~ /^\s*[A-Z_]{3,}\s*$/;
390
391   # write in ROLE
392   $db->insert_hash('ROLE',{'GAME' => $self->{-game},
393                            'PLAYER' => $self->{-user},
394                            'NICKNAME' => $name,
395                            'ROLE' => $role,
396                            'GENDER' => $gender,
397                            'DESCRIPTION' => $desc}
398                             );
399   if($role eq 'OBSERVER'){
400     $db->commit();
401     return 1;
402   }
403
404   # choose home:
405   my $home = $homes[rand($#homes + 1)]->[0];
406
407   if($role eq 'GOD'){
408     # read actual default manapool from GAME
409     my ($mana,$ts) = $db->read_game($self->{-game},'START_MANA,TEMPLE_SIZE');
410     $mana += $ts * 2;
411
412     # write GAME, PLAYER, MANA in GOD
413     $db->insert_hash('GOD',{'GAME' => $self->{-game},
414                             'PLAYER' => $self->{-user},
415                             'MANA' => $mana});
416
417     # choose second and third home
418     #     my $home2 = $home;
419     #     my $home3 = $home;
420     #     if($#homes > 0){
421     #       while($home2 eq $home or $home3 eq $home or $home2 eq $home3){
422     #   $home2 = $homes[rand($#homes + 1)]->[0];
423     #   $home3 = $homes[rand($#homes + 1)]->[0];
424     #       }
425     #     }
426
427     #     # change OWNER in MAP where LOCATION=$home or LOCATION=$home2
428     #     #   ($home,$home2) = $db->quote_all($home,$home2);
429     #     $db->update_hash('MAP',
430     #                "GAME=$self->{-game} AND".
431     #                " (LOCATION=$home OR LOCATION=$home2 OR LOCATION=$home3)",
432     #                {'HOME' => $self->{-user}});
433
434   }else{ # eartling
435     # write GAME, PLAYER in EARTHLING
436     $db->insert_hash('EARTHLING',{'GAME' => $self->{-game},
437                                   'PLAYER' => $self->{-user}});
438
439     # change OCCUPANT, OWNER in MAP where LOCATION=$home
440     #    ($home) = $db->quote_all($home);
441     $db->update_hash('MAP',
442                      "GAME=$self->{-game} AND LOCATION=$home",
443                      {'HOME' => $self->{-user},
444                       'OCCUPANT' => $self->{-user}});
445
446     # change PLAYER of WARRIORS OR PRIESTs in MOBILE where LOCATION=$home
447     $db->update_hash('MOBILE',
448                      "GAME=$self->{-game} AND LOCATION=$home AND OWNER=-1",
449                      {'OWNER' => $self->{-user}});
450
451     # give additional start-warriors
452     my $warriors = $db->select_array('MOBILE',
453                                      'ID,COUNT',
454                                      "GAME=$self->{-game} AND LOCATION=$home ".
455                                      "AND OWNER=$self->{-user} AND TYPE=WARRIOR");
456     my @w = @$warriors;
457     if($#w > -1){
458       $db->update_hash('MOBILE',
459                        "ID=$w[0]->[0]",
460                        {'COUNT' => "COUNT + $::conf->{-START_WARRIORS}"},
461                        'noquote');
462     }else{
463       $db->insert_hash('MOBILE',
464                        {'ID' => $db->find_first_free('MOBILE','ID'),
465                         'GAME' => $self->{-game},
466                         'LOCATION' => $home,
467                         'TYPE' => 'WARRIOR',
468                         'COUNT' => $::conf->{-START_WARRIORS},
469                         'OWNER' => $self->{-user},
470                         'AVAILABLE' => 'Y'});
471     }
472
473     # modify PRODUCE Command
474     $db->update_hash('COMMAND',
475                      "GAME=$self->{-game} AND COMMAND=PRODUCE ".
476                      "AND LOCATION=$home",
477                      # TODO: open question: is this redundant information?
478                      {'PLAYER' => $self->{-user},
479                       'ARGUMENTS' => "ROLE=$self->{-user}"});
480
481   }
482
483   # TODO: write MESSAGE to all members of this game: new player with role!
484
485
486   $db->commit();
487   return 1;
488 }
489
490 sub startfield{
491   my ($self) = @_;
492
493   my $cond = "GAME=$self->{-game} AND ";
494   if($self->role($self->{-user}) eq 'OBSERVER'){
495     $cond .= 'TERRAIN='.$self->{-db}->quote('AYMARGEDDON');
496   }else{
497     $cond .= "HOME=$self->{-user}";
498   }
499   # TODO: what happens if both mountains are flooded?
500   return $self->{-db}->select_array('MAP','LOCATION',$cond)->[0]->[0];
501 }
502
503
504 sub open_homes{
505   my ($self,$role) = @_;
506   my $terrain = ($role eq 'GOD') ? 'MOUNTAIN' : 'CITY';
507   # ($terrain) = $self->{-db}->quote_all($terrain);
508   my $cond = 'GAME='.$self->{-game}." AND HOME=-1 AND TERRAIN=$terrain";
509   return @{$self->{-db}->select_array('MAP','LOCATION',$cond)};
510 }
511
512 sub is_open{
513   my ($self,$terrain) = @_;
514
515   my $cond = "GAME=$self->{-game} AND HOME=-1";
516   if($terrain){
517     $terrain = $self->{-db}->quote($terrain);
518     $cond .= "AND TERRAIN=$terrain";
519   }
520   my $unused = $self->{-db}->select_array('MAP','LOCATION','',$cond);
521   my @arr = @$unused;
522
523   return $#arr+1;
524 }
525
526 # TODO performance: we can do this whole function in one sophisticated SQL-statement.
527 sub incarnation_place{
528   my ($self,$player) = @_;
529   $player = $self->{-user} unless defined $player;
530
531   my $temples = $self->{-db}->select_array('MAP','LOCATION',
532                                            "TEMPLE='Y' AND HOME=$player");
533
534   my $place;
535   my $max_priests = 0;
536   for my $temple (@$temples){
537     my $loc = $temple->[0];
538     Util::log("check for $loc...",1);
539     # my ($qloc,$type,$yes) = $self->{-db}->quote_all($loc,'PRIEST','Y');
540     my $priests = $self->{-db}->single_hash_select('MOBILE',
541                                                    "ADORING=$player AND ".
542                                                    "LOCATION=$loc AND ".
543                                                    "TYPE=PRIEST AND ".
544                                                    "AVAILABLE=Y AND ".
545                                                    "GAME=$self->{-game}");
546
547     if(defined $priests and $priests->{'COUNT'} > $max_priests){
548       $place = $loc;
549       $max_priests = $priests->{'COUNT'};
550     }
551   }
552   return $place;
553 }
554
555 sub read_fortune{
556   my $self = shift;
557
558   my ($fortune) = $self->{-db}->read_game($self->{-game},
559                                           'FORTUNE');
560   return $fortune;
561 }
562
563 # returns also empty neighbours, but no attacked neighbours
564 sub own_neighbours{
565   my ($self,$loc,$player) = @_;
566   $player = $self->{player} unless defined $player;
567
568   # print "own_neighbours($loc,$player)\n";
569   my $map = HexTorus->new($self->get_size());
570   my $location = Location->from_string($loc);
571   my @neighbours = $map->neighbours($location);
572   my @own_neighbours;
573   for my $n (@neighbours){
574     my $n_string = $n->to_string();
575     my ($occ,$att,$terrain) = $self->read_field('OCCUPANT,ATTACKER,TERRAIN',$n_string);
576     Util::log("$n_string occupied by $occ, attacked by $att",2);
577     next if $att;
578     next if $::conf->{-FIGHTS_WITHOUT_OWNER}->{$terrain} and not $occ;
579     push @own_neighbours, $n_string if $occ == $player or $occ <= 0;
580   }
581   # print Dumper \@own_neighbours;
582   Util::log("own_neighbours($loc,$player): @own_neighbours",2);
583   return @own_neighbours;
584 }
585
586 sub is_in_direction_from{
587   my($self,$to,$from) = @_;
588
589   my $map = HexTorus->new($self->get_size());
590   my $to_location = Location->from_string($to);
591   my $from_location = Location->from_string($from);
592
593   return $map->get_direction($from_location,$to_location);
594 }
595
596 sub show_statistic{
597   my($self) = @_;
598   my $db = $self->{-db};
599
600   my @earthlings = $self->get_all_roles('EARTHLING');
601   my @gods = $self->get_all_roles('GOD');
602
603   # show for god: own mana,
604   my $out = '';
605   if($self->is_god()){
606     # own mana
607     $out .= $db->loc('OWN_MANA',$self->get_mana());
608   }
609
610   # show for all: #priests of god (?), #citys of earthling, #temples to build,
611   #               speed of game, fortune, last battle, fighting strength of earthlings
612   #               #temples of god
613
614   # strength of every god in last battle
615   $out .= $db->loc('LAST_BATTLE_HEADING') . '<p>';
616   for my $god (@gods){
617     # my $god = $god->[0];
618
619     my $strength=$self->strength_in_last_battle($god);
620     $out .= $db->loc('LAST_BATTLE_LINE',$self->charname($god),$strength) . '<br>';
621
622     # TODO?: count priests
623   }
624
625   # count citys
626   $out .= '<p>' . $db->loc('CITY_HEADING'). '<p>';
627   for my $player (@earthlings){
628     # $player = $player->[0];
629     my $citys = $db->count('MAP',
630                            "GAME=$self->{-game} AND OCCUPANT=$player AND TERRAIN=CITY");
631     $out .= $db->loc('STATISTIC_EARTHLING_CITY',
632                      $self->charname($player),
633                      $citys).'<br>';
634   }
635   $out .= '<p>';
636
637   # count temples to build for the end of the world
638   $out .= $db->loc('STATISTIC_UNBUILD', $self->unbuild()). " " .
639     $db->loc('STATISTIC_NEW_TEMPLES', $self->under_construction())."<p>\n";
640
641   my $game = $db->single_hash_select('GAME',
642                                      "GAME=$self->{-game}");
643   my $fortune = $game->{'FORTUNE'};
644   $out .= $db->loc('STATISTIC_FORTUNE',$fortune);
645
646   my $speed = $game->{'SPEED'};
647   $out .= $db->loc('STATISTIC_SPEED',"$speed sec");
648
649   return $out;
650 }
651
652 # returns number of places for temples
653 sub building_places{
654   my $self = shift;
655   return $self->{-db}->count('MAP',
656                              "(TERRAIN=ISLE OR TERRAIN=MOUNTAIN) ".
657                              "AND GAME=$self->{-game}");
658 }
659
660 # returns number of unbuild temples
661 sub unbuild{
662   my $self = shift;
663   return $self->{-db}->count('MAP',
664                              "(TERRAIN=ISLE OR TERRAIN=MOUNTAIN) ".
665                              "AND TEMPLE=N AND GAME=$self->{-game}");
666 }
667
668 # returns number of temples or arks which are currently under construction
669 sub under_construction{
670   my ($self,$type) = @_;
671   $type = 'TEMPLE' unless defined $type;
672   return $self->{-db}->count('EVENT',
673                              "TAG=EVENT_BUILD_$type");
674
675 }
676
677 sub strength_in_last_battle{
678   my($self,$god) = @_;
679   $god = $self->{-player} unless defined $god;
680   my $db = $self->{-db};
681
682   my $god_hash =
683     $db->single_hash_select('GOD',
684                             "GAME=$self->{-game} AND PLAYER=$god");
685
686   my $aymargeddon =
687     $db->single_hash_select('MAP',
688                             "GAME=$self->{-game} AND".
689                             " TERRAIN=AYMARGEDDON")->{'LOCATION'};
690   my $avatars = $self->count_mobile('AVATAR',$aymargeddon,$god);
691
692   my $strength = $::conf->{-LAST_BATTLE}->{-AVATAR} * $avatars +
693     $::conf->{-LAST_BATTLE}->{-DEATH_AVATAR} * $god_hash->{'DEATH_AVATAR'} +
694       $::conf->{-LAST_BATTLE}->{-DEATH_HERO} * $god_hash->{'DEATH_HERO'};
695
696   return $strength;
697
698 }
699
700 sub mobile_to_html{
701   my ($self, $loc,$own,$occ,$temple,$ter,
702       $oid,$otype,$oown,$oado,$ocnt,$ostat,$omove) = @_;
703 # field infos:
704 #  loc:    location of the field
705 #  own:    the owner of the field (for cities and temples) (HOME)
706 #  occ:    the occupant of the field
707 #  temple: wether there is a temple or not
708 #  ter:    terrain of field
709 # mobile infos:
710 #  oid:    id of the mobile
711 #  otype:  type of the mobile
712 #  oown:   owner of the mobile
713 #  oado:   which god the mobile adores
714 #  ocnt:   mobile count
715 #  ostat:  status of the mobile (BLOCK, IGNORE or HELP)
716 #  omove:  the id of the mobile to move with (unused here)
717
718   my $user = $self->{-user};
719   my $db = $self->{-db};
720   my $aym = $self;
721
722   my $out = $ocnt.' ';
723   if($oown == $user){
724     $out .= $db->loc('PREP_OWN_PL').' '.$aym->mobile_string($otype,2);
725     if($otype eq 'PRIEST' or $otype eq 'PROPHET'){
726       $out .= $db->loc('ADJ_ADORING').' '.$aym->charname($oado);
727       if($own != $oado){
728         $out .= ' (<a href="command.epl?cmd=CH_STATUS&other='.$oado.'">'.
729           $aym->relation_string($oado).
730             '</a>, <a href="command.epl?cmd=SEND_MSG&other='.$oado.'">'.
731               $db->loc('SEND_MESSAGE').'</a>)';
732       }
733       if(($ter eq 'ISLE' or $ter eq 'MOUNTAIN') and $temple eq 'N'){
734         $out .=' (<a href="command.epl?cmd=BUILD_TEMPLE&mob='.$oid.'&loc='.$loc.'">';
735         $out .= $db->loc('CMD_BUILD_TEMPLE').'</a>)';
736       }
737     }elsif($otype eq 'HERO'){
738       $out .= $db->loc('ADJ_ADORING');#.' <a href="command.epl?cmd=CH_ADORING&mob='.
739         # $oid.'">';
740       $out .= ' ' . $aym->charname($oado); #.'</a>';
741       if($own != $oado){
742         $out .= ' (<a href="command.epl?cmd=CH_STATUS&other='.$oado.'">'.
743           $aym->relation_string($oado).
744             '</a>, <a href="command.epl?cmd=SEND_MSG&other='.$oado.'">'.
745               $db->loc('SEND_MESSAGE').'</a>)';
746       }
747     }elsif($otype eq 'AVATAR'){
748       $out .= ' (<a href="command.epl?cmd=CH_ACTION&mob='.$oid.'">'.
749         $aym->mobile_string($ostat,1).'</a>)';
750       if($temple eq 'Y'){
751         $out .= " (<a href=\"command.epl?cmd=DESTROY&loc=$loc\">".
752           $db->loc('CMD_DESTROY').'</a>)';
753       }
754     }
755     $out .= ' (<a href="command.epl?cmd=MOVE&mob='.$oid.'&loc='.$loc.'">'.
756       $db->loc('CMD_MOVE').'</a>)';
757
758   }else{
759     $out .= $aym->mobile_string($otype, $ocnt);
760
761     $out .= ' '.$db->loc('PREP_OWN_SG').' ';
762     $out .= $db->loc('ART_DAT_PL').' ' if $aym->gender($oown) eq 'PLURAL';
763     $out .= $aym->charname($oown);
764     if($own != $oown and $occ != $oown){
765       $out .= ' (<a href="command.epl?cmd=CH_STATUS&other='.$oown.'">'.
766         $aym->relation_string($oown).'</a>,'.
767             '<a href="command.epl?cmd=SEND_MSG&other='.$oown.'">'.
768               $db->loc('SEND_MESSAGE').'</a>)';
769     }
770
771     if($otype eq 'PRIEST' or $otype eq 'PROPHET'or $otype eq 'HERO'){
772       $out .= $db->loc('ADJ_ADORING').' ';
773       if($oado == $user){
774         $out .= $db->loc( ($aym->gender($user) eq 'PLURAL') ?
775                           'PPRO_DAT3_PL' : 'PPRO_DAT3_SG');
776       }else{
777         $out .= $aym->charname($oado);
778         if($own != $oown and $occ != $oown){
779           $out .= ' (<a href="command.epl?cmd=CH_STATUS&other='.$oado.'">'.
780           $aym->relation_string($oado).
781             '</a>, <a href="command.epl?cmd=SEND_MSG&other='.$oado.'">'.
782               $db->loc('SEND_MESSAGE').'</a>)';
783         }
784       }
785     }elsif($otype eq 'WARRIOR' and $aym->is_god($user)){
786       $out .= ' (<a href="command.epl?cmd=BLESS_PRIEST&mob='.$oid.'">'.
787         $db->loc('CMD_BLESS_PRIEST').'</a>)';
788       if($own==$user and $temple eq 'Y'){
789         $out .= ' (<a href="command.epl?cmd=BLESS_HERO&mob='.$oid.'">'.
790           $db->loc('CMD_BLESS_HERO').'</a>)';
791       }
792     }
793   }
794   return $out;
795 }
796
797 # this overloads the same function in Game.pm
798 # we dont look on arks, that is special for Aymargeddon
799 #sub own_in_mobile{
800 #  my($self,$loc,$player,$active) = @_;
801 #  my $cond = "GAME=$self->{-game} AND LOCATION=$loc".
802 #    " AND TYPE!=ARK AND (OWNER=$player OR ADORING=$player)";
803 #  if(defined $active){
804 #    # my $y = $self->{-db}->quote('Y');
805 #    $cond .= " AND AVAILABLE='Y'";
806 #  }
807 #  return $self->{-db}->select_array('MOBILE','ID',$cond);
808 #}
809
810
811 # returns true if foreign eartlings approach to field
812 sub foreign_earthling_approaching{
813   my ($self,$loc,$earthling) = @_;
814
815   # TODO BUG: if $earthling < 1 => different names in different languages...
816   my $name = $self->charname($earthling);
817   my $ret = $self->{-db}->count('EVENT',
818                                 "LOCATION=$loc AND ".
819                                 "(TAG=EVENT_MOBILE_APPROACHING OR ".
820                                 "TAG=EVENT_ARK_APPROACHING) AND ".
821                                 "ARG1 != $name AND ".
822                                 "ARG4 != MOBILE_AVATAR AND ".
823                                 "ARG4 != MOBILE_AVATAR_PL");
824
825   return $ret;
826 }
827
828 # returns true if own avatar is there and if no god-fight is running
829 sub avatar_available{
830   my ($self,$loc,$god,$command) = @_;
831
832   my $avatars = $self->own_in_mobile($loc,$god,1);
833   my @avatars = @$avatars;
834
835   my ($godfight) = $self->read_field('GOD_ATTACKER',$loc);
836
837   unless($#avatars >= 0 and not $godfight){
838     $self->send_message_to($god,
839                            {'MSG_TAG' => "MSG_$command\_NEED_AVATAR",
840                             'ARG1' => $loc}) if defined $command;
841     return 0;
842   }
843
844   return 1;
845 }
846
847 1;