diff --git a/js-src/components/bottom-panel.tsx b/js-src/components/bottom-panel.tsx
index 758bd78..a8e3d21 100644
--- a/js-src/components/bottom-panel.tsx
+++ b/js-src/components/bottom-panel.tsx
@@ -1,6 +1,7 @@
import * as React from 'react'
import type { Action, ActionHash } from '@lastres/action'
+import OutputPacketExecuteAction from '@lastres/output-packet/execute_action'
import PresentationItem from '@lastres/components/presentation-item'
import Presentation from '@lastres/components/presentation'
@@ -51,12 +52,21 @@ export default function BottomPanel (props: BottomPanelProps): JSX.Element {
if (action.is_disabled) {
style.background = 'lightgray'
}
- return
+ function onClick (): void {
+ if (action.is_disabled) {
+ return
+ }
+ if (props.websocket !== null) {
+ new OutputPacketExecuteAction(action.identifier)
+ .send(props.websocket)
+ }
+ }
+ return
{action.name}
{
printDisabledReason(action)
}
-
+
})
}
>
diff --git a/js-src/output-packet/execute_action.ts b/js-src/output-packet/execute_action.ts
new file mode 100644
index 0000000..8db95c5
--- /dev/null
+++ b/js-src/output-packet/execute_action.ts
@@ -0,0 +1,23 @@
+import OutputPacket from '@lastres/output-packet'
+
+export interface OutputPacketExecuteActionData {
+ action: string
+}
+
+export default class OutputPacketExecuteAction extends OutputPacket {
+ action: string
+ constructor (action: string) {
+ super()
+ this.action = action
+ }
+
+ command (): string {
+ return 'execute_action'
+ }
+
+ data (): OutputPacketExecuteActionData {
+ return {
+ action: this.action
+ }
+ }
+}
diff --git a/lib/LasTres/Battle.pm b/lib/LasTres/Battle.pm
index 90229cb..dc5a64b 100644
--- a/lib/LasTres/Battle.pm
+++ b/lib/LasTres/Battle.pm
@@ -107,8 +107,6 @@ sub loser ($self) {
sub end ($self) {
require LasTres::Redis;
my $redis = LasTres::Redis->new;
- $self->team1->on_end_combat;
- $self->team2->on_end_combat;
$self->team1->current_battle(undef);
$self->team1->update;
if ( defined $self->team2 ) {
@@ -116,6 +114,8 @@ sub end ($self) {
$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 {
diff --git a/lib/LasTres/Controller/Websocket/InputPacket.pm b/lib/LasTres/Controller/Websocket/InputPacket.pm
index d7acb8c..52635c2 100644
--- a/lib/LasTres/Controller/Websocket/InputPacket.pm
+++ b/lib/LasTres/Controller/Websocket/InputPacket.pm
@@ -10,4 +10,7 @@ use feature 'signatures';
use Moo::Role;
requires qw/new handle identifier/;
+
+## IMPLEMENTORS MUST IMPLEMENT
+# sub handle ( $self, $ws, $session, $data );
1;
diff --git a/lib/LasTres/Controller/Websocket/InputPacket/ExecuteAction.pm b/lib/LasTres/Controller/Websocket/InputPacket/ExecuteAction.pm
new file mode 100644
index 0000000..aabba59
--- /dev/null
+++ b/lib/LasTres/Controller/Websocket/InputPacket/ExecuteAction.pm
@@ -0,0 +1,45 @@
+package LasTres::Controller::Websocket::InputPacket::ExecuteAction;
+
+use v5.36.0;
+use strict;
+use warnings;
+use utf8;
+
+use Moo;
+use List::AllUtils;
+
+sub identifier {
+ return 'execute_action';
+}
+
+sub handle ( $self, $ws, $session, $data ) {
+ if ( ref $data ne 'HASH' ) {
+ return $ws->send( to_json( { error => "Data should be a hashref." } ) );
+ }
+ if ( !defined $session->{pj} ) {
+ return $ws->send(
+ to_json( { error => 'The pj for this session does not exist.' } ) );
+ }
+ $session->{pj} = $session->{pj}->get_from_storage;
+ my $pj = $session->{pj};
+ my $action_id = $data->{action};
+ if ( !defined $action_id ) {
+ return $ws->send( to_json( { error => 'No action set.' } ) );
+ }
+ my @actions = $pj->actions->@*;
+ my ($action) = List::AllUtils::onlyres { $_->identifier eq $action_id && $_ } @actions;
+ if (!defined $action) {
+ return $ws->send( to_json( { error => "Could not find action $action_id." } ) );
+ }
+ if ( $action->is_disabled($pj) ) {
+ return $ws->send( to_json( { error => "@{[$action->identifier]} is disabled." } ) );
+ }
+ $action->callback($pj);
+ my $team = $pj->team;
+ for my $member ( $team->combat_members->@* ) {
+ $member->update_team_sprites;
+ $member->update_location;
+ $member->update_actions;
+ }
+}
+1;
diff --git a/lib/LasTres/Controller/Websocket/InputPacket/MoveBetweenLocations.pm b/lib/LasTres/Controller/Websocket/InputPacket/MoveBetweenLocations.pm
index 9ba4976..f17f150 100644
--- a/lib/LasTres/Controller/Websocket/InputPacket/MoveBetweenLocations.pm
+++ b/lib/LasTres/Controller/Websocket/InputPacket/MoveBetweenLocations.pm
@@ -44,14 +44,14 @@ sub handle ( $self, $ws, $session, $data ) {
return $ws->send( to_json( { error => "The location is malformed" } ) );
}
$session->{pj} = $session->{pj}->get_from_storage;
- my $pj = $session->{pj};
- if ( !defined $pj ) {
+ if ( !defined $session->{pj} ) {
return $ws->send(
to_json(
{ error => 'You have not set a pj yet for this websocket.' }
)
);
}
+ my $pj = $session->{pj};
my $team = $pj->team;
my $leader = $team->leader;
if ( $leader->uuid ne $pj->uuid ) {
diff --git a/lib/LasTres/Location.pm b/lib/LasTres/Location.pm
index 807d3d0..0db6d88 100644
--- a/lib/LasTres/Location.pm
+++ b/lib/LasTres/Location.pm
@@ -103,6 +103,7 @@ sub on_pj_arrival ( $self, $pj ) {
}
$self->show_intro($pj);
$pj->update_location;
+ $pj->update_team_sprites;
$pj->update_actions;
}
@@ -170,6 +171,7 @@ sub on_pj_moving ( $self, $pj ) {
);
$pj->update_location;
$pj->update_actions;
+ $pj->update_team_sprites;
}
## DO NOT EXTEND NOT SUPPORTED.
diff --git a/lib/LasTres/PJAction/DefaultHeal.pm b/lib/LasTres/PJAction/DefaultHeal.pm
index b88f447..4700a8b 100644
--- a/lib/LasTres/PJAction/DefaultHeal.pm
+++ b/lib/LasTres/PJAction/DefaultHeal.pm
@@ -67,7 +67,6 @@ sub callback($self, $pj) {
$member->health($member->max_health);
$member->mana($member->max_mana);
$member->update;
- $member->update_team_sprites;
}
if (Scalar::Util::blessed($self) eq __PACKAGE__) {
$self->_callback_unique_sleep($pj);
diff --git a/lib/LasTres/Schema/Result/Team.pm b/lib/LasTres/Schema/Result/Team.pm
index 74ce178..497503a 100644
--- a/lib/LasTres/Schema/Result/Team.pm
+++ b/lib/LasTres/Schema/Result/Team.pm
@@ -137,6 +137,7 @@ sub on_blackout ($self) {
for my $pj ( $self->members ) {
$pj->update_team_sprites;
$pj->update_location;
+ $pj->update_actions;
}
}
@@ -213,8 +214,9 @@ sub on_end_combat ($self) {
require LasTres::Redis;
my $redis = LasTres::Redis->new;
for my $pj ( $self->members ) {
- $redis->publish( $redis->pj_subscription($pj),
- to_json( { command => 'update-team-sprites' } ) );
+ $pj->update_team_sprites;
+ $pj->update_location;
+ $pj->update_actions;
}
}
diff --git a/public/css/styles.css b/public/css/styles.css
index 05cc650..172ba52 100644
--- a/public/css/styles.css
+++ b/public/css/styles.css
@@ -20,7 +20,7 @@ body {
body label.bar-container div.bar div.filled {
background: lightgreen;
height: 100%; }
- body div.action {
+ body a.action {
border: solid 1px black;
text-decoration: underline;
display: flex;
@@ -28,9 +28,8 @@ body {
align-content: center;
justify-content: center;
align-items: center;
- flex-direction: column;
- width: 100%; }
- body div.action div.disabled-reason {
+ flex-direction: column; }
+ body a.action div.disabled-reason {
text-decoration: none; }
body div.pj-list-item {
display: flex;
diff --git a/public/css/styles.scss b/public/css/styles.scss
index 0c53485..437215f 100644
--- a/public/css/styles.scss
+++ b/public/css/styles.scss
@@ -26,7 +26,7 @@ body {
}
}
}
- div.action {
+ a.action {
border: solid 1px black;
text-decoration: underline;
display: flex;
@@ -35,7 +35,6 @@ body {
justify-content: center;
align-items: center;
flex-direction: column;
- width: 100%;
div.disabled-reason {
text-decoration: none;
}
diff --git a/public/js/bundle.js b/public/js/bundle.js
index e4c924d..529a979 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(props) {\n const actionHash = props.actionHash;\n function printListActions() {\n if (actionHash === null) {\n return react__WEBPACK_IMPORTED_MODULE_0__.createElement(react__WEBPACK_IMPORTED_MODULE_0__.Fragment, null);\n }\n const listOfActionKeys = Object.keys(actionHash).sort((a, b) => {\n const isDisabledComparisionValue = +actionHash[a].is_disabled - +actionHash[b].is_disabled;\n if (isDisabledComparisionValue !== 0) {\n return isDisabledComparisionValue;\n }\n if (actionHash[a].name < actionHash[b].name) {\n return -1;\n }\n if (actionHash[a].name > actionHash[b].name) {\n return 1;\n }\n return 0;\n });\n function printDisabledReason(action) {\n if (!action.is_disabled || action.disabled_reason === null) {\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\", { className: \"disabled-reason\", style: { color: 'red' } }, action.disabled_reason));\n }\n return react__WEBPACK_IMPORTED_MODULE_0__.createElement(react__WEBPACK_IMPORTED_MODULE_0__.Fragment, null,\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"p\", null, \"Acciones disponibles.\"),\n listOfActionKeys.map((key) => {\n const style = {};\n const action = actionHash[key];\n if (action.is_disabled) {\n style.background = 'lightgray';\n }\n return react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"div\", { className: \"action\", style: style, key: action.identifier },\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"p\", null, action.name),\n printDisabledReason(action));\n }));\n }\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, printListActions()),\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?");
+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_output_packet_execute_action__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @lastres/output-packet/execute_action */ \"./js-src/output-packet/execute_action.ts\");\n/* harmony import */ var _lastres_components_presentation_item__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @lastres/components/presentation-item */ \"./js-src/components/presentation-item.tsx\");\n/* harmony import */ var _lastres_components_presentation__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @lastres/components/presentation */ \"./js-src/components/presentation.tsx\");\n\n\n\n\nfunction BottomPanel(props) {\n const actionHash = props.actionHash;\n function printListActions() {\n if (actionHash === null) {\n return react__WEBPACK_IMPORTED_MODULE_0__.createElement(react__WEBPACK_IMPORTED_MODULE_0__.Fragment, null);\n }\n const listOfActionKeys = Object.keys(actionHash).sort((a, b) => {\n const isDisabledComparisionValue = +actionHash[a].is_disabled - +actionHash[b].is_disabled;\n if (isDisabledComparisionValue !== 0) {\n return isDisabledComparisionValue;\n }\n if (actionHash[a].name < actionHash[b].name) {\n return -1;\n }\n if (actionHash[a].name > actionHash[b].name) {\n return 1;\n }\n return 0;\n });\n function printDisabledReason(action) {\n if (!action.is_disabled || action.disabled_reason === null) {\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\", { className: \"disabled-reason\", style: { color: 'red' } }, action.disabled_reason));\n }\n return react__WEBPACK_IMPORTED_MODULE_0__.createElement(react__WEBPACK_IMPORTED_MODULE_0__.Fragment, null,\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"p\", null, \"Acciones disponibles.\"),\n listOfActionKeys.map((key) => {\n const style = {};\n const action = actionHash[key];\n if (action.is_disabled) {\n style.background = 'lightgray';\n }\n function onClick() {\n if (action.is_disabled) {\n return;\n }\n if (props.websocket !== null) {\n new _lastres_output_packet_execute_action__WEBPACK_IMPORTED_MODULE_1__[\"default\"](action.identifier)\n .send(props.websocket);\n }\n }\n return react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"a\", { onClick: onClick, className: \"action\", style: style, key: action.identifier },\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(\"p\", null, action.name),\n printDisabledReason(action));\n }));\n }\n return (react__WEBPACK_IMPORTED_MODULE_0__.createElement(_lastres_components_presentation__WEBPACK_IMPORTED_MODULE_3__[\"default\"], null,\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(_lastres_components_presentation_item__WEBPACK_IMPORTED_MODULE_2__[\"default\"], null, printListActions()),\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(_lastres_components_presentation_item__WEBPACK_IMPORTED_MODULE_2__[\"default\"], null),\n react__WEBPACK_IMPORTED_MODULE_0__.createElement(_lastres_components_presentation_item__WEBPACK_IMPORTED_MODULE_2__[\"default\"], null)));\n}\n\n\n//# sourceURL=webpack://LasTres/./js-src/components/bottom-panel.tsx?");
/***/ }),
@@ -290,6 +290,16 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpac
/***/ }),
+/***/ "./js-src/output-packet/execute_action.ts":
+/*!************************************************!*\
+ !*** ./js-src/output-packet/execute_action.ts ***!
+ \************************************************/
+/***/ ((__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 */ OutputPacketExecuteAction)\n/* harmony export */ });\n/* harmony import */ var _lastres_output_packet__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @lastres/output-packet */ \"./js-src/output-packet.ts\");\n\nclass OutputPacketExecuteAction extends _lastres_output_packet__WEBPACK_IMPORTED_MODULE_0__[\"default\"] {\n constructor(action) {\n super();\n this.action = action;\n }\n command() {\n return 'execute_action';\n }\n data() {\n return {\n action: this.action\n };\n }\n}\n\n\n//# sourceURL=webpack://LasTres/./js-src/output-packet/execute_action.ts?");
+
+/***/ }),
+
/***/ "./js-src/output-packet/init.ts":
/*!**************************************!*\
!*** ./js-src/output-packet/init.ts ***!
diff --git a/start_docker.sh b/start_docker.sh
index b0d5012..09b67d2 100644
--- a/start_docker.sh
+++ b/start_docker.sh
@@ -8,9 +8,8 @@ DOCKER_BUILD_PARAMS="$CURRENT_DIR -t $DOCKER_TAG"
DOCKER_RUN_PARAMS="run -it -v /var/run/postgresql/:/var/run/postgresql/ -v $CURRENT_DIR:/var/lib/las_tres/LasTres -v /var/run/redis/:/var/run/redis --name LasTresDocker -p 3000:3000 $DOCKER_TAG"
CHECKSUM_DOCKER_FILE="$CURRENT_DIR/.dockerfile_checksum"
-perl -pe 's/\{\{UID\}\}/'"$UID/" Dockerfile.template > Dockerfile
-
OLD_CHECKSUM_DOCKER="$(cat $CHECKSUM_DOCKER_FILE 2> /dev/null)"
+perl -pe 's/\{\{UID\}\}/'"$UID/" Dockerfile.template > Dockerfile
CURRENT_CHECKSUM_DOCKER="$(sha512sum Dockerfile | awk '{ print $1 }')"
if ! [ -f las_tres.yml ]; then
@@ -37,7 +36,7 @@ if [[ $OLD_CHECKSUM_DOCKER != $CURRENT_CHECKSUM_DOCKER ]]; then
echo "$OLD_CHECKSUM_DOCKER != $CURRENT_CHECKSUM_DOCKER rebuilding docker";
echo $SUDO docker container rm LasTresDocker
- $SUDO docker container rm LasTresDocker
+ $SUDO docker container rm LasTresDocker ;
echo $SUDO docker build $DOCKER_BUILD_PARAMS
$SUDO docker build $DOCKER_BUILD_PARAMS
echo $CURRENT_CHECKSUM_DOCKER > $CHECKSUM_DOCKER_FILE