DEADSOFTWARE

Add chest
authorfredboy <fredboy@protonmail.com>
Fri, 10 May 2024 15:20:13 +0000 (22:20 +0700)
committerfredboy <fredboy@protonmail.com>
Fri, 10 May 2024 15:20:13 +0000 (22:20 +0700)
34 files changed:
android/assets/chest.png
android/assets/chest_large.png [new file with mode: 0644]
android/assets/json/game_items.json
android/assets/json/texture_regions.json
android/assets/textures/blocks/chest.png [new file with mode: 0644]
core/src/ru/deadsoftware/cavedroid/game/GameModule.java
core/src/ru/deadsoftware/cavedroid/game/GameProc.java
core/src/ru/deadsoftware/cavedroid/game/GameSaver.java
core/src/ru/deadsoftware/cavedroid/game/actions/UseBlockActionsModule.kt
core/src/ru/deadsoftware/cavedroid/game/actions/useblock/UseChestAction.kt [new file with mode: 0644]
core/src/ru/deadsoftware/cavedroid/game/actions/useblock/UseFurnaceAction.kt
core/src/ru/deadsoftware/cavedroid/game/debug/DebugInfoStringsProvider.kt
core/src/ru/deadsoftware/cavedroid/game/input/MouseInputHandlersModule.kt
core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/PauseGameKeyboardInputHandler.kt
core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/CloseGameWindowMouseInputHandler.kt
core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/SelectChestInventoryItemMouseInputHandler.kt [new file with mode: 0644]
core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/SelectFurnaceInventoryItemMouseInputHandler.kt
core/src/ru/deadsoftware/cavedroid/game/model/block/Block.kt
core/src/ru/deadsoftware/cavedroid/game/model/item/InventoryItem.kt
core/src/ru/deadsoftware/cavedroid/game/model/mapper/BlockMapper.kt
core/src/ru/deadsoftware/cavedroid/game/objects/container/Chest.kt [new file with mode: 0644]
core/src/ru/deadsoftware/cavedroid/game/objects/container/Container.kt [new file with mode: 0644]
core/src/ru/deadsoftware/cavedroid/game/objects/container/ContainerController.kt [new file with mode: 0644]
core/src/ru/deadsoftware/cavedroid/game/objects/container/Furnace.kt [moved from core/src/ru/deadsoftware/cavedroid/game/objects/furnace/Furnace.kt with 71% similarity]
core/src/ru/deadsoftware/cavedroid/game/objects/furnace/FurnaceController.kt [deleted file]
core/src/ru/deadsoftware/cavedroid/game/render/BlocksRenderer.kt
core/src/ru/deadsoftware/cavedroid/game/render/WindowsRenderer.kt
core/src/ru/deadsoftware/cavedroid/game/render/windows/ChestWindowRenderer.kt [new file with mode: 0644]
core/src/ru/deadsoftware/cavedroid/game/render/windows/FurnaceWindowRenderer.kt
core/src/ru/deadsoftware/cavedroid/game/ui/windows/GameWindowsConfigs.kt
core/src/ru/deadsoftware/cavedroid/game/ui/windows/GameWindowsManager.kt
core/src/ru/deadsoftware/cavedroid/game/ui/windows/inventory/ChestInventoryWindow.kt [new file with mode: 0644]
core/src/ru/deadsoftware/cavedroid/game/ui/windows/inventory/FurnaceInventoryWindow.kt
core/src/ru/deadsoftware/cavedroid/game/world/GameWorld.java

index 961891f208d6ec2683ac56668344b7f7e5eb69b3..2c6d0c6b69b62d25ab98655cf0093ecd56e87269 100644 (file)
Binary files a/android/assets/chest.png and b/android/assets/chest.png differ
diff --git a/android/assets/chest_large.png b/android/assets/chest_large.png
new file mode 100644 (file)
index 0000000..961891f
Binary files /dev/null and b/android/assets/chest_large.png differ
index 77493459c2bfaded590e57a0a959d577014b2799..95d4c7a084900a815d3ca228b606c36fa74d7997 100644 (file)
       "tool_level": 1,
       "tool_type": "pickaxe",
       "meta": "furnace"
+    },
+    "chest": {
+      "hp": 180,
+      "collision": true,
+      "transparent": true,
+      "drop": "chest",
+      "texture": "chest",
+      "tool_level": 0,
+      "tool_type": "axe",
+      "meta": "chest",
+      "top": 2,
+      "left": 1,
+      "right": 1,
+      "sprite_top": 2,
+      "sprite_left": 1,
+      "sprite_right": 1
     }
   },
   "items": {
       "type": "block",
       "texture": "furnace_off"
     },
+    "chest": {
+      "name": "Chest",
+      "type": "block",
+      "texture": "chest"
+    },
     "sapling_spruce": {
       "name": "Spruce Sapling",
       "type": "block",
index 1800acda7225565dd9241f9fed465bda20a55821..1042b61aecb810ce709b8fad2a8355985dca97f9 100644 (file)
       "h": 14
     }
   },
