214 lines
5.3 KiB
Perl
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;
|