Adding known word, npcs in locations, auto empty npcs and actions in
locations, etc.
This commit is contained in:
parent
c189bb1f08
commit
cbecf68f9f
@ -1,6 +1,8 @@
|
||||
import * as React from 'react'
|
||||
|
||||
import type { Action, ActionHash } from '@lastres/action'
|
||||
import type { TalkNPCs, TalkNPC } from '@lastres/talk-npc'
|
||||
|
||||
import OutputPacketExecuteAction from '@lastres/output-packet/execute_action'
|
||||
|
||||
import PresentationItem from '@lastres/components/presentation-item'
|
||||
@ -9,7 +11,7 @@ import Presentation from '@lastres/components/presentation'
|
||||
export interface BottomPanelProps {
|
||||
websocket: WebSocket | null
|
||||
actionHash: ActionHash | null
|
||||
|
||||
talkNPCs: TalkNPCs | null
|
||||
}
|
||||
|
||||
export interface Style {
|
||||
@ -71,6 +73,45 @@ export default function BottomPanel (props: BottomPanelProps): JSX.Element {
|
||||
}
|
||||
</>
|
||||
}
|
||||
function printAvatar (npc: TalkNPC): JSX.Element {
|
||||
if (npc.icon === undefined) {
|
||||
return <></>
|
||||
}
|
||||
return <div className="avatar">
|
||||
<img src={npc.icon}/><div className="shadow"/>
|
||||
</div>
|
||||
}
|
||||
function printTalkNpcs (): JSX.Element {
|
||||
const npcs = props.talkNPCs
|
||||
if (npcs === null) {
|
||||
return <></>
|
||||
}
|
||||
return (
|
||||
<>
|
||||
{
|
||||
Object.keys(npcs).map((identifier) => {
|
||||
const npc = npcs[identifier]
|
||||
return <div key={npc.identifier} className="talk-npc">
|
||||
<div className="detail">
|
||||
<div className="name-container">
|
||||
{
|
||||
printAvatar(npc)
|
||||
}
|
||||
<div className="name">
|
||||
<p>{npc.name}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="buttons">
|
||||
<button>Hablar.</button>
|
||||
<button>Decir palabra.</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
})
|
||||
}
|
||||
</>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<Presentation>
|
||||
<PresentationItem>
|
||||
@ -79,6 +120,9 @@ export default function BottomPanel (props: BottomPanelProps): JSX.Element {
|
||||
}
|
||||
</PresentationItem>
|
||||
<PresentationItem>
|
||||
{
|
||||
printTalkNpcs()
|
||||
}
|
||||
</PresentationItem>
|
||||
<PresentationItem>
|
||||
</PresentationItem>
|
||||
|
@ -4,6 +4,7 @@ import type { PJ } from '@lastres/pj'
|
||||
import type { Location } from '@lastres/location'
|
||||
import type { LogLine } from '@lastres/log-line'
|
||||
import type { ActionHash } from '@lastres/action'
|
||||
import type { TalkNPCs } from '@lastres/talk-npc'
|
||||
|
||||
import UpperPanel from '@lastres/components/upper-panel'
|
||||
import BottomPanel from '@lastres/components/bottom-panel'
|
||||
@ -49,13 +50,14 @@ export default function Game (props: GameProps): JSX.Element {
|
||||
const [movingTo, setMovingTo] = React.useState<Location | null>(null)
|
||||
const [remainingFrames, setRemainingFrames] = React.useState<number | null>(null)
|
||||
const [actionHash, setActionHash] = React.useState<ActionHash | null>(null)
|
||||
const [talkNPCs, setTalkNPCs] = React.useState<TalkNPCs | null>(null)
|
||||
const logPresentationRef = React.useRef<HTMLDivElement>(null)
|
||||
const websocket = props.websocket
|
||||
const setWebsocket = props.setWebsocket
|
||||
window.setTimeout(() => {
|
||||
setWebsocket((websocket): WebSocket | null => {
|
||||
if (websocket === null) {
|
||||
console.log('Opening websocket');
|
||||
console.log('Opening websocket')
|
||||
const locationProtocol = window.location.protocol
|
||||
if (locationProtocol == null) {
|
||||
return null
|
||||
@ -74,7 +76,7 @@ export default function Game (props: GameProps): JSX.Element {
|
||||
return
|
||||
}
|
||||
window.clearInterval(interval)
|
||||
}, 1000)
|
||||
}, 100000)
|
||||
}
|
||||
const inputPackets = new InputPackets(setTeamPJs,
|
||||
setEnemyTeamPJs, setIsBattling,
|
||||
@ -82,7 +84,7 @@ export default function Game (props: GameProps): JSX.Element {
|
||||
logLines, setLogLines, setError,
|
||||
setScrollLog, logPresentationRef,
|
||||
setMovingTo, setRemainingFrames,
|
||||
setActionHash)
|
||||
setActionHash, setTalkNPCs)
|
||||
webSocket.onmessage = (event) => {
|
||||
const packet = JSON.parse(event.data)
|
||||
inputPackets.handle(packet)
|
||||
@ -111,7 +113,9 @@ export default function Game (props: GameProps): JSX.Element {
|
||||
logPresentationRef={logPresentationRef}
|
||||
movingTo={movingTo}
|
||||
remainingFrames={remainingFrames}/>
|
||||
<BottomPanel actionHash={actionHash} websocket={websocket}/>
|
||||
<BottomPanel actionHash={actionHash}
|
||||
websocket={websocket}
|
||||
talkNPCs={talkNPCs}/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ import type { Location } from '@lastres/location'
|
||||
import type InputPacket from '@lastres/input-packet'
|
||||
import type { LogLine } from '@lastres/log-line'
|
||||
import type { ActionHash } from '@lastres/action'
|
||||
import type { TalkNPCs } from '@lastres/talk-npc'
|
||||
import InputPacketInfo from '@lastres/input-packet/info'
|
||||
import InputPacketPong from '@lastres/input-packet/pong'
|
||||
|
||||
@ -21,6 +22,7 @@ type LogPresentationRef = React.RefObject<HTMLDivElement>
|
||||
type SetMovingTo = (set: Location | null) => void
|
||||
type SetRemainingFrames = (set: number | null) => void
|
||||
type SetActionHash = (set: ActionHash | null) => void
|
||||
type SetTalkNPCs = (set: TalkNPCs | null) => void
|
||||
|
||||
interface Packet {
|
||||
command: string
|
||||
@ -44,6 +46,7 @@ export default class InputPackets {
|
||||
setMovingTo: SetMovingTo
|
||||
setRemainingFrames: SetRemainingFrames
|
||||
setActionHash: SetActionHash
|
||||
setTalkNPCs: SetTalkNPCs
|
||||
constructor (setTeamPJs: SetTeamPJs,
|
||||
setEnemyTeamPJs: SetEnemyTeamPJs,
|
||||
setIsBattling: SetIsBattling,
|
||||
@ -56,7 +59,8 @@ export default class InputPackets {
|
||||
logPresentationRef: LogPresentationRef,
|
||||
setMovingTo: SetMovingTo,
|
||||
setRemainingFrames: SetRemainingFrames,
|
||||
setActionHash: SetActionHash) {
|
||||
setActionHash: SetActionHash,
|
||||
setTalkNPCs: SetTalkNPCs) {
|
||||
this.setTeamPJs = setTeamPJs
|
||||
this.setEnemyTeamPJs = setEnemyTeamPJs
|
||||
this.setCurrentLocation = setCurrentLocation
|
||||
@ -70,6 +74,7 @@ export default class InputPackets {
|
||||
this.setRemainingFrames = setRemainingFrames
|
||||
this.setIsBattling = setIsBattling
|
||||
this.setActionHash = setActionHash
|
||||
this.setTalkNPCs = setTalkNPCs
|
||||
}
|
||||
|
||||
handle (packet: Packet): void {
|
||||
@ -143,6 +148,9 @@ export default class InputPackets {
|
||||
this.setMovingTo(null)
|
||||
}
|
||||
}
|
||||
if (data.npcs !== undefined) {
|
||||
this.setTalkNPCs(data.npcs)
|
||||
}
|
||||
if (data.remaining_frames !== undefined) {
|
||||
this.setRemainingFrames(data.remaining_frames)
|
||||
}
|
||||
|
@ -8,6 +8,8 @@ use utf8;
|
||||
use Moo;
|
||||
use List::AllUtils;
|
||||
|
||||
use JSON qw/to_json/;
|
||||
|
||||
sub identifier {
|
||||
return 'execute_action';
|
||||
}
|
||||
|
@ -79,6 +79,7 @@ sub handle ( $self, $ws, $session, $data ) {
|
||||
$self->_enemy_team_pjs($session),
|
||||
clear => $JSON::true,
|
||||
$self->_available_actions($pj),
|
||||
$self->_npcs($pj),
|
||||
);
|
||||
$info_packet_to_send->send($ws);
|
||||
my $redis = LasTres::Redis->new;
|
||||
@ -104,6 +105,15 @@ sub _enemy_team_pjs ( $self, $session ) {
|
||||
);
|
||||
}
|
||||
|
||||
sub _npcs ( $self, $pj ) {
|
||||
my $npcs_hash = $pj->talk_npcs;
|
||||
for my $identifier ( keys %$npcs_hash ) {
|
||||
my $npc = $npcs_hash->{$identifier};
|
||||
$npcs_hash->{$identifier} = $npc->hash;
|
||||
}
|
||||
return ( npcs => $npcs_hash );
|
||||
}
|
||||
|
||||
sub _location_data ( $self, $pj ) {
|
||||
my $connected_places = $self->_get_connected_places($pj);
|
||||
my $team = $pj->team->get_from_storage;
|
||||
@ -163,11 +173,12 @@ sub _on_redis_event ( $self, $ws, $session, $message, $topic, $topics ) {
|
||||
}
|
||||
if ( $data->{command} eq 'update-actions' ) {
|
||||
LasTres::Controller::Websocket::OutputPacket::Info->new(
|
||||
$self->_available_actions($pj) )->send($ws);
|
||||
$self->_available_actions($pj),
|
||||
$self->_npcs($pj) )->send($ws);
|
||||
}
|
||||
}
|
||||
|
||||
sub _available_actions ($self, $pj) {
|
||||
sub _available_actions ( $self, $pj ) {
|
||||
return ( available_actions =>
|
||||
{ map { $_->identifier => $_->hash($pj) } $pj->actions->@* }, );
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ has is_battling => ( is => 'rw' );
|
||||
|
||||
has remaining_frames => ( is => 'rw' );
|
||||
has available_actions => ( is => 'rw' );
|
||||
has npcs => ( is => 'rw' );
|
||||
|
||||
sub identifier {
|
||||
return 'info';
|
||||
@ -42,6 +43,7 @@ sub data ($self) {
|
||||
my $remaining_frames = $self->remaining_frames;
|
||||
my $is_battling = $self->is_battling;
|
||||
my $available_actions = $self->available_actions;
|
||||
my $npcs = $self->npcs;
|
||||
|
||||
if ( defined $is_battling ) {
|
||||
$is_battling = $is_battling ? $JSON::true : $JSON::false;
|
||||
@ -82,7 +84,11 @@ sub data ($self) {
|
||||
? ( available_actions => $available_actions )
|
||||
: ()
|
||||
),
|
||||
|
||||
(
|
||||
(defined $npcs)
|
||||
? ( npcs => $npcs)
|
||||
: ()
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -8,4 +8,7 @@ use warnings;
|
||||
sub INTRO_MESSAGE_SENT_FLAG {
|
||||
return 'INTRO_MESSAGE_FLAG_SENT';
|
||||
}
|
||||
sub TALKED_WITH_OLD_MAN_AND_LEARNED_TO_SAY_DEVOTA {
|
||||
return 'TALKED_WITH_OLD_MAN_AND_LEARNED_TO_SAY_DEVOTA';
|
||||
}
|
||||
1;
|
||||
|
@ -13,16 +13,31 @@ use Moo::Role;
|
||||
use JSON qw/to_json from_json/;
|
||||
use utf8;
|
||||
|
||||
requires qw/identifier name description parent actions npcs/;
|
||||
requires qw/identifier name description parent/;
|
||||
|
||||
## Implement action($self, $pj);
|
||||
## Implement npcs($self, $pj);
|
||||
## Implement description($self, $pj = undef);
|
||||
# Will be printed to the user.
|
||||
## Implement name($self, $pj = undef);
|
||||
## Implement identifier($self, $pj = undef);
|
||||
# Must be unique across locations of this area.
|
||||
|
||||
my $planets = LasTres::Planets->new;
|
||||
|
||||
## OVERRIDE
|
||||
# The available actions to do in
|
||||
# this location, must return hashref,
|
||||
# can be an empty one though.
|
||||
sub actions($self, $pj) {
|
||||
return [];
|
||||
}
|
||||
## OVERRIDE
|
||||
# The available persons to talk with
|
||||
# Must return a hashref, can be a empty
|
||||
# one though.
|
||||
sub npcs($self, $pj) {
|
||||
return [];
|
||||
}
|
||||
|
||||
## OVERRIDE
|
||||
# Whenever a player can visit this place.
|
||||
# The player to compute will always be the leader.
|
||||
|
@ -90,12 +90,19 @@ sub _start_battle ( $self, $pj ) {
|
||||
}
|
||||
]);
|
||||
|
||||
my $max_level_rabbit = 3;
|
||||
if ($pj->level > 7) {
|
||||
$max_level_rabbit = 4;
|
||||
}
|
||||
if ($pj->level > 9) {
|
||||
$max_level_rabbit = 8;
|
||||
}
|
||||
my $battle = LasTres::Battle->start_battle_machine($team,
|
||||
[
|
||||
LasTres::EnemyArea->new(
|
||||
race => 'conejo',
|
||||
nick => 'Conejo territorial.',
|
||||
level => LasTres::Util::rand_range_int(1,3),
|
||||
level => LasTres::Util::rand_range_int(1,$max_level_rabbit),
|
||||
)
|
||||
]
|
||||
);
|
||||
|
@ -27,14 +27,6 @@ sub parent {
|
||||
return LasTres::Planet::Bahdder::BosqueDelHeroe::BosqueDelHeroeI->instance;
|
||||
}
|
||||
|
||||
sub actions {
|
||||
return [];
|
||||
}
|
||||
|
||||
sub npcs {
|
||||
return [];
|
||||
}
|
||||
|
||||
sub connected_places {
|
||||
return [
|
||||
LasTres::Planet::Bahdder::BosqueDelHeroe::TribuDeLaLima::Entrada->instance,
|
||||
|
@ -30,14 +30,6 @@ sub parent {
|
||||
return LasTres::Planet::Bahdder::BosqueDelHeroe::BosqueDelHeroeI->instance;
|
||||
}
|
||||
|
||||
sub actions {
|
||||
return [];
|
||||
}
|
||||
|
||||
sub npcs {
|
||||
return [];
|
||||
}
|
||||
|
||||
sub connected_places {
|
||||
return [
|
||||
LasTres::Planet::Bahdder::BosqueDelHeroe::TribuDeLaLima::Entrada->instance,
|
||||
|
@ -34,11 +34,11 @@ sub parent {
|
||||
return LasTres::Planet::Bahdder::BosqueDelHeroe::TribuDeLaLima->instance;
|
||||
}
|
||||
|
||||
sub actions {
|
||||
sub actions($self, $pj) {
|
||||
return [ LasTres::PJAction::GolpearArbolCentralTribuDeLaLima->new ];
|
||||
}
|
||||
|
||||
sub npcs {
|
||||
sub npcs($self, $pj) {
|
||||
return [ LasTres::TalkingNPC::AncianoTribuLima->new ];
|
||||
}
|
||||
|
||||
|
@ -42,14 +42,6 @@ sub _build_parent {
|
||||
return LasTres::Planet::Bahdder::BosqueDelHeroe::TribuDeLaLima->instance;
|
||||
}
|
||||
|
||||
sub actions {
|
||||
return [];
|
||||
}
|
||||
|
||||
sub npcs {
|
||||
return [];
|
||||
}
|
||||
|
||||
sub connected_places {
|
||||
return [
|
||||
LasTres::Planet::Bahdder::BosqueDelHeroe::BosqueDelHeroeI::TribuDeLaLima->instance,
|
||||
|
@ -5,7 +5,7 @@ use v5.36.0;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
our $VERSION = 12;
|
||||
our $VERSION = 13;
|
||||
|
||||
use feature 'signatures';
|
||||
|
||||
|
@ -6,9 +6,10 @@ use strict;
|
||||
use warnings;
|
||||
|
||||
use feature 'signatures';
|
||||
use parent 'DBIx::Class::Core';
|
||||
use utf8;
|
||||
|
||||
use parent 'DBIx::Class::Core';
|
||||
|
||||
use UUID::URandom qw/create_uuid_string/;
|
||||
use List::AllUtils;
|
||||
use Data::Dumper;
|
||||
@ -122,6 +123,8 @@ __PACKAGE__->has_many( 'logs', 'LasTres::Schema::Result::PJLog', 'owner' );
|
||||
__PACKAGE__->has_many( 'known_places',
|
||||
'LasTres::Schema::Result::PJKnownPlaces', 'owner' );
|
||||
__PACKAGE__->has_many( 'flags', 'LasTres::Schema::Result::PJFlag', 'owner' );
|
||||
__PACKAGE__->has_many( 'known_words', 'LasTres::Schema::Result::PJKnownWord',
|
||||
'owner' );
|
||||
__PACKAGE__->belongs_to( 'born_stats', 'LasTres::Schema::Result::Stats' );
|
||||
__PACKAGE__->belongs_to( 'training_stats', 'LasTres::Schema::Result::Stats' );
|
||||
__PACKAGE__->belongs_to( 'inventory', 'LasTres::Schema::Result::Inventory' );
|
||||
@ -131,6 +134,53 @@ __PACKAGE__->belongs_to( 'equipment', 'LasTres::Schema::Result::Equipment' );
|
||||
__PACKAGE__->belongs_to( 'team', 'LasTres::Schema::Result::Team' );
|
||||
__PACKAGE__->belongs_to( 'owner', 'LasTres::Schema::Result::Player' );
|
||||
|
||||
sub knows_word ( $self, $word ) {
|
||||
$self = $self->get_from_storage;
|
||||
if ( !$word->does('LasTres::Word') ) {
|
||||
die 'The received word does not implement LasTres::Word.';
|
||||
}
|
||||
my @words =
|
||||
$self->known_words->search( { identifier => $word->identifier } );
|
||||
if ( !scalar @words ) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub teach_word ( $self, $word ) {
|
||||
require LasTres::Schema;
|
||||
my $schema = LasTres::Schema->Schema;
|
||||
my $result_set_words = $schema->resultset('PJKnownWord');
|
||||
$self = $self->get_from_storage;
|
||||
if ( !$word->does('LasTres::Word') ) {
|
||||
die 'The received word does not implement LasTres::Word.';
|
||||
}
|
||||
if ($self->knows_word($word)) {
|
||||
return;
|
||||
}
|
||||
my $known_word = $result_set_words->new(
|
||||
{ identifier => $word->identifier, owner => $self->uuid } );
|
||||
$known_word->insert;
|
||||
my $team = $self->team;
|
||||
$team->append_log_line([
|
||||
{
|
||||
color => 'green',
|
||||
text => $self->nick,
|
||||
},
|
||||
{
|
||||
text => ' aprendió la palabra '
|
||||
},
|
||||
{
|
||||
color => 'purple',
|
||||
text => $word->name,
|
||||
},
|
||||
{
|
||||
text => '.'
|
||||
}
|
||||
]);
|
||||
|
||||
}
|
||||
|
||||
sub knows_location ( $self, $location ) {
|
||||
require LasTres::Schema;
|
||||
my $schema = LasTres::Schema->Schema;
|
||||
@ -470,7 +520,7 @@ sub update_location ($self) {
|
||||
to_json( { command => 'update-location' } ) );
|
||||
}
|
||||
|
||||
sub update_actions($self) {
|
||||
sub update_actions ($self) {
|
||||
require LasTres::Redis;
|
||||
my $redis = LasTres::Redis->new;
|
||||
$redis->publish( $redis->pj_subscription($self),
|
||||
@ -503,7 +553,27 @@ sub actions ($self) {
|
||||
return \@actions;
|
||||
}
|
||||
|
||||
sub talking_npcs($self) {
|
||||
sub talk_npcs ($self) {
|
||||
my @npcs;
|
||||
$self = $self->get_from_storage;
|
||||
my $team = $self->team;
|
||||
my $location = $team->location;
|
||||
if ( defined $team->battle ) {
|
||||
return $self->_npc_list_to_hash( \@npcs );
|
||||
}
|
||||
if ( $team->is_moving ) {
|
||||
return $self->_npc_list_to_hash( \@npcs );
|
||||
}
|
||||
my $location_npcs = $location->npcs($self);
|
||||
@npcs = ( @npcs, @$location_npcs );
|
||||
return $self->_npc_list_to_hash( \@npcs );
|
||||
}
|
||||
|
||||
sub _npc_list_to_hash ( $self, $npcs ) {
|
||||
return { map { ( $_->identifier => $_ ) } @$npcs };
|
||||
}
|
||||
|
||||
sub talking_npcs ($self) {
|
||||
return [];
|
||||
}
|
||||
|
||||
|
36
lib/LasTres/Schema/Result/PJKnownWord.pm
Normal file
36
lib/LasTres/Schema/Result/PJKnownWord.pm
Normal file
@ -0,0 +1,36 @@
|
||||
package LasTres::Schema::Result::PJKnownWord;
|
||||
|
||||
use v5.36.0;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use feature 'signatures';
|
||||
|
||||
use parent 'DBIx::Class::Core';
|
||||
|
||||
use Data::Dumper;
|
||||
|
||||
use Moo;
|
||||
|
||||
__PACKAGE__->table('player_pjs_known_words');
|
||||
|
||||
__PACKAGE__->add_columns(
|
||||
identifier => {
|
||||
data_type => 'text',
|
||||
is_nullable => 0,
|
||||
},
|
||||
owner => {
|
||||
data_type => 'uuid',
|
||||
is_nullable => 0,
|
||||
is_foreign_key => 1,
|
||||
},
|
||||
);
|
||||
|
||||
__PACKAGE__->set_primary_key( 'owner', 'identifier' );
|
||||
|
||||
__PACKAGE__->belongs_to( 'owner', 'LasTres::Schema::Result::PJ' );
|
||||
|
||||
sub sqlt_deploy_hook ( $self, $sqlt_table ) {
|
||||
$sqlt_table->add_index( name => 'index_known_word', fields => [qw/owner identifier/] );
|
||||
}
|
||||
1;
|
@ -24,21 +24,34 @@ requires qw/identifier name/;
|
||||
## IMPLEMENTORS MUST EXTEND
|
||||
# sub talk($self,$pj,$word);
|
||||
|
||||
## DO NOT EXTEND NOT SUPPORTED.
|
||||
sub hash ($self) {
|
||||
return {
|
||||
identifier => $self->identifier,
|
||||
name => $self->name,
|
||||
(
|
||||
( defined $self->icon )
|
||||
? ( icon => $self->icon )
|
||||
: ()
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
## OVERRIDE
|
||||
sub icon {
|
||||
return undef;
|
||||
return;
|
||||
}
|
||||
|
||||
## OVERRIDE
|
||||
sub color ( $self, $pj ) {
|
||||
return 'blue',;
|
||||
return 'blue';
|
||||
}
|
||||
|
||||
## OVERRIDE
|
||||
# Refer to show_wordlessly_talk_started for
|
||||
# detail about when it is convenient to
|
||||
# override.
|
||||
sub show_told_word($self, $pj, $word) {
|
||||
sub show_told_word ( $self, $pj, $word ) {
|
||||
my $team = $pj->team;
|
||||
$team->append_log_line(
|
||||
[
|
||||
@ -85,7 +98,7 @@ sub show_told_word($self, $pj, $word) {
|
||||
# },
|
||||
# {
|
||||
# text => ' ladra a ',
|
||||
#
|
||||
#
|
||||
# },
|
||||
# {
|
||||
# text => $pj,
|
||||
@ -97,7 +110,7 @@ sub show_told_word($self, $pj, $word) {
|
||||
# ]
|
||||
# );
|
||||
# }
|
||||
sub show_wordlessly_talk_started($self, $pj) {
|
||||
sub show_wordlessly_talk_started ( $self, $pj ) {
|
||||
my $team = $pj->team;
|
||||
$team->append_log_line(
|
||||
[
|
||||
@ -133,14 +146,14 @@ sub talk ( $self, $pj, $word ) {
|
||||
$pj = $pj->get_from_storage;
|
||||
my $team = $pj->team;
|
||||
if ( defined $word ) {
|
||||
$self->show_told_word($pj, $word);
|
||||
$self->show_told_word( $pj, $word );
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
## OVERRIDE
|
||||
sub verb($self, $pj) {
|
||||
sub verb ( $self, $pj ) {
|
||||
return 'dice';
|
||||
}
|
||||
|
||||
@ -154,7 +167,8 @@ sub send_response_dialog ( $self, $pj, $array_text ) {
|
||||
$team->append_log_line(
|
||||
[
|
||||
{ text => $self->name($pj), color => $self->color($pj) },
|
||||
{ text => " @{[$self->verb($pj)]}.- " }, @$array_text
|
||||
{ text => " @{[$self->verb($pj)]}.- " },
|
||||
@$array_text
|
||||
]
|
||||
);
|
||||
}
|
||||
@ -162,8 +176,9 @@ sub send_response_dialog ( $self, $pj, $array_text ) {
|
||||
## DO NOT EXTEND NOT SUPPORTED.
|
||||
{
|
||||
my %hash;
|
||||
sub instance($class) {
|
||||
if (!exists $hash{$class}) {
|
||||
|
||||
sub instance ($class) {
|
||||
if ( !exists $hash{$class} ) {
|
||||
$hash{$class} = $class->new;
|
||||
}
|
||||
return $hash{$class};
|
||||
|
@ -9,6 +9,8 @@ use feature 'signatures';
|
||||
|
||||
use Moo;
|
||||
|
||||
use LasTres::Flags;
|
||||
|
||||
with 'LasTres::TalkingNPC';
|
||||
|
||||
sub talk ( $self, $pj, $word ) {
|
||||
@ -22,11 +24,23 @@ sub identifier {
|
||||
return 'anciano_tribu_de_la_lima';
|
||||
}
|
||||
|
||||
sub icon {
|
||||
return '/img/anciano.png';
|
||||
}
|
||||
|
||||
sub name {
|
||||
return 'Anciano';
|
||||
}
|
||||
|
||||
sub wordlessly_talk ( $self, $pj ) {
|
||||
if ($pj->get_flag(LasTres::Flags::TALKED_WITH_OLD_MAN_AND_LEARNED_TO_SAY_DEVOTA)) {
|
||||
$self->send_response_dialog([
|
||||
{
|
||||
text => '¿A que esperas, ve a hablar con la Devota?'
|
||||
}
|
||||
]);
|
||||
return;
|
||||
}
|
||||
$self->send_response_dialog(
|
||||
[
|
||||
{
|
||||
@ -43,5 +57,6 @@ sub wordlessly_talk ( $self, $pj ) {
|
||||
}
|
||||
]
|
||||
);
|
||||
$pj->set_flag(LasTres::Flags::TALKED_WITH_OLD_MAN_AND_LEARNED_TO_SAY_DEVOTA);
|
||||
}
|
||||
1;
|
||||
|
@ -17,4 +17,16 @@ requires qw/name identifier/;
|
||||
# Identifier must be unique across words, failure
|
||||
# to do so can result in a error or undefined
|
||||
# behavior.
|
||||
|
||||
## DO NOT EXTEND NOT SUPPORTED.
|
||||
{
|
||||
my %hash;
|
||||
|
||||
sub instance ($class) {
|
||||
if ( !exists $hash{$class} ) {
|
||||
$hash{$class} = $class->new;
|
||||
}
|
||||
return $hash{$class};
|
||||
}
|
||||
}
|
||||
1;
|
||||
|
16
lib/LasTres/Word/Devota.pm
Normal file
16
lib/LasTres/Word/Devota.pm
Normal file
@ -0,0 +1,16 @@
|
||||
package LasTres::Word::Devota;
|
||||
|
||||
use v5.36.0;
|
||||
use strict;
|
||||
use warnings;
|
||||
use utf8;
|
||||
|
||||
use feature 'signatures';
|
||||
|
||||
sub name {
|
||||
return 'Devota';
|
||||
}
|
||||
|
||||
sub identifier {
|
||||
return 'devota';
|
||||
}
|
@ -11,6 +11,48 @@ body {
|
||||
padding: 0px;
|
||||
height: 100vh;
|
||||
background: ghostwhite; }
|
||||
body div.talk-npc div.detail {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border-radius: 3px;
|
||||
min-height: 100px;
|
||||
border: solid 1px black;
|
||||
align-items: center;
|
||||
align-content: center;
|
||||
justify-content: center; }
|
||||
body div.talk-npc div.name-container {
|
||||
display: flex;
|
||||
padding: 10px; }
|
||||
body div.talk-npc div.name-container div.avatar {
|
||||
width: 100%;
|
||||
aspect-ratio: 1/1;
|
||||
border-radius: 50%;
|
||||
background: lightgray;
|
||||
margin-right: 2%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative; }
|
||||
body div.talk-npc div.name-container div.avatar img {
|
||||
animation-name: move-avatar;
|
||||
animation-duration: 0.5s;
|
||||
animation-iteration-count: infinite;
|
||||
width: 80%;
|
||||
aspect-ratio: 1/1;
|
||||
z-index: 1; }
|
||||
body div.talk-npc div.name-container div.avatar div.shadow {
|
||||
top: 78%;
|
||||
position: absolute;
|
||||
width: 50%;
|
||||
aspect-ratio: 7/2;
|
||||
background: darkgray;
|
||||
border-radius: 50%; }
|
||||
body div.talk-npc div.name-container div.name {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center; }
|
||||
body div.talk-npc div.buttons {
|
||||
padding: 10px; }
|
||||
body label.bar-container {
|
||||
width: 90%; }
|
||||
body label.bar-container div.bar {
|
||||
|
@ -14,6 +14,57 @@ body {
|
||||
padding: 0px;
|
||||
height: 100vh;
|
||||
background: ghostwhite;
|
||||
div.talk-npc {
|
||||
div.detail {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border-radius: 3px;
|
||||
min-height: 100px;
|
||||
border: solid 1px black;
|
||||
align-items: center;
|
||||
align-content: center;
|
||||
justify-content: center;
|
||||
}
|
||||
div.name-container {
|
||||
display: flex;
|
||||
padding: 10px;
|
||||
div.avatar {
|
||||
width: 100%;
|
||||
aspect-ratio: 1/1;
|
||||
border-radius: 50%;
|
||||
background: lightgray;
|
||||
margin-right: 2%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
img {
|
||||
animation-name: move-avatar;
|
||||
animation-duration: 0.5s;
|
||||
animation-iteration-count: infinite;
|
||||
width: 80%;
|
||||
aspect-ratio: 1/1;
|
||||
z-index: 1;
|
||||
}
|
||||
div.shadow {
|
||||
top: 78%;
|
||||
position: absolute;
|
||||
width: 50%;
|
||||
aspect-ratio: 7/2;
|
||||
background: darkgray;
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
||||
div.name {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
div.buttons {
|
||||
padding: 10px;
|
||||
}
|
||||
}
|
||||
label.bar-container {
|
||||
width: 90%;
|
||||
div.bar {
|
||||
|
BIN
public/img/anciano.png
Normal file
BIN
public/img/anciano.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 78 KiB |
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user