+  "chest": {
+    "chest": {
+      "w": 176,
+      "h": 168
+    }
+  },
   "buttons": {
     "button_0": {
       "w": 200,
diff --git a/android/assets/textures/blocks/chest.png b/android/assets/textures/blocks/chest.png
new file mode 100644 (file)
index 0000000..a2ca371
Binary files /dev/null and b/android/assets/textures/blocks/chest.png differ
index 2385230df15533a680a84a871a487f0e71642cf6..d57ab337e9e49c0cbc872ee037cb42b407908d24 100644 (file)
@@ -6,7 +6,7 @@ import ru.deadsoftware.cavedroid.MainConfig;
 import ru.deadsoftware.cavedroid.game.mobs.MobsController;
 import ru.deadsoftware.cavedroid.game.model.block.Block;
 import ru.deadsoftware.cavedroid.game.objects.drop.DropController;
-import ru.deadsoftware.cavedroid.game.objects.furnace.FurnaceController;
+import ru.deadsoftware.cavedroid.game.objects.container.ContainerController;
 import ru.deadsoftware.cavedroid.game.ui.TooltipManager;
 import ru.deadsoftware.cavedroid.game.world.GameWorld;
 
@@ -46,11 +46,11 @@ public class GameModule {
 
     @Provides
     @GameScope
-    public static FurnaceController provideFurnaceController(MainConfig mainConfig, GameItemsHolder gameItemsHolder) {
+    public static ContainerController provideFurnaceController(MainConfig mainConfig, DropController dropController, GameItemsHolder gameItemsHolder) {
         load(mainConfig, gameItemsHolder);
-        FurnaceController controller = data != null ? data.retrueveFurnaceController() : new FurnaceController();
+        ContainerController controller = data != null ? data.retrieveFurnaceController() : new ContainerController(dropController, gameItemsHolder);
         makeDataNullIfEmpty();
-        controller.init(gameItemsHolder);
+        controller.init(dropController, gameItemsHolder);
         return controller;
     }
 
@@ -74,12 +74,12 @@ public class GameModule {
                                              DropController dropController,
                                              MobsController mobsController,
                                              GameItemsHolder gameItemsHolder,
-                                             FurnaceController furnaceController) {
+                                             ContainerController containerController) {
         load(mainConfig, gameItemsHolder);
         Block[][] fm = data != null ? data.retrieveForeMap() : null;
         Block[][] bm = data != null ? data.retrieveBackMap() : null;
         makeDataNullIfEmpty();
-        return new GameWorld(dropController, mobsController, gameItemsHolder, furnaceController, fm, bm);
+        return new GameWorld(dropController, mobsController, gameItemsHolder, containerController, fm, bm);
     }
 
 }
index a3fcabbbf4ccfd65466d78e83e46fea7ce428266..29062a44a07d24deff2efcefa40a2ec542a8978a 100644 (file)
@@ -6,7 +6,7 @@ import com.badlogic.gdx.utils.Timer;
 import ru.deadsoftware.cavedroid.MainConfig;
 import ru.deadsoftware.cavedroid.game.mobs.MobsController;
 import ru.deadsoftware.cavedroid.game.mobs.player.Player;
-import ru.deadsoftware.cavedroid.game.objects.furnace.FurnaceController;
+import ru.deadsoftware.cavedroid.game.objects.container.ContainerController;
 import ru.deadsoftware.cavedroid.game.world.GameWorldBlocksLogicControllerTask;
 import ru.deadsoftware.cavedroid.game.world.GameWorldFluidsLogicControllerTask;
 import ru.deadsoftware.cavedroid.game.world.GameWorldMobDamageControllerTask;
@@ -19,7 +19,7 @@ public class GameProc implements Disposable {
     private final GamePhysics mGamePhysics;
     private final GameRenderer mGameRenderer;
     private final MobsController mMobsController;
-    private final FurnaceController mFurnaceController;
+    private final ContainerController mContainerController;
     private final GameItemsHolder mGameItemsHolder;
     private final GameWorldFluidsLogicControllerTask mGameWorldFluidsLogicControllerTask;
     private final GameWorldBlocksLogicControllerTask mGameWorldBlocksLogicControllerTask;
@@ -32,7 +32,7 @@ public class GameProc implements Disposable {
                     GamePhysics gamePhysics,
                     GameRenderer gameRenderer,
                     MobsController mobsController,
-                    FurnaceController furnaceController,
+                    ContainerController containerController,
                     GameItemsHolder gameItemsHolder,
                     GameWorldFluidsLogicControllerTask gameWorldFluidsLogicControllerTask,
                     GameWorldBlocksLogicControllerTask gameWorldBlocksLogicControllerTask,
@@ -41,7 +41,7 @@ public class GameProc implements Disposable {
         mGamePhysics = gamePhysics;
         mGameRenderer = gameRenderer;
         mMobsController = mobsController;
-        mFurnaceController = furnaceController;
+        mContainerController = containerController;
         mGameItemsHolder = gameItemsHolder;
         mGameWorldFluidsLogicControllerTask = gameWorldFluidsLogicControllerTask;
         mGameWorldBlocksLogicControllerTask = gameWorldBlocksLogicControllerTask;
@@ -64,7 +64,7 @@ public class GameProc implements Disposable {
     public void update(float delta) {
         mGamePhysics.update(delta);
         mGameRenderer.render(delta);
-        mFurnaceController.update(mGameItemsHolder);
+        mContainerController.update();
     }
 
     public void show() {
index dd1618640957ce3bbb200a7f509145daad838674..39d227844ac1badb1d7898e28490d37019535e70 100644 (file)
@@ -6,7 +6,7 @@ import ru.deadsoftware.cavedroid.MainConfig;
 import ru.deadsoftware.cavedroid.game.mobs.MobsController;
 import ru.deadsoftware.cavedroid.game.model.block.Block;
 import ru.deadsoftware.cavedroid.game.objects.drop.DropController;
-import ru.deadsoftware.cavedroid.game.objects.furnace.FurnaceController;
+import ru.deadsoftware.cavedroid.game.objects.container.ContainerController;
 import ru.deadsoftware.cavedroid.game.world.GameWorld;
 
 import javax.annotation.CheckForNull;
@@ -25,18 +25,18 @@ public class GameSaver {
         @CheckForNull
         private DropController mDropController;
         @CheckForNull
-        private FurnaceController mFurnaceController;
+        private ContainerController mContainerController;
         @CheckForNull
         private Block[][] mForeMap, mBackMap;
 
         public Data(MobsController mobsController,
                     DropController dropController,
-                    FurnaceController furnaceController,
+                    ContainerController containerController,
                     Block[][] foreMap,
                     Block[][] backMap) {
             mMobsController = mobsController;
             mDropController = dropController;
-            mFurnaceController = furnaceController;
+            mContainerController = containerController;
             mForeMap = foreMap;
             mBackMap = backMap;
         }
@@ -55,11 +55,11 @@ public class GameSaver {
             return dropController;
         }
 
-        public FurnaceController retrueveFurnaceController() {
-            assert mFurnaceController != null;
-            FurnaceController furnaceController = mFurnaceController;
-            mFurnaceController = null;
-            return furnaceController;
+        public ContainerController retrieveFurnaceController() {
+            assert mContainerController != null;
+            ContainerController containerController = mContainerController;
+            mContainerController = null;
+            return containerController;
         }
 
         public Block[][] retrieveForeMap() {
@@ -77,7 +77,11 @@ public class GameSaver {
         }
 
         public boolean isEmpty() {
-            return mMobsController == null && mDropController == null && mForeMap == null && mBackMap == null;
+            return mMobsController == null &&
+                    mDropController == null &&
+                    mContainerController == null &&
+                    mForeMap == null &&
+                    mBackMap == null;
         }
     }
 
@@ -198,12 +202,12 @@ public class GameSaver {
             int version = in.readInt();
             DropController dropController;
             MobsController mobsController;
-            FurnaceController furnaceController;
+            ContainerController containerController;
 
             if (SAVE_VERSION == version) {
                 dropController = (DropController) in.readObject();
                 mobsController = (MobsController) in.readObject();
-                furnaceController = (FurnaceController) in.readObject();
+                containerController = (ContainerController) in.readObject();
             } else {
                 throw new Exception("version mismatch");
             }
@@ -218,7 +222,7 @@ public class GameSaver {
                 throw new Exception("couldn't load");
             }
 
-            return new Data(mobsController, dropController, furnaceController, foreMap, backMap);
+            return new Data(mobsController, dropController, containerController, foreMap, backMap);
         } catch (Exception e) {
             Gdx.app.error("GameSaver", e.getMessage());
         }
@@ -229,7 +233,7 @@ public class GameSaver {
     public static void save(MainConfig mainConfig,
                             DropController dropController,
                             MobsController mobsController,
-                            FurnaceController furnaceController,
+                            ContainerController containerController,
                             GameWorld gameWorld) {
         String folder = mainConfig.getGameFolder();
         FileHandle file = Gdx.files.absolute(folder + "/saves/");
@@ -247,7 +251,7 @@ public class GameSaver {
             out.writeInt(SAVE_VERSION);
             out.writeObject(dropController);
             out.writeObject(mobsController);
-            out.writeObject(furnaceController);
+            out.writeObject(containerController);
             out.close();
 
             saveDict(Gdx.files.absolute(folder + "/saves/dict"), dict);
index 5b2a169018564609c38a9741a675b85b4d6f7d9c..7458dfc9b5e3e9e6f69a1c84af354c24b98023d3 100644 (file)
@@ -6,6 +6,7 @@ import dagger.multibindings.IntoMap
 import dagger.multibindings.StringKey
 import ru.deadsoftware.cavedroid.game.GameScope
 import ru.deadsoftware.cavedroid.game.actions.useblock.IUseBlockAction
+import ru.deadsoftware.cavedroid.game.actions.useblock.UseChestAction
 import ru.deadsoftware.cavedroid.game.actions.useblock.UseCraftingTableAction
 import ru.deadsoftware.cavedroid.game.actions.useblock.UseFurnaceAction
 
@@ -27,4 +28,12 @@ class UseBlockActionsModule {
     fun bindUseFurnaceTableAction(action: UseFurnaceAction): IUseBlockAction {
         return action
     }
+
+    @Binds
+    @IntoMap
+    @StringKey(UseChestAction.KEY)
+    @GameScope
+    fun bindUseChestAction(action: UseChestAction): IUseBlockAction {
+        return action
+    }
 }
diff --git a/core/src/ru/deadsoftware/cavedroid/game/actions/useblock/UseChestAction.kt b/core/src/ru/deadsoftware/cavedroid/game/actions/useblock/UseChestAction.kt
new file mode 100644 (file)
index 0000000..fa50c94
--- /dev/null
@@ -0,0 +1,26 @@
+package ru.deadsoftware.cavedroid.game.actions.useblock
+
+import ru.deadsoftware.cavedroid.game.GameScope
+import ru.deadsoftware.cavedroid.game.model.block.Block
+import ru.deadsoftware.cavedroid.game.objects.container.Chest
+import ru.deadsoftware.cavedroid.game.ui.windows.GameWindowsManager
+import ru.deadsoftware.cavedroid.game.world.GameWorld
+import javax.inject.Inject
+
+@GameScope
+class UseChestAction @Inject constructor(
+    private val gameWorld: GameWorld,
+    private val gameWindowsManager: GameWindowsManager,
+) : IUseBlockAction {
+
+    override fun perform(block: Block, x: Int, y: Int) {
+        val chest = (gameWorld.getForegroundContainer(x, y) as? Chest)
+            ?: (gameWorld.getBackgroundContainer(x, y) as? Chest)
+            ?: return
+        gameWindowsManager.openChest(chest)
+    }
+
+    companion object {
+        const val KEY = "chest"
+    }
+}
\ No newline at end of file
index 88a6a7fb107c01ffa6021ce51ccb243f24c90885..7c30402caf1aa29bb3f9ec1f5eff42bf3a66684b 100644 (file)
@@ -2,18 +2,18 @@ package ru.deadsoftware.cavedroid.game.actions.useblock
 
 import ru.deadsoftware.cavedroid.game.GameScope
 import ru.deadsoftware.cavedroid.game.model.block.Block
-import ru.deadsoftware.cavedroid.game.objects.furnace.FurnaceController
 import ru.deadsoftware.cavedroid.game.ui.windows.GameWindowsManager
+import ru.deadsoftware.cavedroid.game.world.GameWorld
 import javax.inject.Inject
 
 @GameScope
 class UseFurnaceAction @Inject constructor(
-    private val furnaceController: FurnaceController,
+    private val gameWorld: GameWorld,
     private val gameWindowsManager: GameWindowsManager,
 ) : IUseBlockAction {
 
     override fun perform(block: Block, x: Int, y: Int) {
-        val furnace = furnaceController.getFurnace(x, y, 0) ?: furnaceController.getFurnace(x, y, 1) ?: return
+        val furnace = gameWorld.getForegroundFurnace(x, y) ?: gameWorld.getBackgroundFurnace(x, y) ?: return
         gameWindowsManager.openFurnace(furnace)
     }
 
index df1dd06e2e705643b0c71456192e420f75f8989a..51dc335c50b3b302ea8cb7ce7d2ee50efe0fbe52 100644 (file)
@@ -3,6 +3,7 @@ package ru.deadsoftware.cavedroid.game.debug
 import com.badlogic.gdx.Gdx
 import ru.deadsoftware.cavedroid.game.GameScope
 import ru.deadsoftware.cavedroid.game.mobs.MobsController
+import ru.deadsoftware.cavedroid.game.objects.container.ContainerController
 import ru.deadsoftware.cavedroid.game.objects.drop.DropController
 import ru.deadsoftware.cavedroid.game.world.GameWorld
 import javax.inject.Inject
@@ -11,7 +12,8 @@ import javax.inject.Inject
 class DebugInfoStringsProvider @Inject constructor(
     private val mobsController: MobsController,
     private val dropController: DropController,
-    private val gameWorld: GameWorld
+    private val containerController: ContainerController,
+    private val gameWorld: GameWorld,
 ) {
 
     fun getDebugStrings(): List<String> {
@@ -27,6 +29,7 @@ class DebugInfoStringsProvider @Inject constructor(
             "Swim: ${player.swim}",
             "Mobs: ${mobsController.mobs.size}",
             "Drops: ${dropController.size}",
+            "Containers: ${containerController.size}",
             "Block: ${gameWorld.getForeMap(player.cursorX, player.cursorY).params.key}",
             "Hand: ${player.inventory.activeItem.item.params.key}",
             "Game mode: ${player.gameMode}",
index fe9bba635138f3b6e31a591ca3c5e48f1e3ce7a2..f0c3b3b13f3579ee07a47ec2fa34bf906407c802 100644 (file)
@@ -87,4 +87,11 @@ object MouseInputHandlersModule {
     fun bindJoystickInputHandler(handler: JoystickInputHandler): IGameInputHandler<MouseInputAction> {
         return handler
     }
+
+    @Binds
+    @IntoSet
+    @GameScope
+    fun bindSelectChestInventoryItemMouseInputHandler(handler: SelectChestInventoryItemMouseInputHandler): IGameInputHandler<MouseInputAction> {
+        return handler
+    }
 }
\ No newline at end of file
index 8ba35c1d87c82695a4c208338dd44a0d563a75a9..8f0f49441addb93cc8dd1832cb3ae6168a0c8b5a 100644 (file)
@@ -8,7 +8,7 @@ import ru.deadsoftware.cavedroid.game.input.action.KeyboardInputAction
 import ru.deadsoftware.cavedroid.game.input.action.keys.KeyboardInputActionKey
 import ru.deadsoftware.cavedroid.game.mobs.MobsController
 import ru.deadsoftware.cavedroid.game.objects.drop.DropController
-import ru.deadsoftware.cavedroid.game.objects.furnace.FurnaceController
+import ru.deadsoftware.cavedroid.game.objects.container.ContainerController
 import ru.deadsoftware.cavedroid.game.world.GameWorld
 import javax.inject.Inject
 
@@ -18,7 +18,7 @@ class PauseGameKeyboardInputHandler @Inject constructor(
     private val dropController: DropController,
     private val mobsController: MobsController,
     private val gameWorld: GameWorld,
-    private val furnaceController: FurnaceController,
+    private val containerController: ContainerController,
 ) : IGameInputHandler<KeyboardInputAction> {
 
     override fun checkConditions(action: KeyboardInputAction): Boolean {
@@ -26,7 +26,7 @@ class PauseGameKeyboardInputHandler @Inject constructor(
     }
 
     override fun handle(action: KeyboardInputAction) {
-        GameSaver.save(mainConfig, dropController, mobsController, furnaceController, gameWorld)
+        GameSaver.save(mainConfig, dropController, mobsController, containerController, gameWorld)
         mainConfig.caveGame.quitGame()
     }
 }
\ No newline at end of file
index ddc41e268613e2dd6129f5892e187be04e5e8df3..f6f6cfc97eeb83ad0a126225decd6d84b260e685 100644 (file)
@@ -24,6 +24,7 @@ class CloseGameWindowMouseInputHandler @Inject constructor(
     private val survivalInventoryTexture get() = requireNotNull(Assets.textureRegions["survival"])
     private val craftingInventoryTexture get() = requireNotNull(Assets.textureRegions["crafting_table"])
     private val furnaceInventoryTexture get() = requireNotNull(Assets.textureRegions["furnace"])
+    private val chestInventoryTexture get() = requireNotNull(Assets.textureRegions["chest"])
 
     override fun checkConditions(action: MouseInputAction): Boolean {
         return gameWindowsManager.getCurrentWindow() != GameUiWindow.NONE &&
@@ -38,6 +39,7 @@ class CloseGameWindowMouseInputHandler @Inject constructor(
             GameUiWindow.SURVIVAL_INVENTORY -> survivalInventoryTexture
             GameUiWindow.CRAFTING_TABLE -> craftingInventoryTexture
             GameUiWindow.FURNACE -> furnaceInventoryTexture
+            GameUiWindow.CHEST -> chestInventoryTexture
             else -> throw UnsupportedOperationException("Cant close window ${window.name}")
         }
     }
diff --git a/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/SelectChestInventoryItemMouseInputHandler.kt b/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/SelectChestInventoryItemMouseInputHandler.kt
new file mode 100644 (file)
index 0000000..3d1bfae
--- /dev/null
@@ -0,0 +1,131 @@
+package ru.deadsoftware.cavedroid.game.input.handler.mouse
+
+import com.badlogic.gdx.Gdx
+import ru.deadsoftware.cavedroid.game.GameItemsHolder
+import ru.deadsoftware.cavedroid.game.GameScope
+import ru.deadsoftware.cavedroid.game.GameUiWindow
+import ru.deadsoftware.cavedroid.game.input.IGameInputHandler
+import ru.deadsoftware.cavedroid.game.input.action.MouseInputAction
+import ru.deadsoftware.cavedroid.game.input.action.keys.MouseInputActionKey
+import ru.deadsoftware.cavedroid.game.input.isInsideWindow
+import ru.deadsoftware.cavedroid.game.mobs.MobsController
+import ru.deadsoftware.cavedroid.game.model.item.InventoryItem
+import ru.deadsoftware.cavedroid.game.objects.drop.DropController
+import ru.deadsoftware.cavedroid.game.ui.windows.GameWindowsConfigs
+import ru.deadsoftware.cavedroid.game.ui.windows.GameWindowsManager
+import ru.deadsoftware.cavedroid.game.ui.windows.inventory.ChestInventoryWindow
+import ru.deadsoftware.cavedroid.game.ui.windows.inventory.SurvivalInventoryWindow
+import ru.deadsoftware.cavedroid.misc.Assets
+import javax.inject.Inject
+
+@GameScope
+class SelectChestInventoryItemMouseInputHandler @Inject constructor(
+    private val gameWindowsManager: GameWindowsManager,
+    private val mobsController: MobsController,
+    private val gameItemsHolder: GameItemsHolder,
+    private val dropController: DropController,
+) : IGameInputHandler<MouseInputAction> {
+
+    private val chestWindowTexture get() = requireNotNull(Assets.textureRegions["chest"])
+
+    override fun checkConditions(action: MouseInputAction): Boolean {
+        return gameWindowsManager.getCurrentWindow() == GameUiWindow.CHEST &&
+                isInsideWindow(action, chestWindowTexture) &&
+                (action.actionKey is MouseInputActionKey.Left || action.actionKey is MouseInputActionKey.Right || action.actionKey is MouseInputActionKey.Screen)
+                && (action.actionKey.touchUp || action.actionKey is MouseInputActionKey.Screen)
+    }
+
+    private fun handleInsideContentGrid(action: MouseInputAction, xOnGrid: Int, yOnGrid: Int) {
+        val window = gameWindowsManager.currentWindow as ChestInventoryWindow
+
+        val itemIndex = ((xOnGrid.toInt() + yOnGrid.toInt() * GameWindowsConfigs.Chest.contentsInRow))
+
+        if (action.actionKey is MouseInputActionKey.Screen) {
+            if (!action.actionKey.touchUp) {
+                window.onLeftCLick(window.chest.items as MutableList<InventoryItem?>, gameItemsHolder, itemIndex, action.actionKey.pointer)
+            } else {
+                if (action.actionKey.pointer == window.selectItemPointer) {
+                    window.onLeftCLick(window.chest.items  as MutableList<InventoryItem?>, gameItemsHolder, itemIndex, action.actionKey.pointer)
+                } else {
+                    window.onRightClick(window.chest.items  as MutableList<InventoryItem?>, itemIndex)
+                }
+            }
+        } else if (action.actionKey is MouseInputActionKey.Left) {
+            window.onLeftCLick(window.chest.items  as MutableList<InventoryItem?>, gameItemsHolder, itemIndex)
+        } else {
+            window.onRightClick(window.chest.items as MutableList<InventoryItem?>, itemIndex)
+        }
+
+        Gdx.app.debug(
+            TAG,
+            "selected item: ${window.selectedItem?.item?.params?.key ?: "null"}; index $itemIndex, grid ($xOnGrid;$yOnGrid)"
+        )
+    }
+
+    private fun handleInsideInventoryGrid(action: MouseInputAction, xOnGrid: Int, yOnGrid: Int) {
+        val window = gameWindowsManager.currentWindow as ChestInventoryWindow
+
+        var itemIndex = ((xOnGrid.toInt() + yOnGrid.toInt() * GameWindowsConfigs.Chest.itemsInRow))
+        itemIndex += GameWindowsConfigs.Chest.hotbarCells
+
+        if (itemIndex >= mobsController.player.inventory.size) {
+            itemIndex -= mobsController.player.inventory.size
+        }
+
+        if (action.actionKey is MouseInputActionKey.Screen) {
+            if (!action.actionKey.touchUp) {
+                window.onLeftCLick(mobsController.player.inventory.items as MutableList<InventoryItem?>, gameItemsHolder, itemIndex, action.actionKey.pointer)
+            } else {
+                if (action.actionKey.pointer == window.selectItemPointer) {
+                    window.onLeftCLick(mobsController.player.inventory.items as MutableList<InventoryItem?>, gameItemsHolder, itemIndex, action.actionKey.pointer)
+                } else {
+                    window.onRightClick(mobsController.player.inventory.items as MutableList<InventoryItem?>, itemIndex)
+                }
+            }
+        } else if (action.actionKey is MouseInputActionKey.Left) {
+            window.onLeftCLick(mobsController.player.inventory.items as MutableList<InventoryItem?>, gameItemsHolder, itemIndex)
+        } else {
+            window.onRightClick(mobsController.player.inventory.items as MutableList<InventoryItem?>, itemIndex)
+        }
+
+        Gdx.app.debug(
+            TAG,
+            "selected item: ${window.selectedItem?.item?.params?.key ?: "null"}; index $itemIndex, grid ($xOnGrid;$yOnGrid)"
+        )
+    }
+
+    override fun handle(action: MouseInputAction) {
+        val chestTexture = chestWindowTexture
+
+        val xOnWindow = action.screenX - (action.cameraViewport.width / 2 - chestTexture.regionWidth / 2)
+        val yOnWindow = action.screenY - (action.cameraViewport.height / 2 - chestTexture.regionHeight / 2)
+
+        val xOnGrid = (xOnWindow - GameWindowsConfigs.Chest.itemsGridMarginLeft) /
+                GameWindowsConfigs.Chest.itemsGridColWidth
+        val yOnGrid = (yOnWindow - GameWindowsConfigs.Chest.itemsGridMarginTop) /
+                GameWindowsConfigs.Chest.itemsGridRowHeight
+
+        val xOnContent = (xOnWindow - GameWindowsConfigs.Chest.contentsMarginLeft) /
+                GameWindowsConfigs.Chest.itemsGridColWidth
+        val yOnContent = (yOnWindow - GameWindowsConfigs.Chest.contentsMarginTop) /
+                GameWindowsConfigs.Chest.itemsGridRowHeight
+
+        val isInsideInventoryGrid = xOnGrid >= 0 && xOnGrid < GameWindowsConfigs.Chest.itemsInRow &&
+                yOnGrid >= 0 && yOnGrid < GameWindowsConfigs.Chest.itemsInCol
+
+        val isInsideContentGrid = xOnContent >= 0 && xOnContent < GameWindowsConfigs.Chest.contentsInRow &&
+                yOnContent >= 0 && yOnContent < GameWindowsConfigs.Chest.contentsInCol
+
+
+        if (isInsideInventoryGrid) {
+            handleInsideInventoryGrid(action, xOnGrid.toInt(), yOnGrid.toInt())
+        } else if (isInsideContentGrid) {
+            handleInsideContentGrid(action, xOnContent.toInt(), yOnContent.toInt())
+        }
+    }
+
+    companion object {
+        private const val TAG = "SelectChestInventoryItemMouseInputHandler"
+
+    }
+}
\ No newline at end of file
index 839135e425d7ab829ad55087ceec31982df81323..e11c433ad3749d5f136c66f9bff9f95174124166 100644 (file)
@@ -1,7 +1,6 @@
 package ru.deadsoftware.cavedroid.game.input.handler.mouse
 
 import com.badlogic.gdx.Gdx
-import com.badlogic.gdx.utils.TimeUtils
 import ru.deadsoftware.cavedroid.game.GameItemsHolder
 import ru.deadsoftware.cavedroid.game.GameScope
 import ru.deadsoftware.cavedroid.game.GameUiWindow
@@ -13,7 +12,7 @@ import ru.deadsoftware.cavedroid.game.mobs.MobsController
 import ru.deadsoftware.cavedroid.game.model.item.InventoryItem
 import ru.deadsoftware.cavedroid.game.model.item.InventoryItem.Companion.isNoneOrNull
 import ru.deadsoftware.cavedroid.game.objects.drop.DropController
-import ru.deadsoftware.cavedroid.game.objects.furnace.Furnace
+import ru.deadsoftware.cavedroid.game.objects.container.Furnace
 import ru.deadsoftware.cavedroid.game.ui.windows.GameWindowsConfigs
 import ru.deadsoftware.cavedroid.game.ui.windows.GameWindowsManager
 import ru.deadsoftware.cavedroid.game.ui.windows.inventory.FurnaceInventoryWindow
@@ -78,18 +77,18 @@ class SelectFurnaceInventoryItemMouseInputHandler @Inject constructor(
 
         if (action.actionKey is MouseInputActionKey.Screen) {
             if (!action.actionKey.touchUp) {
-                window.onLeftCLick(window.furnace.items, gameItemsHolder, Furnace.FUEL_INDEX, action.actionKey.pointer)
+                window.onLeftCLick(window.furnace.items as MutableList<InventoryItem?>, gameItemsHolder, Furnace.FUEL_INDEX, action.actionKey.pointer)
             } else {
                 if (action.actionKey.pointer == window.selectItemPointer) {
-                    window.onLeftCLick(window.furnace.items, gameItemsHolder, Furnace.FUEL_INDEX, action.actionKey.pointer)
+                    window.onLeftCLick(window.furnace.items as MutableList<InventoryItem?>, gameItemsHolder, Furnace.FUEL_INDEX, action.actionKey.pointer)
                 } else {
-                    window.onRightClick(window.furnace.items, Furnace.FUEL_INDEX)
+                    window.onRightClick(window.furnace.items as MutableList<InventoryItem?>, Furnace.FUEL_INDEX)
                 }
             }
         } else if (action.actionKey is MouseInputActionKey.Left || action.actionKey is MouseInputActionKey.Screen) {
-            window.onLeftCLick(window.furnace.items, gameItemsHolder, Furnace.FUEL_INDEX)
+            window.onLeftCLick(window.furnace.items as MutableList<InventoryItem?>, gameItemsHolder, Furnace.FUEL_INDEX)
         } else {
-            window.onRightClick(window.furnace.items, Furnace.FUEL_INDEX)
+            window.onRightClick(window.furnace.items as MutableList<InventoryItem?>, Furnace.FUEL_INDEX)
         }
     }
 
@@ -98,18 +97,18 @@ class SelectFurnaceInventoryItemMouseInputHandler @Inject constructor(
 
         if (action.actionKey is MouseInputActionKey.Screen) {
             if (!action.actionKey.touchUp) {
-                window.onLeftCLick(window.furnace.items, gameItemsHolder, Furnace.INPUT_INDEX, action.actionKey.pointer)
+                window.onLeftCLick(window.furnace.items as MutableList<InventoryItem?>, gameItemsHolder, Furnace.INPUT_INDEX, action.actionKey.pointer)
             } else {
                 if (action.actionKey.pointer == window.selectItemPointer) {
-                    window.onLeftCLick(window.furnace.items, gameItemsHolder, Furnace.INPUT_INDEX, action.actionKey.pointer)
+                    window.onLeftCLick(window.furnace.items as MutableList<InventoryItem?>, gameItemsHolder, Furnace.INPUT_INDEX, action.actionKey.pointer)
                 } else {
-                    window.onRightClick(window.furnace.items, Furnace.INPUT_INDEX)
+                    window.onRightClick(window.furnace.items as MutableList<InventoryItem?>, Furnace.INPUT_INDEX)
                 }
             }
         } else if (action.actionKey is MouseInputActionKey.Left || action.actionKey is MouseInputActionKey.Screen) {
-            window.onLeftCLick(window.furnace.items, gameItemsHolder, Furnace.INPUT_INDEX)
+            window.onLeftCLick(window.furnace.items as MutableList<InventoryItem?>, gameItemsHolder, Furnace.INPUT_INDEX)
         } else {
-            window.onRightClick(window.furnace.items, Furnace.INPUT_INDEX)
+            window.onRightClick(window.furnace.items as MutableList<InventoryItem?>, Furnace.INPUT_INDEX)
         }
     }
 
@@ -159,7 +158,7 @@ class SelectFurnaceInventoryItemMouseInputHandler @Inject constructor(
                 } else {
                     window.selectedItem = window.furnace.result
                 }
-                window.furnace.items[Furnace.RESULT_INDEX] = null
+                window.furnace.items[Furnace.RESULT_INDEX] = gameItemsHolder.fallbackItem.toInventoryItem()
             }
         }
 
index 2e268d046261913cefb1737b0d37bf51703ab198..fa99bfd91ed2afa2ed63221b23374ba221ad1baa 100644 (file)
@@ -111,11 +111,21 @@ sealed class Block {
         return this is Slab
     }
 
+    fun isContainer(): Boolean {
+        contract { returns(true) implies (this@Block is Container) }
+        return this is Container
+    }
+
     fun isFurnace(): Boolean {
         contract { returns(true) implies (this@Block is Furnace) }
         return this is Furnace
     }
 
+    fun isChest(): Boolean {
+        contract { returns(true) implies (this@Block is Chest) }
+        return this is Chest
+    }
+
     fun isNone(): Boolean {
         contract { returns(true) implies (this@Block is None) }
         return this is None
@@ -130,6 +140,8 @@ sealed class Block {
         )
     }
 
+    sealed class Container() : Block()
+
     data class None(
         override val params: CommonBlockParams
     ) : Block()
@@ -140,7 +152,7 @@ sealed class Block {
 
     data class Furnace(
         override val params: CommonBlockParams,
-    ): Block() {
+    ): Container() {
 
         override val sprite: Sprite
             get() = getSprite(false)
@@ -169,6 +181,10 @@ sealed class Block {
 
     }
 
+    data class Chest(
+        override val params: CommonBlockParams
+    ): Container()
+
     data class Slab(
         override val params: CommonBlockParams,
         val fullBlockKey: String,
index acc0d2931efd026c4cfa3dcb9cba8b6e77322ded..44d3179839d2507e2f42dbcc33d0117c645d777d 100644 (file)
@@ -91,7 +91,9 @@ class InventoryItem @JvmOverloads constructor(
         }
 
         val sprite = item.sprite
-        spriteBatch.drawSprite(sprite, x, y)
+        val placeableMarginTop = (item as? Item.Placeable)?.block?.params?.spriteMargins?.top ?: 0
+        val placeableMarginLeft = (item as? Item.Placeable)?.block?.params?.spriteMargins?.left ?: 0
+        spriteBatch.drawSprite(sprite, x + placeableMarginLeft, y + placeableMarginTop)
 
         if (amount < 2) {
             return
index 2ec9727748b3860071fd3738c46603f28caa3a0d..1b641ed338a420a3cf502af7a9cd50f3e92e98b0 100644 (file)
@@ -24,6 +24,7 @@ class BlockMapper @Inject constructor(
             "lava" -> Lava(commonBlockParams, requireNotNull(dto.state))
             "slab" -> Slab(commonBlockParams, requireNotNull(dto.fullBlock), requireNotNull(dto.otherPart))
             "furnace" -> Furnace(commonBlockParams)
+            "chest" -> Chest(commonBlockParams)
             "none" -> None(commonBlockParams)
             else -> Normal(commonBlockParams)
         }
diff --git a/core/src/ru/deadsoftware/cavedroid/game/objects/container/Chest.kt b/core/src/ru/deadsoftware/cavedroid/game/objects/container/Chest.kt
new file mode 100644 (file)
index 0000000..be820bc
--- /dev/null
@@ -0,0 +1,14 @@
+package ru.deadsoftware.cavedroid.game.objects.container
+
+import ru.deadsoftware.cavedroid.game.GameItemsHolder
+
+class Chest(gameItemsHolder: GameItemsHolder) : Container(SIZE, gameItemsHolder) {
+
+    override fun update(gameItemsHolder: GameItemsHolder) {
+        // no-op
+    }
+
+    companion object {
+        private const val SIZE = 27
+    }
+}
\ No newline at end of file
diff --git a/core/src/ru/deadsoftware/cavedroid/game/objects/container/Container.kt b/core/src/ru/deadsoftware/cavedroid/game/objects/container/Container.kt
new file mode 100644 (file)
index 0000000..1e13c64
--- /dev/null
@@ -0,0 +1,24 @@
+package ru.deadsoftware.cavedroid.game.objects.container
+
+import ru.deadsoftware.cavedroid.game.GameItemsHolder
+import ru.deadsoftware.cavedroid.game.model.item.InventoryItem
+import java.io.Serializable
+import javax.annotation.OverridingMethodsMustInvokeSuper
+
+abstract class Container(
+    val size: Int,
+    gameItemsHolder: GameItemsHolder
+) : Serializable {
+
+    private val _items = Array(size) { gameItemsHolder.fallbackItem.toInventoryItem() }
+
+    val items get() = _items.asList() as MutableList<InventoryItem>
+
+    @OverridingMethodsMustInvokeSuper
+    open fun initItems(gameItemsHolder: GameItemsHolder) {
+        _items.forEach { it.init(gameItemsHolder) }
+    }
+
+    abstract fun update(gameItemsHolder: GameItemsHolder)
+
+}
\ No newline at end of file
diff --git a/core/src/ru/deadsoftware/cavedroid/game/objects/container/ContainerController.kt b/core/src/ru/deadsoftware/cavedroid/game/objects/container/ContainerController.kt
new file mode 100644 (file)
index 0000000..3facb6f
--- /dev/null
@@ -0,0 +1,86 @@
+package ru.deadsoftware.cavedroid.game.objects.container
+
+import com.badlogic.gdx.Gdx
+import ru.deadsoftware.cavedroid.game.GameItemsHolder
+import ru.deadsoftware.cavedroid.game.GameScope
+import ru.deadsoftware.cavedroid.game.model.block.Block
+import ru.deadsoftware.cavedroid.game.model.item.InventoryItem.Companion.isNoneOrNull
+import ru.deadsoftware.cavedroid.game.objects.drop.DropController
+import ru.deadsoftware.cavedroid.misc.utils.px
+import java.io.Serializable
+import javax.inject.Inject
+
+@GameScope
+class ContainerController @Inject constructor(
+    _dropController: DropController,
+    _gameItemsHolder: GameItemsHolder
+) : Serializable {
+
+    @Suppress("UNNECESSARY_LATEINIT")
+    @Transient
+    private lateinit var dropController: DropController
+
+    @Suppress("UNNECESSARY_LATEINIT")
+    @Transient
+    private lateinit var gameItemsHolder: GameItemsHolder
+
+    private val containerMap = mutableMapOf<String, Container>()
+
+    val size get() = containerMap.size
+
+    init {
+        dropController = _dropController
+        gameItemsHolder = _gameItemsHolder
+    }
+
+    fun init(dropController: DropController, gameItemsHolder: GameItemsHolder) {
+        this.dropController = dropController
+        this.gameItemsHolder = gameItemsHolder
+        containerMap.forEach { (_, container) -> container.initItems(gameItemsHolder) }
+    }
+
+    fun getContainer(x: Int, y: Int, z: Int): Container? {
+        return containerMap["$x;$y;$z"]
+    }
+
+    fun addContainer(x: Int, y: Int, z: Int, clazz: Class<out Block.Container>) {
+        val container = when (clazz) {
+            Block.Furnace::class.java -> Furnace(gameItemsHolder)
+            Block.Chest::class.java -> Chest(gameItemsHolder)
+            else -> {
+                Gdx.app.error(TAG, "Unknown container class $clazz")
+                return
+            }
+        }
+        containerMap["$x;$y;$z"] = container
+    }
+
+    @JvmOverloads
+    fun destroyContainer(x: Int, y: Int, z: Int, dropItems: Boolean = true) {
+        val container = containerMap.remove("$x;$y;$z") ?: return
+
+        if (!dropItems) {
+            return
+        }
+
+        val xPx = (x + .5f).px
+        val yPx = (y + .5f).px
+
+        container.items.forEach { item ->
+            if (!item.isNoneOrNull()) {
+                dropController.addDrop(xPx, yPx, item)
+            }
+        }
+    }
+
+    fun update() {
+        containerMap.forEach { (_, container) ->
+            container.update(gameItemsHolder)
+        }
+    }
+
+    companion object {
+        private const val TAG = "ContainerController"
+    }
+
+}
\ No newline at end of file
similarity index 71%
rename from core/src/ru/deadsoftware/cavedroid/game/objects/furnace/Furnace.kt
rename to core/src/ru/deadsoftware/cavedroid/game/objects/container/Furnace.kt
index 0265cb053625ffd1920a2b5ddba7602227921e33..1a75e89f83657b8222c2a7ba5e2e54f17bcf0508 100644 (file)
@@ -1,4 +1,4 @@
-package ru.deadsoftware.cavedroid.game.objects.furnace
+package ru.deadsoftware.cavedroid.game.objects.container
 
 import com.badlogic.gdx.Gdx
 import com.badlogic.gdx.math.MathUtils
@@ -7,25 +7,22 @@ import ru.deadsoftware.cavedroid.game.GameItemsHolder
 import ru.deadsoftware.cavedroid.game.model.item.InventoryItem
 import ru.deadsoftware.cavedroid.game.model.item.InventoryItem.Companion.isNoneOrNull
 import ru.deadsoftware.cavedroid.game.model.item.Item
-import java.io.Serializable
 
-class Furnace : Serializable {
-
-    val items = MutableList<InventoryItem?>(3) { null }
-
-    var fuel: InventoryItem?
+class Furnace(gameItemsHolder: GameItemsHolder) : Container(SIZE, gameItemsHolder) {
+    
+    var fuel: InventoryItem
         get() = items[FUEL_INDEX]
         set(value) {
             items[FUEL_INDEX] = value
         }
 
-    var input: InventoryItem?
+    var input: InventoryItem
         get() = items[INPUT_INDEX]
         set(value) {
             items[INPUT_INDEX] = value
         }
 
-    var result: InventoryItem?
+    var result: InventoryItem
         get() = items[RESULT_INDEX]
         set(value) {
             items[RESULT_INDEX] = value
@@ -56,27 +53,27 @@ class Furnace : Serializable {
 
     fun init(gameItemsHolder: GameItemsHolder) {
         currentFuel = currentFuelKey?.let { gameItemsHolder.getItem(it) }
-        items.forEach { it?.init(gameItemsHolder) }
+        items.forEach { it.init(gameItemsHolder) }
     }
 
     fun canSmelt(): Boolean {
-        return (result.isNoneOrNull() || (result?.item?.params?.key == input?.item?.params?.smeltProductKey) )&&
-                !input.isNoneOrNull() && input?.item?.params?.smeltProductKey != null &&
+        return (result.isNoneOrNull() || (result.item.params.key == input.item.params.smeltProductKey) )&&
+                !input.isNoneOrNull() && input.item.params.smeltProductKey != null &&
                 (!fuel.isNoneOrNull() || burnProgress > 0f)
     }
 
-    private fun startBurning() {
-        requireNotNull(fuel?.item?.params?.burningTimeMs) { "Cant start burning without fuel" }
-        currentFuel = fuel!!.item
-        fuel!!.subtract()
-        if (fuel!!.amount <= 0) {
-            fuel = null
+    private fun startBurning(gameItemsHolder: GameItemsHolder) {
+        requireNotNull(fuel.item.params.burningTimeMs) { "Cant start burning without fuel" }
+        currentFuel = fuel.item
+        fuel.subtract()
+        if (fuel.amount <= 0) {
+            fuel = gameItemsHolder.fallbackItem.toInventoryItem()
         }
         startBurnTimeMs = TimeUtils.millis()
         burnProgress = 0f
     }
 
-    fun update(gameItemsHolder: GameItemsHolder) {
+    override fun update(gameItemsHolder: GameItemsHolder) {
         if (currentFuel?.isNone() == true) {
             currentFuel = null
         }
@@ -96,7 +93,7 @@ class Furnace : Serializable {
 
         if (currentFuel?.isNone() == false && burnProgress >= 1f) {
             if (canSmelt()) {
-                startBurning()
+                startBurning(gameItemsHolder)
             } else {
                 currentFuel = null
                 burnProgress = 0f
@@ -108,7 +105,7 @@ class Furnace : Serializable {
             return
         }
         if (currentFuel == null && !fuel.isNoneOrNull()) {
-            startBurning()
+            startBurning(gameItemsHolder)
             smeltStarTimeMs = startBurnTimeMs
             smeltProgress = 0f
         }
@@ -119,15 +116,16 @@ class Furnace : Serializable {
         }
 
         if (isActive && smeltProgress >= 1f) {
-            val res = gameItemsHolder.getItem(input!!.item.params.smeltProductKey!!)
+            val productKey = requireNotNull(input.item.params.smeltProductKey)
+            val res = gameItemsHolder.getItem(productKey)
             if (result.isNoneOrNull())  {
                 result = res.toInventoryItem()
             } else {
-                result!!.add()
+                result.add()
             }
-            input!!.subtract()
-            if (input!!.amount <= 0) {
-                input = null
+            input.subtract()
+            if (input.amount <= 0) {
+                input = gameItemsHolder.fallbackItem.toInventoryItem()
             }
             smeltStarTimeMs = TimeUtils.millis()
             smeltProgress = 0f
@@ -135,6 +133,7 @@ class Furnace : Serializable {
     }
 
     companion object {
+        private const val SIZE = 3
         private const val TAG = "Furnace"
 
         const val FUEL_INDEX = 0
diff --git a/core/src/ru/deadsoftware/cavedroid/game/objects/furnace/FurnaceController.kt b/core/src/ru/deadsoftware/cavedroid/game/objects/furnace/FurnaceController.kt
deleted file mode 100644 (file)
index ccc3972..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-package ru.deadsoftware.cavedroid.game.objects.furnace
-
-import ru.deadsoftware.cavedroid.game.GameItemsHolder
-import ru.deadsoftware.cavedroid.game.GameScope
-import ru.deadsoftware.cavedroid.game.objects.drop.DropController
-import ru.deadsoftware.cavedroid.misc.utils.px
-import java.io.Serializable
-import javax.inject.Inject
-
-@GameScope
-class FurnaceController @Inject constructor() : Serializable {
-
-    private val furnaceMap = mutableMapOf<String, Furnace>()
-
-    fun init(gameItemsHolder: GameItemsHolder) {
-        furnaceMap.forEach { _, fur -> fur.init(gameItemsHolder) }
-    }
-
-    fun getFurnace(x: Int, y: Int, z: Int): Furnace? {
-        return furnaceMap["$x;$y;$z"]
-    }
-
-    fun addFurnace(x: Int, y: Int, z: Int) {
-        furnaceMap["$x;$y;$z"] = Furnace()
-    }
-
-    fun destroyFurnace(x: Int, y: Int, z: Int, dropController: DropController) {
-        val furnace = furnaceMap.remove("$x;$y;$z") ?: return
-        val xPx = (x + .5f).px
-        val yPx = (y + .5f).px
-
-        furnace.input?.let { dropController.addDrop(xPx, yPx, it) }
-        furnace.fuel?.let { dropController.addDrop(xPx, yPx, it) }
-        furnace.result?.let { dropController.addDrop(xPx, yPx, it) }
-    }
-
-    fun update(gameItemsHolder: GameItemsHolder) {
-        furnaceMap.forEach { _, furnace ->
-            furnace.update(gameItemsHolder)
-        }
-    }
-
-}
\ No newline at end of file
index 5af20e82f86a6b02ed319457fa97581c8edd425f..68af67b1242e23b979cd3e9b37cd445b8044ac80 100644 (file)
@@ -86,7 +86,7 @@ abstract class BlocksRenderer(
         if (foregroundBlock.canSeeThrough && !backgroundBlock.isNone()) {
             val drawX = x.px - viewport.x
             val drawY = y.px - viewport.y
-            if (backgroundBlock.isFurnace()) {
+            if (backgroundBlock is Block.Furnace) {
                 backgroundBlock.draw(spriteBatch, drawX, drawY, gameWorld.getBackgroundFurnace(x, y)?.isActive ?: false)
             } else {
                 backgroundBlock.draw(spriteBatch, drawX, drawY)
@@ -101,7 +101,7 @@ abstract class BlocksRenderer(
             val drawX = x.px - viewport.x
             val drawY = y.px - viewport.y
 
-            if (foregroundBlock.isFurnace()) {
+            if (foregroundBlock is Block.Furnace) {
                 foregroundBlock.draw(spriteBatch, drawX, drawY, gameWorld.getForegroundFurnace(x, y)?.isActive ?: false)
             } else {
                 foregroundBlock.draw(spriteBatch, drawX, drawY)
index f87c5bda2bbb165eef14154a0d143edfa8417687..fa37f8dc3d71798056ae72378bcca3e49991cb35 100644 (file)
@@ -6,10 +6,7 @@ import com.badlogic.gdx.graphics.glutils.ShapeRenderer
 import com.badlogic.gdx.math.Rectangle
 import ru.deadsoftware.cavedroid.game.GameScope
 import ru.deadsoftware.cavedroid.game.GameUiWindow
-import ru.deadsoftware.cavedroid.game.render.windows.CraftingWindowRenderer
-import ru.deadsoftware.cavedroid.game.render.windows.CreativeWindowRenderer
-import ru.deadsoftware.cavedroid.game.render.windows.FurnaceWindowRenderer
-import ru.deadsoftware.cavedroid.game.render.windows.SurvivalWindowRenderer
+import ru.deadsoftware.cavedroid.game.render.windows.*
 import ru.deadsoftware.cavedroid.game.ui.windows.GameWindowsManager
 import javax.inject.Inject
 
@@ -20,6 +17,7 @@ class WindowsRenderer @Inject constructor(
     private val craftingWindowRenderer: CraftingWindowRenderer,
     private val gameWindowsManager: GameWindowsManager,
     private val furnaceWindowRenderer: FurnaceWindowRenderer,
+    private val chestWindowRenderer: ChestWindowRenderer,
 ) : IGameRenderer {
 
     override val renderLayer get() = RENDER_LAYER
@@ -30,6 +28,7 @@ class WindowsRenderer @Inject constructor(
             GameUiWindow.SURVIVAL_INVENTORY -> survivalWindowRenderer.draw(spriteBatch, shapeRenderer, viewport, delta)
             GameUiWindow.CRAFTING_TABLE -> craftingWindowRenderer.draw(spriteBatch, shapeRenderer, viewport, delta)
             GameUiWindow.FURNACE -> furnaceWindowRenderer.draw(spriteBatch, shapeRenderer, viewport, delta)
+            GameUiWindow.CHEST -> chestWindowRenderer.draw(spriteBatch, shapeRenderer, viewport, delta)
             GameUiWindow.NONE -> return
             else -> Gdx.app.error(TAG, "Cannot draw window: ${windowType.name}")
         }
diff --git a/core/src/ru/deadsoftware/cavedroid/game/render/windows/ChestWindowRenderer.kt b/core/src/ru/deadsoftware/cavedroid/game/render/windows/ChestWindowRenderer.kt
new file mode 100644 (file)
index 0000000..78178bc
--- /dev/null
@@ -0,0 +1,93 @@
+package ru.deadsoftware.cavedroid.game.render.windows
+
+import com.badlogic.gdx.Gdx
+import com.badlogic.gdx.graphics.g2d.SpriteBatch
+import com.badlogic.gdx.graphics.glutils.ShapeRenderer
+import com.badlogic.gdx.math.MathUtils
+import com.badlogic.gdx.math.Rectangle
+import ru.deadsoftware.cavedroid.MainConfig
+import ru.deadsoftware.cavedroid.game.GameItemsHolder
+import ru.deadsoftware.cavedroid.game.GameScope
+import ru.deadsoftware.cavedroid.game.mobs.Mob
+import ru.deadsoftware.cavedroid.game.mobs.MobsController
+import ru.deadsoftware.cavedroid.game.render.IGameRenderer
+import ru.deadsoftware.cavedroid.game.render.WindowsRenderer
+import ru.deadsoftware.cavedroid.game.ui.windows.GameWindowsConfigs
+import ru.deadsoftware.cavedroid.game.ui.windows.GameWindowsManager
+import ru.deadsoftware.cavedroid.game.ui.windows.inventory.ChestInventoryWindow
+import ru.deadsoftware.cavedroid.game.ui.windows.inventory.SurvivalInventoryWindow
+import ru.deadsoftware.cavedroid.misc.Assets
+import javax.inject.Inject
+import kotlin.math.atan
+
+@GameScope
+class ChestWindowRenderer @Inject constructor(
+    private val mainConfig: MainConfig,
+    private val mobsController: MobsController,
+    private val gameWindowsManager: GameWindowsManager,
+    private val gameItemsHolder: GameItemsHolder,
+) : AbstractWindowRenderer(), IGameRenderer {
+
+    override val renderLayer get() = WindowsRenderer.RENDER_LAYER
+
+    private val chestWindowTexture get() = requireNotNull(Assets.textureRegions[CHEST_WINDOW_KEY])
+    
+    
+    override fun draw(spriteBatch: SpriteBatch, shapeRenderer: ShapeRenderer, viewport: Rectangle, delta: Float) {
+        val windowTexture = chestWindowTexture
+        val window = gameWindowsManager.currentWindow as ChestInventoryWindow
+
+        val windowX = viewport.width / 2 - windowTexture.regionWidth / 2
+        val windowY = viewport.height / 2 - windowTexture.regionHeight / 2
+
+        spriteBatch.draw(windowTexture, windowX, windowY)
+
+        drawItemsGrid(
+            spriteBatch = spriteBatch,
+            shapeRenderer = shapeRenderer,
+            gridX = windowX + GameWindowsConfigs.Chest.contentsMarginLeft,
+            gridY = windowY + GameWindowsConfigs.Chest.contentsMarginTop,
+            items = window.chest.items,
+            itemsInRow = GameWindowsConfigs.Chest.itemsInRow,
+            cellWidth = GameWindowsConfigs.Chest.itemsGridColWidth,
+            cellHeight = GameWindowsConfigs.Chest.itemsGridRowHeight,
+        )
+        
+        drawItemsGrid(
+            spriteBatch = spriteBatch,
+            shapeRenderer = shapeRenderer,
+            gridX = windowX + GameWindowsConfigs.Chest.itemsGridMarginLeft,
+            gridY = windowY + GameWindowsConfigs.Chest.itemsGridMarginTop,
+            items = mobsController.player.inventory.items.asSequence()
+                .drop(GameWindowsConfigs.Chest.hotbarCells)
+                .take(GameWindowsConfigs.Chest.itemsInCol * GameWindowsConfigs.Chest.itemsInRow)
+                .asIterable(),
+            itemsInRow = GameWindowsConfigs.Chest.itemsInRow,
+            cellWidth = GameWindowsConfigs.Chest.itemsGridColWidth,
+            cellHeight = GameWindowsConfigs.Chest.itemsGridRowHeight,
+        )
+
+        drawItemsGrid(
+            spriteBatch = spriteBatch,
+            shapeRenderer = shapeRenderer,
+            gridX = windowX + GameWindowsConfigs.Chest.itemsGridMarginLeft,
+            gridY = windowY + windowTexture.regionHeight - GameWindowsConfigs.Chest.hotbarOffsetFromBottom,
+            items = mobsController.player.inventory.items.asSequence()
+                .take(GameWindowsConfigs.Chest.hotbarCells)
+                .asIterable(),
+            itemsInRow = GameWindowsConfigs.Chest.hotbarCells,
+            cellWidth = GameWindowsConfigs.Chest.itemsGridColWidth,
+            cellHeight = GameWindowsConfigs.Chest.itemsGridRowHeight,
+        )
+
+        window.selectedItem?.drawSelected(
+            spriteBatch = spriteBatch,
+            x = Gdx.input.x * (viewport.width / Gdx.graphics.width),
+            y = Gdx.input.y * (viewport.height / Gdx.graphics.height)
+        )
+    }
+
+    companion object {
+        private const val CHEST_WINDOW_KEY = "chest"
+    }
+}
\ No newline at end of file
index a9635025fd00371c2cdbdae240e9101d65529b3d..3037009a5c8e843e84ddb089e29369baa06c3e23 100644 (file)
@@ -4,12 +4,10 @@ import com.badlogic.gdx.Gdx
 import com.badlogic.gdx.graphics.g2d.SpriteBatch
 import com.badlogic.gdx.graphics.glutils.ShapeRenderer
 import com.badlogic.gdx.math.Rectangle
-import com.badlogic.gdx.utils.TimeUtils
 import ru.deadsoftware.cavedroid.MainConfig
 import ru.deadsoftware.cavedroid.game.GameItemsHolder
 import ru.deadsoftware.cavedroid.game.GameScope
 import ru.deadsoftware.cavedroid.game.mobs.MobsController
-import ru.deadsoftware.cavedroid.game.objects.furnace.Furnace
 import ru.deadsoftware.cavedroid.game.render.IGameRenderer
 import ru.deadsoftware.cavedroid.game.render.WindowsRenderer
 import ru.deadsoftware.cavedroid.game.ui.windows.GameWindowsConfigs
index 0a8ddf8e45019d9ec2e84d5b605f6c1de71f333a..2f1d2645aac11d7bd84b33e76eaf784b7025de60 100644 (file)
@@ -101,4 +101,24 @@ object GameWindowsConfigs {
         const val progressMarginTop = 34f
         const val progressWidth = 24f
     }
+
+    data object Chest {
+        const val itemsGridMarginLeft = 8f
+        const val itemsGridMarginTop = 86f
+
+        const val itemsGridRowHeight = 18f
+        const val itemsGridColWidth = 18f
+
+        const val hotbarCells = 9
+        const val hotbarOffsetFromBottom = 24f
+
+        const val itemsInRow = 9
+        const val itemsInCol = 5
+
+        const val contentsMarginLeft = 8f
+        const val contentsMarginTop = 18f
+
+        const val contentsInRow = 9
+        const val contentsInCol = 3
+    }
 }
\ No newline at end of file
index 1b6611af1e06601615ebc4d6802801c6491cee86..32494ed4e7721784b9a057b129819a4451cf34a3 100644 (file)
@@ -3,8 +3,9 @@ package ru.deadsoftware.cavedroid.game.ui.windows
 import ru.deadsoftware.cavedroid.game.GameScope
 import ru.deadsoftware.cavedroid.game.GameUiWindow
 import ru.deadsoftware.cavedroid.game.mobs.MobsController
+import ru.deadsoftware.cavedroid.game.objects.container.Chest
 import ru.deadsoftware.cavedroid.game.objects.drop.DropController
-import ru.deadsoftware.cavedroid.game.objects.furnace.Furnace
+import ru.deadsoftware.cavedroid.game.objects.container.Furnace
 import ru.deadsoftware.cavedroid.game.ui.TooltipManager
 import ru.deadsoftware.cavedroid.game.ui.windows.inventory.*
 import javax.inject.Inject
@@ -38,6 +39,10 @@ class GameWindowsManager @Inject constructor(
         currentWindow = FurnaceInventoryWindow(furnace)
     }
 
+    fun openChest(chest: Chest) {
+        currentWindow = ChestInventoryWindow(chest)
+    }
+
     fun openCrafting() {
         currentWindow = CraftingInventoryWindow()
     }
diff --git a/core/src/ru/deadsoftware/cavedroid/game/ui/windows/inventory/ChestInventoryWindow.kt b/core/src/ru/deadsoftware/cavedroid/game/ui/windows/inventory/ChestInventoryWindow.kt
new file mode 100644 (file)
index 0000000..6f4a4fe
--- /dev/null
@@ -0,0 +1,13 @@
+package ru.deadsoftware.cavedroid.game.ui.windows.inventory
+
+import ru.deadsoftware.cavedroid.game.GameUiWindow
+import ru.deadsoftware.cavedroid.game.model.item.InventoryItem
+import ru.deadsoftware.cavedroid.game.objects.container.Chest
+
+class ChestInventoryWindow(val chest: Chest) : AbstractInventoryWindow() {
+
+    override val type = GameUiWindow.CHEST
+
+    override var selectedItem: InventoryItem? = null
+
+}
\ No newline at end of file
index 5adaac63ddb4631b4ce6fd3000e176502931e835..42f7038f4313f4caea875042c925b44d0cdc93e9 100644 (file)
@@ -2,7 +2,7 @@ package ru.deadsoftware.cavedroid.game.ui.windows.inventory
 
 import ru.deadsoftware.cavedroid.game.GameUiWindow
 import ru.deadsoftware.cavedroid.game.model.item.InventoryItem
-import ru.deadsoftware.cavedroid.game.objects.furnace.Furnace
+import ru.deadsoftware.cavedroid.game.objects.container.Furnace
 
 class FurnaceInventoryWindow(
     val furnace: Furnace,
index 0d5a80ae49cf7fccbf9d7c3aff5723e451bf5c84..c038f1541d21822f90c122a75e30961dfee1fa40 100644 (file)
@@ -8,9 +8,10 @@ import ru.deadsoftware.cavedroid.game.model.block.Block;
 import ru.deadsoftware.cavedroid.game.model.item.InventoryItem;
 import ru.deadsoftware.cavedroid.game.model.item.Item;
 import ru.deadsoftware.cavedroid.game.model.world.generator.WorldGeneratorConfig;
+import ru.deadsoftware.cavedroid.game.objects.container.Container;
 import ru.deadsoftware.cavedroid.game.objects.drop.DropController;
-import ru.deadsoftware.cavedroid.game.objects.furnace.Furnace;
-import ru.deadsoftware.cavedroid.game.objects.furnace.FurnaceController;
+import ru.deadsoftware.cavedroid.game.objects.container.Furnace;
+import ru.deadsoftware.cavedroid.game.objects.container.ContainerController;
 import ru.deadsoftware.cavedroid.misc.utils.MeasureUnitsUtilsKt;
 
 import javax.annotation.CheckForNull;
@@ -19,10 +20,13 @@ import javax.inject.Inject;
 @GameScope
 public class GameWorld {
 
+    private static final int FOREGROUND_Z = 0;
+    private static final int BACKGROUND_Z = 1;
+
     private final DropController mDropController;
     private final MobsController mMobsController;
     private final GameItemsHolder mGameItemsHolder;
-    private final FurnaceController mFurnaceController;
+    private final ContainerController mContainerController;
 
     private final int mWidth;
     private final int mHeight;
@@ -35,13 +39,13 @@ public class GameWorld {
     public GameWorld(DropController dropController,
                      MobsController mobsController,
                      GameItemsHolder gameItemsHolder,
-                     FurnaceController furnaceController,
+                     ContainerController containerController,
                      @CheckForNull Block[][] foreMap,
                      @CheckForNull Block[][] backMap) {
         mDropController = dropController;
         mMobsController = mobsController;
         mGameItemsHolder = gameItemsHolder;
-        mFurnaceController = furnaceController;
+        mContainerController = containerController;
 
         boolean isNewGame = foreMap == null || backMap == null;
 
@@ -129,6 +133,12 @@ public class GameWorld {
             return;
         }
 
+        mContainerController.destroyContainer(x, y, layer, false);
+
+        if (value.isContainer()) {
+            mContainerController.addContainer(x, y, layer, (Class<? extends Block.Container>) value.getClass());
+        }
+
         if (layer == 0) {
             mForeMap[x][y] = value;
         } else {
@@ -146,19 +156,19 @@ public class GameWorld {
     }
 
     public boolean hasForeAt(int x, int y) {
-        return getMap(x, y, 0) != mGameItemsHolder.getFallbackBlock();
+        return getMap(x, y, FOREGROUND_Z) != mGameItemsHolder.getFallbackBlock();
     }
 
     public boolean hasBackAt(int x, int y) {
-        return getMap(x, y, 1) != mGameItemsHolder.getFallbackBlock();
+        return getMap(x, y, BACKGROUND_Z) != mGameItemsHolder.getFallbackBlock();
     }
 
     public Block getForeMap(int x, int y) {
-        return getMap(x, y, 0);
+        return getMap(x, y, FOREGROUND_Z);
     }
 
     public void setForeMap(int x, int y, Block block) {
-        setMap(x, y, 0, block);
+        setMap(x, y, FOREGROUND_Z, block);
     }
 
     public void resetForeMap(int x, int y) {
@@ -166,20 +176,15 @@ public class GameWorld {
     }
 
     public Block getBackMap(int x, int y) {
-        return getMap(x, y, 1);
+        return getMap(x, y, BACKGROUND_Z);
     }
 
     public void setBackMap(int x, int y, Block block) {
-        setMap(x, y, 1, block);
+        setMap(x, y, BACKGROUND_Z, block);
     }
 
     public boolean placeToForeground(int x, int y, Block value) {
         if (!hasForeAt(x, y) || value == mGameItemsHolder.getFallbackBlock() || !getForeMap(x, y).hasCollision()) {
-
-            if (value.isFurnace()) {
-                mFurnaceController.addFurnace(x, y, 0);
-            }
-
             setForeMap(x, y, value);
             return true;
         } else if (value instanceof Block.Slab && isSameSlab(value, getForeMap(x, y))) {
@@ -191,10 +196,7 @@ public class GameWorld {
 
     public boolean placeToBackground(int x, int y, Block value) {
         if (value == mGameItemsHolder.getFallbackBlock() || (getBackMap(x, y) == mGameItemsHolder.getFallbackBlock() && value.hasCollision()) &&
-                (!value.isTransparent() || value == mGameItemsHolder.getBlock("glass"))) {
-            if (value.isFurnace()) {
-                mFurnaceController.addFurnace(x, y, 1);
-            }
+                (!value.isTransparent() || value == mGameItemsHolder.getBlock("glass") || value.isChest() || value.isSlab())) {
             setBackMap(x, y, value);
             return true;
         }
@@ -219,8 +221,8 @@ public class GameWorld {
 
     public void destroyForeMap(int x, int y) {
         Block block = getForeMap(x, y);
-        if (block.isFurnace()) {
-            mFurnaceController.destroyFurnace(x, y, 0, mDropController);
+        if (block.isContainer()) {
+            mContainerController.destroyContainer(x, y, FOREGROUND_Z);
         }
         if (block.hasDrop() && shouldDrop(block)) {
             for (int i = 0; i < block.getParams().getDropInfo().getCount(); i++) {
@@ -237,9 +239,6 @@ public class GameWorld {
 
     public void destroyBackMap(int x, int y) {
         Block block = getBackMap(x, y);
-        if (block.isFurnace()) {
-            mFurnaceController.destroyFurnace(x, y, 0, mDropController);
-        }
         if (block.hasDrop() && shouldDrop(block)) {
             for (int i = 0; i < block.getParams().getDropInfo().getCount(); i++) {
                 mDropController.addDrop(transformX(x) * 16 + 4, y * 16 + 4, mGameItemsHolder.getItem(block.getDrop()));
@@ -249,13 +248,42 @@ public class GameWorld {
         placeToBackground(x, y, mGameItemsHolder.getFallbackBlock());
     }
 
+    @CheckForNull
+    private Container getContainerAt(int x, int y, int z) {
+        return mContainerController.getContainer(transformX(x), y, z);
+    }
+
+    @CheckForNull
+    public Container getForegroundContainer(int x, int y) {
+        return getContainerAt(x, y, FOREGROUND_Z);
+    }
+
+    @CheckForNull
+    public Container getBackgroundContainer(int x, int y) {
+        return getContainerAt(x, y, BACKGROUND_Z);
+    }
+
     @CheckForNull
     public Furnace getForegroundFurnace(int x, int y) {
-        return mFurnaceController.getFurnace(x, y, 0);
+        @CheckForNull
+        final Container container = getForegroundContainer(x, y);
+
+        if (container instanceof Furnace) {
+            return (Furnace) container;
+        }
+
+        return null;
     }
 
     @CheckForNull
     public Furnace getBackgroundFurnace(int x, int y) {
-        return mFurnaceController.getFurnace(x, y, 1);
+        @CheckForNull
+        final Container container = getBackgroundContainer(x, y);
+
+        if (container instanceof Furnace) {
+            return (Furnace) container;
+        }
+
+        return null;
     }
 }
\ No newline at end of file