diff --git a/js-src/components/bottom-panel.tsx b/js-src/components/bottom-panel.tsx
index 4747d8a..0a8e83f 100644
--- a/js-src/components/bottom-panel.tsx
+++ b/js-src/components/bottom-panel.tsx
@@ -11,7 +11,12 @@ export default function BottomPanel (): JSX.Element {
return (
- hola
+
+
+
+
+
+
)
diff --git a/js-src/components/game.tsx b/js-src/components/game.tsx
index 4994a86..a005345 100644
--- a/js-src/components/game.tsx
+++ b/js-src/components/game.tsx
@@ -63,12 +63,15 @@ export default function Game (props: GameProps): JSX.Element {
new OutputPacketInit(selectedPJ.uuid).send(webSocket)
let interval: number = 0
interval = window.setInterval(() => {
+ if (webSocket.readyState === WebSocket.CONNECTING) {
+ return
+ }
if (webSocket.readyState === WebSocket.OPEN) {
new OutputPacketPing().send(webSocket)
return
}
window.clearInterval(interval)
- }, 250000)
+ }, 1000)
}
const inputPackets = new InputPackets(setTeamPJs,
setEnemyTeamPJs, setIsBattling,
@@ -91,7 +94,7 @@ export default function Game (props: GameProps): JSX.Element {
}
return websocket
})
- }, 100)
+ }, 10)
return (
<>
>
}
- return <>>
+ const image = pj.health > 0 ? pj.image : '/img/skull.png'
+ return <>>
}
function printExperience (): JSX.Element {
if (pj.experience_to_next_level_current === undefined || pj.experience_to_next_level_complete === undefined) {
diff --git a/lib/LasTres/Area.pm b/lib/LasTres/Area.pm
index 45777a3..60263a7 100644
--- a/lib/LasTres/Area.pm
+++ b/lib/LasTres/Area.pm
@@ -20,51 +20,72 @@ has children => (
);
## OVERRIDE
+# If true the entire map will be discovered when you step into the Area.
sub get_auto_discover ($self) {
return 0;
}
## OVERRIDE
+# The number of intervals of 10 seconds until you can reach
+# other location.
sub frames_to_move ($self) {
return 5;
}
## OVERRIDE
+# The number of intervals of 10 seconds until you can
+# possibly discover a new location when exploring.
sub frames_to_explore ($self) {
return 7;
}
## OVERRIDE
+# Whenever wild enemies will appear on explore or move.
sub has_movement_auto_combat ($self) {
return 0;
}
## OVERRIDE
+# The minimum number of enemies that will appear for every PJ
+# when a battle is determined to take place on movement.
+# Adjustable to the $pj, you should be careful with it being undef.
sub min_enemies_per_head ($self, $pj = undef) {
return 1;
}
## OVERRIDE
+# The maximum number of enemies that will appear for every PJ
+# when a battle is determined to take place on movement.
+# Adjustable to the $pj, you should be careful with it being undef.
sub max_enemies_per_head ($self, $pj = undef) {
return 1;
}
## OVERRIDE
+# The list of possible enemies on random encounter exploring or moving.
+# You can adjust them to the level of the player using the $pj variable.
+# Beware that this can be undef.
sub list_of_enemies ( $self, $pj = undef ) {
return [];
}
## OVERRIDE
+# The percentual chance of random combat encounter on movement or explore.
sub chance_combat ($self) {
return 50;
}
-## OVERRIDE (Always use $self->SUPER::on_move_explore_frame.)
+## OVERRIDE (Always use $self->SUPER::on_move_explore_frame($self, $team).)
+# What to on movement and explore frame.
+# You can use this to make the user encounter drops for example, but if you
+# do not call the SUPER function you will lose functionality.
sub on_move_explore_frame ( $self, $team ) {
return if $self->_try_to_start_battle($team);
}
sub _try_to_start_battle ( $self, $team ) {
+ require LasTres::Redis;
+ my $redis = LasTres::Redis->new;
if ( !$self->has_movement_auto_combat ) {
## Combat not enabled.
return 0;
@@ -77,53 +98,27 @@ sub _try_to_start_battle ( $self, $team ) {
## Creating enemy team.
my $battle = LasTres::Battle->new( team1 => $team, last_frame => 0 );
my $team2 = LasTres::EnemyTeam->new( current_battle => $battle->uuid );
- my @enemy_members;
- $self->_generate_enemies_team($team2, \@enemy_members, $team);
+ my @enemy_members = @{$self->_generate_enemies_team($team)};
if ( !scalar @enemy_members ) {
## No enemies generated.
return 0;
}
- $team2->members( \@enemy_members );
- $battle->team2($team2);
- $battle->save_redis;
- $team->current_battle( $battle->uuid );
- my @enemy_log_list;
- my $first = 1;
- for my $member ($team2->combat_members->@*) {
- if (!$first) {
- push @enemy_log_list, { text => ', ' };
- }
- $first = 0;
- push @enemy_log_list, {
- color => 'red',
- text => $member->nick,
- };
- push @enemy_log_list, {
- text => " NIVEL @{[$member->level]} VIDA @{[$member->health]}/@{[$member->max_health]}"
- };
- }
- for my $member ($team->members) {
- $member->append_log_line([
- {
- text => 'Empieza un combate contra: '
- },
- @enemy_log_list
- ]);
- }
- $team->update;
+ LasTres::Battle->start_battle_machine($team, \@enemy_members);
return 1;
}
-sub _generate_enemies_team ($self, $enemy_team, $enemy_members_array, $team) {
+sub _generate_enemies_team ($self, $team) {
+ my @enemy_members_array;
for my $pj ( @{$team->combat_members} ) {
my $number_of_enemies =
LasTres::Util::rand_range_int( $self->min_enemies_per_head($pj),
$self->max_enemies_per_head($pj) );
- $self->_generate_n_enemies_pj( $enemy_team, $number_of_enemies, $enemy_members_array, $pj );
+ $self->_generate_n_enemies_pj( $number_of_enemies, \@enemy_members_array, $pj );
}
+ return \@enemy_members_array;
}
-sub _generate_n_enemies_pj ( $self, $enemy_team, $number_of_enemies,
+sub _generate_n_enemies_pj ( $self, $number_of_enemies,
$enemy_members_array, $pj )
{
my @list_possible_enemies = @{ $self->list_of_enemies($pj) };
@@ -135,11 +130,12 @@ sub _generate_n_enemies_pj ( $self, $enemy_team, $number_of_enemies,
my $choice_enemy_index =
LasTres::Util::rand_range_int( 0, $#list_possible_enemies );
my $choice_enemy = $list_possible_enemies[$choice_enemy_index];
- push @$enemy_members_array, $choice_enemy->generate($enemy_team);
+ push @$enemy_members_array, $choice_enemy;
}
}
## OVERRIDE
+# Determines if the explore functionality is enabled for this area.
sub can_explore {
return 1;
}
diff --git a/lib/LasTres/Battle.pm b/lib/LasTres/Battle.pm
index b4d52aa..90229cb 100644
--- a/lib/LasTres/Battle.pm
+++ b/lib/LasTres/Battle.pm
@@ -47,53 +47,58 @@ sub sanity_check ($self) {
}
sub winner ($self) {
- if ($self->team2->is_defeated) {
+ if ( $self->team2->is_defeated ) {
return $self->team1;
}
- if ($self->team1->is_defeated) {
+ 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};
+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) {
+ 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;
+ 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];
}
- $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);
+ }
+ 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);
- $combat_target->update;
}
-sub get_enemy_team ($self, $team) {
- if ($self->team1->uuid ne $team->uuid) {
+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) {
+ if ( $self->team2->is_defeated ) {
return $self->team2;
}
- if ($self->team1->is_defeated) {
+ if ( $self->team1->is_defeated ) {
return $self->team1;
}
return;
@@ -130,15 +135,16 @@ 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));
+ 3600 * 6, JSON::to_json( $self->to_json ) );
}
sub get_redis ( $class, $uuid ) {
require LasTres::Redis;
- my $redis = LasTres::Redis->new;
+ my $redis = LasTres::Redis->new;
my $hash_self;
eval {
- $hash_self = JSON::from_json($redis->db->get( $redis->battle_key($uuid) ));
+ $hash_self =
+ JSON::from_json( $redis->db->get( $redis->battle_key($uuid) ) );
};
if ($@) {
return;
@@ -151,8 +157,8 @@ 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}),
+ team1 => $class->deserialize_team( $hash->{team1} ),
+ team2 => $class->deserialize_team( $hash->{team2} ),
last_frame => $hash->{last_frame},
);
}
@@ -163,4 +169,45 @@ sub deserialize_team ( $class, $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;
diff --git a/lib/LasTres/CombatCapableEntity.pm b/lib/LasTres/CombatCapableEntity.pm
index 52a1c10..04d4554 100644
--- a/lib/LasTres/CombatCapableEntity.pm
+++ b/lib/LasTres/CombatCapableEntity.pm
@@ -14,8 +14,8 @@ use JSON qw/to_json from_json/;
requires(
'uuid', 'race_string', 'nick', 'born_stats',
'health', 'mana', 'training_stats', 'experience',
- 'combat_action', 'combat_target', 'team', 'update',
- 'gain_experience', 'update_team_sprites'
+ 'combat_action', 'combat_target', 'team',
+ 'gain_experience', 'update_team_sprites', 'get_from_storage',
);
sub append_log_line {
@@ -34,6 +34,14 @@ sub race ($self) {
return $race;
}
+## OVERRIDE (Call super)
+sub update($self) {
+ $self = $self->get_from_storage;
+ if ( $self->health < 1 ) {
+ $self->on_faint;
+ }
+}
+
sub attack ( $self, $enemy_entity ) {
my $defense = $enemy_entity->resistance;
my $attack = $self->strength;
@@ -95,22 +103,11 @@ sub attack ( $self, $enemy_entity ) {
]
);
}
- if ( $enemy_entity->health == 0 ) {
- $enemy_entity->on_faint($self);
- }
+ $enemy_entity->update;
}
-sub on_faint($self, $attacker) {
+sub on_faint($self) {
my $team2 = $self->team;
- my $team1 = $attacker->team;
- for my $member ( $team1->combat_members->@* ) {
- $member->append_log_line(
- [
- { color => 'red', text => "@{[$self->nick]}" },
- { text => " se ha debilitado." },
- ]
- );
- }
for my $member ( $team2->combat_members->@* ) {
$member->append_log_line(
[
@@ -119,7 +116,21 @@ sub on_faint($self, $attacker) {
]
);
}
- $attacker->gain_experience((($self->race->experience_drop_base * $self->level)/7)*1.5);
+ my $battle = $team2->battle;
+ if (!defined $battle) {
+ return;
+ }
+ my $team1 = $battle->get_enemy_team($team2);
+ for my $member ( $team1->combat_members->@* ) {
+ $member->append_log_line(
+ [
+ { color => 'red', text => "@{[$self->nick]}" },
+ { text => " se ha debilitado." },
+ ]
+ );
+ $member->gain_experience((($self->race->experience_drop_base * $self->level)/7));
+ }
+
}
sub level ($self) {
diff --git a/lib/LasTres/Controller/PJ.pm b/lib/LasTres/Controller/PJ.pm
index 140a2cb..9c03292 100644
--- a/lib/LasTres/Controller/PJ.pm
+++ b/lib/LasTres/Controller/PJ.pm
@@ -152,7 +152,7 @@ sub _insert_new_player ( $self, $owner, $full_name, $short_name, $nick, $race )
intelligence => $self->_get_random_born_stat,
});
$born_stats->insert;
- my $training_stats = $schema->resultset->new({
+ my $training_stats = $schema->resultset('Stats')->new({
uuid => $uuid_training_stats,
health => 0,
strength => 0,
diff --git a/lib/LasTres/Enemy.pm b/lib/LasTres/Enemy.pm
index e5ed32f..8dc7fa7 100644
--- a/lib/LasTres/Enemy.pm
+++ b/lib/LasTres/Enemy.pm
@@ -162,10 +162,6 @@ sub to_hash_display ($self) {
sub gain_experience {
}
-sub update ($self) {
- return $self;
-}
-
sub to_hash ($self) {
return {
kind => 'NPCEnemy',
@@ -192,5 +188,9 @@ sub from_hash ( $class, $hash ) {
zmana => $hash->{mana},
);
}
+
+sub get_from_storage($self) {
+ return $self;
+}
with 'LasTres::RedisEnemy';
1;
diff --git a/lib/LasTres/EventLoop.pm b/lib/LasTres/EventLoop.pm
index 0e10e17..afe6f44 100644
--- a/lib/LasTres/EventLoop.pm
+++ b/lib/LasTres/EventLoop.pm
@@ -96,7 +96,7 @@ sub _increment_frame_for_combat($self, $battle_uuid) {
for my $entity (@combat_members) {
$battle->try_turn($entity);
if (my $winner = $battle->winner) {
- next;
+ last;
}
$battle->save_redis;
}
diff --git a/lib/LasTres/Location.pm b/lib/LasTres/Location.pm
index 9116847..0f355f7 100644
--- a/lib/LasTres/Location.pm
+++ b/lib/LasTres/Location.pm
@@ -15,39 +15,74 @@ use utf8;
requires qw/identifier name description parent actions npcs/;
+## Implement action($self, $pj);
+## Implement npcs($self, $pj);
+## Implement description($self, $pj = undef);
+## Implement name($self, $pj = undef);
+## Implement identifier($self, $pj = undef);
+
my $planets = LasTres::Planets->new;
## OVERRIDE
+# Whenever a player can visit this place.
+# The player to compute will always be the leader.
sub can_visit ( $self, $pj ) {
return 1;
}
## OVERRIDE
+# Whenever a player can discover this location with explore.
+# The player will be always the leader.
+# Alternative methods to explore will be able to discover this place
+# for the pj.
sub can_discover ( $self, $pj ) {
return 1;
}
## OVERRIDE
+# The percentual chance to discover this place with explore.
sub chance_discover ( $self, $pj ) {
return 50;
}
## OVERRIDE
+# Whenever this can be the last discovery option in explore to let the
+# player discover at least something.
sub allow_forced_discovery ( $self, $pj ) {
return 1;
}
## OVERRIDE
+# The order for the percentual random calculation, the higher the less priority
+# it has for discover and the later it will be forcedfully discovered.
sub order ($self) {
return 1000;
}
## OVERRIDE
+# A place that is a spawn will have a healing action that can be changed
+# and if a team faints they will be teleported there and the action will
+# be triggered, the healing action may cost some resource when the action
+# is triggered manually by the user, if the player cannot pay it the
+# action may appear as disabled.
sub is_spawn($self) {
return 0;
}
+## OVERRIDE
+# Return object should ideally extend LasTres::PJAction::DefaultHeal
+# following the advice in this file.
+sub healing_action($self) {
+ if ($self->is_spawn) {
+ require LasTres::PJAction::DefaultHeal;
+ return LasTres::PJAction::DefaultHeal->new;
+ }
+}
+
## OVERRIDE (Always use $self->SUPER::on_team_arrival.)
+# The code to be executed when a team reachs this location.
+# It is important that you call super or you will lose
+# REALLY important behaviour such as knows_location.
sub on_team_arrival ( $self, $team ) {
$team = $team->get_from_storage;
for my $pj ( $team->members ) {
@@ -56,6 +91,9 @@ sub on_team_arrival ( $self, $team ) {
}
## OVERRIDE (Always use $self->SUPER::on_pj_arrival.)
+# The code to be executed when a pj reachs this location.
+# Call super or bad things will happen such as losing
+# knows_location and update-location.
sub on_pj_arrival ( $self, $pj ) {
require LasTres::Redis;
$pj = $pj->get_from_storage;
@@ -68,18 +106,20 @@ sub on_pj_arrival ( $self, $pj ) {
to_json( { command => 'update-location' } ) );
}
+## DO NOT EXTEND NOT SUPPORTED.
sub show_intro ( $self, $pj ) {
$pj->append_log_line(
[
{ text => 'Estas en ' },
- { color => 'red', text => $self->parent->name },
+ { color => 'red', text => $self->parent->name($pj) },
{ text => '/' },
- { color => 'green', text => $self->name },
+ { color => 'green', text => $self->name($pj) },
]
);
$pj->append_log_line( [ { text => $pj->location->description }, ] );
}
+## DO NOT EXTEND NOT SUPPORTED.
sub move ( $self, $team ) {
$team = $team->get_from_storage;
my $current_location = $team->location;
@@ -103,6 +143,8 @@ sub move ( $self, $team ) {
}
## OVERRIDE (Always use $self->SUPER::on_team_moving.)
+# This is called when a team starts their travel
+# to this location, always call SUPER.
sub on_team_moving ( $self, $team ) {
$team = $team->get_from_storage;
for my $pj ( $team->members ) {
@@ -111,6 +153,9 @@ sub on_team_moving ( $self, $team ) {
$team->send_frame_to_members;
}
+## OVERRIDE (Always use $self->SUPER::on_pj_moving.)
+# This is called when a pj is approaching this location
+# via move. It is really important to call super.
sub on_pj_moving ( $self, $pj ) {
require LasTres::Redis;
my $redis = LasTres::Redis->new;
@@ -118,15 +163,16 @@ sub on_pj_moving ( $self, $pj ) {
$pj->append_log_line(
[
{ text => 'Tu equipo se está moviendo a ' },
- { color => 'red', text => $self->parent->name },
+ { color => 'red', text => $self->parent->name($pj) },
{ text => '/' },
- { color => 'green', text => $self->name },
+ { color => 'green', text => $self->name($pj) },
]
);
$redis->publish( $redis->pj_subscription($pj),
to_json( { command => 'update-location' } ) );
}
+## DO NOT EXTEND NOT SUPPORTED.
sub place_team ( $self, $team ) {
$team = $team->get_from_storage;
if ($self->is_spawn) {
@@ -137,6 +183,7 @@ sub place_team ( $self, $team ) {
$self->on_team_arrival($team);
}
+## DO NOT EXTEND NOT SUPPORTED.
sub to_array ($self) {
my $hash = $self->hash;
return [
@@ -145,10 +192,12 @@ sub to_array ($self) {
];
}
+## DO NOT EXTEND NOT SUPPORTED.
sub to_json_array ($self) {
return to_json( $self->to_array );
}
+## DO NOT EXTEND NOT SUPPORTED.
sub is_connected_by_move ( $self, $otherLocation, $pj = undef ) {
if ( !defined $otherLocation ) {
die '$otherLocation must be defined in is_connected.';
@@ -162,6 +211,7 @@ sub is_connected_by_move ( $self, $otherLocation, $pj = undef ) {
return 0;
}
+## DO NOT EXTEND NOT SUPPORTED.
sub get_available_locations_to_move_to ( $self, $pj = undef ) {
if ( defined $pj ) {
$pj = $pj->get_from_storage;
@@ -185,6 +235,7 @@ sub get_available_locations_to_move_to ( $self, $pj = undef ) {
return $connected_places;
}
+## DO NOT EXTEND NOT SUPPORTED.
sub pj_is_moving ( $self, $pj = undef ) {
if ( defined $pj ) {
$pj = $pj->get_from_storage;
@@ -192,6 +243,7 @@ sub pj_is_moving ( $self, $pj = undef ) {
return defined $pj && $pj->team->is_moving;
}
+## DO NOT EXTEND NOT SUPPORTED.
sub _get_neighbour_locations_accesible ( $self, $pj ) {
my $places = [];
@$places = @{ $self->parent->children };
@@ -202,6 +254,7 @@ sub _get_neighbour_locations_accesible ( $self, $pj ) {
return $places;
}
+## DO NOT EXTEND NOT SUPPORTED.
sub get ( $planet_id, $super_area_id, $area_id, $location_id ) {
my $planet = $planets->hash->{$planet_id};
if ( !defined $planet ) {
@@ -225,6 +278,7 @@ sub get ( $planet_id, $super_area_id, $area_id, $location_id ) {
return $location;
}
+## DO NOT EXTEND NOT SUPPORTED.
sub hash ($self) {
my $location = $self;
if ( !Moo::Role::does_role( $location, 'LasTres::Location' ) ) {
diff --git a/lib/LasTres/PJAction/.exists b/lib/LasTres/PJAction/.exists
new file mode 100644
index 0000000..e69de29
diff --git a/lib/LasTres/Planet/Bahdder.pm b/lib/LasTres/Planet/Bahdder.pm
index 9396c2f..f987de7 100644
--- a/lib/LasTres/Planet/Bahdder.pm
+++ b/lib/LasTres/Planet/Bahdder.pm
@@ -15,37 +15,13 @@ use Module::Pluggable search_path => ['LasTres::Planet::Bahdder'],
die $error;
};
-has super_areas => (
- is => 'ro',
- lazy => 1,
- builder => \&_build_super_areas,
-);
-
-has identifier => (
- is => 'ro',
- lazy => 1,
- builder => \&_build_identifier,
-);
-
-has name => (
- is => 'ro',
- lazy => 1,
- builder => \&_build_name,
-);
-
-has description => (
- is => 'ro',
- lazy => 1,
- builder => \&_build_description,
-);
-
with 'LasTres::Planet';
-sub _build_identifier {
+sub identifier {
return 'bahdder',
}
-sub _build_super_areas {
+sub super_areas {
my $self = shift;
my $hash = {};
my @super_areas = $self->plugins();
@@ -55,11 +31,11 @@ sub _build_super_areas {
return $hash;
}
-sub _build_name {
+sub name {
return 'Bahdder';
}
-sub _build_description {
+sub description {
return 'Archivo de la Patrulla Galáctica: Bahdder es uno de los planetas con mayor población de la galaxia con una población estimada '
. 'de tres mil millones de individuos pertenecientes a especies consideradas inteligentes. '
. 'Es conocido como el planeta origen de los Yaren; no obstante la presencia de los mismos en este planeta es actualmente simbólica. '
diff --git a/lib/LasTres/Planet/Bahdder/BosqueDelHeroe.pm b/lib/LasTres/Planet/Bahdder/BosqueDelHeroe.pm
index 61d8b30..dbf539c 100644
--- a/lib/LasTres/Planet/Bahdder/BosqueDelHeroe.pm
+++ b/lib/LasTres/Planet/Bahdder/BosqueDelHeroe.pm
@@ -19,27 +19,6 @@ use Module::Pluggable search_path => ['LasTres::Planet::Bahdder::BosqueDelHeroe'
use LasTres::Planet::Bahdder;
-has areas => (
- is => 'ro',
- builder => \&_build_areas,
- lazy => 1,
-);
-
-has identifier => (
- is => 'ro',
- builder => \&_build_identifier,
-);
-
-has name => (
- is => 'ro',
- builder => \&_build_name,
-);
-
-has description => (
- is => 'ro',
- builder => \&_build_description,
-);
-
has parent => (
is => 'ro',
builder => \&_build_parent,
@@ -47,11 +26,11 @@ has parent => (
with 'LasTres::SuperArea';
-sub _build_identifier {
+sub identifier {
return 'bosque_del_heroe';
}
-sub _build_areas {
+sub areas {
my $self = shift;
my $hash = {};
my @areas = $self->plugins();
@@ -61,11 +40,11 @@ sub _build_areas {
return $hash;
}
-sub _build_name {
+sub name {
return 'Bosque del Héroe';
}
-sub _build_description {
+sub description {
return 'El Bosque del Héroe es el pulmón del planeta Bahdder. '
. 'Se cree que solo una pequeña parte de las especies que viven en el mismo han sido catalogadas. '
. 'Los áldimor viven en este bosque en armonía con la naturaleza. '
diff --git a/lib/LasTres/Planet/Bahdder/BosqueDelHeroe/BosqueDelHeroeI.pm b/lib/LasTres/Planet/Bahdder/BosqueDelHeroe/BosqueDelHeroeI.pm
index cd21e1a..d034d82 100644
--- a/lib/LasTres/Planet/Bahdder/BosqueDelHeroe/BosqueDelHeroeI.pm
+++ b/lib/LasTres/Planet/Bahdder/BosqueDelHeroe/BosqueDelHeroeI.pm
@@ -19,22 +19,6 @@ use Moo;
use LasTres::Planet::Bahdder::BosqueDelHeroe;
-has locations => (
- is => 'ro',
- builder => \&_build_locations,
- lazy => 1,
-);
-
-has identifier => (
- is => 'ro',
- builder => \&_build_identifier,
-);
-
-has name => (
- is => 'ro',
- builder => \&_build_name,
-);
-
has parent => (
is => 'ro',
builder => \&_build_parent,
@@ -42,11 +26,11 @@ has parent => (
with 'LasTres::Area';
-sub _build_identifier {
+sub identifier {
return 'bosque_del_heroe_i';
}
-sub _build_locations {
+sub locations {
my $self = shift;
my $hash = {};
my @locations = $self->plugins();
@@ -56,7 +40,7 @@ sub _build_locations {
return $hash;
}
-sub _build_name {
+sub name {
return 'Bosque del Héroe (I)';
}
diff --git a/lib/LasTres/Planet/Bahdder/BosqueDelHeroe/BosqueDelHeroeI/TribuDeLaLima.pm b/lib/LasTres/Planet/Bahdder/BosqueDelHeroe/BosqueDelHeroeI/TribuDeLaLima.pm
index cebe16d..bcfdf20 100644
--- a/lib/LasTres/Planet/Bahdder/BosqueDelHeroe/BosqueDelHeroeI/TribuDeLaLima.pm
+++ b/lib/LasTres/Planet/Bahdder/BosqueDelHeroe/BosqueDelHeroeI/TribuDeLaLima.pm
@@ -10,61 +10,31 @@ use Moo;
use LasTres::Planet::Bahdder::BosqueDelHeroe::BosqueDelHeroeI;
-has identifier => (
- is => 'ro',
- builder => \&_build_identifier,
-);
-
-has name => (
- is => 'ro',
- builder => \&_build_name,
-);
-
-has description => (
- is => 'ro',
- builder => \&_build_description,
-);
-
-has parent => (
- is => 'ro',
- builder => \&_build_parent,
-);
-
-has actions => (
- is => 'ro',
- builder => \&_build_actions,
-);
-
-has npcs => (
- is => 'ro',
- builder => \&_build_npcs,
-);
-
with 'LasTres::Location';
-sub _build_identifier {
+sub identifier {
return 'tribu_de_la_lima';
}
-sub _build_name {
+sub name {
return 'Tribu de la Lima (Exterior)';
}
-sub _build_description {
+sub description {
return 'La Tribu de la Lima se siente como un hogar seas o no de aquí. '
. 'Las casitas están improvisadas con paja que los aldeanos intercambian con otras tribus. '
. 'Los cultivos de lima están siempre buscando trabajadores, el sueldo es una parte de lo cosechado. ';
}
-sub _build_parent {
+sub parent {
return LasTres::Planet::Bahdder::BosqueDelHeroe::BosqueDelHeroeI->instance;
}
-sub _build_actions {
+sub actions {
return [];
}
-sub _build_npcs {
+sub npcs {
return [];
}
diff --git a/lib/LasTres/Planet/Bahdder/BosqueDelHeroe/TribuDeLaLima/ArbolCentral.pm b/lib/LasTres/Planet/Bahdder/BosqueDelHeroe/TribuDeLaLima/ArbolCentral.pm
index 5c9ac67..5be8f58 100644
--- a/lib/LasTres/Planet/Bahdder/BosqueDelHeroe/TribuDeLaLima/ArbolCentral.pm
+++ b/lib/LasTres/Planet/Bahdder/BosqueDelHeroe/TribuDeLaLima/ArbolCentral.pm
@@ -51,4 +51,8 @@ sub instance {
}
return $singleton;
}
+
+sub is_spawn {
+ return 1;
+}
1;
diff --git a/lib/LasTres/Planet/Bahdder/BosqueDelHeroe/TribuDeLaLima/Entrada.pm b/lib/LasTres/Planet/Bahdder/BosqueDelHeroe/TribuDeLaLima/Entrada.pm
index 2556e23..6f9a60f 100644
--- a/lib/LasTres/Planet/Bahdder/BosqueDelHeroe/TribuDeLaLima/Entrada.pm
+++ b/lib/LasTres/Planet/Bahdder/BosqueDelHeroe/TribuDeLaLima/Entrada.pm
@@ -13,51 +13,26 @@ use Moo;
use LasTres::Planet::Bahdder::BosqueDelHeroe::TribuDeLaLima;
-has identifier => (
- is => 'ro',
- builder => \&_build_identifier,
-);
-
-has name => (
- is => 'ro',
- builder => \&_build_name,
-);
-
-has description => (
- is => 'ro',
- builder => \&_build_description,
-);
-
has parent => (
is => 'ro',
builder => \&_build_parent,
);
-has actions => (
- is => 'ro',
- builder => \&_build_actions,
-);
-
-has npcs => (
- is => 'ro',
- builder => \&_build_npcs,
-);
-
with 'LasTres::Location';
sub is_spawn {
return 1;
}
-sub _build_identifier {
+sub identifier {
return 'entrada';
}
-sub _build_name {
+sub name {
return 'Entrada';
}
-sub _build_description {
+sub description {
return 'Un cartel reza. "Tribu de la Lima. Considerate bienvenido si '
. 'no eres un ladrón o un maleante, '
. 'en caso contrario recorre en sentido inverso el sendero de tus pisadas."';
@@ -67,11 +42,11 @@ sub _build_parent {
return LasTres::Planet::Bahdder::BosqueDelHeroe::TribuDeLaLima->instance;
}
-sub _build_actions {
+sub actions {
return [];
}
-sub _build_npcs {
+sub npcs {
return [];
}
diff --git a/lib/LasTres/Race.pm b/lib/LasTres/Race.pm
index c09cfc1..ed3e66b 100644
--- a/lib/LasTres/Race.pm
+++ b/lib/LasTres/Race.pm
@@ -9,15 +9,16 @@ use feature 'signatures';
use Moo::Role;
-requires qw/spawn identifier name name_selection description is_playable base_stats experience_drop_base/;
+requires
+ qw/spawn identifier name name_selection description is_playable base_stats experience_drop_base/;
-sub hash($self) {
+sub hash ($self) {
return {
- identifier => $self->identifier,
- name => $self->name,
+ identifier => $self->identifier,
+ name => $self->name,
name_selection => $self->name_selection,
- description => $self->description,
- is_playable => $self->is_playable,
- }
+ description => $self->description,
+ is_playable => $self->is_playable,
+ };
}
1;
diff --git a/lib/LasTres/Race/Aldimor.pm b/lib/LasTres/Race/Aldimor.pm
index fc427a6..837cdd2 100644
--- a/lib/LasTres/Race/Aldimor.pm
+++ b/lib/LasTres/Race/Aldimor.pm
@@ -12,7 +12,7 @@ use Moo;
use UUID::URandom qw/create_uuid_string/;
use LasTres::Stats;
-use LasTres::Planet::Bahdder::BosqueDelHeroe::BosqueDelHeroeI::TribuDeLaLima;
+use LasTres::Planet::Bahdder::BosqueDelHeroe::TribuDeLaLima::ArbolCentral;
has base_stats => (
is => 'ro',
@@ -57,7 +57,7 @@ sub image {
sub _build_spawn {
return
- LasTres::Planet::Bahdder::BosqueDelHeroe::BosqueDelHeroeI::TribuDeLaLima
+ LasTres::Planet::Bahdder::BosqueDelHeroe::TribuDeLaLima::ArbolCentral
->instance;
}
diff --git a/lib/LasTres/Schema/Result/PJ.pm b/lib/LasTres/Schema/Result/PJ.pm
index 94858a1..dd95842 100644
--- a/lib/LasTres/Schema/Result/PJ.pm
+++ b/lib/LasTres/Schema/Result/PJ.pm
@@ -234,12 +234,21 @@ sub update_team_sprites ($self) {
to_json( { command => 'update-team-sprites' } ) );
}
+sub update ($self) {
+ $self->SUPER::update();
+ if ( !defined $self->team->battle && $self->team->is_defeated ) {
+
+ # Out of combat blackout.
+ $self->team->on_blackout();
+ }
+}
+
sub on_level_up ( $self, $old_level ) {
my $old_experience = $self->experience;
my $team = $self->team;
my $enemy_team = $self->_enemy_team;
$self = $self->get_from_storage;
- $self->health($self->max_health);
+ $self->health( $self->max_health );
$self->update;
for my $member ( $team->combat_members->@* ) {
$member->update_team_sprites;
@@ -299,6 +308,7 @@ sub gain_experience ( $self, $experience_to_gain ) {
my $current_battle = $team->current_battle;
$self->experience( $old_experience + $experience_to_gain );
$self->update;
+
for my $member ( $team->combat_members->@* ) {
$member->append_log_line(
[
@@ -453,5 +463,37 @@ sub mana {
return $self->_mana;
}
+sub update_location ($self) {
+ require LasTres::Redis;
+ my $redis = LasTres::Redis->new;
+ $redis->publish( $redis->pj_subscription($self),
+ to_json( { command => 'update-location' } ) );
+}
+
+sub actions ($self) {
+ my @actions;
+ $self = $self->get_from_storage;
+ my $team = $self->team;
+ my $location = $team->location;
+ if ( defined $team->battle ) {
+
+ # There should go the battle actions.
+ return;
+ }
+ if ( $team->is_moving ) {
+
+ # Probably there should go the actions still doable when moving.
+ return;
+ }
+
+ # TODO: Handle explore when implemented.
+ # These are static actions.
+ if ( $location->is_spawn ) {
+ push @actions, $location->healing_action;
+ }
+ my $location_actions = $location->actions($self);
+ @actions = ( @actions, @$location_actions );
+ return \@actions;
+}
with 'LasTres::CombatCapableEntity';
1;
diff --git a/lib/LasTres/Schema/Result/Team.pm b/lib/LasTres/Schema/Result/Team.pm
index 107799e..74ce178 100644
--- a/lib/LasTres/Schema/Result/Team.pm
+++ b/lib/LasTres/Schema/Result/Team.pm
@@ -4,6 +4,7 @@ use v5.36.0;
use strict;
use warnings;
+use utf8;
use parent 'DBIx::Class::Core';
@@ -81,7 +82,14 @@ __PACKAGE__->add_columns(
},
);
+sub append_log_line ( $self, $line ) {
+ for my $member ( $self->combat_members->@* ) {
+ $member->append_log_line($line);
+ }
+}
+
sub is_defeated ($self) {
+ $self = $self->get_from_storage;
my @members = $self->members;
my @alive_members = grep { $_->health > 0 } @members;
if ( !scalar @alive_members ) {
@@ -103,9 +111,19 @@ sub combat_members_serializable ( $self, $pj = undef ) {
sub on_win_combat ($self) {
}
-sub on_lose_combat ($self) {
+sub on_blackout ($self) {
+ for my $pj ( $self->members ) {
+ $pj->append_log_line(
+ [
+ {
+ text =>
+'No queda nadie en el equipo que pueda luchar, volvéis al último punto de aparición.'
+ }
+ ]
+ );
+ }
require LasTres::Redis;
- my $redis = LasTres::Redis->new;
+ my $redis = LasTres::Redis->new;
my $last_spawn = $self->get_spawn;
$last_spawn->place_team($self);
$self->is_moving(0);
@@ -117,10 +135,13 @@ sub on_lose_combat ($self) {
}
$self->update;
for my $pj ( $self->members ) {
- $redis->publish( $redis->pj_subscription($pj),
- to_json( { command => 'update-team-sprites' } ) );
+ $pj->update_team_sprites;
+ $pj->update_location;
}
+}
+sub on_lose_combat ($self) {
+ $self->on_blackout;
}
sub update ($self) {
@@ -188,7 +209,7 @@ sub combat_members ($self) {
return [@members];
}
-sub on_end_combat($self) {
+sub on_end_combat ($self) {
require LasTres::Redis;
my $redis = LasTres::Redis->new;
for my $pj ( $self->members ) {
@@ -219,7 +240,6 @@ sub from_serializable ( $class, $hash ) {
}
__PACKAGE__->set_primary_key('uuid');
-__PACKAGE__->add_unique_constraint( u_name => ['name'] );
__PACKAGE__->has_many( 'members', 'LasTres::Schema::Result::PJ', 'team' );
__PACKAGE__->belongs_to( 'leader', 'LasTres::Schema::Result::PJ' );
diff --git a/public/img/skull.png b/public/img/skull.png
new file mode 100644
index 0000000..92d5a34
Binary files /dev/null and b/public/img/skull.png differ
diff --git a/public/js/bundle.js b/public/js/bundle.js
index 7757dda..367282b 100644
--- a/public/js/bundle.js
+++ b/public/js/bundle.js
@@ -86,7 +86,7 @@ eval("\n\nif (false) {} else {\n module.exports = __webpack_require__(/*! ./cjs
\********************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
-eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ BottomPanel)\n/* harmony export */ });\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ \"./node_modules/react/index.js\");\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _lastres_components_presentation_item__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @lastres/components/presentation-item */ \"./js-src/components/presentation-item.tsx\");\n/* harmony import */ var _lastres_components_presentation__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @lastres/components/presentation */ \"./js-src/components/presentation.tsx\");\n\n\n\nfunction BottomPanel() {\n return (react__WEBPACK_IMPORTED_MODULE_0__.createElement(_lastres_components_presentation__WEBPACK_IMPORTED_MODULE_2__[\"default\"], null,\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(_lastres_components_presentation_item__WEBPACK_IMPORTED_MODULE_1__[\"default\"], null, \"hola\")));\n}\n\n\n//# sourceURL=webpack://LasTres/./js-src/components/bottom-panel.tsx?");
+eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ BottomPanel)\n/* harmony export */ });\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ \"./node_modules/react/index.js\");\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _lastres_components_presentation_item__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @lastres/components/presentation-item */ \"./js-src/components/presentation-item.tsx\");\n/* harmony import */ var _lastres_components_presentation__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @lastres/components/presentation */ \"./js-src/components/presentation.tsx\");\n\n\n\nfunction BottomPanel() {\n return (react__WEBPACK_IMPORTED_MODULE_0__.createElement(_lastres_components_presentation__WEBPACK_IMPORTED_MODULE_2__[\"default\"], null,\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(_lastres_components_presentation_item__WEBPACK_IMPORTED_MODULE_1__[\"default\"], null),\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(_lastres_components_presentation_item__WEBPACK_IMPORTED_MODULE_1__[\"default\"], null),\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(_lastres_components_presentation_item__WEBPACK_IMPORTED_MODULE_1__[\"default\"], null),\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(_lastres_components_presentation_item__WEBPACK_IMPORTED_MODULE_1__[\"default\"], null)));\n}\n\n\n//# sourceURL=webpack://LasTres/./js-src/components/bottom-panel.tsx?");
/***/ }),
@@ -96,7 +96,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac
\************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
-eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ Game)\n/* harmony export */ });\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ \"./node_modules/react/index.js\");\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _lastres_components_upper_panel__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @lastres/components/upper-panel */ \"./js-src/components/upper-panel.tsx\");\n/* harmony import */ var _lastres_components_bottom_panel__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @lastres/components/bottom-panel */ \"./js-src/components/bottom-panel.tsx\");\n/* harmony import */ var _lastres_components_pj_selection_menu__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @lastres/components/pj-selection-menu */ \"./js-src/components/pj-selection-menu.tsx\");\n/* harmony import */ var _lastres_output_packet_init__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @lastres/output-packet/init */ \"./js-src/output-packet/init.ts\");\n/* harmony import */ var _lastres_output_packet_ping__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @lastres/output-packet/ping */ \"./js-src/output-packet/ping.ts\");\n/* harmony import */ var _lastres_input_packets__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! @lastres/input-packets */ \"./js-src/input-packets.ts\");\n\n\n\n\n\n\n\nfunction Game(props) {\n const selectedPJ = props.selectedPJ;\n if (selectedPJ === null) {\n return (react__WEBPACK_IMPORTED_MODULE_0__.createElement(react__WEBPACK_IMPORTED_MODULE_0__.Fragment, null,\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(_lastres_components_pj_selection_menu__WEBPACK_IMPORTED_MODULE_3__[\"default\"], { setSelectedPJ: props.setSelectedPJ, userWantsToCreatePJ: props.userWantsToCreatePJ, setUserWantsToCreatePJ: props.setUserWantsToCreatePJ, error: props.error, setError: props.setError })));\n }\n const [teamPJs, setTeamPJs] = react__WEBPACK_IMPORTED_MODULE_0__.useState(null);\n const [enemyTeamPJs, setEnemyTeamPJs] = react__WEBPACK_IMPORTED_MODULE_0__.useState(null);\n const [isBattling, setIsBattling] = react__WEBPACK_IMPORTED_MODULE_0__.useState(null);\n const [currentLocation, setCurrentLocation] = react__WEBPACK_IMPORTED_MODULE_0__.useState(null);\n const [connectedLocations, setConnectedLocations] = react__WEBPACK_IMPORTED_MODULE_0__.useState(null);\n const [logLines, setLogLines] = react__WEBPACK_IMPORTED_MODULE_0__.useState(null);\n const [error, setError] = react__WEBPACK_IMPORTED_MODULE_0__.useState(null);\n const [scrollLog, setScrollLog] = react__WEBPACK_IMPORTED_MODULE_0__.useState(null);\n const [movingTo, setMovingTo] = react__WEBPACK_IMPORTED_MODULE_0__.useState(null);\n const [remainingFrames, setRemainingFrames] = react__WEBPACK_IMPORTED_MODULE_0__.useState(null);\n const logPresentationRef = react__WEBPACK_IMPORTED_MODULE_0__.useRef(null);\n const websocket = props.websocket;\n const setWebsocket = props.setWebsocket;\n window.setTimeout(() => {\n setWebsocket((websocket) => {\n if (websocket === null) {\n const locationProtocol = window.location.protocol;\n if (locationProtocol == null) {\n return null;\n }\n const protocol = locationProtocol.match(/https:/) != null ? 'wss' : 'ws';\n const webSocket = new WebSocket(`${protocol}://${window.location.host}/ws`);\n webSocket.onopen = () => {\n new _lastres_output_packet_init__WEBPACK_IMPORTED_MODULE_4__[\"default\"](selectedPJ.uuid).send(webSocket);\n let interval = 0;\n interval = window.setInterval(() => {\n if (webSocket.readyState === WebSocket.OPEN) {\n new _lastres_output_packet_ping__WEBPACK_IMPORTED_MODULE_5__[\"default\"]().send(webSocket);\n return;\n }\n window.clearInterval(interval);\n }, 250000);\n };\n const inputPackets = new _lastres_input_packets__WEBPACK_IMPORTED_MODULE_6__[\"default\"](setTeamPJs, setEnemyTeamPJs, setIsBattling, setCurrentLocation, setConnectedLocations, logLines, setLogLines, setError, setScrollLog, logPresentationRef, setMovingTo, setRemainingFrames);\n webSocket.onmessage = (event) => {\n const packet = JSON.parse(event.data);\n inputPackets.handle(packet);\n };\n webSocket.onerror = (event) => {\n console.log(event);\n };\n webSocket.onclose = (event) => {\n console.log('Websocket closed');\n setWebsocket(null);\n };\n return webSocket;\n }\n return websocket;\n });\n }, 100);\n return (react__WEBPACK_IMPORTED_MODULE_0__.createElement(react__WEBPACK_IMPORTED_MODULE_0__.Fragment, null,\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(_lastres_components_upper_panel__WEBPACK_IMPORTED_MODULE_1__[\"default\"], { teamPJs: teamPJs, enemyTeamPJs: enemyTeamPJs, isBattling: isBattling, currentLocation: currentLocation, connectedLocations: connectedLocations, logLines: logLines, websocket: websocket, logPresentationRef: logPresentationRef, movingTo: movingTo, remainingFrames: remainingFrames }),\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(_lastres_components_bottom_panel__WEBPACK_IMPORTED_MODULE_2__[\"default\"], null)));\n}\n\n\n//# sourceURL=webpack://LasTres/./js-src/components/game.tsx?");
+eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ Game)\n/* harmony export */ });\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ \"./node_modules/react/index.js\");\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _lastres_components_upper_panel__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @lastres/components/upper-panel */ \"./js-src/components/upper-panel.tsx\");\n/* harmony import */ var _lastres_components_bottom_panel__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @lastres/components/bottom-panel */ \"./js-src/components/bottom-panel.tsx\");\n/* harmony import */ var _lastres_components_pj_selection_menu__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @lastres/components/pj-selection-menu */ \"./js-src/components/pj-selection-menu.tsx\");\n/* harmony import */ var _lastres_output_packet_init__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @lastres/output-packet/init */ \"./js-src/output-packet/init.ts\");\n/* harmony import */ var _lastres_output_packet_ping__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @lastres/output-packet/ping */ \"./js-src/output-packet/ping.ts\");\n/* harmony import */ var _lastres_input_packets__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! @lastres/input-packets */ \"./js-src/input-packets.ts\");\n\n\n\n\n\n\n\nfunction Game(props) {\n const selectedPJ = props.selectedPJ;\n if (selectedPJ === null) {\n return (react__WEBPACK_IMPORTED_MODULE_0__.createElement(react__WEBPACK_IMPORTED_MODULE_0__.Fragment, null,\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(_lastres_components_pj_selection_menu__WEBPACK_IMPORTED_MODULE_3__[\"default\"], { setSelectedPJ: props.setSelectedPJ, userWantsToCreatePJ: props.userWantsToCreatePJ, setUserWantsToCreatePJ: props.setUserWantsToCreatePJ, error: props.error, setError: props.setError })));\n }\n const [teamPJs, setTeamPJs] = react__WEBPACK_IMPORTED_MODULE_0__.useState(null);\n const [enemyTeamPJs, setEnemyTeamPJs] = react__WEBPACK_IMPORTED_MODULE_0__.useState(null);\n const [isBattling, setIsBattling] = react__WEBPACK_IMPORTED_MODULE_0__.useState(null);\n const [currentLocation, setCurrentLocation] = react__WEBPACK_IMPORTED_MODULE_0__.useState(null);\n const [connectedLocations, setConnectedLocations] = react__WEBPACK_IMPORTED_MODULE_0__.useState(null);\n const [logLines, setLogLines] = react__WEBPACK_IMPORTED_MODULE_0__.useState(null);\n const [error, setError] = react__WEBPACK_IMPORTED_MODULE_0__.useState(null);\n const [scrollLog, setScrollLog] = react__WEBPACK_IMPORTED_MODULE_0__.useState(null);\n const [movingTo, setMovingTo] = react__WEBPACK_IMPORTED_MODULE_0__.useState(null);\n const [remainingFrames, setRemainingFrames] = react__WEBPACK_IMPORTED_MODULE_0__.useState(null);\n const logPresentationRef = react__WEBPACK_IMPORTED_MODULE_0__.useRef(null);\n const websocket = props.websocket;\n const setWebsocket = props.setWebsocket;\n window.setTimeout(() => {\n setWebsocket((websocket) => {\n if (websocket === null) {\n const locationProtocol = window.location.protocol;\n if (locationProtocol == null) {\n return null;\n }\n const protocol = locationProtocol.match(/https:/) != null ? 'wss' : 'ws';\n const webSocket = new WebSocket(`${protocol}://${window.location.host}/ws`);\n webSocket.onopen = () => {\n new _lastres_output_packet_init__WEBPACK_IMPORTED_MODULE_4__[\"default\"](selectedPJ.uuid).send(webSocket);\n let interval = 0;\n interval = window.setInterval(() => {\n if (webSocket.readyState === WebSocket.CONNECTING) {\n return;\n }\n if (webSocket.readyState === WebSocket.OPEN) {\n new _lastres_output_packet_ping__WEBPACK_IMPORTED_MODULE_5__[\"default\"]().send(webSocket);\n return;\n }\n window.clearInterval(interval);\n }, 1000);\n };\n const inputPackets = new _lastres_input_packets__WEBPACK_IMPORTED_MODULE_6__[\"default\"](setTeamPJs, setEnemyTeamPJs, setIsBattling, setCurrentLocation, setConnectedLocations, logLines, setLogLines, setError, setScrollLog, logPresentationRef, setMovingTo, setRemainingFrames);\n webSocket.onmessage = (event) => {\n const packet = JSON.parse(event.data);\n inputPackets.handle(packet);\n };\n webSocket.onerror = (event) => {\n console.log(event);\n };\n webSocket.onclose = (event) => {\n console.log('Websocket closed');\n setWebsocket(null);\n };\n return webSocket;\n }\n return websocket;\n });\n }, 10);\n return (react__WEBPACK_IMPORTED_MODULE_0__.createElement(react__WEBPACK_IMPORTED_MODULE_0__.Fragment, null,\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(_lastres_components_upper_panel__WEBPACK_IMPORTED_MODULE_1__[\"default\"], { teamPJs: teamPJs, enemyTeamPJs: enemyTeamPJs, isBattling: isBattling, currentLocation: currentLocation, connectedLocations: connectedLocations, logLines: logLines, websocket: websocket, logPresentationRef: logPresentationRef, movingTo: movingTo, remainingFrames: remainingFrames }),\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(_lastres_components_bottom_panel__WEBPACK_IMPORTED_MODULE_2__[\"default\"], null)));\n}\n\n\n//# sourceURL=webpack://LasTres/./js-src/components/game.tsx?");
/***/ }),
@@ -156,7 +156,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac
\********************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
-eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ PJListItem)\n/* harmony export */ });\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ \"./node_modules/react/index.js\");\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _lastres_components_pj_health_like_bar__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @lastres/components/pj-health-like-bar */ \"./js-src/components/pj-health-like-bar.tsx\");\n\n\nfunction PJListItem(props) {\n const pj = props.pj;\n function avatar() {\n if (pj.image === undefined) {\n return react__WEBPACK_IMPORTED_MODULE_0__.createElement(react__WEBPACK_IMPORTED_MODULE_0__.Fragment, null);\n }\n return react__WEBPACK_IMPORTED_MODULE_0__.createElement(react__WEBPACK_IMPORTED_MODULE_0__.Fragment, null,\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"img\", { src: pj.image }),\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"div\", { className: \"shadow\" }));\n }\n function printExperience() {\n if (pj.experience_to_next_level_current === undefined || pj.experience_to_next_level_complete === undefined) {\n return react__WEBPACK_IMPORTED_MODULE_0__.createElement(react__WEBPACK_IMPORTED_MODULE_0__.Fragment, null);\n }\n return (react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"p\", null,\n \"Experiencia: \",\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"span\", { style: { color: 'red' } }, pj.experience_to_next_level_current),\n \"/\",\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"span\", { style: { color: 'green' } }, pj.experience_to_next_level_complete)));\n }\n return (react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"div\", { className: \"pj-list-item\" },\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"div\", { className: \"avatar\" }, avatar()),\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"div\", { className: \"data\" },\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"p\", null,\n pj.nick,\n \" Nivel \",\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"span\", { style: { color: 'red' } },\n pj.level,\n \".\")),\n printExperience(),\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"label\", { className: \"bar-container\" },\n \"Salud\",\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(_lastres_components_pj_health_like_bar__WEBPACK_IMPORTED_MODULE_1__[\"default\"], { value: pj.health, max: pj.max_health })),\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"label\", { className: \"bar-container\" },\n \"Mana\",\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(_lastres_components_pj_health_like_bar__WEBPACK_IMPORTED_MODULE_1__[\"default\"], { value: pj.mana, max: pj.max_mana })))));\n}\n\n\n//# sourceURL=webpack://LasTres/./js-src/components/pj-list-item.tsx?");
+eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (/* binding */ PJListItem)\n/* harmony export */ });\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ \"./node_modules/react/index.js\");\n/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var _lastres_components_pj_health_like_bar__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @lastres/components/pj-health-like-bar */ \"./js-src/components/pj-health-like-bar.tsx\");\n\n\nfunction PJListItem(props) {\n const pj = props.pj;\n function avatar() {\n if (pj.image === undefined) {\n return react__WEBPACK_IMPORTED_MODULE_0__.createElement(react__WEBPACK_IMPORTED_MODULE_0__.Fragment, null);\n }\n const image = pj.health > 0 ? pj.image : '/img/skull.png';\n return react__WEBPACK_IMPORTED_MODULE_0__.createElement(react__WEBPACK_IMPORTED_MODULE_0__.Fragment, null,\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"img\", { src: image }),\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"div\", { className: \"shadow\" }));\n }\n function printExperience() {\n if (pj.experience_to_next_level_current === undefined || pj.experience_to_next_level_complete === undefined) {\n return react__WEBPACK_IMPORTED_MODULE_0__.createElement(react__WEBPACK_IMPORTED_MODULE_0__.Fragment, null);\n }\n return (react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"p\", null,\n \"Experiencia: \",\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"span\", { style: { color: 'red' } }, pj.experience_to_next_level_current),\n \"/\",\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"span\", { style: { color: 'green' } }, pj.experience_to_next_level_complete)));\n }\n return (react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"div\", { className: \"pj-list-item\" },\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"div\", { className: \"avatar\" }, avatar()),\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"div\", { className: \"data\" },\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"p\", null,\n pj.nick,\n \" Nivel \",\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"span\", { style: { color: 'red' } },\n pj.level,\n \".\")),\n printExperience(),\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"label\", { className: \"bar-container\" },\n \"Salud\",\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(_lastres_components_pj_health_like_bar__WEBPACK_IMPORTED_MODULE_1__[\"default\"], { value: pj.health, max: pj.max_health })),\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"label\", { className: \"bar-container\" },\n \"Mana\",\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(_lastres_components_pj_health_like_bar__WEBPACK_IMPORTED_MODULE_1__[\"default\"], { value: pj.mana, max: pj.max_mana })))));\n}\n\n\n//# sourceURL=webpack://LasTres/./js-src/components/pj-list-item.tsx?");
/***/ }),