diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e68f9ff..3525ea0c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ # Changelog ## Unreleased +- Add: parameter to define the percentage of points that should be added to the + jackpot. Also enables disabling of the jackpot. - … ## v0.1.1 diff --git a/src/gamble-handler.ts b/src/gamble-handler.ts index 830089fa..d4945294 100644 --- a/src/gamble-handler.ts +++ b/src/gamble-handler.ts @@ -17,16 +17,26 @@ type Logger = { export class GambleHandler { private readonly gamblingMode: GambleMode; private readonly minimumEntry: number; + private readonly jackpotPercent: number; + private readonly jackpotEnabled: boolean; private readonly logger: Logger; - constructor(mode: GambleMode, logger: Logger, minimumEntry: number) { + constructor(mode: GambleMode, logger: Logger, minimumEntry: number, jackpotPercent: number) { this.gamblingMode = mode; this.logger = logger; this.minimumEntry = Math.floor(minimumEntry); + + if (jackpotPercent <= 0) { + this.jackpotPercent = 0; + this.jackpotEnabled = false; + } else { + this.jackpotPercent = jackpotPercent / 100; + this.jackpotEnabled = true; + } } handle(params: Params, entry: GambleEntry): Effect[] { - const gambleResult = this.gamblingMode.winnings(entry.userPointsEntered); + const gambleResult = this.gamblingMode.winnings(entry.userPointsEntered, this.jackpotEnabled); this.logger.info(`${gambleResult}`); return this.gambleResultEffects(params, entry.user, gambleResult); } @@ -55,12 +65,15 @@ export class GambleHandler { const pointsRemove = new CurrencyEffect(params.currencyId, CurrencyAction.Remove, username, result.amount); effects.push(pointsRemove); - const resetJackpot = new UpdateCounterEffect( - params.jackpotCounterId, - UpdateCounterEffectMode.Increment, - result.amount, - ); - effects.push(resetJackpot); + const jackpotAddAmount = Math.floor(result.amount * this.jackpotPercent); + if (jackpotAddAmount > 0) { + const addToJackpot = new UpdateCounterEffect( + params.jackpotCounterId, + UpdateCounterEffectMode.Increment, + jackpotAddAmount, + ); + effects.push(addToJackpot); + } const message = GambleHandler.replaceMessagePlaceholders(params, result, params.messageLost); effects.push(new ChatMessageEffect(message)); diff --git a/src/main.ts b/src/main.ts index 6187786b..661993a0 100644 --- a/src/main.ts +++ b/src/main.ts @@ -19,6 +19,7 @@ export interface Params { jackpotCounterId: string; currentJackpotAmount: string; minimumEntry: number; + jackpotPercent: number; messageJackpotWon: string; messageWon: string; @@ -38,6 +39,7 @@ export function defaultParams(): Params { jackpotCounterId: '71dd1e86-178d-491d-8f61-9c5851faf8a8', currentJackpotAmount: '$counter[jackpot]', minimumEntry: 100, + jackpotPercent: 100, userCurrentPoints: '$currency[points, $user]', messageJackpotWon: 'Rolled %roll. $user won the jackpot of %amount points and now has a total of %newTotal.', @@ -89,6 +91,13 @@ export class GamblingScript implements Firebot.CustomScript { description: 'Minimum Entry', secondaryDescription: 'The minimum amount of points users can gamble.', }, + jackpotPercent: { + type: 'number', + default: params.jackpotPercent, + description: 'Jackpot Percent', + secondaryDescription: + 'Defines which percentage of the lost points should go into the jackpot. Should be >= 0. Values < 0 will be used as 0 and disables the jackpot. E.g. ‘50’ means that 50% of the lost points are added to the jackpot.', + }, messageJackpotWon: { type: 'string', default: params.messageJackpotWon, @@ -139,6 +148,7 @@ export class GamblingScript implements Firebot.CustomScript { new GambleModePercentage(), logger, runRequest.parameters.minimumEntry, + runRequest.parameters.jackpotPercent, ); } diff --git a/src/model/gamble-mode-percentage.ts b/src/model/gamble-mode-percentage.ts index 689411df..df73b19b 100644 --- a/src/model/gamble-mode-percentage.ts +++ b/src/model/gamble-mode-percentage.ts @@ -14,8 +14,10 @@ export class GambleModePercentage implements GambleMode { * - Roll 0: `gamblingAmount` is lost. * * @param gamblingAmount the amount the user entered into the bet. + * @param jackpotEnabled unused. */ - winnings(gamblingAmount: number): GambleResult { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + winnings(gamblingAmount: number, jackpotEnabled: boolean = true): GambleResult { const roll = GambleModePercentage.randIntInclusive(this.maxRoll); if (roll === this.neutralValue) { @@ -39,6 +41,7 @@ export class GambleModePercentage implements GambleMode { * @private */ private static randIntInclusive(max: number): number { + // Node crypto module for proper randomness is not available in Firebot return Math.floor(Math.random() * (max + 1)); } } diff --git a/src/model/gamble-mode.ts b/src/model/gamble-mode.ts index 16db6d43..9f15df84 100644 --- a/src/model/gamble-mode.ts +++ b/src/model/gamble-mode.ts @@ -1,5 +1,5 @@ import { GambleResult } from './gamble-result'; export interface GambleMode { - winnings: (gamblingAmount: number) => GambleResult; + winnings: (gamblingAmount: number, jackpotEnabled: boolean) => GambleResult; } diff --git a/tests/gamble-hander.spec.ts b/tests/gamble-hander.spec.ts index a179eacd..3948df9e 100644 --- a/tests/gamble-hander.spec.ts +++ b/tests/gamble-hander.spec.ts @@ -1,11 +1,11 @@ import { GambleHandler } from '../src/gamble-handler'; import { GambleModePercentage } from '../src/model/gamble-mode-percentage'; -import { ArgumentsOf, replaceMessageParams, mockExpectedRoll } from './helpers'; +import { ArgumentsOf, mockExpectedRoll, replaceMessageParams } from './helpers'; import { ScriptModules } from 'firebot-custom-scripts-types'; import { defaultParams, Params } from '../src/main'; import { GambleResult, GambleResultType } from '../src/model/gamble-result'; import { ChatMessageEffect } from '../src/helpers/effects/chat-message-effect'; -import { CurrencyEffect, CurrencyAction } from '../src/helpers/effects/currency-effect'; +import { CurrencyAction, CurrencyEffect } from '../src/helpers/effects/currency-effect'; import { UpdateCounterEffect, UpdateCounterEffectMode } from '../src/helpers/effects/update-counter-effect'; import { GambleEntry } from '../src/model/gamble-entry'; @@ -16,8 +16,6 @@ const mockLogger = { error: jest.fn>(), }; -const gambleHandler = new GambleHandler(new GambleModePercentage(), mockLogger, 100); - const params = defaultParams(); params.currentJackpotAmount = '1000'; params.userCurrentPoints = '10000'; @@ -61,6 +59,8 @@ describe('The Gambling Handler Message Replacer', () => { }); describe('The Gambling Handler Effect Creator', () => { + const gambleHandler = new GambleHandler(new GambleModePercentage(), mockLogger, 100, 100); + const effectCreator = (params: Params, result: GambleResult) => // @ts-ignore gambleHandler.gambleResultEffects(params, 'pirak__', result); @@ -106,6 +106,8 @@ describe('The Gambling Handler Effect Creator', () => { }); describe('The Gambling Handler', () => { + const gambleHandler = new GambleHandler(new GambleModePercentage(), mockLogger, 100, 100); + it('should for neutral results only create a chat message', async () => { const entry = new GambleEntry('pirak__', 10000, 1000); mockExpectedRoll(50); @@ -148,4 +150,65 @@ describe('The Gambling Handler', () => { expect(gambleHandler.handle(params, entry)).toEqual(expectedEffects); }); + + it('should disable the jackpot for jackpotPercents <= 0', async () => { + const mode = new GambleModePercentage(); + const mockFn = jest + .spyOn(mode, 'winnings') + .mockImplementation(() => new GambleResult(GambleResultType.Lost, 40, 120)); + + const entry = new GambleEntry('pirak__', 10000, 1000); + const gambleHandler = new GambleHandler(mode, mockLogger, 100, 0); + + const expectedEffects = [ + new CurrencyEffect(defaultParams().currencyId, CurrencyAction.Remove, 'pirak__', 120), + new ChatMessageEffect(replaceMessageParams(defaultParams().messageLost, 40, 120, 10000 - 120)), + ]; + + expect(gambleHandler.handle(params, entry)).toEqual(expectedEffects); + expect(mockFn).toHaveBeenCalledWith(1000, false); + + // jackpotPercent -1 should be used as 0 + const gambleHandler2 = new GambleHandler(mode, mockLogger, 100, -1); + expect(gambleHandler2.handle(params, entry)).toEqual(expectedEffects); + expect(mockFn).toHaveBeenCalledWith(1000, false); + }); + + it('should take the jackpot percent into account for values > 0', async () => { + const mode = new GambleModePercentage(); + const mockFn = jest + .spyOn(mode, 'winnings') + .mockImplementationOnce(() => new GambleResult(GambleResultType.Lost, 40, 120)); + + const entry = new GambleEntry('pirak__', 10000, 1000); + const gambleHandler = new GambleHandler(mode, mockLogger, 100, 50); + + const expectedEffects = [ + new CurrencyEffect(defaultParams().currencyId, CurrencyAction.Remove, 'pirak__', 120), + new UpdateCounterEffect(params.jackpotCounterId, UpdateCounterEffectMode.Increment, 60), + new ChatMessageEffect(replaceMessageParams(defaultParams().messageLost, 40, 120, 10000 - 120)), + ]; + + expect(gambleHandler.handle(params, entry)).toEqual(expectedEffects); + expect(mockFn).toHaveBeenCalledWith(1000, true); + }); + + it('should round down the amount added to the jackpot', async () => { + const mode = new GambleModePercentage(); + const mockFn = jest + .spyOn(mode, 'winnings') + .mockImplementationOnce(() => new GambleResult(GambleResultType.Lost, 40, 49)); + + const entry = new GambleEntry('pirak__', 10000, 1000); + const gambleHandler = new GambleHandler(mode, mockLogger, 100, 50); + + const expectedEffects = [ + new CurrencyEffect(defaultParams().currencyId, CurrencyAction.Remove, 'pirak__', 49), + new UpdateCounterEffect(params.jackpotCounterId, UpdateCounterEffectMode.Increment, 24), + new ChatMessageEffect(replaceMessageParams(defaultParams().messageLost, 40, 49, 10000 - 49)), + ]; + + expect(gambleHandler.handle(params, entry)).toEqual(expectedEffects); + expect(mockFn).toHaveBeenCalledWith(1000, true); + }); });