diff options
| author | ilotterytea <iltsu@alright.party> | 2024-10-08 00:28:11 +0500 |
|---|---|---|
| committer | ilotterytea <iltsu@alright.party> | 2024-10-08 00:28:11 +0500 |
| commit | 46c21d8ab1bc51ff6171d4f1482705ac82cfd6ba (patch) | |
| tree | dd5b9e598499d5061d0dca2c39e052b7cf680d59 | |
| parent | 753f8c14974933dc8ac8859e4ccab94d8a6bdedc (diff) | |
feat: SLOTS🤑🤑🎰
21 files changed, 434 insertions, 1 deletions
diff --git a/assets/i18n/en_us.json b/assets/i18n/en_us.json index d318c97..d685e21 100644 --- a/assets/i18n/en_us.json +++ b/assets/i18n/en_us.json @@ -47,6 +47,12 @@ "gifts.points": "[ORANGE]{WAVE=1.0;1.0;0.5}+%s Points{ENDWAVE}{CLEARCOLOR}", "gifts.new_pet": "{RAINBOW}{WAVE=1.0;1.0;0.5}New pet! (%s){ENDWAVE}{ENDRAINBOW}", + "minigame.slots.nothing": "YOU WON NOTHINGG", + "minigame.slots.prize": "YOU WON %s P$", + "minigame.slots.bet": "BET", + "minigame.slots.spin_button": "SPIN", + "minigame.slots.exit_button": " X ", + "game.inventory.title": "Inventory", "pet.bror.name": "The Suspicious and Sleepy Bro", diff --git a/assets/i18n/ru_ru.json b/assets/i18n/ru_ru.json index 1912382..8cf68b0 100644 --- a/assets/i18n/ru_ru.json +++ b/assets/i18n/ru_ru.json @@ -40,6 +40,12 @@ "game.multiplier": "%s/жмяк", "game.newPoint": "{SHAKE}{RAINBOW}+%s{ENDRAINBOW}{ENDSHAKE}", + "minigame.slots.nothing": "ТЫ НИЧЕГО НЕ ВЫИГРАЛ", + "minigame.slots.prize": "ТЫ ВЫИГРАЛ %s P$", + "minigame.slots.bet": "СТАВКА", + "minigame.slots.spin_button": "КРУТАНУТЬ", + "minigame.slots.exit_button": " X ", + "game.inventory.title": "Инвентарь", "dialogs.not_enough_points": "Недостаточно поинтов!", diff --git a/assets/mus/minigames/slots/slots_loop.mp3 b/assets/mus/minigames/slots/slots_loop.mp3 Binary files differnew file mode 100644 index 0000000..be8f331 --- /dev/null +++ b/assets/mus/minigames/slots/slots_loop.mp3 diff --git a/assets/sfx/minigames/slots/slots_big_win.ogg b/assets/sfx/minigames/slots/slots_big_win.ogg Binary files differnew file mode 100644 index 0000000..e42a6b9 --- /dev/null +++ b/assets/sfx/minigames/slots/slots_big_win.ogg diff --git a/assets/sfx/minigames/slots/slots_fail.ogg b/assets/sfx/minigames/slots/slots_fail.ogg Binary files differnew file mode 100644 index 0000000..0081a02 --- /dev/null +++ b/assets/sfx/minigames/slots/slots_fail.ogg diff --git a/assets/sfx/minigames/slots/slots_lock.ogg b/assets/sfx/minigames/slots/slots_lock.ogg Binary files differnew file mode 100644 index 0000000..faa743c --- /dev/null +++ b/assets/sfx/minigames/slots/slots_lock.ogg diff --git a/assets/sfx/minigames/slots/slots_medium_win.ogg b/assets/sfx/minigames/slots/slots_medium_win.ogg Binary files differnew file mode 100644 index 0000000..f2031ad --- /dev/null +++ b/assets/sfx/minigames/slots/slots_medium_win.ogg diff --git a/assets/sfx/minigames/slots/slots_small_win.ogg b/assets/sfx/minigames/slots/slots_small_win.ogg Binary files differnew file mode 100644 index 0000000..3bbf64d --- /dev/null +++ b/assets/sfx/minigames/slots/slots_small_win.ogg diff --git a/assets/sfx/minigames/slots/slots_start.ogg b/assets/sfx/minigames/slots/slots_start.ogg Binary files differnew file mode 100644 index 0000000..54e45fd --- /dev/null +++ b/assets/sfx/minigames/slots/slots_start.ogg diff --git a/assets/sprites/gui/ui.skin b/assets/sprites/gui/ui.skin index 4a1bd53..04598a4 100644 --- a/assets/sprites/gui/ui.skin +++ b/assets/sprites/gui/ui.skin @@ -45,6 +45,10 @@ tooltip: { file: ../../fnt/FontText.fnt, scaledSize: 19 + }, + slots: { + file: ../../fnt/FontText.fnt, + scaledSize: 16 } }, com.badlogic.gdx.scenes.scene2d.ui.TextButton$TextButtonStyle: { @@ -85,6 +89,10 @@ store_item_price_disabled: { font: store_item_price, fontColor: store_item_price_disabled + }, + slots: { + font: slots, + fontColor: white } }, com.badlogic.gdx.scenes.scene2d.ui.TextField$TextFieldStyle: { diff --git a/assets/sprites/minigames/slots/arbuz.png b/assets/sprites/minigames/slots/arbuz.png Binary files differnew file mode 100644 index 0000000..b8616ed --- /dev/null +++ b/assets/sprites/minigames/slots/arbuz.png diff --git a/assets/sprites/minigames/slots/background.png b/assets/sprites/minigames/slots/background.png Binary files differnew file mode 100644 index 0000000..7d22fe7 --- /dev/null +++ b/assets/sprites/minigames/slots/background.png diff --git a/assets/sprites/minigames/slots/buter.png b/assets/sprites/minigames/slots/buter.png Binary files differnew file mode 100644 index 0000000..c6c789a --- /dev/null +++ b/assets/sprites/minigames/slots/buter.png diff --git a/assets/sprites/minigames/slots/corn.png b/assets/sprites/minigames/slots/corn.png Binary files differnew file mode 100644 index 0000000..60e1195 --- /dev/null +++ b/assets/sprites/minigames/slots/corn.png diff --git a/assets/sprites/minigames/slots/icecream.png b/assets/sprites/minigames/slots/icecream.png Binary files differnew file mode 100644 index 0000000..83e93c8 --- /dev/null +++ b/assets/sprites/minigames/slots/icecream.png diff --git a/assets/sprites/minigames/slots/kebab.png b/assets/sprites/minigames/slots/kebab.png Binary files differnew file mode 100644 index 0000000..696514b --- /dev/null +++ b/assets/sprites/minigames/slots/kebab.png diff --git a/assets/sprites/minigames/slots/kochan.png b/assets/sprites/minigames/slots/kochan.png Binary files differnew file mode 100644 index 0000000..371770c --- /dev/null +++ b/assets/sprites/minigames/slots/kochan.png diff --git a/assets/sprites/minigames/slots/onions.png b/assets/sprites/minigames/slots/onions.png Binary files differnew file mode 100644 index 0000000..c05e633 --- /dev/null +++ b/assets/sprites/minigames/slots/onions.png diff --git a/assets/sprites/minigames/slots/treat.png b/assets/sprites/minigames/slots/treat.png Binary files differnew file mode 100644 index 0000000..66a37a0 --- /dev/null +++ b/assets/sprites/minigames/slots/treat.png diff --git a/core/src/kz/ilotterytea/maxon/screens/SlotsMinigameScreen.kt b/core/src/kz/ilotterytea/maxon/screens/SlotsMinigameScreen.kt new file mode 100644 index 0000000..863f295 --- /dev/null +++ b/core/src/kz/ilotterytea/maxon/screens/SlotsMinigameScreen.kt @@ -0,0 +1,407 @@ +package kz.ilotterytea.maxon.screens + +import com.badlogic.gdx.Gdx +import com.badlogic.gdx.Input +import com.badlogic.gdx.InputMultiplexer +import com.badlogic.gdx.InputProcessor +import com.badlogic.gdx.Screen +import com.badlogic.gdx.assets.AssetManager +import com.badlogic.gdx.audio.Music +import com.badlogic.gdx.audio.Sound +import com.badlogic.gdx.graphics.GL20 +import com.badlogic.gdx.graphics.Texture +import com.badlogic.gdx.graphics.g2d.TextureAtlas +import com.badlogic.gdx.scenes.scene2d.Actor +import com.badlogic.gdx.scenes.scene2d.InputEvent +import com.badlogic.gdx.scenes.scene2d.Stage +import com.badlogic.gdx.scenes.scene2d.ui.Image +import com.badlogic.gdx.scenes.scene2d.ui.Label +import com.badlogic.gdx.scenes.scene2d.ui.Skin +import com.badlogic.gdx.scenes.scene2d.ui.Stack +import com.badlogic.gdx.scenes.scene2d.ui.Table +import com.badlogic.gdx.scenes.scene2d.ui.TextButton +import com.badlogic.gdx.scenes.scene2d.ui.TextField +import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener +import com.badlogic.gdx.scenes.scene2d.utils.ClickListener +import com.badlogic.gdx.utils.Align +import com.badlogic.gdx.utils.Timer +import com.badlogic.gdx.utils.Timer.Task +import com.badlogic.gdx.utils.viewport.FitViewport +import com.badlogic.gdx.utils.viewport.ScreenViewport +import kz.ilotterytea.maxon.MaxonGame +import kz.ilotterytea.maxon.player.Savegame +import kz.ilotterytea.maxon.screens.game.GameScreen +import kz.ilotterytea.maxon.utils.formatters.NumberFormatter +import kotlin.math.roundToInt +import kotlin.math.roundToLong +import kotlin.random.Random + +private enum class Slot(val multiplier: Int) { + Arbuz(5), + Icecream(30), + Kochan(80), + Buter(120), + Corn(200), + Kebab(500), + Onions(1000), + Treat(2500), +} + +private class SlotImage(slot: Slot, assetManager: AssetManager) : Image(assetManager.get("sprites/minigames/slots/${slot.name.lowercase()}.png", Texture::class.java)) + +class SlotsMinigameScreen : Screen { + private val savegame = Savegame.getInstance() + + private val game = MaxonGame.getInstance() + private val stage = Stage(FitViewport(800f, 600f)) + + private var spinButton: TextButton? = null + private var exitButton: TextButton? = null + + private var prize = 0.0 + private var prizeLabel: Label? = null + private var moneyLabel: Label? = null + + private var stake = 0.0 + private var stakeField: TextField? = null + + private var loseSlot = Slot.values()[0] + private var loseStreak = 0 + private var maxLoseStreak = Random.nextInt(20, 50) + + private var finished = false + private var disabled = false + private var lockedColumns = -1 + private val columnSlots = arrayListOf<Slot>() + private val columns = Table() + + private val tasks = arrayListOf<Pair<Task, Float>>() + + private val audioLoop: Music = game.assetManager.get("mus/minigames/slots/slots_loop.mp3") + + override fun show() { + // Skins + val skin = game.assetManager.get("sprites/gui/ui.skin", Skin::class.java) + + // Main table + val table = Table() + table.setFillParent(true) + table.align(Align.center) + + stage.addActor(table) + + // Background + val background = Image(game.assetManager.get("sprites/minigames/slots/background.png", Texture::class.java)) + background.zIndex = 2 + + table.add(background) + + // Buttons + spinButton = TextButton(game.locale.TranslatableText("minigame.slots.spin_button"), skin) + spinButton?.isDisabled = true + spinButton?.width = 420f + spinButton?.setPosition(62f, 60f) + spinButton?.addListener(object : ClickListener() { + override fun clicked(event: InputEvent?, x: Float, y: Float) { + if (spinButton?.isDisabled == true) return + super.clicked(event, x, y) + restart() + } + }) + stage.addActor(spinButton) + + exitButton = TextButton(game.locale.TranslatableText("minigame.slots.exit_button"), skin) + exitButton?.setPosition(62f, stage.height / 2f - 150f) + exitButton?.addListener(object : ClickListener() { + override fun clicked(event: InputEvent?, x: Float, y: Float) { + if (exitButton?.isDisabled == true) return + super.clicked(event, x, y) + game.screen = GameScreen() + } + }) + + stage.addActor(exitButton) + + // Labels + prizeLabel = Label("", skin, "slots") + prizeLabel?.setAlignment(Align.center) + prizeLabel?.setPosition(stage.width / 2f - 180f, stage.height / 2f + 80f) + stage.addActor(prizeLabel) + + val moneyIcon = Image(game.assetManager.get("sprites/gui/player_icons.atlas", TextureAtlas::class.java).findRegion("points")) + moneyIcon.setSize(20f, 20f) + moneyIcon.setPosition(stage.width / 2f + 60f, stage.height / 2f - 180f) + stage.addActor(moneyIcon) + + moneyLabel = Label(NumberFormatter.format(savegame.money.toLong()), skin, "slots") + moneyLabel?.setAlignment(Align.right) + moneyLabel?.setPosition(stage.width / 2f, stage.height / 2f - 180f) + stage.addActor(moneyLabel) + + val stakeLabel = Label(game.locale.TranslatableText("minigame.slots.bet"), skin, "slots") + stakeLabel.setAlignment(Align.center) + stakeLabel.setPosition(stage.width / 2f - 40f, stage.height / 2f - 100f) + stage.addActor(stakeLabel) + + stakeField = TextField("", skin) + stakeField?.messageText = "---" + stakeField?.setTextFieldFilter { _, c -> c.toString().matches(Regex("^[0-9]*\$")) } + stakeField?.addListener(object : ChangeListener() { + override fun changed(event: ChangeEvent?, actor: Actor?) { + val textField = actor as TextField + if (textField.isDisabled) return + + var value = textField.text?.toLongOrNull() + + if (value != null) { + if (value > savegame.money.toLong()) { + value = savegame.money.roundToLong() + } + + textField.text = value.toString() + stake = value.toDouble() + + spinButton?.isDisabled = stake <= 0.0 + } + } + }) + stakeField?.setPosition(stage.width / 2f - 70f, stage.height / 2f - 150f) + + stage.addActor(stakeField) + + // Slot columns + columns.x = 62f + columns.y = stage.height / 2f + columns.width = 424f + stage.addActor(columns) + + for (i in 0..2) { + columnSlots.add(Slot.values()[Random.nextInt(0, Slot.values().size)]) + } + + reRoll() + + val updateTask = object : Task() { + override fun run() { + reRoll() + } + } + + tasks.add(Pair(updateTask, 0.1f)) + + val lockColumnTask = object : Task() { + override fun run() { + val sound = game.assetManager.get("sfx/minigames/slots/slots_lock.ogg", Sound::class.java) + sound.play() + + lockedColumns += 1 + + if (lockedColumns > 1) { + finish() + } + } + } + + tasks.add(Pair(lockColumnTask, 2f)) + + disableSlotMachineIfNoStake() + + audioLoop.isLooping = true + + Gdx.input.inputProcessor = stage + } + + override fun render(delta: Float) { + Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT or GL20.GL_DEPTH_BUFFER_BIT) + Gdx.gl.glClearColor(0f, 0f, 0f, 1f) + + stage.act(delta) + stage.draw() + } + + private fun reRoll() { + val array = arrayListOf<Slot>() + + for (i in 0 until columnSlots.size) { + while (true) { + var x = columnSlots[i] + + if (i <= lockedColumns) { + if (loseStreak >= maxLoseStreak) { + x = loseSlot + } + + array.add(x) + break + } + + val slot = Slot.values()[Random.nextInt(0, Slot.values().size)] + + if (x.ordinal != slot.ordinal) { + array.add(slot) + break + } + } + } + + columnSlots.clear() + columns.clear() + + for (x in array) { + columnSlots.add(x) + columns.add(SlotImage(x, game.assetManager)) + .size(100f, 100f) + .expandX() + } + } + + + private fun finish() { + if (audioLoop.isPlaying) audioLoop.stop() + + finished = true + stakeField?.isDisabled = false + exitButton?.isDisabled = false + spinButton?.isDisabled = false + + for (x in tasks) { + x.first.cancel() + } + + giveReward() + updateLabels() + disableSlotMachineIfNoStake() + } + + private fun restart() { + if (game.prefs.getBoolean("music", true)) audioLoop.play() + + val sound = game.assetManager.get<Sound>("sfx/minigames/slots/slots_start.ogg") + sound.play() + + prizeLabel?.setText("") + + exitButton?.isDisabled = true + spinButton?.isDisabled = true + stakeField?.isDisabled = true + + loseSlot = Slot.values()[Random.nextInt(0,3)] + finished = false + lockedColumns = -1 + loseStreak = 0 + prize = 0.0 + maxLoseStreak = Random.nextInt(20, 50) + + reRoll() + + for (task in tasks) { + Timer.schedule(task.first, task.second, task.second) + } + } + + private fun giveReward() { + val first = columnSlots[0] + var same = false + + for (x in columnSlots) { + same = x.ordinal == first.ordinal + + if (!same) { + break + } + } + + playRewardSound(same, first) + + if (!same) { + loseStreak++ + savegame.money -= stake + return + } + + prize = stake * first.multiplier + savegame.money += prize + } + + private fun updateLabels() { + val prizeText = if (prize == 0.0) { + game.locale.TranslatableText("minigame.slots.nothing") + } else { + game.locale.FormattedText("minigame.slots.prize", NumberFormatter.format(prize.toLong())) + } + + prizeLabel?.setText(prizeText) + + if (stake.toLong() > savegame.money.toLong()) { + stake = savegame.money + + val stakeText = if (savegame.money.roundToInt() <= 0) { + "---" + } else { + NumberFormatter.format(savegame.money.toLong()) + } + + stakeField?.text = stakeText + } + + moneyLabel?.setText(NumberFormatter.format(savegame.money.roundToLong())) + } + + private fun disableSlotMachineIfNoStake() { + if (savegame.money.toLong() > 0) { + return + } + + disabled = true + + stakeField?.messageText = "---" + stakeField?.text = "---" + stakeField?.isDisabled = disabled + spinButton?.isDisabled = disabled + + for (x in tasks) { + x.first.cancel() + } + } + + private fun playRewardSound(same: Boolean, slot: Slot) { + val path = if (!same) { + "fail" + } else { + when (slot.ordinal) { + in 0..1 -> "small_win" + in 2..4 -> "medium_win" + else -> "big_win" + } + } + + val sound = game.assetManager.get("sfx/minigames/slots/slots_$path.ogg", Sound::class.java) + sound.play() + } + + override fun resize(width: Int, height: Int) { + stage.viewport.update(width, height, true) + } + + override fun pause() { + dispose() + } + + override fun resume() { + show() + } + + override fun hide() { + dispose() + } + + override fun dispose() { + for (x in tasks) { + x.first.cancel() + } + + tasks.clear() + stage.dispose() + audioLoop.stop() + } +}
\ No newline at end of file diff --git a/core/src/kz/ilotterytea/maxon/screens/game/GameScreen.java b/core/src/kz/ilotterytea/maxon/screens/game/GameScreen.java index b5f99be..c02226d 100644 --- a/core/src/kz/ilotterytea/maxon/screens/game/GameScreen.java +++ b/core/src/kz/ilotterytea/maxon/screens/game/GameScreen.java @@ -31,6 +31,7 @@ import kz.ilotterytea.maxon.player.MaxonItem; import kz.ilotterytea.maxon.player.MaxonItemRegister; import kz.ilotterytea.maxon.player.Savegame; import kz.ilotterytea.maxon.screens.MenuScreen; +import kz.ilotterytea.maxon.screens.SlotsMinigameScreen; import kz.ilotterytea.maxon.screens.game.shop.ShopUI; import kz.ilotterytea.maxon.ui.*; import kz.ilotterytea.maxon.ui.game.QuickActionsTable; @@ -99,7 +100,7 @@ public class GameScreen implements Screen, InputProcessor { decalBatch = new DecalBatch(new CameraGroupStrategy(camera)); decals = new ArrayList<>(); - TextureRegion[] playerTextureRegions = SpriteUtils.splitToTextureRegions(game.assetManager.get("sprites/sheet/loadingCircle.png", Texture.class), 112, 112, 10, 5); + ArrayList<TextureRegion> playerTextureRegions = SpriteUtils.splitToTextureRegions(game.assetManager.get("sprites/sheet/loadingCircle.png", Texture.class), 112, 112, 10, 5); decalPlayer = new DecalPlayer(savegame, playerTextureRegions); decals.add(decalPlayer.getDecal()); @@ -320,6 +321,11 @@ public class GameScreen implements Screen, InputProcessor { @Override public boolean keyDown(int keycode) { + if (Gdx.input.isKeyPressed(Input.Keys.K)) { + game.setScreen(new SlotsMinigameScreen()); + dispose(); + } + if (Gdx.input.isKeyPressed(Input.Keys.ESCAPE)) { savegame.setElapsedTime((System.currentTimeMillis() - playTimestamp) + savegame.getElapsedTime()); savegame.save(); |
