Skip to content

Commit

Permalink
* デバッグできないのでコマンド追加
Browse files Browse the repository at this point in the history
* ゲームとしておみくじを追加
* 翻訳を追加
  • Loading branch information
nmori committed Jan 1, 2024
1 parent 7cc57d9 commit c798ffd
Show file tree
Hide file tree
Showing 8 changed files with 316 additions and 4 deletions.
2 changes: 2 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"type": "node",
"request": "launch",
"name": "Electron: Main",
"env": {"NODE_ENV": "development"},
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron",
"runtimeArgs": [
".",
Expand All @@ -14,6 +15,7 @@
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron.cmd"
},
"outputCapture": "std",
"sourceMaps": true,
"preLaunchTask": "grunt-prep"
},
{
Expand Down
3 changes: 2 additions & 1 deletion src/backend/games/builtin-game-loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ exports.loadGames = () => {
'bid/bid',
'heist/heist',
'slots/slots',
'trivia/trivia'
'trivia/trivia',
'omikuji/omikuji'
].forEach(filename => {
const definition = require(`./builtin/${filename}.js`);
gameManager.registerGame(definition);
Expand Down
141 changes: 141 additions & 0 deletions src/backend/games/builtin/omikuji/omikuji-command.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
"use strict";

const util = require("../../../utility");
const twitchChat = require("../../../chat/twitch-chat");
const commandManager = require("../../../chat/commands/CommandManager");
const gameManager = require("../../game-manager");
const currencyDatabase = require("../../../database/currencyDatabase");
const customRolesManager = require("../../../roles/custom-roles-manager");
const teamRolesManager = require("../../../roles/team-roles-manager");
const twitchRolesManager = require("../../../../shared/twitch-roles");
const omikujiMachine = require("./omikuji-machine");
const logger = require("../../../logwrapper");
const moment = require("moment");
const NodeCache = require("node-cache");

const activeOmikuji = new NodeCache({checkperiod: 2});
const cooldownCache = new NodeCache({checkperiod: 5});

const OMIKUJI_COMMAND_ID = "firebot:omikuji";

const omikujiCommand = {
definition: {
id: OMIKUJI_COMMAND_ID,
name: "おみくじをひく",
active: true,
trigger: "!omikuji",
description: "おみくじを開始します",
autoDeleteTrigger: false,
scanWholeMessage: false,
hideCooldowns: true,
subCommands: [
]
},
onTriggerEvent: async event => {

const { userCommand } = event;

const omikujiSettings = gameManager.getGameSettings("firebot-omikuji");
const chatter = omikujiSettings.settings.chatSettings.chatter;
const username = userCommand.commandSender;

let wagerAmount = omikujiSettings.settings.currencySettings.defaultWager;

if (activeOmikuji.get(username)) {
if (omikujiSettings.settings.generalMessages.alreadySpinning) {
const alreadySpinningMsg = omikujiSettings.settings.generalMessages.alreadySpinning
.replace("{username}", username);

await twitchChat.sendChatMessage(alreadySpinningMsg, null, chatter);
}

return;
}

const cooldownExpireTime = cooldownCache.get(username);
if (cooldownExpireTime && moment().isBefore(cooldownExpireTime)) {
if (omikujiSettings.settings.generalMessages.onCooldown) {
const timeRemainingDisplay = util.secondsForHumans(Math.abs(moment().diff(cooldownExpireTime, 'seconds')));
const cooldownMsg = omikujiSettings.settings.generalMessages.onCooldown
.replace("{username}", username).replace("{timeRemaining}", timeRemainingDisplay);

await twitchChat.sendChatMessage(cooldownMsg, null, chatter);
}

return;
}


const currencyId = omikujiSettings.settings.currencySettings.currencyId;
let userBalance;
try {
userBalance = await currencyDatabase.getUserCurrencyAmount(username, currencyId);
} catch (error) {
logger.error(error);
userBalance = 0;
}

if (userBalance < wagerAmount) {
if (omikujiSettings.settings.generalMessages.notEnough) {
const notEnoughMsg = omikujiSettings.settings.generalMessages.notEnough
.replace("{username}", username);

await twitchChat.sendChatMessage(notEnoughMsg, null, chatter);
}

return;
}

activeOmikuji.set(username, true);

const cooldownSecs = omikujiSettings.settings.cooldownSettings.cooldown;
if (cooldownSecs && cooldownSecs > 0) {
const expireTime = moment().add(cooldownSecs, 'seconds');
cooldownCache.set(username, expireTime, cooldownSecs);
}

try {
await currencyDatabase.adjustCurrencyForUser(username, currencyId, -Math.abs(wagerAmount));
} catch (error) {
logger.error(error);
await twitchChat.sendChatMessage(`Sorry ${username}, there was an error deducting currency from your balance so the spin has been canceled.`, null, chatter);
activeOmikuji.del(username);
return;
}

const spinInActionMsg = omikujiSettings.settings.generalMessages.spinInAction
.replace("{username}", username);
const omikujiList = omikujiSettings.settings.omikujiSettings.OmikujiSpec;
const showSpinInActionMsg = !!omikujiSettings.settings.generalMessages.spinInAction;
const successfulResult = await omikujiMachine.omikuji(showSpinInActionMsg, spinInActionMsg, omikujiList, chatter);

if (omikujiSettings.settings.generalMessages.spinSuccessful) {
const spinSuccessfulMsg = omikujiSettings.settings.generalMessages.spinSuccessful
.replace("{username}", username)
.replace("{omikujiResult}", successfulResult);
await twitchChat.sendChatMessage(spinSuccessfulMsg, null, chatter);
}

activeOmikuji.del(username);

}
};

function registerSpinCommand() {
if (!commandManager.hasSystemCommand(OMIKUJI_COMMAND_ID)) {
commandManager.registerSystemCommand(omikujiCommand);
}
}

function unregisterSpinCommand() {
commandManager.unregisterSystemCommand(OMIKUJI_COMMAND_ID);
}

function purgeCaches() {
cooldownCache.flushAll();
activeOmikuji.flushAll();
}

exports.purgeCaches = purgeCaches;
exports.registerSpinCommand = registerSpinCommand;
exports.unregisterSpinCommand = unregisterSpinCommand;
23 changes: 23 additions & 0 deletions src/backend/games/builtin/omikuji/omikuji-machine.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
"use strict";
const twitchChat = require("../../../chat/twitch-chat");
const util = require("../../../utility");

async function omikuji(showSpinInActionMsg, spinInActionMsg, OmikujiSpec, chatter) {

let successCount = 0;

if (showSpinInActionMsg) {
await twitchChat.sendChatMessage(spinInActionMsg, null, chatter);
}

await util.wait(2000);

var omikujiSpecArray = OmikujiSpec.split('\n');

var seed = Date.now();
var randomIndex = Math.floor(seed % omikujiSpecArray.length);
var randomElement = omikujiSpecArray[randomIndex];
return randomElement;
}

exports.omikuji = omikuji;
144 changes: 144 additions & 0 deletions src/backend/games/builtin/omikuji/omikuji.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
"use strict";

const spinCommand = require("./omikuji-command");

/**
* @type {import('../../game-manager').FirebotGame}
*/
module.exports = {
id: "firebot-omikuji",
name: "おみくじ",
subtitle: "おみくじを引きます",
description: "おみくじをひきます。「!omikuji」と入力して、おみくじと賞金を決定します!",
icon: "fa-solid fa-ticket",
settingCategories: {
currencySettings: {
title: "通貨設定",
sortRank: 1,
settings: {
currencyId: {
type: "currency-select",
title: "通貨",
description: "このゲームで使用する通貨",
sortRank: 1,
validation: {
required: true
}
},
defaultWager: {
type: "number",
title: "おみくじ金額",
description: "おみくじを引くのに必要な金額。",
placeholder: "金額を入れる",
tip: "必須",
sortRank: 2,
validation: {
min: 0
}
}
}
},
omikujiSettings: {
title: "回転設定",
sortRank: 2,
settings: {
OmikujiSpec: {
type: "string",
title: "おみくじの種類",
description: "おみくじの役名を1行1役でいれます",
useTextArea: true,
default: "大吉\n小吉\n吉\n末吉\n凶\n大凶",
tip: "2つ以上いれましょう",
sortRank: 1
}
}
},
cooldownSettings: {
title: "再実行までの待ち時間",
sortRank: 3,
settings: {
cooldown: {
type: "number",
title: "待ち時間 (秒)",
placeholder: "時間を入れる",
tip: "待ち時間は視聴者ごとに適用されます",
default: 300,
validation: {
min: 0
}
}
}
},
generalMessages: {
title: "一般メッセージ",
sortRank: 5,
settings: {
alreadySpinning: {
type: "string",
title: "すでに、おみくじ中",
description: "おみくじの指示が速すぎる場合(メッセージが不要な場合は空白にします)",
useTextArea: true,
default: "{username}、今おみくじ引いているところですよ",
tip: "有効な変数 variables: {username}",
sortRank: 1
},
onCooldown: {
type: "string",
title: "再実行までの待ち時間中",
description: "ユーザーが待ち時間を満了していない時(メッセージが不要な場合は空白にします)",
useTextArea: true,
default: "{username}, 再度おみくじを引くまでの残り時間: {timeRemaining}",
tip: "有効な変数: {username}, {timeRemaining}",
sortRank: 2
},
notEnough: {
type: "string",
title: "不十分",
description: "選択した金額を賭けるだけの十分な資金がない場合(メッセージなしの場合は空欄のまま)。",
useTextArea: true,
default: "{username}, この金額を賭けるだけの資金がありません",
tip: "有効な変数: {username}",
sortRank: 8
},
spinInAction: {
type: "string",
title: "おみくじ中",
description: "おみくじが行われている時(メッセージなしの場合は空欄のまま)",
useTextArea: true,
default: "{username}の運勢は...",
tip: "有効な変数: {username}",
sortRank: 9
},
spinSuccessful: {
type: "string",
title: "おみくじ完了",
description: "おみくじが終了した時(メッセージなしの場合は空欄のまま)",
useTextArea: true,
default: "{username}の運勢は {omikujiResult} でした!",
tip: "有効な変数: {username}, {omikujiResult}",
sortRank: 10
}
}
},
chatSettings: {
title: "チャット設定",
sortRank: 6,
settings: {
chatter: {
type: "chatter-select",
title: "アカウント"
}
}
}
},
onLoad: () => {
spinCommand.registerSpinCommand();
},
onUnload: () => {
spinCommand.unregisterSpinCommand();
spinCommand.purgeCaches();
},
onSettingsUpdate: () => {
spinCommand.purgeCaches();
}
};
2 changes: 1 addition & 1 deletion src/backend/games/builtin/slots/slots.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ module.exports = {
id: "firebot-slots",
name: "スロット",
subtitle: "回して勝つ",
description: "Tこのゲームでは、視聴者がスロットマシンで通貨を賭けることができます。必要なのは、チャットで「!spin [wagerAmount]」と入力してレバーを引くだけである!レバーを引くと、3つのリールが回転し、それぞれHITまたはMISSします。HITした数が賞金を決定します!",
description: "このゲームでは、視聴者がスロットマシンで通貨を賭けることができます。必要なのは、チャットで「!spin [wagerAmount]」と入力してレバーを引くだけである!レバーを引くと、3つのリールが回転し、それぞれHITまたはMISSします。HITした数が賞金を決定します!",
icon: "fa-dice-three",
settingCategories: {
currencySettings: {
Expand Down
2 changes: 1 addition & 1 deletion src/gui/app/directives/sidebar/sidebar.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
<ul class="pl-0">
<nav-link page="Chat Feed" name="{{'SIDEBAR.CHAT.CHAT_FEED' | translate }}" icon="fa-signal-stream"></nav-link>
<nav-category name="Triggers" pad-top="true"></nav-category>
<nav-category name="{{'SIDEBAR.TRIGGER' | translate }}" pad-top="true"></nav-category>
<nav-link page="Commands" name="{{'SIDEBAR.CHAT.COMMANDS' | translate }}" icon="fa-exclamation"></nav-link>
<nav-link page="Events" name="{{'SIDEBAR.OTHER.EVENTS' | translate }}" icon="fa-list"></nav-link>
<nav-link page="Timers" name="{{'SIDEBAR.OTHER.TIME_BASED' | translate }}" icon="fa-stopwatch"></nav-link>
Expand Down
3 changes: 2 additions & 1 deletion src/gui/app/lang/locale-ja.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@
"MIXER_TOGGLE": "クリックで接続変更",
"OPEN_CONNECTION_PANNEL": "接続パネルを開く"
},
"ABOUT": "ツールについて"
"ABOUT": "ツールについて",
"TRIGGER": "起動条件"
},
"BUTTONS": {
"BUTTONS": "ボタン",
Expand Down

0 comments on commit c798ffd

Please sign in to comment.