LasTres/lib/LasTres/Battle.pm

214 lines
5.3 KiB
Perl

package LasTres::Battle;
use v5.36.0;
use strict;
use warnings;
use feature 'signatures';
use Moo;
use UUID::URandom qw/create_uuid_string/;
use LasTres::Util;
use LasTres::EnemyTeam;
use JSON qw//;
has uuid => (
is => 'rw',
default => \&_build_uuid,
);
has team1 => (
is => 'rw',
required => 1,
);
has team2 => ( is => 'rw', );
has last_frame => (
is => 'rw',
required => 1,
);
sub sanity_check ($self) {
my $team1 = $self->team1;
my $team2 = $self->team2;
if ( !defined $team2 ) {
return 0;
}
if ( !defined $team1->current_battle
|| !defined $team2->current_battle
|| $team1->current_battle ne $self->uuid
|| $team2->current_battle ne $self->uuid )
{
return 0;
}
return 1;
}
sub winner ($self) {
if ( $self->team2->is_defeated ) {
return $self->team1;
}
if ( $self->team1->is_defeated ) {
return $self->team2;
}
return;
}
sub try_turn ( $self, $entity ) {
my $combat_target = $entity->combat_target;
my $enemy_team = $self->get_enemy_team( $entity->team );
my @combat_members_enemy = @{ $enemy_team->combat_members };
@combat_members_enemy = grep { $_->health > 0 } @combat_members_enemy;
if ( $entity->health <= 0 ) {
# This entity is out of the battle.
return;
}
if ( defined $entity->combat_target ) {
{
my @target_list_only_one_should_match =
grep { $combat_target eq $_->uuid } @combat_members_enemy;
if ( !scalar @target_list_only_one_should_match ) {
undef($combat_target);
next;
}
$combat_target = $target_list_only_one_should_match[0];
}
}
if ( !defined $combat_target ) {
$combat_target =
$combat_members_enemy[ LasTres::Util::rand_range_int( 0,
$#combat_members_enemy ) ];
$entity->combat_target( $combat_target->uuid );
$entity->update;
}
$entity->attack($combat_target);
}
sub get_enemy_team ( $self, $team ) {
if ( $self->team1->uuid ne $team->uuid ) {
return $self->team1;
}
return $self->team2;
}
sub loser ($self) {
if ( $self->team2->is_defeated ) {
return $self->team2;
}
if ( $self->team1->is_defeated ) {
return $self->team1;
}
return;
}
sub end ($self) {
require LasTres::Redis;
my $redis = LasTres::Redis->new;
$self->team1->current_battle(undef);
$self->team1->update;
if ( defined $self->team2 ) {
$self->team2->current_battle(undef);
$self->team2->update;
}
$redis->db->expire( $redis->battle_key( $self->uuid ), 0 );
$self->team1->on_end_combat;
$self->team2->on_end_combat;
}
sub _build_uuid {
return create_uuid_string();
}
sub to_json ($self) {
return {
uuid => $self->uuid,
team1 => $self->team1->to_serializable,
team2 => $self->team2->to_serializable,
last_frame => $self->last_frame,
};
}
sub save_redis ($self) {
require LasTres::Redis;
my $redis = LasTres::Redis->new;
$redis->db->setex( $redis->battle_key( $self->uuid ),
3600 * 6, JSON::to_json( $self->to_json ) );
}
sub get_redis ( $class, $uuid ) {
require LasTres::Redis;
my $redis = LasTres::Redis->new;
my $hash_self;
eval {
$hash_self =
JSON::from_json( $redis->db->get( $redis->battle_key($uuid) ) );
};
if ($@) {
return;
}
return $class->from_json( $uuid, $hash_self );
}
sub from_json ( $class, $uuid, $hash ) {
# I do not take the hash uuid since if redis lies that could be really bad.
return $class->new(
uuid => $uuid,
team1 => $class->deserialize_team( $hash->{team1} ),
team2 => $class->deserialize_team( $hash->{team2} ),
last_frame => $hash->{last_frame},
);
}
sub deserialize_team ( $class, $team_hash ) {
if ( $team_hash->{is_db} ) {
return LasTres::Schema::Result::Team->from_serializable($team_hash);
}
return LasTres::EnemyTeam->from_serializable($team_hash);
}
sub start_battle_machine ( $class, $team, $enemy_area_array ) {
my @enemy_area_array = @$enemy_area_array;
my $battle = LasTres::Battle->new( team1 => $team, last_frame => 0 );
my $team2 = LasTres::EnemyTeam->new( current_battle => $battle->uuid );
my @enemies_array = ( map { $_->generate($team2) } @$enemy_area_array );
my @enemy_log_list;
my $first_log = 1;
$team2->members( \@enemies_array );
$battle->team2($team2);
$battle->save_redis;
$team->current_battle( $battle->uuid );
for my $member ( $team2->combat_members->@* ) {
if ( !$first_log ) {
push @enemy_log_list, { text => ', ' };
}
$first_log = 0;
push @enemy_log_list,
{
color => 'red',
text => $member->nick,
};
push @enemy_log_list,
{ text =>
" Nivel @{[$member->level]} Salud @{[$member->health]}/@{[$member->max_health]}"
};
}
for my $member ( $team->members ) {
$member->append_log_line(
[
{
text => 'Empieza un combate contra: '
},
@enemy_log_list
]
);
}
$team->update;
return $battle;
}
1;