From: fredboy Date: Wed, 15 May 2024 18:43:26 +0000 (+0700) Subject: Add my repo for automultibind X-Git-Url: https://deadsoftware.ru/gitweb?p=cavedroid.git;a=commitdiff_plain;h=HEAD;hp=387ad284ceb79b07cba3726fa7350b7e83916815 Add my repo for automultibind --- diff --git a/.gitignore b/.gitignore index e03f558..b24a8ed 100644 --- a/.gitignore +++ b/.gitignore @@ -119,3 +119,5 @@ Thumbs.db release-*/ keystore.properties + +*/build/ diff --git a/COPYING b/COPYING index 6d0eb3a..90ecac3 100644 --- a/COPYING +++ b/COPYING @@ -1,7 +1,13 @@ This game is distributed under MIT License (see LICENSE). -Textures used in this game: +Textures used in this game (in android/assets/pp directory): Pixel Perfection by XSSheep is licensed under a Creative Commons Attribution-Share Alike 4.0 International License. https://creativecommons.org/licenses/by-sa/4.0/ +On screen joystick is CC-0 from opengameart.org: +https://opengameart.org/content/mmorpg-virtual-joysticks + +Font is Minecraft Font by JDGraphics licensed as Public Domain: +https://www.fontspace.com/minecraft-font-f28180 + Some scripts from stack overflow are distributed under applicable licenses diff --git a/README.md b/README.md index 684c5a3..bf5e371 100644 --- a/README.md +++ b/README.md @@ -3,10 +3,18 @@ [![GitHub Tag](https://img.shields.io/github/v/tag/fredboy/cavedroid)](https://github.com/fredboy/cavedroid/tags)
2D Minecraft clone for Android and Desktop.
Written in Java using libGDX framework.
+
+ Screenshot + +![Screenshot](https://fredboy.ru/pub/cavedroid/screenshot.png) + +
+ ## Binary releases You can download apk and jar from here:
## Build instructions +You need to publish [my ksp processor](https://github.com/fredboy/automultibind) to mavenLocal repository first. ### Android To build for Android use
`./gradlew android:assemble`
diff --git a/android/assets/health.png b/android/assets/health.png deleted file mode 100644 index 93314e6..0000000 Binary files a/android/assets/health.png and /dev/null differ diff --git a/android/assets/icons/icon128.png b/android/assets/icons/icon128.png index 19e4532..08d0b74 100644 Binary files a/android/assets/icons/icon128.png and b/android/assets/icons/icon128.png differ diff --git a/android/assets/icons/icon256.png b/android/assets/icons/icon256.png index 3b8b92b..4e36964 100644 Binary files a/android/assets/icons/icon256.png and b/android/assets/icons/icon256.png differ diff --git a/android/assets/icons/icon512.png b/android/assets/icons/icon512.png new file mode 100644 index 0000000..35aa45b Binary files /dev/null and b/android/assets/icons/icon512.png differ diff --git a/android/assets/joy_background.png b/android/assets/joy_background.png new file mode 100644 index 0000000..b1ea80b Binary files /dev/null and b/android/assets/joy_background.png differ diff --git a/android/assets/joy_stick.png b/android/assets/joy_stick.png new file mode 100644 index 0000000..525dd7f Binary files /dev/null and b/android/assets/joy_stick.png differ diff --git a/android/assets/json/crafting.json b/android/assets/json/crafting.json index 6f651bb..9a67e01 100644 --- a/android/assets/json/crafting.json +++ b/android/assets/json/crafting.json @@ -3,24 +3,28 @@ "input": ["log_oak", "none", "none", "none", "none", "none", "none", "none", "none"], "count": 4 }, + "planks_spruce": { + "input": ["log_spruce", "none", "none", "none", "none", "none", "none", "none", "none"], + "count": 4 + }, "stick": { - "input": ["planks_oak", "none", "none", "planks_oak", "none", "none", "none", "none", "none"], + "input": ["planks.*", "none", "none", "planks.*", "none", "none", "none", "none", "none"], "count": 4 }, "wood_pickaxe": { - "input": ["planks_oak", "planks_oak", "planks_oak", "none", "stick", "none", "none", "stick", "none"], + "input": ["planks.*", "planks.*", "planks.*", "none", "stick", "none", "none", "stick", "none"], "count": 59 }, "wood_axe": { - "input": ["planks_oak", "planks_oak", "none", "planks_oak", "stick", "none", "none", "stick", "none"], + "input": ["planks.*", "planks.*", "none", "planks.*", "stick", "none", "none", "stick", "none"], "count": 60 }, "wood_sword": { - "input": ["none", "planks_oak", "none", "none", "planks_oak", "none", "none", "stick", "none"], + "input": ["planks.*", "none", "none", "planks.*", "none", "none", "stick", "none", "none"], "count": 60 }, "wood_shovel": { - "input": ["none", "planks_oak", "none", "none", "stick", "none", "none", "stick", "none"], + "input": ["planks.*", "none", "none", "stick", "none", "none", "stick", "none", "none"], "count": 59 }, "stone_pickaxe": { @@ -32,11 +36,75 @@ "count": 131 }, "stone_sword": { - "input": ["none", "cobblestone", "none", "none", "cobblestone", "none", "none", "stick", "none"], + "input": ["cobblestone", "none", "none", "cobblestone", "none", "none", "stick", "none", "none"], "count": 132 }, "stone_shovel": { - "input": ["none", "cobblestone", "none", "none", "stick", "none", "none", "stick", "none"], + "input": ["cobblestone", "none", "none", "stick", "none", "none", "stick", "none", "none"], "count": 131 + }, + "iron_pickaxe": { + "input": ["iron_ingot", "iron_ingot", "iron_ingot", "none", "stick", "none", "none", "stick", "none"], + "count": 251 + }, + "iron_axe": { + "input": ["iron_ingot", "iron_ingot", "none", "iron_ingot", "stick", "none", "none", "stick", "none"], + "count": 250 + }, + "iron_sword": { + "input": ["iron_ingot", "none", "none", "iron_ingot", "none", "none", "stick", "none", "none"], + "count": 251 + }, + "iron_shovel": { + "input": ["iron_ingot", "none", "none", "stick", "none", "none", "stick", "none", "none"], + "count": 250 + }, + "gold_pickaxe": { + "input": ["gold_ingot", "gold_ingot", "gold_ingot", "none", "stick", "none", "none", "stick", "none"], + "count": 33 + }, + "gold_axe": { + "input": ["gold_ingot", "gold_ingot", "none", "gold_ingot", "stick", "none", "none", "stick", "none"], + "count": 32 + }, + "gold_sword": { + "input": ["gold_ingot", "none", "none", "gold_ingot", "none", "none", "stick", "none", "none"], + "count": 33 + }, + "gold_shovel": { + "input": ["gold_ingot", "none", "none", "stick", "none", "none", "stick", "none", "none"], + "count": 32 + }, + "diamond_pickaxe": { + "input": ["diamond", "diamond", "diamond", "none", "stick", "none", "none", "stick", "none"], + "count": 1562 + }, + "diamond_axe": { + "input": ["diamond", "diamond", "none", "diamond", "stick", "none", "none", "stick", "none"], + "count": 1561 + }, + "diamond_sword": { + "input": ["diamond", "none", "none", "diamond", "none", "none", "stick", "none", "none"], + "count": 1562 + }, + "diamond_shovel": { + "input": ["diamond", "none", "none", "stick", "none", "none", "stick", "none", "none"], + "count": 1561 + }, + "snow_block": { + "input": ["snowball", "snowball", "none", "snowball", "snowball", "none", "none", "none", "none"], + "count": 1 + }, + "crafting_table": { + "input": ["planks.*", "planks.*", "none", "planks.*", "planks.*", "none", "none", "none", "none"] + }, + "furnace": { + "input": ["cobblestone", "cobblestone", "cobblestone", "cobblestone", "none", "cobblestone", "cobblestone", "cobblestone", "cobblestone"] + }, + "chest": { + "input": ["planks_.*", "planks_.*", "planks_.*", "planks_.*", "none", "planks_.*", "planks_.*", "planks_.*", "planks_.*"] + }, + "bed": { + "input": ["wool_.*", "wool_.*", "wool_.*", "planks_.*", "planks_.*", "planks_.*", "none", "none", "none"] } } \ No newline at end of file diff --git a/android/assets/json/game_items.json b/android/assets/json/game_items.json index d6c3b44..5c11576 100644 --- a/android/assets/json/game_items.json +++ b/android/assets/json/game_items.json @@ -49,6 +49,20 @@ "tool_level": 0, "tool_type": "axe" }, + "planks_spruce": { + "hp": 180, + "drop": "planks_spruce", + "texture": "planks_spruce", + "tool_level": 0, + "tool_type": "axe" + }, + "crafting_table": { + "hp": 180, + "drop": "crafting_table", + "texture": "crafting_table", + "tool_level": 0, + "tool_type": "axe" + }, "sapling_oak": { "collision": false, "transparent": true, @@ -57,6 +71,14 @@ "texture": "sapling_oak", "hp": 0 }, + "sapling_spruce": { + "collision": false, + "transparent": true, + "block_required": true, + "drop": "sapling_spruce", + "texture": "sapling_spruce", + "hp": 0 + }, "bedrock": { "drop": "bedrock", "texture": "bedrock" @@ -145,6 +167,21 @@ "tool_type": "shears", "tint": "#5AC557" }, + "log_spruce": { + "hp": 180, + "drop": "log_spruce", + "texture": "log_spruce", + "tool_level": 0, + "tool_type": "axe" + }, + "leaves_spruce": { + "hp": 21, + "drop": "leaves_spruce", + "texture": "leaves_spruce", + "tool_level": 1, + "tool_type": "shears", + "tint": "#486D4E" + }, "sponge": { "hp": 54, "drop": "sponge", @@ -191,7 +228,7 @@ "collision": false, "background": true, "transparent": true, - "drop": "none", + "drop": "bed", "texture": "bed_l", "tool_level": 0, "tool_type": "axe" @@ -201,7 +238,7 @@ "collision": false, "background": true, "transparent": true, - "drop": "none", + "drop": "bed", "texture": "bed_r", "tool_level": 0, "tool_type": "axe" @@ -487,6 +524,32 @@ "tool_level": 0, "tool_type": "axe" }, + "spruce_slab_bottom": { + "top": 8, + "sprite_top": 8, + "hp": 180, + "transparent": true, + "drop": "spruce_slab", + "meta": "slab", + "texture": "planks_spruce", + "full_block": "planks_spruce", + "other_part": "spruce_slab_top", + "tool_level": 0, + "tool_type": "axe" + }, + "spruce_slab_top": { + "bottom": 8, + "sprite_bottom": 8, + "hp": 180, + "transparent": true, + "drop": "spruce_slab", + "meta": "slab", + "texture": "planks_spruce", + "full_block": "planks_spruce", + "other_part": "spruce_slab_bottom", + "tool_level": 0, + "tool_type": "axe" + }, "cobblestone_slab_bottom": { "top": 8, "sprite_top": 8, @@ -683,6 +746,56 @@ "texture": "obsidian", "tool_level": 4, "tool_type": "pickaxe" + }, + "snow": { + "top": 14, + "sprite_top": 14, + "collision": false, + "transparent": true, + "drop": "snowball", + "texture": "snow", + "hp": 6, + "tool_level": 1, + "tool_type": "shovel", + "block_required": true + }, + "snow_block": { + "collision": true, + "transparent": true, + "drop": "snowball", + "drop_count": 4, + "texture": "snow", + "hp": 60, + "tool_level": 1, + "tool_type": "shovel" + }, + "furnace": { + "hp": 1050, + "collision": true, + "transparent": false, + "drop": "furnace", + "texture": "furnace", + "animated": true, + "frames": 2, + "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": { @@ -709,37 +822,59 @@ "cobblestone": { "name": "Cobblestone", "type": "block", - "texture": "cobblestone" + "texture": "cobblestone", + "smelt_product": "stone" }, "planks_oak": { "name": "Oak Planks", "type": "block", - "texture": "planks_oak" + "texture": "planks_oak", + "burning_time": 15000 }, "sapling_oak": { "name": "Oak Sapling", "type": "block", - "texture": "sapling_oak" + "texture": "sapling_oak", + "burning_time": 5000 }, - "bedrock": { - "name": "Bedrock", + "planks_spruce": { + "name": "Spruce Planks", "type": "block", - "texture": "bedrock" + "texture": "planks_spruce", + "burning_time": 15000 }, - "water": { - "name": "Water", + "crafting_table": { + "name": "Crafting Table", "type": "block", - "texture": "water" + "texture": "crafting_table", + "burning_time": 15000 }, - "lava": { - "name": "Lava", + "furnace": { + "name": "Furnace", + "type": "block", + "texture": "furnace_off" + }, + "chest": { + "name": "Chest", + "type": "block", + "texture": "chest" + }, + "sapling_spruce": { + "name": "Spruce Sapling", + "type": "block", + "texture": "sapling_spruce", + "burning_time": 5000 + }, + "bedrock": { + "name": "Bedrock", "type": "block", - "texture": "lava" + "texture": "bedrock" }, "sand": { "name": "Sand", "type": "block", - "texture": "sand" + "texture": "sand", + "smelt_product": "glass" }, "gravel": { "name": "Gravel", @@ -749,33 +884,51 @@ "gold_ore": { "name": "Golden Ore", "type": "block", - "texture": "gold_ore" + "texture": "gold_ore", + "smelt_product": "gold_ingot" }, "iron_ore": { "name": "Iron Ore", "type": "block", - "texture": "iron_ore" + "texture": "iron_ore", + "smelt_product": "iron_ingot" }, "coal_ore": { "name": "Coal Ore", "type": "block", - "texture": "coal_ore" + "texture": "coal_ore", + "smelt_product": "coal" }, "diamond_ore": { "name": "Diamond Ore", "type": "block", - "texture": "diamond_ore" + "texture": "diamond_ore", + "smelt_product": "diamond" }, "log_oak": { "name": "Wood", "type": "block", - "texture": "log_oak" + "texture": "log_oak", + "burning_time": 15000, + "smelt_product": "charcoal" }, "leaves_oak": { "name": "Leaves", "type": "block", "texture": "leaves_oak" }, + "log_spruce": { + "name": "Spruce", + "type": "block", + "texture": "log_spruce", + "burning_time": 15000, + "smelt_product": "charcoal" + }, + "leaves_spruce": { + "name": "Spruce Leaves", + "type": "block", + "texture": "leaves_spruce" + }, "glass": { "name": "Glass", "type": "block", @@ -784,7 +937,8 @@ "lapis_ore": { "name": "Lapis Ore", "type": "block", - "texture": "lapis_ore" + "texture": "lapis_ore", + "smelt_product": "lapis_lazuli" }, "lapis_block": { "name": "Lapis Block", @@ -811,7 +965,8 @@ "name": "Dead Bush", "type": "block", "texture": "deadbush", - "origin_x": 0.5 + "origin_x": 0.5, + "burning_time": 5000 }, "bricks": { "name": "Bricks", @@ -956,7 +1111,16 @@ "type": "slab", "texture": "oak_slab", "top_slab_block": "oak_slab_top", - "bottom_slab_block": "oak_slab_bottom" + "bottom_slab_block": "oak_slab_bottom", + "burn_time": 7500 + }, + "spruce_slab": { + "name": "Spruce Slab", + "type": "slab", + "texture": "spruce_slab", + "top_slab_block": "spruce_slab_top", + "bottom_slab_block": "spruce_slab_bottom", + "burn_time": 7500 }, "cobblestone_slab": { "name": "Cobblestone Slab", @@ -994,9 +1158,15 @@ "type": "block", "texture": "obsidian" }, + "snow_block": { + "name": "Snow Block", + "type": "block", + "texture": "snow" + }, "stick": { "name": "Stick", - "texture": "stick" + "texture": "stick", + "burning_time": 5000 }, "wood_sword": { "name": "Wooden Sword", @@ -1004,7 +1174,8 @@ "texture": "wood_sword", "origin_x": 0.125, "tool_level": 1, - "max_stack": 60 + "max_stack": 60, + "burning_time": 10000 }, "stone_sword": { "name": "Stone Sword", @@ -1085,7 +1256,8 @@ "texture": "wood_pickaxe", "origin_x": 0.125, "tool_level" : 1, - "max_stack": 59 + "max_stack": 59, + "burning_time": 10000 }, "stone_pickaxe": { "name": "Stone Pickaxe", @@ -1126,7 +1298,8 @@ "texture": "wood_axe", "origin_x": 0.125, "tool_level" : 1, - "max_stack": 60 + "max_stack": 60, + "burning_time": 10000 }, "stone_axe": { "name": "Stone Axe", @@ -1171,7 +1344,7 @@ }, "bucket_empty": { "name": "Empty Bucket", - "type": "bucket", + "type": "usable", "texture": "bucket_empty", "origin_x": 0.25, "action_key": "use_empty_bucket", @@ -1179,7 +1352,7 @@ }, "bucket_water": { "name": "Water Bucket", - "type": "bucket", + "type": "usable", "texture": "bucket_water", "origin_x": 0.25, "action_key": "use_water_bucket", @@ -1187,11 +1360,65 @@ }, "bucket_lava": { "name": "Lava Bucket", - "type": "bucket", + "type": "usable", "texture": "bucket_lava", "origin_x": 0.25, "action_key": "use_lava_bucket", - "max_stack": 1 + "max_stack": 1, + "burning_time": 1000000 + }, + "snowball": { + "name": "Snowball", + "type": "usable", + "texture": "snowball", + "action_key": "use_snow_ball_action", + "max_stack": 16 + }, + "coal": { + "name": "Coal", + "texture": "coal", + "burning_time": 80000, + "origin_x": 0.25 + }, + "charcoal": { + "name": "Charcoal", + "texture": "charcoal", + "burning_time": 80000, + "origin_x": 0.25 + }, + "iron_ingot": { + "name": "Iron Ingot", + "texture": "iron_ingot", + "origin_x": 0.5 + }, + "gold_ingot": { + "name": "Gold Ingot", + "texture": "gold_ingot", + "origin_x": 0.5 + }, + "diamond": { + "name": "Diamond", + "texture": "diamond", + "origin_x": 0.5 + }, + "lapis_lazuli": { + "name": "Lapis Lazuli", + "texture": "lapis_lazuli", + "origin_x": 0.5 + }, + "bed": { + "name": "Bed", + "type": "usable", + "texture": "bed", + "action_key": "use_bed_action" + }, + "spawn_egg_pig": { + "name": "Pig Spawn Egg", + "type": "usable", + "texture": "spawn_egg", + "tint": "#EDBFB4", + "action_key": "use_spawn_egg_pig", + "origin_x": 0.5 } } } diff --git a/android/assets/json/menu_main_buttons.json b/android/assets/json/menu_main_buttons.json index c52f47c..97d0938 100644 --- a/android/assets/json/menu_main_buttons.json +++ b/android/assets/json/menu_main_buttons.json @@ -6,6 +6,9 @@ "label": "Load Game", "type": 0 }, + "options": { + "label": "Settings" + }, "quit": { "label": "Quit" } diff --git a/android/assets/json/menu_options_buttons.json b/android/assets/json/menu_options_buttons.json new file mode 100644 index 0000000..bb956cd --- /dev/null +++ b/android/assets/json/menu_options_buttons.json @@ -0,0 +1,14 @@ +{ + "dyncam": { + "option_type": "boolean", + "label": "Dynamic Camera: %%value%%" + }, + "fullscreen": { + "option_type": "boolean", + "label": "Fullscreen: %%value%%", + "visible_on_android": false + }, + "back": { + "label": "Back" + } +} \ No newline at end of file diff --git a/android/assets/json/texture_regions.json b/android/assets/json/texture_regions.json index 8000980..3c6e7af 100644 --- a/android/assets/json/texture_regions.json +++ b/android/assets/json/texture_regions.json @@ -35,9 +35,20 @@ "y": 26, "w": 26, "h": 26 + }, + "inv": { + "x": 78, + "y": 26, + "w": 26, + "h": 26 + }, + "pause": { + "x": 104, + "w": 26, + "h": 26 } }, - "allitems": { + "pp/allitems": { "creative": { "w": 176, "h": 136 @@ -49,19 +60,42 @@ "h": 15 } }, - "inventory": { + "pp/inventory": { "survival": { "w": 176, "h": 166 } }, - "crafting_table": { + "pp/crafting_table": { "crafting_table": { "w": 176, "h": 166 } }, - "buttons": { + "pp/furnace": { + "furnace": { + "w": 176, + "h": 166 + }, + "furnace_burn": { + "x": 176, + "w": 14, + "h": 14 + }, + "furnace_progress": { + "x": 176, + "y": 14, + "w": 24, + "h": 14 + } + }, + "pp/chest": { + "chest": { + "w": 176, + "h": 168 + } + }, + "pp/buttons": { "button_0": { "w": 200, "h": 20 @@ -77,7 +111,7 @@ "h": 20 } }, - "gui": { + "pp/gui": { "hotbar": { "y": 16, "w": 182, @@ -93,16 +127,20 @@ "h": 16 } }, - "shade": {}, + "pp/shade": {}, "gamelogo": {}, - "background": {}, - "health":{ + "pp/background": {}, + "pp/health":{ "heart_whole": { "w": 9 }, "heart_half": { "x": 9, "w": 9 + }, + "heart_empty": { + "x": 18, + "w": 9 } } } \ No newline at end of file diff --git a/android/assets/json/touch_buttons.json b/android/assets/json/touch_buttons.json index cddaf53..cbb9a15 100644 --- a/android/assets/json/touch_buttons.json +++ b/android/assets/json/touch_buttons.json @@ -1,53 +1,23 @@ { - "up": { - "x": 26, - "y": -52, - "w": 26, - "h": 26, - "key": "W" - }, - "down": { - "x": 26, - "y": -26, - "w": 26, - "h": 26, - "key": "S" - }, - "left": { - "x": 0, - "y": -26, - "w": 26, - "h": 26, - "key": "A" - }, - "right": { - "x": 52, - "y": -26, - "w": 26, - "h": 26, - "key": "D" - }, "alt": { - "x": 78, - "y": -26, - "w": 26, - "h": 26, + "x": -48, + "y": -48, + "w": 48, + "h": 48, "key": "L-Alt" }, - "lmb": { - "x": -52, - "y": -26, - "w": 26, - "h": 26, - "mouse": true, - "key": "Left" + "inv": { + "x": -96, + "y": -48, + "w": 48, + "h": 48, + "key": "E" }, - "rmb": { - "x": -26, - "y": -26, - "w": 26, - "h": 26, - "mouse": true, - "key": "Right" + "pause": { + "x": -48, + "y": 0, + "w": 48, + "h": 48, + "key": "Escape" } } \ No newline at end of file diff --git a/android/assets/allitems.png b/android/assets/pp/allitems.png similarity index 100% rename from android/assets/allitems.png rename to android/assets/pp/allitems.png diff --git a/android/assets/background.png b/android/assets/pp/background.png similarity index 100% rename from android/assets/background.png rename to android/assets/pp/background.png diff --git a/android/assets/background_top.png b/android/assets/pp/background_top.png similarity index 100% rename from android/assets/background_top.png rename to android/assets/pp/background_top.png diff --git a/android/assets/break.png b/android/assets/pp/break.png similarity index 100% rename from android/assets/break.png rename to android/assets/pp/break.png diff --git a/android/assets/buttons.png b/android/assets/pp/buttons.png similarity index 100% rename from android/assets/buttons.png rename to android/assets/pp/buttons.png diff --git a/android/assets/pp/chest.png b/android/assets/pp/chest.png new file mode 100644 index 0000000..2c6d0c6 Binary files /dev/null and b/android/assets/pp/chest.png differ diff --git a/android/assets/pp/chest_large.png b/android/assets/pp/chest_large.png new file mode 100644 index 0000000..961891f Binary files /dev/null and b/android/assets/pp/chest_large.png differ diff --git a/android/assets/crafting_table.png b/android/assets/pp/crafting_table.png similarity index 100% rename from android/assets/crafting_table.png rename to android/assets/pp/crafting_table.png diff --git a/android/assets/pp/furnace.png b/android/assets/pp/furnace.png new file mode 100644 index 0000000..fc04793 Binary files /dev/null and b/android/assets/pp/furnace.png differ diff --git a/android/assets/gui.png b/android/assets/pp/gui.png similarity index 100% rename from android/assets/gui.png rename to android/assets/pp/gui.png diff --git a/android/assets/pp/health.png b/android/assets/pp/health.png new file mode 100644 index 0000000..99011d5 Binary files /dev/null and b/android/assets/pp/health.png differ diff --git a/android/assets/inventory.png b/android/assets/pp/inventory.png similarity index 100% rename from android/assets/inventory.png rename to android/assets/pp/inventory.png diff --git a/android/assets/mobs/char/0_0.png b/android/assets/pp/mobs/char/0_0.png similarity index 100% rename from android/assets/mobs/char/0_0.png rename to android/assets/pp/mobs/char/0_0.png diff --git a/android/assets/mobs/char/0_1.png b/android/assets/pp/mobs/char/0_1.png similarity index 100% rename from android/assets/mobs/char/0_1.png rename to android/assets/pp/mobs/char/0_1.png diff --git a/android/assets/mobs/char/0_2.png b/android/assets/pp/mobs/char/0_2.png similarity index 100% rename from android/assets/mobs/char/0_2.png rename to android/assets/pp/mobs/char/0_2.png diff --git a/android/assets/mobs/char/0_3.png b/android/assets/pp/mobs/char/0_3.png similarity index 100% rename from android/assets/mobs/char/0_3.png rename to android/assets/pp/mobs/char/0_3.png diff --git a/android/assets/mobs/char/1_0.png b/android/assets/pp/mobs/char/1_0.png similarity index 100% rename from android/assets/mobs/char/1_0.png rename to android/assets/pp/mobs/char/1_0.png diff --git a/android/assets/mobs/char/1_1.png b/android/assets/pp/mobs/char/1_1.png similarity index 100% rename from android/assets/mobs/char/1_1.png rename to android/assets/pp/mobs/char/1_1.png diff --git a/android/assets/mobs/char/1_2.png b/android/assets/pp/mobs/char/1_2.png similarity index 100% rename from android/assets/mobs/char/1_2.png rename to android/assets/pp/mobs/char/1_2.png diff --git a/android/assets/mobs/char/1_3.png b/android/assets/pp/mobs/char/1_3.png similarity index 100% rename from android/assets/mobs/char/1_3.png rename to android/assets/pp/mobs/char/1_3.png diff --git a/android/assets/mobs/pig/0_0.png b/android/assets/pp/mobs/pig/0_0.png similarity index 100% rename from android/assets/mobs/pig/0_0.png rename to android/assets/pp/mobs/pig/0_0.png diff --git a/android/assets/mobs/pig/0_1.png b/android/assets/pp/mobs/pig/0_1.png similarity index 100% rename from android/assets/mobs/pig/0_1.png rename to android/assets/pp/mobs/pig/0_1.png diff --git a/android/assets/mobs/pig/1_0.png b/android/assets/pp/mobs/pig/1_0.png similarity index 100% rename from android/assets/mobs/pig/1_0.png rename to android/assets/pp/mobs/pig/1_0.png diff --git a/android/assets/mobs/pig/1_1.png b/android/assets/pp/mobs/pig/1_1.png similarity index 100% rename from android/assets/mobs/pig/1_1.png rename to android/assets/pp/mobs/pig/1_1.png diff --git a/android/assets/shade.png b/android/assets/pp/shade.png similarity index 100% rename from android/assets/shade.png rename to android/assets/pp/shade.png diff --git a/android/assets/textures/blocks/bed_l.png b/android/assets/pp/textures/blocks/bed_l.png similarity index 100% rename from android/assets/textures/blocks/bed_l.png rename to android/assets/pp/textures/blocks/bed_l.png diff --git a/android/assets/textures/blocks/bed_r.png b/android/assets/pp/textures/blocks/bed_r.png similarity index 100% rename from android/assets/textures/blocks/bed_r.png rename to android/assets/pp/textures/blocks/bed_r.png diff --git a/android/assets/textures/blocks/bedrock.png b/android/assets/pp/textures/blocks/bedrock.png similarity index 100% rename from android/assets/textures/blocks/bedrock.png rename to android/assets/pp/textures/blocks/bedrock.png diff --git a/android/assets/textures/blocks/bookshelf.png b/android/assets/pp/textures/blocks/bookshelf.png similarity index 100% rename from android/assets/textures/blocks/bookshelf.png rename to android/assets/pp/textures/blocks/bookshelf.png diff --git a/android/assets/textures/blocks/bricks.png b/android/assets/pp/textures/blocks/bricks.png similarity index 100% rename from android/assets/textures/blocks/bricks.png rename to android/assets/pp/textures/blocks/bricks.png diff --git a/android/assets/textures/blocks/cactus.png b/android/assets/pp/textures/blocks/cactus.png similarity index 100% rename from android/assets/textures/blocks/cactus.png rename to android/assets/pp/textures/blocks/cactus.png diff --git a/android/assets/textures/blocks/cake.png b/android/assets/pp/textures/blocks/cake.png similarity index 100% rename from android/assets/textures/blocks/cake.png rename to android/assets/pp/textures/blocks/cake.png diff --git a/android/assets/pp/textures/blocks/chest.png b/android/assets/pp/textures/blocks/chest.png new file mode 100644 index 0000000..a2ca371 Binary files /dev/null and b/android/assets/pp/textures/blocks/chest.png differ diff --git a/android/assets/textures/blocks/clay.png b/android/assets/pp/textures/blocks/clay.png similarity index 100% rename from android/assets/textures/blocks/clay.png rename to android/assets/pp/textures/blocks/clay.png diff --git a/android/assets/textures/blocks/coal_block.png b/android/assets/pp/textures/blocks/coal_block.png similarity index 100% rename from android/assets/textures/blocks/coal_block.png rename to android/assets/pp/textures/blocks/coal_block.png diff --git a/android/assets/textures/blocks/coal_ore.png b/android/assets/pp/textures/blocks/coal_ore.png similarity index 100% rename from android/assets/textures/blocks/coal_ore.png rename to android/assets/pp/textures/blocks/coal_ore.png diff --git a/android/assets/textures/blocks/cobblestone.png b/android/assets/pp/textures/blocks/cobblestone.png similarity index 100% rename from android/assets/textures/blocks/cobblestone.png rename to android/assets/pp/textures/blocks/cobblestone.png diff --git a/android/assets/textures/blocks/cobblestone_mossy.png b/android/assets/pp/textures/blocks/cobblestone_mossy.png similarity index 100% rename from android/assets/textures/blocks/cobblestone_mossy.png rename to android/assets/pp/textures/blocks/cobblestone_mossy.png diff --git a/android/assets/textures/blocks/crafting_table.png b/android/assets/pp/textures/blocks/crafting_table.png similarity index 100% rename from android/assets/textures/blocks/crafting_table.png rename to android/assets/pp/textures/blocks/crafting_table.png diff --git a/android/assets/textures/blocks/dandelion.png b/android/assets/pp/textures/blocks/dandelion.png similarity index 100% rename from android/assets/textures/blocks/dandelion.png rename to android/assets/pp/textures/blocks/dandelion.png diff --git a/android/assets/textures/blocks/deadbush.png b/android/assets/pp/textures/blocks/deadbush.png similarity index 100% rename from android/assets/textures/blocks/deadbush.png rename to android/assets/pp/textures/blocks/deadbush.png diff --git a/android/assets/textures/blocks/diamond_block.png b/android/assets/pp/textures/blocks/diamond_block.png similarity index 100% rename from android/assets/textures/blocks/diamond_block.png rename to android/assets/pp/textures/blocks/diamond_block.png diff --git a/android/assets/textures/blocks/diamond_ore.png b/android/assets/pp/textures/blocks/diamond_ore.png similarity index 100% rename from android/assets/textures/blocks/diamond_ore.png rename to android/assets/pp/textures/blocks/diamond_ore.png diff --git a/android/assets/textures/blocks/dirt.png b/android/assets/pp/textures/blocks/dirt.png similarity index 100% rename from android/assets/textures/blocks/dirt.png rename to android/assets/pp/textures/blocks/dirt.png diff --git a/android/assets/pp/textures/blocks/furnace.png b/android/assets/pp/textures/blocks/furnace.png new file mode 100644 index 0000000..080d8ad Binary files /dev/null and b/android/assets/pp/textures/blocks/furnace.png differ diff --git a/android/assets/textures/blocks/glass.png b/android/assets/pp/textures/blocks/glass.png similarity index 100% rename from android/assets/textures/blocks/glass.png rename to android/assets/pp/textures/blocks/glass.png diff --git a/android/assets/textures/blocks/gold_block.png b/android/assets/pp/textures/blocks/gold_block.png similarity index 100% rename from android/assets/textures/blocks/gold_block.png rename to android/assets/pp/textures/blocks/gold_block.png diff --git a/android/assets/textures/blocks/gold_ore.png b/android/assets/pp/textures/blocks/gold_ore.png similarity index 100% rename from android/assets/textures/blocks/gold_ore.png rename to android/assets/pp/textures/blocks/gold_ore.png diff --git a/android/assets/textures/blocks/grass.png b/android/assets/pp/textures/blocks/grass.png similarity index 100% rename from android/assets/textures/blocks/grass.png rename to android/assets/pp/textures/blocks/grass.png diff --git a/android/assets/textures/blocks/grass_snowed.png b/android/assets/pp/textures/blocks/grass_snowed.png similarity index 100% rename from android/assets/textures/blocks/grass_snowed.png rename to android/assets/pp/textures/blocks/grass_snowed.png diff --git a/android/assets/textures/blocks/gravel.png b/android/assets/pp/textures/blocks/gravel.png similarity index 100% rename from android/assets/textures/blocks/gravel.png rename to android/assets/pp/textures/blocks/gravel.png diff --git a/android/assets/textures/blocks/iron_bars.png b/android/assets/pp/textures/blocks/iron_bars.png similarity index 100% rename from android/assets/textures/blocks/iron_bars.png rename to android/assets/pp/textures/blocks/iron_bars.png diff --git a/android/assets/textures/blocks/iron_block.png b/android/assets/pp/textures/blocks/iron_block.png similarity index 100% rename from android/assets/textures/blocks/iron_block.png rename to android/assets/pp/textures/blocks/iron_block.png diff --git a/android/assets/textures/blocks/iron_ore.png b/android/assets/pp/textures/blocks/iron_ore.png similarity index 100% rename from android/assets/textures/blocks/iron_ore.png rename to android/assets/pp/textures/blocks/iron_ore.png diff --git a/android/assets/textures/blocks/ladder.png b/android/assets/pp/textures/blocks/ladder.png similarity index 100% rename from android/assets/textures/blocks/ladder.png rename to android/assets/pp/textures/blocks/ladder.png diff --git a/android/assets/textures/blocks/lapis_block.png b/android/assets/pp/textures/blocks/lapis_block.png similarity index 100% rename from android/assets/textures/blocks/lapis_block.png rename to android/assets/pp/textures/blocks/lapis_block.png diff --git a/android/assets/pp/textures/blocks/lapis_ore.png b/android/assets/pp/textures/blocks/lapis_ore.png new file mode 100644 index 0000000..44fcd7f Binary files /dev/null and b/android/assets/pp/textures/blocks/lapis_ore.png differ diff --git a/android/assets/textures/blocks/lava_flow.png b/android/assets/pp/textures/blocks/lava_flow.png similarity index 100% rename from android/assets/textures/blocks/lava_flow.png rename to android/assets/pp/textures/blocks/lava_flow.png diff --git a/android/assets/textures/blocks/lava_still.png b/android/assets/pp/textures/blocks/lava_still.png similarity index 100% rename from android/assets/textures/blocks/lava_still.png rename to android/assets/pp/textures/blocks/lava_still.png diff --git a/android/assets/textures/blocks/leaves_oak.png b/android/assets/pp/textures/blocks/leaves_oak.png similarity index 100% rename from android/assets/textures/blocks/leaves_oak.png rename to android/assets/pp/textures/blocks/leaves_oak.png diff --git a/android/assets/pp/textures/blocks/leaves_spruce.png b/android/assets/pp/textures/blocks/leaves_spruce.png new file mode 100644 index 0000000..0be1897 Binary files /dev/null and b/android/assets/pp/textures/blocks/leaves_spruce.png differ diff --git a/android/assets/textures/blocks/log_birch.png b/android/assets/pp/textures/blocks/log_birch.png similarity index 100% rename from android/assets/textures/blocks/log_birch.png rename to android/assets/pp/textures/blocks/log_birch.png diff --git a/android/assets/textures/blocks/log_oak.png b/android/assets/pp/textures/blocks/log_oak.png similarity index 100% rename from android/assets/textures/blocks/log_oak.png rename to android/assets/pp/textures/blocks/log_oak.png diff --git a/android/assets/textures/blocks/log_spruce.png b/android/assets/pp/textures/blocks/log_spruce.png similarity index 100% rename from android/assets/textures/blocks/log_spruce.png rename to android/assets/pp/textures/blocks/log_spruce.png diff --git a/android/assets/textures/blocks/mushroom_brown.png b/android/assets/pp/textures/blocks/mushroom_brown.png similarity index 100% rename from android/assets/textures/blocks/mushroom_brown.png rename to android/assets/pp/textures/blocks/mushroom_brown.png diff --git a/android/assets/textures/blocks/mushroom_red.png b/android/assets/pp/textures/blocks/mushroom_red.png similarity index 100% rename from android/assets/textures/blocks/mushroom_red.png rename to android/assets/pp/textures/blocks/mushroom_red.png diff --git a/android/assets/textures/blocks/noteblock.png b/android/assets/pp/textures/blocks/noteblock.png similarity index 100% rename from android/assets/textures/blocks/noteblock.png rename to android/assets/pp/textures/blocks/noteblock.png diff --git a/android/assets/textures/blocks/obsidian.png b/android/assets/pp/textures/blocks/obsidian.png similarity index 100% rename from android/assets/textures/blocks/obsidian.png rename to android/assets/pp/textures/blocks/obsidian.png diff --git a/android/assets/textures/blocks/planks_birch.png b/android/assets/pp/textures/blocks/planks_birch.png similarity index 100% rename from android/assets/textures/blocks/planks_birch.png rename to android/assets/pp/textures/blocks/planks_birch.png diff --git a/android/assets/textures/blocks/planks_oak.png b/android/assets/pp/textures/blocks/planks_oak.png similarity index 100% rename from android/assets/textures/blocks/planks_oak.png rename to android/assets/pp/textures/blocks/planks_oak.png diff --git a/android/assets/textures/blocks/planks_spruce.png b/android/assets/pp/textures/blocks/planks_spruce.png similarity index 100% rename from android/assets/textures/blocks/planks_spruce.png rename to android/assets/pp/textures/blocks/planks_spruce.png diff --git a/android/assets/textures/blocks/rose.png b/android/assets/pp/textures/blocks/rose.png similarity index 100% rename from android/assets/textures/blocks/rose.png rename to android/assets/pp/textures/blocks/rose.png diff --git a/android/assets/textures/blocks/sand.png b/android/assets/pp/textures/blocks/sand.png similarity index 100% rename from android/assets/textures/blocks/sand.png rename to android/assets/pp/textures/blocks/sand.png diff --git a/android/assets/textures/blocks/sandstone.png b/android/assets/pp/textures/blocks/sandstone.png similarity index 100% rename from android/assets/textures/blocks/sandstone.png rename to android/assets/pp/textures/blocks/sandstone.png diff --git a/android/assets/textures/blocks/sapling_birch.png b/android/assets/pp/textures/blocks/sapling_birch.png similarity index 100% rename from android/assets/textures/blocks/sapling_birch.png rename to android/assets/pp/textures/blocks/sapling_birch.png diff --git a/android/assets/textures/blocks/sapling_oak.png b/android/assets/pp/textures/blocks/sapling_oak.png similarity index 100% rename from android/assets/textures/blocks/sapling_oak.png rename to android/assets/pp/textures/blocks/sapling_oak.png diff --git a/android/assets/textures/blocks/sapling_spruce.png b/android/assets/pp/textures/blocks/sapling_spruce.png similarity index 100% rename from android/assets/textures/blocks/sapling_spruce.png rename to android/assets/pp/textures/blocks/sapling_spruce.png diff --git a/android/assets/pp/textures/blocks/snow.png b/android/assets/pp/textures/blocks/snow.png new file mode 100644 index 0000000..20a836e Binary files /dev/null and b/android/assets/pp/textures/blocks/snow.png differ diff --git a/android/assets/textures/blocks/sponge.png b/android/assets/pp/textures/blocks/sponge.png similarity index 100% rename from android/assets/textures/blocks/sponge.png rename to android/assets/pp/textures/blocks/sponge.png diff --git a/android/assets/textures/blocks/sponge_wet.png b/android/assets/pp/textures/blocks/sponge_wet.png similarity index 100% rename from android/assets/textures/blocks/sponge_wet.png rename to android/assets/pp/textures/blocks/sponge_wet.png diff --git a/android/assets/textures/blocks/stone.png b/android/assets/pp/textures/blocks/stone.png similarity index 100% rename from android/assets/textures/blocks/stone.png rename to android/assets/pp/textures/blocks/stone.png diff --git a/android/assets/textures/blocks/stone_slab.png b/android/assets/pp/textures/blocks/stone_slab.png similarity index 100% rename from android/assets/textures/blocks/stone_slab.png rename to android/assets/pp/textures/blocks/stone_slab.png diff --git a/android/assets/textures/blocks/stonebrick.png b/android/assets/pp/textures/blocks/stonebrick.png similarity index 100% rename from android/assets/textures/blocks/stonebrick.png rename to android/assets/pp/textures/blocks/stonebrick.png diff --git a/android/assets/textures/blocks/tallgrass.png b/android/assets/pp/textures/blocks/tallgrass.png similarity index 100% rename from android/assets/textures/blocks/tallgrass.png rename to android/assets/pp/textures/blocks/tallgrass.png diff --git a/android/assets/textures/blocks/water_flow.png b/android/assets/pp/textures/blocks/water_flow.png similarity index 100% rename from android/assets/textures/blocks/water_flow.png rename to android/assets/pp/textures/blocks/water_flow.png diff --git a/android/assets/textures/blocks/water_still.png b/android/assets/pp/textures/blocks/water_still.png similarity index 100% rename from android/assets/textures/blocks/water_still.png rename to android/assets/pp/textures/blocks/water_still.png diff --git a/android/assets/textures/blocks/web.png b/android/assets/pp/textures/blocks/web.png similarity index 100% rename from android/assets/textures/blocks/web.png rename to android/assets/pp/textures/blocks/web.png diff --git a/android/assets/textures/blocks/wool_colored_black.png b/android/assets/pp/textures/blocks/wool_colored_black.png similarity index 100% rename from android/assets/textures/blocks/wool_colored_black.png rename to android/assets/pp/textures/blocks/wool_colored_black.png diff --git a/android/assets/textures/blocks/wool_colored_blue.png b/android/assets/pp/textures/blocks/wool_colored_blue.png similarity index 100% rename from android/assets/textures/blocks/wool_colored_blue.png rename to android/assets/pp/textures/blocks/wool_colored_blue.png diff --git a/android/assets/textures/blocks/wool_colored_brown.png b/android/assets/pp/textures/blocks/wool_colored_brown.png similarity index 100% rename from android/assets/textures/blocks/wool_colored_brown.png rename to android/assets/pp/textures/blocks/wool_colored_brown.png diff --git a/android/assets/textures/blocks/wool_colored_cyan.png b/android/assets/pp/textures/blocks/wool_colored_cyan.png similarity index 100% rename from android/assets/textures/blocks/wool_colored_cyan.png rename to android/assets/pp/textures/blocks/wool_colored_cyan.png diff --git a/android/assets/textures/blocks/wool_colored_gray.png b/android/assets/pp/textures/blocks/wool_colored_gray.png similarity index 100% rename from android/assets/textures/blocks/wool_colored_gray.png rename to android/assets/pp/textures/blocks/wool_colored_gray.png diff --git a/android/assets/textures/blocks/wool_colored_green.png b/android/assets/pp/textures/blocks/wool_colored_green.png similarity index 100% rename from android/assets/textures/blocks/wool_colored_green.png rename to android/assets/pp/textures/blocks/wool_colored_green.png diff --git a/android/assets/textures/blocks/wool_colored_light_blue.png b/android/assets/pp/textures/blocks/wool_colored_light_blue.png similarity index 100% rename from android/assets/textures/blocks/wool_colored_light_blue.png rename to android/assets/pp/textures/blocks/wool_colored_light_blue.png diff --git a/android/assets/textures/blocks/wool_colored_lime.png b/android/assets/pp/textures/blocks/wool_colored_lime.png similarity index 100% rename from android/assets/textures/blocks/wool_colored_lime.png rename to android/assets/pp/textures/blocks/wool_colored_lime.png diff --git a/android/assets/textures/blocks/wool_colored_magenta.png b/android/assets/pp/textures/blocks/wool_colored_magenta.png similarity index 100% rename from android/assets/textures/blocks/wool_colored_magenta.png rename to android/assets/pp/textures/blocks/wool_colored_magenta.png diff --git a/android/assets/textures/blocks/wool_colored_orange.png b/android/assets/pp/textures/blocks/wool_colored_orange.png similarity index 100% rename from android/assets/textures/blocks/wool_colored_orange.png rename to android/assets/pp/textures/blocks/wool_colored_orange.png diff --git a/android/assets/textures/blocks/wool_colored_pink.png b/android/assets/pp/textures/blocks/wool_colored_pink.png similarity index 100% rename from android/assets/textures/blocks/wool_colored_pink.png rename to android/assets/pp/textures/blocks/wool_colored_pink.png diff --git a/android/assets/textures/blocks/wool_colored_purple.png b/android/assets/pp/textures/blocks/wool_colored_purple.png similarity index 100% rename from android/assets/textures/blocks/wool_colored_purple.png rename to android/assets/pp/textures/blocks/wool_colored_purple.png diff --git a/android/assets/textures/blocks/wool_colored_red.png b/android/assets/pp/textures/blocks/wool_colored_red.png similarity index 100% rename from android/assets/textures/blocks/wool_colored_red.png rename to android/assets/pp/textures/blocks/wool_colored_red.png diff --git a/android/assets/textures/blocks/wool_colored_silver.png b/android/assets/pp/textures/blocks/wool_colored_silver.png similarity index 100% rename from android/assets/textures/blocks/wool_colored_silver.png rename to android/assets/pp/textures/blocks/wool_colored_silver.png diff --git a/android/assets/textures/blocks/wool_colored_white.png b/android/assets/pp/textures/blocks/wool_colored_white.png similarity index 100% rename from android/assets/textures/blocks/wool_colored_white.png rename to android/assets/pp/textures/blocks/wool_colored_white.png diff --git a/android/assets/textures/blocks/wool_colored_yellow.png b/android/assets/pp/textures/blocks/wool_colored_yellow.png similarity index 100% rename from android/assets/textures/blocks/wool_colored_yellow.png rename to android/assets/pp/textures/blocks/wool_colored_yellow.png diff --git a/android/assets/pp/textures/items/bed.png b/android/assets/pp/textures/items/bed.png new file mode 100644 index 0000000..0e1565d Binary files /dev/null and b/android/assets/pp/textures/items/bed.png differ diff --git a/android/assets/textures/items/bucket_empty.png b/android/assets/pp/textures/items/bucket_empty.png similarity index 100% rename from android/assets/textures/items/bucket_empty.png rename to android/assets/pp/textures/items/bucket_empty.png diff --git a/android/assets/textures/items/bucket_lava.png b/android/assets/pp/textures/items/bucket_lava.png similarity index 100% rename from android/assets/textures/items/bucket_lava.png rename to android/assets/pp/textures/items/bucket_lava.png diff --git a/android/assets/textures/items/bucket_milk.png b/android/assets/pp/textures/items/bucket_milk.png similarity index 100% rename from android/assets/textures/items/bucket_milk.png rename to android/assets/pp/textures/items/bucket_milk.png diff --git a/android/assets/textures/items/bucket_water.png b/android/assets/pp/textures/items/bucket_water.png similarity index 100% rename from android/assets/textures/items/bucket_water.png rename to android/assets/pp/textures/items/bucket_water.png diff --git a/android/assets/pp/textures/items/charcoal.png b/android/assets/pp/textures/items/charcoal.png new file mode 100644 index 0000000..9fe49a7 Binary files /dev/null and b/android/assets/pp/textures/items/charcoal.png differ diff --git a/android/assets/pp/textures/items/coal.png b/android/assets/pp/textures/items/coal.png new file mode 100644 index 0000000..c94ebad Binary files /dev/null and b/android/assets/pp/textures/items/coal.png differ diff --git a/android/assets/pp/textures/items/diamond.png b/android/assets/pp/textures/items/diamond.png new file mode 100644 index 0000000..eff11e0 Binary files /dev/null and b/android/assets/pp/textures/items/diamond.png differ diff --git a/android/assets/textures/items/diamond_axe.png b/android/assets/pp/textures/items/diamond_axe.png similarity index 100% rename from android/assets/textures/items/diamond_axe.png rename to android/assets/pp/textures/items/diamond_axe.png diff --git a/android/assets/textures/items/diamond_hoe.png b/android/assets/pp/textures/items/diamond_hoe.png similarity index 100% rename from android/assets/textures/items/diamond_hoe.png rename to android/assets/pp/textures/items/diamond_hoe.png diff --git a/android/assets/textures/items/diamond_pickaxe.png b/android/assets/pp/textures/items/diamond_pickaxe.png similarity index 100% rename from android/assets/textures/items/diamond_pickaxe.png rename to android/assets/pp/textures/items/diamond_pickaxe.png diff --git a/android/assets/textures/items/diamond_shovel.png b/android/assets/pp/textures/items/diamond_shovel.png similarity index 100% rename from android/assets/textures/items/diamond_shovel.png rename to android/assets/pp/textures/items/diamond_shovel.png diff --git a/android/assets/textures/items/diamond_sword.png b/android/assets/pp/textures/items/diamond_sword.png similarity index 100% rename from android/assets/textures/items/diamond_sword.png rename to android/assets/pp/textures/items/diamond_sword.png diff --git a/android/assets/textures/items/gold_axe.png b/android/assets/pp/textures/items/gold_axe.png similarity index 100% rename from android/assets/textures/items/gold_axe.png rename to android/assets/pp/textures/items/gold_axe.png diff --git a/android/assets/textures/items/gold_hoe.png b/android/assets/pp/textures/items/gold_hoe.png similarity index 100% rename from android/assets/textures/items/gold_hoe.png rename to android/assets/pp/textures/items/gold_hoe.png diff --git a/android/assets/pp/textures/items/gold_ingot.png b/android/assets/pp/textures/items/gold_ingot.png new file mode 100644 index 0000000..b159455 Binary files /dev/null and b/android/assets/pp/textures/items/gold_ingot.png differ diff --git a/android/assets/textures/items/gold_pickaxe.png b/android/assets/pp/textures/items/gold_pickaxe.png similarity index 100% rename from android/assets/textures/items/gold_pickaxe.png rename to android/assets/pp/textures/items/gold_pickaxe.png diff --git a/android/assets/textures/items/gold_shovel.png b/android/assets/pp/textures/items/gold_shovel.png similarity index 100% rename from android/assets/textures/items/gold_shovel.png rename to android/assets/pp/textures/items/gold_shovel.png diff --git a/android/assets/textures/items/gold_sword.png b/android/assets/pp/textures/items/gold_sword.png similarity index 100% rename from android/assets/textures/items/gold_sword.png rename to android/assets/pp/textures/items/gold_sword.png diff --git a/android/assets/textures/items/iron_axe.png b/android/assets/pp/textures/items/iron_axe.png similarity index 100% rename from android/assets/textures/items/iron_axe.png rename to android/assets/pp/textures/items/iron_axe.png diff --git a/android/assets/textures/items/iron_hoe.png b/android/assets/pp/textures/items/iron_hoe.png similarity index 100% rename from android/assets/textures/items/iron_hoe.png rename to android/assets/pp/textures/items/iron_hoe.png diff --git a/android/assets/pp/textures/items/iron_ingot.png b/android/assets/pp/textures/items/iron_ingot.png new file mode 100644 index 0000000..1ff5c69 Binary files /dev/null and b/android/assets/pp/textures/items/iron_ingot.png differ diff --git a/android/assets/textures/items/iron_pickaxe.png b/android/assets/pp/textures/items/iron_pickaxe.png similarity index 100% rename from android/assets/textures/items/iron_pickaxe.png rename to android/assets/pp/textures/items/iron_pickaxe.png diff --git a/android/assets/textures/items/iron_shovel.png b/android/assets/pp/textures/items/iron_shovel.png similarity index 100% rename from android/assets/textures/items/iron_shovel.png rename to android/assets/pp/textures/items/iron_shovel.png diff --git a/android/assets/textures/items/iron_sword.png b/android/assets/pp/textures/items/iron_sword.png similarity index 100% rename from android/assets/textures/items/iron_sword.png rename to android/assets/pp/textures/items/iron_sword.png diff --git a/android/assets/pp/textures/items/lapis_lazuli.png b/android/assets/pp/textures/items/lapis_lazuli.png new file mode 100644 index 0000000..84bdcd4 Binary files /dev/null and b/android/assets/pp/textures/items/lapis_lazuli.png differ diff --git a/android/assets/textures/items/shears.png b/android/assets/pp/textures/items/shears.png similarity index 100% rename from android/assets/textures/items/shears.png rename to android/assets/pp/textures/items/shears.png diff --git a/android/assets/pp/textures/items/snowball.png b/android/assets/pp/textures/items/snowball.png new file mode 100644 index 0000000..56a11e9 Binary files /dev/null and b/android/assets/pp/textures/items/snowball.png differ diff --git a/android/assets/pp/textures/items/spawn_egg.png b/android/assets/pp/textures/items/spawn_egg.png new file mode 100644 index 0000000..8733a83 Binary files /dev/null and b/android/assets/pp/textures/items/spawn_egg.png differ diff --git a/android/assets/textures/items/stick.png b/android/assets/pp/textures/items/stick.png similarity index 100% rename from android/assets/textures/items/stick.png rename to android/assets/pp/textures/items/stick.png diff --git a/android/assets/textures/items/stone_axe.png b/android/assets/pp/textures/items/stone_axe.png similarity index 100% rename from android/assets/textures/items/stone_axe.png rename to android/assets/pp/textures/items/stone_axe.png diff --git a/android/assets/textures/items/stone_hoe.png b/android/assets/pp/textures/items/stone_hoe.png similarity index 100% rename from android/assets/textures/items/stone_hoe.png rename to android/assets/pp/textures/items/stone_hoe.png diff --git a/android/assets/textures/items/stone_pickaxe.png b/android/assets/pp/textures/items/stone_pickaxe.png similarity index 100% rename from android/assets/textures/items/stone_pickaxe.png rename to android/assets/pp/textures/items/stone_pickaxe.png diff --git a/android/assets/textures/items/stone_shovel.png b/android/assets/pp/textures/items/stone_shovel.png similarity index 100% rename from android/assets/textures/items/stone_shovel.png rename to android/assets/pp/textures/items/stone_shovel.png diff --git a/android/assets/textures/items/stone_sword.png b/android/assets/pp/textures/items/stone_sword.png similarity index 100% rename from android/assets/textures/items/stone_sword.png rename to android/assets/pp/textures/items/stone_sword.png diff --git a/android/assets/textures/items/wood_axe.png b/android/assets/pp/textures/items/wood_axe.png similarity index 100% rename from android/assets/textures/items/wood_axe.png rename to android/assets/pp/textures/items/wood_axe.png diff --git a/android/assets/textures/items/wood_hoe.png b/android/assets/pp/textures/items/wood_hoe.png similarity index 100% rename from android/assets/textures/items/wood_hoe.png rename to android/assets/pp/textures/items/wood_hoe.png diff --git a/android/assets/textures/items/wood_pickaxe.png b/android/assets/pp/textures/items/wood_pickaxe.png similarity index 100% rename from android/assets/textures/items/wood_pickaxe.png rename to android/assets/pp/textures/items/wood_pickaxe.png diff --git a/android/assets/textures/items/wood_shovel.png b/android/assets/pp/textures/items/wood_shovel.png similarity index 100% rename from android/assets/textures/items/wood_shovel.png rename to android/assets/pp/textures/items/wood_shovel.png diff --git a/android/assets/textures/items/wood_sword.png b/android/assets/pp/textures/items/wood_sword.png similarity index 100% rename from android/assets/textures/items/wood_sword.png rename to android/assets/pp/textures/items/wood_sword.png diff --git a/android/assets/textures/blocks/furnace_off.png b/android/assets/textures/blocks/furnace_off.png deleted file mode 100644 index 6d9b405..0000000 Binary files a/android/assets/textures/blocks/furnace_off.png and /dev/null differ diff --git a/android/assets/textures/blocks/furnace_on.png b/android/assets/textures/blocks/furnace_on.png deleted file mode 100644 index ecbc607..0000000 Binary files a/android/assets/textures/blocks/furnace_on.png and /dev/null differ diff --git a/android/assets/textures/blocks/lapis_ore.png b/android/assets/textures/blocks/lapis_ore.png deleted file mode 100644 index 04a4630..0000000 Binary files a/android/assets/textures/blocks/lapis_ore.png and /dev/null differ diff --git a/android/assets/touch_gui.png b/android/assets/touch_gui.png index b194413..57dffc4 100644 Binary files a/android/assets/touch_gui.png and b/android/assets/touch_gui.png differ diff --git a/android/build.gradle b/android/build.gradle index d64557a..d52b9e9 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,4 +1,9 @@ +buildscript { + configurations { natives } +} + plugins { + id "com.android.application" id "kotlin-android" } @@ -32,10 +37,12 @@ android { } defaultConfig { applicationId "ru.deadsoftware.cavedroid" - minSdkVersion 24 + minSdkVersion 19 targetSdkVersion 34 - versionCode 19 - versionName "alpha0.6.2" + versionCode 25 + versionName "alpha0.9.2" + + multiDexEnabled true } applicationVariants.all { variant -> variant.outputs.all { @@ -123,4 +130,18 @@ task run(type: Exec) { def adb = path + "/platform-tools/adb" commandLine "$adb", 'shell', 'am', 'start', '-n', 'ru.deadsoftware.cavedroid/ru.deadsoftware.cavedroid.AndroidLauncher' +} + +dependencies { + implementation project(":core") + implementation platform("org.jetbrains.kotlin:kotlin-bom:$kotlinVersion") + api "com.badlogicgames.gdx:gdx-backend-android:$gdxVersion" + natives "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-armeabi-v7a" + natives "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-arm64-v8a" + natives "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-x86" + natives "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-x86_64" + + configurations.implementation { + exclude group: 'org.jetbrains.kotlin', module: 'kotlin-stdlib-jdk8' + } } \ No newline at end of file diff --git a/android/debug/res/drawable-anydpi-v26/ic_launcher_foreground.xml b/android/debug/res/drawable-anydpi-v26/ic_launcher_foreground.xml deleted file mode 100644 index 4535da3..0000000 --- a/android/debug/res/drawable-anydpi-v26/ic_launcher_foreground.xml +++ /dev/null @@ -1,106 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/android/debug/res/drawable-hdpi/ic_launcher.png b/android/debug/res/drawable-hdpi/ic_launcher.png index 9c5bde7..595b5c6 100644 Binary files a/android/debug/res/drawable-hdpi/ic_launcher.png and b/android/debug/res/drawable-hdpi/ic_launcher.png differ diff --git a/android/debug/res/drawable-mdpi/ic_launcher.png b/android/debug/res/drawable-mdpi/ic_launcher.png index 7e8a490..76e15c3 100644 Binary files a/android/debug/res/drawable-mdpi/ic_launcher.png and b/android/debug/res/drawable-mdpi/ic_launcher.png differ diff --git a/android/debug/res/drawable-xhdpi/ic_launcher.png b/android/debug/res/drawable-xhdpi/ic_launcher.png index 88f3a21..1c55208 100644 Binary files a/android/debug/res/drawable-xhdpi/ic_launcher.png and b/android/debug/res/drawable-xhdpi/ic_launcher.png differ diff --git a/android/debug/res/drawable-xxhdpi/ic_launcher.png b/android/debug/res/drawable-xxhdpi/ic_launcher.png index ca5ae82..94f1374 100644 Binary files a/android/debug/res/drawable-xxhdpi/ic_launcher.png and b/android/debug/res/drawable-xxhdpi/ic_launcher.png differ diff --git a/android/debug/res/drawable-xxxhdpi/ic_launcher.png b/android/debug/res/drawable-xxxhdpi/ic_launcher.png index 89ce105..88ddb67 100644 Binary files a/android/debug/res/drawable-xxxhdpi/ic_launcher.png and b/android/debug/res/drawable-xxxhdpi/ic_launcher.png differ diff --git a/android/debug/res/drawable/ic_launcher_foreground.xml b/android/debug/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 0000000..c963cce --- /dev/null +++ b/android/debug/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,162 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/android/ic_launcher-web.png b/android/ic_launcher-web.png index f6a837e..9d5fc15 100644 Binary files a/android/ic_launcher-web.png and b/android/ic_launcher-web.png differ diff --git a/android/res/drawable-anydpi-v26/ic_launcher_background.xml b/android/res/drawable-anydpi-v26/ic_launcher_background.xml deleted file mode 100644 index b398624..0000000 --- a/android/res/drawable-anydpi-v26/ic_launcher_background.xml +++ /dev/null @@ -1,127 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/android/res/drawable-anydpi-v26/ic_launcher_foreground.xml b/android/res/drawable-anydpi-v26/ic_launcher_foreground.xml deleted file mode 100644 index ce92ea1..0000000 --- a/android/res/drawable-anydpi-v26/ic_launcher_foreground.xml +++ /dev/null @@ -1,106 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/android/res/drawable-hdpi/ic_launcher.png b/android/res/drawable-hdpi/ic_launcher.png index ace457e..2b9989e 100644 Binary files a/android/res/drawable-hdpi/ic_launcher.png and b/android/res/drawable-hdpi/ic_launcher.png differ diff --git a/android/res/drawable-mdpi/ic_launcher.png b/android/res/drawable-mdpi/ic_launcher.png index ed09826..4657268 100644 Binary files a/android/res/drawable-mdpi/ic_launcher.png and b/android/res/drawable-mdpi/ic_launcher.png differ diff --git a/android/res/drawable-xhdpi/ic_launcher.png b/android/res/drawable-xhdpi/ic_launcher.png index 190d16d..739b6ce 100644 Binary files a/android/res/drawable-xhdpi/ic_launcher.png and b/android/res/drawable-xhdpi/ic_launcher.png differ diff --git a/android/res/drawable-xxhdpi/ic_launcher.png b/android/res/drawable-xxhdpi/ic_launcher.png index b58006b..1c1aa90 100644 Binary files a/android/res/drawable-xxhdpi/ic_launcher.png and b/android/res/drawable-xxhdpi/ic_launcher.png differ diff --git a/android/res/drawable-xxxhdpi/ic_launcher.png b/android/res/drawable-xxxhdpi/ic_launcher.png index a4b6775..0f64585 100644 Binary files a/android/res/drawable-xxxhdpi/ic_launcher.png and b/android/res/drawable-xxxhdpi/ic_launcher.png differ diff --git a/android/res/drawable/ic_launcher_background.xml b/android/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..bae566f --- /dev/null +++ b/android/res/drawable/ic_launcher_background.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + diff --git a/android/res/drawable/ic_launcher_foreground.xml b/android/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 0000000..a30acde --- /dev/null +++ b/android/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/android/src/ru/deadsoftware/cavedroid/AndroidLauncher.java b/android/src/ru/deadsoftware/cavedroid/AndroidLauncher.java index e7aad50..3f38ad4 100644 --- a/android/src/ru/deadsoftware/cavedroid/AndroidLauncher.java +++ b/android/src/ru/deadsoftware/cavedroid/AndroidLauncher.java @@ -18,7 +18,8 @@ public class AndroidLauncher extends AndroidApplication { e.printStackTrace(); exit(); } - CaveGame caveGame = new CaveGame(gameFolder, true, null); + CaveGame caveGame = new CaveGame(gameFolder, true, + new AndroidPreferencesStore(getApplicationContext()), null); caveGame.setDebug(BuildConfig.DEBUG); initialize(caveGame, config); } diff --git a/android/src/ru/deadsoftware/cavedroid/AndroidPreferencesStore.kt b/android/src/ru/deadsoftware/cavedroid/AndroidPreferencesStore.kt new file mode 100644 index 0000000..4b16659 --- /dev/null +++ b/android/src/ru/deadsoftware/cavedroid/AndroidPreferencesStore.kt @@ -0,0 +1,26 @@ +package ru.deadsoftware.cavedroid + +import android.content.Context +import ru.deadsoftware.cavedroid.prefs.PreferencesStore + +class AndroidPreferencesStore( + private val context: Context +) : PreferencesStore { + + private val sharedPreferences by lazy { context.getSharedPreferences(SHARED_PREFS_NAME, Context.MODE_PRIVATE) } + + override fun getPreference(key: String): String? { + return sharedPreferences.getString(key, null) + } + + override fun setPreference(key: String, value: String?) { + with(sharedPreferences.edit()) { + putString(key, value) + apply() + } + } + + private companion object { + private const val SHARED_PREFS_NAME = "cavedroid_prefs" + } +} \ No newline at end of file diff --git a/build.gradle b/build.gradle index dddba92..60a1bb3 100644 --- a/build.gradle +++ b/build.gradle @@ -1,12 +1,18 @@ buildscript { - ext { appName = "CaveDroid" + gdxVersion = '1.12.0' + guavaVersion = '28.1' + daggerVersion = '2.51.1' - kotlinVersion = '1.9.23' + + kotlinVersion = '1.9.24' + kspVersion = '1.9.24-1.0.20' kotlinSerializationVersion = '1.6.3' + + kotlinpoetKspVersion = '1.16.0' } repositories { @@ -24,8 +30,7 @@ buildscript { } allprojects { - - version = 'alpha0.6.2' + version = 'alpha0.9.2' repositories { mavenLocal() @@ -34,51 +39,6 @@ allprojects { maven { url "https://oss.sonatype.org/content/repositories/snapshots/" } maven { url "https://oss.sonatype.org/content/repositories/releases/" } maven { url "https://jitpack.io" } + maven { url "https://mvn.fredboy.ru/releases/" } } } - -project(":desktop") { - apply plugin: "java-library" - - dependencies { - implementation project(":core") - implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:$kotlinSerializationVersion" - api "com.badlogicgames.gdx:gdx-backend-lwjgl3:$gdxVersion" - api "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-desktop" - } -} - -project(":android") { - apply plugin: "android" - - configurations { natives } - - dependencies { - implementation project(":core") - implementation platform("org.jetbrains.kotlin:kotlin-bom:1.9.23") - api "com.badlogicgames.gdx:gdx-backend-android:$gdxVersion" - natives "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-armeabi-v7a" - natives "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-arm64-v8a" - natives "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-x86" - natives "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-x86_64" - - configurations.implementation { - exclude group: 'org.jetbrains.kotlin', module: 'kotlin-stdlib-jdk8' - } - } -} - -project(":core") { - apply plugin: "java-library" - - - dependencies { - api "com.badlogicgames.gdx:gdx:$gdxVersion" - api "com.google.guava:guava:$guavaVersion-android" - api "com.google.dagger:dagger:$daggerVersion" - implementation 'org.jetbrains:annotations:23.1.0' - implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion" - implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:$kotlinSerializationVersion" - annotationProcessor "com.google.dagger:dagger-compiler:$daggerVersion" - } -} \ No newline at end of file diff --git a/core/build.gradle b/core/build.gradle index cdf2ee7..3b061a7 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -1,12 +1,26 @@ plugins { + id "java-library" id "org.jetbrains.kotlin.jvm" id "kotlin" id "idea" id 'org.jetbrains.kotlin.plugin.serialization' version "$kotlinVersion" + id 'com.google.devtools.ksp' version "$kspVersion" } -sourceCompatibility = 17 +java.targetCompatibility = JavaVersion.VERSION_17 +java.sourceCompatibility = JavaVersion.VERSION_17 -sourceSets.main.java.srcDirs = [ "src/" ] +sourceSets.main.java.srcDirs = ["src/"] -java.targetCompatibility = JavaVersion.VERSION_17 \ No newline at end of file +dependencies { + implementation "ru.fredboy:automultibind-annotations:1.0.0" + ksp "ru.fredboy:automultibind-ksp:1.0.0" + + api "com.badlogicgames.gdx:gdx:$gdxVersion" + api "com.google.guava:guava:$guavaVersion-android" + api "com.google.dagger:dagger:$daggerVersion" + implementation 'org.jetbrains:annotations:23.1.0' + implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion" + implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:$kotlinSerializationVersion" + ksp "com.google.dagger:dagger-compiler:$daggerVersion" +} \ No newline at end of file diff --git a/core/src/ru/deadsoftware/cavedroid/CaveGame.java b/core/src/ru/deadsoftware/cavedroid/CaveGame.java index 3960176..9ca34b8 100644 --- a/core/src/ru/deadsoftware/cavedroid/CaveGame.java +++ b/core/src/ru/deadsoftware/cavedroid/CaveGame.java @@ -3,9 +3,11 @@ package ru.deadsoftware.cavedroid; import com.badlogic.gdx.Application; import com.badlogic.gdx.Game; import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.Graphics; import ru.deadsoftware.cavedroid.game.GameScreen; import ru.deadsoftware.cavedroid.misc.Assets; import ru.deadsoftware.cavedroid.misc.utils.AssetLoader; +import ru.deadsoftware.cavedroid.prefs.PreferencesStore; import javax.annotation.Nullable; @@ -13,7 +15,7 @@ public class CaveGame extends Game { private static final String TAG = "CaveGame"; - public static final String VERSION = "alpha 0.6.2"; + public static final String VERSION = "alpha 0.9.2"; private final MainConfig mMainConfig; private final MainComponent mMainComponent; @@ -26,12 +28,19 @@ public class CaveGame extends Game { @Nullable private final String mAssetsPackPath; - public CaveGame(String gameFolder, boolean touch, @Nullable String assetsPackPath) { + public CaveGame(String gameFolder, + boolean touch, + PreferencesStore preferencesStore, + @Nullable String assetsPackPath) { mGameFolder = gameFolder; mTouch = touch; mAssetsPackPath = assetsPackPath; - mMainComponent = DaggerMainComponent.builder().caveGame(this).build(); + mMainComponent = DaggerMainComponent + .builder() + .caveGame(this) + .preferencesStore(preferencesStore) + .build(); mMainConfig = mMainComponent.getMainConfig(); mAssetLoader = mMainComponent.getAssetLoader(); @@ -42,7 +51,7 @@ public class CaveGame extends Game { } private void initConfig() { - int width = mTouch ? 320 : 480; + int width = 480; int height = (int) (width * ((float) Gdx.graphics.getHeight() / Gdx.graphics.getWidth())); mMainConfig.setMainComponent(mMainComponent); @@ -58,6 +67,14 @@ public class CaveGame extends Game { } else { Gdx.app.setLogLevel(Application.LOG_ERROR); } + + mMainConfig.setFullscreenToggleListener((value) -> { + if (value) { + Gdx.graphics.setFullscreenMode(Gdx.graphics.getDisplayMode()); + } else { + Gdx.graphics.setWindowedMode(width, height); + } + }); } public void newGame(int gameMode) { diff --git a/core/src/ru/deadsoftware/cavedroid/MainComponent.java b/core/src/ru/deadsoftware/cavedroid/MainComponent.java index c640fb6..b487c6d 100644 --- a/core/src/ru/deadsoftware/cavedroid/MainComponent.java +++ b/core/src/ru/deadsoftware/cavedroid/MainComponent.java @@ -4,11 +4,12 @@ import dagger.Component; import ru.deadsoftware.cavedroid.game.GameScreen; import ru.deadsoftware.cavedroid.menu.MenuScreen; import ru.deadsoftware.cavedroid.misc.utils.AssetLoader; +import ru.deadsoftware.cavedroid.prefs.PreferencesStore; import javax.inject.Singleton; @Singleton -@Component(dependencies = CaveGame.class) +@Component(dependencies = {CaveGame.class, PreferencesStore.class}) public interface MainComponent { GameScreen getGameScreen(); diff --git a/core/src/ru/deadsoftware/cavedroid/MainConfig.java b/core/src/ru/deadsoftware/cavedroid/MainConfig.java index 6577f29..3ffb506 100644 --- a/core/src/ru/deadsoftware/cavedroid/MainConfig.java +++ b/core/src/ru/deadsoftware/cavedroid/MainConfig.java @@ -1,20 +1,32 @@ package ru.deadsoftware.cavedroid; import ru.deadsoftware.cavedroid.game.GameUiWindow; +import ru.deadsoftware.cavedroid.game.input.Joystick; +import ru.deadsoftware.cavedroid.prefs.PreferencesStore; import javax.annotation.CheckForNull; import javax.annotation.Nullable; import javax.inject.Inject; import javax.inject.Singleton; +import java.util.HashMap; @Singleton public class MainConfig { + private final HashMap mPreferencesCache = new HashMap<>(); + + @CheckForNull + private FullscreenToggleListener mFullscreenToggleListener = null; + private final CaveGame mCaveGame; + private final PreferencesStore mPreferencesStore; @CheckForNull private MainComponent mMainComponent; + @CheckForNull + private Joystick mJoystick; + private GameUiWindow mGameUiWindow; private String mGameFolder; @@ -29,8 +41,9 @@ public class MainConfig { private String mAssetsPackPath = null; @Inject - public MainConfig(CaveGame caveGame) { + public MainConfig(CaveGame caveGame, PreferencesStore preferencesStore) { mCaveGame = caveGame; + mPreferencesStore = preferencesStore; mGameUiWindow = GameUiWindow.NONE; mGameFolder = ""; @@ -113,4 +126,46 @@ public class MainConfig { public void setAssetsPackPath(@Nullable String assetsPackPath) { mAssetsPackPath = assetsPackPath; } + + @CheckForNull + public Joystick getJoystick() { + return mJoystick; + } + + public void setJoystick(@CheckForNull Joystick joystick) { + mJoystick = joystick; + } + + @CheckForNull + public String getPreference(String key) { + if (mPreferencesCache.containsKey(key)) { + return mPreferencesCache.get(key); + } + + String value = mPreferencesStore.getPreference(key); + mPreferencesCache.put(key, value); + + return value; + } + + public void setPreference(String key, String value) { + mPreferencesCache.put(key, value); + mPreferencesStore.setPreference(key, value); + + if (mFullscreenToggleListener != null && key.equals("fullscreen")) { + mFullscreenToggleListener.onFullscreenToggled(Boolean.parseBoolean(value)); + } + } + + public void setFullscreenToggleListener(@Nullable FullscreenToggleListener fullscreenToggleListener) { + mFullscreenToggleListener = fullscreenToggleListener; + } + + public boolean isUseDynamicCamera() { + return Boolean.parseBoolean(getPreference("dyncam")); + } + + public interface FullscreenToggleListener { + void onFullscreenToggled(boolean value); + } } diff --git a/core/src/ru/deadsoftware/cavedroid/game/GameComponent.java b/core/src/ru/deadsoftware/cavedroid/game/GameComponent.java index 2dafcd5..94d37d4 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/GameComponent.java +++ b/core/src/ru/deadsoftware/cavedroid/game/GameComponent.java @@ -2,12 +2,7 @@ package ru.deadsoftware.cavedroid.game; import dagger.Component; import ru.deadsoftware.cavedroid.MainComponent; -import ru.deadsoftware.cavedroid.game.actions.PlaceBlockActionsModule; -import ru.deadsoftware.cavedroid.game.actions.UpdateBlockActionsModule; -import ru.deadsoftware.cavedroid.game.actions.UseItemActionsModule; -import ru.deadsoftware.cavedroid.game.input.KeyboardInputHandlersModule; -import ru.deadsoftware.cavedroid.game.input.MouseInputHandlersModule; -import ru.deadsoftware.cavedroid.game.render.RenderModule; +import ru.deadsoftware.cavedroid.generated.module.*; @GameScope @Component(dependencies = MainComponent.class, @@ -17,7 +12,8 @@ import ru.deadsoftware.cavedroid.game.render.RenderModule; PlaceBlockActionsModule.class, RenderModule.class, KeyboardInputHandlersModule.class, - MouseInputHandlersModule.class + MouseInputHandlersModule.class, + UseBlockActionsModule.class }) public interface GameComponent { GameProc getGameProc(); diff --git a/core/src/ru/deadsoftware/cavedroid/game/GameItemsHolder.kt b/core/src/ru/deadsoftware/cavedroid/game/GameItemsHolder.kt index 832845e..050ae6f 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/GameItemsHolder.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/GameItemsHolder.kt @@ -83,7 +83,7 @@ class GameItemsHolder @Inject constructor( jsonMap.forEach { (key, value) -> craftingRecipes += CraftingRecipe( - input = value.input.map(::getItem), + input = value.input.map(::Regex), output = CraftingResult(getItem(key), value.count) ) } @@ -131,8 +131,20 @@ class GameItemsHolder @Inject constructor( } fun craftItem(input: List): InventoryItem? { + val startIndex = input.indexOfFirst { !it.isNone() }.takeIf { it >= 0 } ?: return null + return try { - craftingRecipes.first { rec -> rec.input == input}.output.toInventoryItem() + craftingRecipes.first { rec -> + for (i in rec.input.indices) { + if (startIndex + i >= input.size) { + return@first rec.input.subList(i, rec.input.size).all { it.matches("none") } + } + if (!input[startIndex + i].params.key.matches(rec.input[i])) { + return@first false + } + } + return@first true + }.output.toInventoryItem() } catch (e: NoSuchElementException) { null } diff --git a/core/src/ru/deadsoftware/cavedroid/game/GameModule.java b/core/src/ru/deadsoftware/cavedroid/game/GameModule.java index 29175da..d57ab33 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/GameModule.java +++ b/core/src/ru/deadsoftware/cavedroid/game/GameModule.java @@ -5,7 +5,9 @@ import dagger.Provides; 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.DropController; +import ru.deadsoftware.cavedroid.game.objects.drop.DropController; +import ru.deadsoftware.cavedroid.game.objects.container.ContainerController; +import ru.deadsoftware.cavedroid.game.ui.TooltipManager; import ru.deadsoftware.cavedroid.game.world.GameWorld; import javax.annotation.CheckForNull; @@ -44,11 +46,25 @@ public class GameModule { @Provides @GameScope - public static MobsController provideMobsController(MainConfig mainConfig, GameItemsHolder gameItemsHolder) { + public static ContainerController provideFurnaceController(MainConfig mainConfig, DropController dropController, GameItemsHolder gameItemsHolder) { load(mainConfig, gameItemsHolder); - MobsController controller = data != null ? data.retrieveMobsController() : new MobsController(gameItemsHolder); + ContainerController controller = data != null ? data.retrieveFurnaceController() : new ContainerController(dropController, gameItemsHolder); makeDataNullIfEmpty(); - controller.getPlayer().initInventory(gameItemsHolder); + controller.init(dropController, gameItemsHolder); + return controller; + } + + @Provides + @GameScope + public static MobsController provideMobsController(MainConfig mainConfig, + GameItemsHolder gameItemsHolder, + TooltipManager tooltipManager) { + load(mainConfig, gameItemsHolder); + MobsController controller = data != null + ? data.retrieveMobsController() + : new MobsController(gameItemsHolder, tooltipManager); + makeDataNullIfEmpty(); + controller.getPlayer().initInventory(gameItemsHolder, tooltipManager); return controller; } @@ -57,12 +73,13 @@ public class GameModule { public static GameWorld provideGameWorld(MainConfig mainConfig, DropController dropController, MobsController mobsController, - GameItemsHolder gameItemsHolder) { + GameItemsHolder gameItemsHolder, + 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, fm, bm); + return new GameWorld(dropController, mobsController, gameItemsHolder, containerController, fm, bm); } } diff --git a/core/src/ru/deadsoftware/cavedroid/game/GamePhysics.java b/core/src/ru/deadsoftware/cavedroid/game/GamePhysics.java index a0c8c37..cb5b37e 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/GamePhysics.java +++ b/core/src/ru/deadsoftware/cavedroid/game/GamePhysics.java @@ -7,10 +7,10 @@ import com.badlogic.gdx.math.Vector2; import ru.deadsoftware.cavedroid.MainConfig; import ru.deadsoftware.cavedroid.game.mobs.Mob; import ru.deadsoftware.cavedroid.game.mobs.MobsController; -import ru.deadsoftware.cavedroid.game.mobs.Player; +import ru.deadsoftware.cavedroid.game.mobs.player.Player; import ru.deadsoftware.cavedroid.game.model.block.Block; -import ru.deadsoftware.cavedroid.game.objects.Drop; -import ru.deadsoftware.cavedroid.game.objects.DropController; +import ru.deadsoftware.cavedroid.game.objects.drop.Drop; +import ru.deadsoftware.cavedroid.game.objects.drop.DropController; import ru.deadsoftware.cavedroid.game.world.GameWorld; import javax.annotation.CheckForNull; @@ -56,7 +56,7 @@ public class GamePhysics { int blY = (int) (mob.getY() + mob.getHeight() - 8); Block block = mGameWorld.getForeMap(blX / 16, blY / 16); - if (checkColl(new Rectangle(blX, mob.getY() - 18, mob.getWidth(), mob.getHeight()))) { + if (checkColl(new Rectangle(blX, mob.getY() - 18, mob.getWidth(), mob.getHeight())) != null) { return false; } @@ -64,7 +64,11 @@ public class GamePhysics { (mob.getY() + mob.getHeight()) - block.getRectangle(blX / 16, blY / 16).y > 8); } - private boolean checkColl(Rectangle rect) { + /** + * @return colliding rect or null if no collision + */ + @CheckForNull + private Rectangle checkColl(Rectangle rect) { int minX = (int) ((rect.x + rect.width / 2) / 16) - 4; int minY = (int) ((rect.y + rect.height / 2) / 16) - 4; int maxX = (int) ((rect.x + rect.width / 2) / 16) + 4; @@ -86,14 +90,15 @@ public class GamePhysics { } block = mGameWorld.getForeMap(x, y); if (block.hasCollision()) { - if (Intersector.overlaps(rect, block.getRectangle(x, y))) { - return true; + final Rectangle blockRect = block.getRectangle(x, y); + if (Intersector.overlaps(rect, blockRect)) { + return blockRect; } } } } - return false; + return null; } private Block getBlock(Rectangle rect) { @@ -113,6 +118,10 @@ public class GamePhysics { private Rectangle getShiftedMagnetingPlayerRect(Drop drop) { final Player player = mMobsController.getPlayer(); + if (!player.inventory.canPickItem(drop)) { + return null; + } + if (drop.canMagnetTo(player)) { return getShiftedPlayerRect(0); } @@ -134,7 +143,7 @@ public class GamePhysics { final Player player = mMobsController.getPlayer(); if (Intersector.overlaps(shiftedPlayerTarget, drop)) { - player.pickUpDrop(drop); + player.inventory.pickDrop(drop); } } @@ -158,11 +167,11 @@ public class GamePhysics { drop.x += dropVelocity.x * delta; drop.y += dropVelocity.y * delta; - if (checkColl(drop)) { + if (checkColl(drop) != null) { dropVelocity.setZero(); do { drop.y--; - } while (checkColl(drop)); + } while (checkColl(drop) != null); } if (playerMagnetTarget != null) { @@ -171,16 +180,21 @@ public class GamePhysics { } private void mobXColl(Mob mob) { - if (checkColl(mob)) { - if (mob.canJump() && !mob.isFlyMode()) { - mob.y -= 8; + if (mob.getVelocity().x == 0f) { + return; + } + + @CheckForNull Rectangle collidingRect = checkColl(mob); + + if (collidingRect != null) { + if (mob.canJump() && !mob.isFlyMode() && collidingRect.y >= mob.y + mob.height - 8) { + mob.y = collidingRect.y - mob.height; + return; } - if (checkColl(mob)) { - if (mob.canJump() && !mob.isFlyMode()) { - mob.y += 8; - } + collidingRect = checkColl(mob); + if (collidingRect != null) { int d = 0; if (mob.getVelocity().x < 0) { @@ -189,12 +203,17 @@ public class GamePhysics { d = -1; } - mob.x = MathUtils.round(mob.getX()); - - while (checkColl(mob)) { - mob.x += d; + if (d < 0) { + mob.x = collidingRect.x - mob.width; + } else { + mob.x = collidingRect.x + collidingRect.width; } +// mob.x = MathUtils.round(mob.getX()); +// while (checkColl(mob) != null) { +// mob.x += d; +// } + if (mob.canJump()) { mob.changeDir(); } @@ -205,7 +224,8 @@ public class GamePhysics { } private void mobYColl(Mob mob) { - if (checkColl(mob)) { + @CheckForNull final Rectangle collidingRect = checkColl(mob); + if (collidingRect != null) { int d = -1; if (mob.getVelocity().y < 0) { @@ -222,17 +242,24 @@ public class GamePhysics { } } - mob.y = MathUtils.round(mob.getY()); - - while (checkColl(mob)) { - mob.y += d; + if (d < 0) { + mob.y = collidingRect.y - mob.height; + } else { + mob.y = collidingRect.y + collidingRect.height; } + +// mob.y = MathUtils.round(mob.getY()); +// +// while (checkColl(mob)) { +// mob.y += d; +// } + mob.getVelocity().y = 0; } else { mob.y += 1; - mob.setCanJump(checkColl(mob)); + mob.setCanJump(checkColl(mob) != null); mob.y -= 1; } @@ -327,7 +354,7 @@ public class GamePhysics { for (Iterator it = mMobsController.getMobs().iterator(); it.hasNext(); ) { Mob mob = it.next(); - mob.ai(mGameWorld, mGameItemsHolder, delta); + mob.ai(mGameWorld, mGameItemsHolder, mMobsController, delta); mobPhy(mob, delta); if (mob.isDead()) { it.remove(); @@ -335,7 +362,7 @@ public class GamePhysics { } playerPhy(player, delta); - player.ai(mGameWorld, mGameItemsHolder, delta); + player.ai(mGameWorld, mGameItemsHolder, mMobsController, delta); if (player.isDead()) { player.respawn(mGameWorld, mGameItemsHolder); } diff --git a/core/src/ru/deadsoftware/cavedroid/game/GameProc.java b/core/src/ru/deadsoftware/cavedroid/game/GameProc.java index 94cd34b..29062a4 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/GameProc.java +++ b/core/src/ru/deadsoftware/cavedroid/game/GameProc.java @@ -5,7 +5,8 @@ import com.badlogic.gdx.utils.Disposable; 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; +import ru.deadsoftware.cavedroid.game.mobs.player.Player; +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; @@ -18,6 +19,8 @@ public class GameProc implements Disposable { private final GamePhysics mGamePhysics; private final GameRenderer mGameRenderer; private final MobsController mMobsController; + private final ContainerController mContainerController; + private final GameItemsHolder mGameItemsHolder; private final GameWorldFluidsLogicControllerTask mGameWorldFluidsLogicControllerTask; private final GameWorldBlocksLogicControllerTask mGameWorldBlocksLogicControllerTask; private final GameWorldMobDamageControllerTask mGameWorldMobDamageControllerTask; @@ -29,6 +32,8 @@ public class GameProc implements Disposable { GamePhysics gamePhysics, GameRenderer gameRenderer, MobsController mobsController, + ContainerController containerController, + GameItemsHolder gameItemsHolder, GameWorldFluidsLogicControllerTask gameWorldFluidsLogicControllerTask, GameWorldBlocksLogicControllerTask gameWorldBlocksLogicControllerTask, GameWorldMobDamageControllerTask gameWorldMobDamageControllerTask @@ -36,6 +41,8 @@ public class GameProc implements Disposable { mGamePhysics = gamePhysics; mGameRenderer = gameRenderer; mMobsController = mobsController; + mContainerController = containerController; + mGameItemsHolder = gameItemsHolder; mGameWorldFluidsLogicControllerTask = gameWorldFluidsLogicControllerTask; mGameWorldBlocksLogicControllerTask = gameWorldBlocksLogicControllerTask; mGameWorldMobDamageControllerTask = gameWorldMobDamageControllerTask; @@ -57,6 +64,7 @@ public class GameProc implements Disposable { public void update(float delta) { mGamePhysics.update(delta); mGameRenderer.render(delta); + mContainerController.update(); } public void show() { diff --git a/core/src/ru/deadsoftware/cavedroid/game/GameRenderer.java b/core/src/ru/deadsoftware/cavedroid/game/GameRenderer.java index e96f3af..93dc8b9 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/GameRenderer.java +++ b/core/src/ru/deadsoftware/cavedroid/game/GameRenderer.java @@ -1,11 +1,17 @@ package ru.deadsoftware.cavedroid.game; import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.Input; +import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.GL20; import com.badlogic.gdx.math.Rectangle; +import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.utils.ObjectMap; +import com.badlogic.gdx.utils.TimeUtils; import ru.deadsoftware.cavedroid.MainConfig; -import ru.deadsoftware.cavedroid.game.input.IGameInputHandler; +import ru.deadsoftware.cavedroid.game.input.IKeyboardInputHandler; +import ru.deadsoftware.cavedroid.game.input.IMouseInputHandler; +import ru.deadsoftware.cavedroid.game.input.Joystick; import ru.deadsoftware.cavedroid.game.input.action.KeyboardInputAction; import ru.deadsoftware.cavedroid.game.input.action.MouseInputAction; import ru.deadsoftware.cavedroid.game.input.action.keys.MouseInputActionKey; @@ -13,12 +19,16 @@ import ru.deadsoftware.cavedroid.game.input.handler.mouse.CursorMouseInputHandle import ru.deadsoftware.cavedroid.game.input.mapper.KeyboardInputActionMapper; import ru.deadsoftware.cavedroid.game.input.mapper.MouseInputActionMapper; import ru.deadsoftware.cavedroid.game.mobs.MobsController; -import ru.deadsoftware.cavedroid.game.mobs.Player; +import ru.deadsoftware.cavedroid.game.mobs.player.Player; import ru.deadsoftware.cavedroid.game.objects.TouchButton; import ru.deadsoftware.cavedroid.game.render.IGameRenderer; -import ru.deadsoftware.cavedroid.game.windows.GameWindowsManager; +import ru.deadsoftware.cavedroid.game.ui.TooltipManager; +import ru.deadsoftware.cavedroid.game.ui.windows.GameWindowsManager; +import ru.deadsoftware.cavedroid.game.world.GameWorld; import ru.deadsoftware.cavedroid.misc.Assets; import ru.deadsoftware.cavedroid.misc.Renderer; +import ru.deadsoftware.cavedroid.misc.utils.MeasureUnitsUtilsKt; +import ru.deadsoftware.cavedroid.misc.utils.RenderingUtilsKt; import javax.annotation.CheckForNull; import javax.inject.Inject; @@ -30,50 +40,159 @@ import java.util.Set; @GameScope public class GameRenderer extends Renderer { + private static final float CAMERA_SPEED = 72f; + private static final float MAX_CAM_DISTANCE_FROM_PLAYER = 64f; + private static final float DRAG_THRESHOLD = 1f; private static final TouchButton nullButton = new TouchButton(null, -1, true); private final MainConfig mMainConfig; private final MobsController mMobsController; + private final GameWorld mGameWorld; private final List mRenderers; private final CursorMouseInputHandler mCursorMouseInputHandler; private final MouseInputActionMapper mMouseInputActionMapper; private final KeyboardInputActionMapper mKeyboardInputActionMapper; - private final Set> mMouseInputHandlers; - private final Set> mKeyboardInputHandlers; + private final Set mMouseInputHandlers; + private final Set mKeyboardInputHandlers; private final GameWindowsManager mGameWindowsManager; + private final TooltipManager mTooltipManager; + + private final TouchButton mouseLeftTouchButton, mouseRightTouchButton; + + private final Vector2 mCamCenterToPlayer = new Vector2(); + + private float mTouchDownX, mTouchDownY; + private long mCameraDelayMs = 0L; @Inject GameRenderer(MainConfig mainConfig, MobsController mobsController, + GameWorld gameWorld, Set renderers, CursorMouseInputHandler cursorMouseInputHandler, MouseInputActionMapper mouseInputActionMapper, KeyboardInputActionMapper keyboardInputActionMapper, - Set> mouseInputHandlers, - Set> keyboardInputHandlers, - GameWindowsManager gameWindowsManager) { + Set mouseInputHandlers, + Set keyboardInputHandlers, + GameWindowsManager gameWindowsManager, + TooltipManager tooltipManager) { super(mainConfig.getWidth(), mainConfig.getHeight()); mMainConfig = mainConfig; mMobsController = mobsController; + mGameWorld = gameWorld; mRenderers = new ArrayList<>(renderers); - mRenderers.sort(Comparator.comparingInt(IGameRenderer::getRenderLayer)); + kotlin.collections.CollectionsKt.sortWith(mRenderers, new Comparator() { + @Override + public int compare(IGameRenderer o1, IGameRenderer o2) { + return o1.getRenderLayer() - o2.getRenderLayer(); + } + }); mCursorMouseInputHandler = cursorMouseInputHandler; mMouseInputActionMapper = mouseInputActionMapper; mKeyboardInputActionMapper = keyboardInputActionMapper; mMouseInputHandlers = mouseInputHandlers; mKeyboardInputHandlers = keyboardInputHandlers; mGameWindowsManager = gameWindowsManager; + mTooltipManager = tooltipManager; + + mouseLeftTouchButton = new TouchButton(new Rectangle(getWidth() / 2, 0f, getWidth() / 2, getHeight() / 2), Input.Buttons.LEFT, true); + mouseRightTouchButton = new TouchButton(new Rectangle(getWidth() / 2, getHeight() / 2, getWidth() / 2, getHeight() / 2), Input.Buttons.RIGHT, true); + + mMainConfig.setJoystick(new Joystick(mMobsController.getPlayer().getSpeed())); Gdx.gl.glClearColor(0f, .6f, .6f, 1f); } - private float mTouchDownX, mTouchDownY; + private void updateDynamicCameraPosition(float delta) { + Player player = mMobsController.getPlayer(); + + float plTargetX = player.getX() + player.getWidth() / 2; + float plTargetY = player.getY() + player.getHeight() / 2; + + float camCenterX = getCamX() + getWidth() / 2; + float camCenterY = getCamY() + getHeight() / 2; + + float camTargetX, camTargetY; + + boolean followPlayer = player.controlMode == Player.ControlMode.WALK || !mMainConfig.isTouch(); + + if (followPlayer) { + camTargetX = plTargetX + Math.min(player.getVelocity().x * 2, getWidth() / 2); + camTargetY = plTargetY + player.getVelocity().y; + } else { + camTargetX = MeasureUnitsUtilsKt.getPx(player.cursorX) + MeasureUnitsUtilsKt.getPx(1) / 2; + camTargetY = MeasureUnitsUtilsKt.getPx(player.cursorY) + MeasureUnitsUtilsKt.getPx(1) / 2; + } + + Vector2 moveVector = new Vector2(camTargetX - camCenterX, camTargetY - camCenterY); + + if (followPlayer && player.getVelocity().isZero()) { + mCameraDelayMs = TimeUtils.millis(); + mCamCenterToPlayer.x = plTargetX - camCenterX; + mCamCenterToPlayer.y = plTargetY - camCenterY; + } + + if (TimeUtils.timeSinceMillis(mCameraDelayMs) < 500L && !player.getVelocity().isZero()) { + updateStaticCameraPosition(plTargetX - mCamCenterToPlayer.x, + camCenterY + moveVector.y * delta * 2); + return; + } + + float camX = getCamX(); + float camY = getCamY(); + float worldWidth = MeasureUnitsUtilsKt.getPx(mGameWorld.getWidth()) - getWidth() / 2; + + if (moveVector.x >= worldWidth) { + camX += mGameWorld.getWidthPx(); + moveVector.x -= mGameWorld.getWidthPx(); + } else if (moveVector.x <= -worldWidth) { + camX -= mGameWorld.getWidthPx(); + moveVector.x += mGameWorld.getWidthPx(); + } + + setCamPos(camX + moveVector.x * delta * 2, camY + moveVector.y * delta * 2); + + + camX = getCamX(); + camY = getCamY(); + + if (camX + getWidth() / 2 > plTargetX + MAX_CAM_DISTANCE_FROM_PLAYER) { + camX = plTargetX + MAX_CAM_DISTANCE_FROM_PLAYER - getWidth() / 2; + } + + if (camY + getHeight() / 2 > plTargetY + MAX_CAM_DISTANCE_FROM_PLAYER) { + camY = plTargetY + MAX_CAM_DISTANCE_FROM_PLAYER - getHeight() / 2; + } - private void updateCameraPosition() { + if (camX + getWidth() / 2 < plTargetX - MAX_CAM_DISTANCE_FROM_PLAYER) { + camX = plTargetX - MAX_CAM_DISTANCE_FROM_PLAYER - getWidth() / 2; + } + + if (camY + getHeight() / 2 < plTargetY - MAX_CAM_DISTANCE_FROM_PLAYER) { + camY = plTargetY - MAX_CAM_DISTANCE_FROM_PLAYER - getHeight() / 2; + } + + setCamPos(camX, camY); + } + + private void updateStaticCameraPosition(float targetX, float targetY) { + setCamPos(targetX - getWidth() / 2, targetY - getHeight() / 2); + } + + private void updateStaticCameraPosition() { Player player = mMobsController.getPlayer(); - setCamPos(player.getX() + player.getWidth() / 2 - getWidth() / 2, - player.getY() + player.getHeight() / 2 - getHeight() / 2); + + updateStaticCameraPosition(player.getX() + player.getWidth() / 2, + player.getY() + player.getHeight() / 2); + } + + private void updateCameraPosition(float delta) { + if (mMainConfig.isUseDynamicCamera()) { + updateDynamicCameraPosition(delta); + } else { + updateStaticCameraPosition(); + } } private float transformScreenX(int screenX) { @@ -86,13 +205,22 @@ public class GameRenderer extends Renderer { private void handleMousePosition() { final Rectangle viewport = getCameraViewport(); + + final float screenX = transformScreenX(Gdx.input.getX()); + final float screenY = transformScreenY(Gdx.input.getY()); + final MouseInputAction action = new MouseInputAction( - Gdx.input.getX() * (viewport.width / Gdx.graphics.getWidth()), - Gdx.input.getY() * (viewport.height / Gdx.graphics.getHeight()), + screenX, + screenY, MouseInputActionKey.None.INSTANCE, viewport); mCursorMouseInputHandler.handle(action); + + if (!mTooltipManager.getCurrentMouseTooltip().isEmpty()) { + RenderingUtilsKt.drawString(spriter, mTooltipManager.getCurrentMouseTooltip(), screenX + 1, screenY + 1, Color.BLACK); + RenderingUtilsKt.drawString(spriter, mTooltipManager.getCurrentMouseTooltip(), screenX, screenY, Color.WHITE); + } } private boolean handleMouseAction(@CheckForNull MouseInputAction action) { @@ -102,7 +230,7 @@ public class GameRenderer extends Renderer { boolean anyProcessed = false; - for (IGameInputHandler handler : mMouseInputHandlers) { + for (IMouseInputHandler handler : mMouseInputHandlers) { final boolean conditions = handler.checkConditions(action); if (conditions) { anyProcessed = true; @@ -114,9 +242,9 @@ public class GameRenderer extends Renderer { return anyProcessed; } - private boolean onMouseActionEvent(int mouseX, int mouseY, int button, boolean touchUp) { + private boolean onMouseActionEvent(int mouseX, int mouseY, int button, boolean touchUp, int pointer) { @CheckForNull MouseInputAction action = mMouseInputActionMapper - .map((float) mouseX, (float) mouseY, getCameraViewport(), button, touchUp); + .map((float) mouseX, (float) mouseY, getCameraViewport(), button, touchUp, pointer); return handleMouseAction(action); } @@ -125,16 +253,22 @@ public class GameRenderer extends Renderer { float touchX = transformScreenX(screenX); float touchY = transformScreenY(screenY); + final Joystick joy = mMainConfig.getJoystick(); + if (mMainConfig.isTouch()) { + if (joy != null && joy.getActive() && joy.getPointer() == pointer) { + return onMouseActionEvent(screenX, screenY, nullButton.getCode(), true, pointer); + } + TouchButton touchedKey = getTouchedKey(touchX, touchY); if (touchedKey.isMouse()) { - return onMouseActionEvent(screenX, screenY, touchedKey.getCode(), true); + return onMouseActionEvent(screenX, screenY, touchedKey.getCode(), true, pointer); } else { return keyUp(touchedKey.getCode()); } } - return onMouseActionEvent(screenX, screenY, button, true); + return onMouseActionEvent(screenX, screenY, button, true, pointer); } private TouchButton getTouchedKey(float touchX, float touchY) { @@ -147,6 +281,15 @@ public class GameRenderer extends Renderer { return button; } } + + if (mouseLeftTouchButton.getRect().contains(touchX, touchY)) { + return mouseLeftTouchButton; + } + + if (mouseRightTouchButton.getRect().contains(touchX, touchY)) { + return mouseRightTouchButton; + } + return nullButton; } @@ -161,13 +304,13 @@ public class GameRenderer extends Renderer { if (mMainConfig.isTouch()) { TouchButton touchedKey = getTouchedKey(touchX, touchY); if (touchedKey.isMouse()) { - return onMouseActionEvent(screenX, screenY, touchedKey.getCode(), false); + return onMouseActionEvent(screenX, screenY, touchedKey.getCode(), false, pointer); } else { return keyDown(touchedKey.getCode()); } } - return onMouseActionEvent(screenX, screenY, button, false); + return onMouseActionEvent(screenX, screenY, button, false, pointer); } @Override @@ -175,12 +318,12 @@ public class GameRenderer extends Renderer { float touchX = transformScreenX(screenX); float touchY = transformScreenY(screenY); - if (Math.abs(touchX - mTouchDownX) < 16 && Math.abs(touchY - mTouchDownY) < 16) { + if (Math.abs(touchX - mTouchDownX) < 16 && Math.abs(touchY - mTouchDownY) < DRAG_THRESHOLD) { return false; } @CheckForNull MouseInputAction action = - mMouseInputActionMapper.mapDragged(screenX, screenY, getCameraViewport()); + mMouseInputActionMapper.mapDragged(screenX, screenY, getCameraViewport(), pointer); return handleMouseAction(action); } @@ -201,7 +344,7 @@ public class GameRenderer extends Renderer { boolean anyProcessed = false; - for (IGameInputHandler handler : mKeyboardInputHandlers) { + for (IKeyboardInputHandler handler : mKeyboardInputHandlers) { final boolean conditions = handler.checkConditions(action); if (conditions) { anyProcessed = true; @@ -225,15 +368,24 @@ public class GameRenderer extends Renderer { @Override public void render(float delta) { - updateCameraPosition(); - handleMousePosition(); -// mGameInput.moveCursor(this); + updateCameraPosition(delta); + + if (mMainConfig.getJoystick() != null && mMainConfig.getJoystick().getActive()) { + mMainConfig.getJoystick().updateState( + transformScreenX(Gdx.input.getX(mMainConfig.getJoystick().getPointer())), + transformScreenY(Gdx.input.getY(mMainConfig.getJoystick().getPointer())) + ); + } Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); spriter.begin(); - mRenderers.forEach(iGameRenderer -> iGameRenderer.draw(spriter, shaper, getCameraViewport(), delta)); + for (IGameRenderer iGameRenderer : mRenderers) { + iGameRenderer.draw(spriter, shaper, getCameraViewport(), delta); + } + handleMousePosition(); spriter.end(); + } } diff --git a/core/src/ru/deadsoftware/cavedroid/game/GameSaver.java b/core/src/ru/deadsoftware/cavedroid/game/GameSaver.java index cb52b3c..39d2278 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/GameSaver.java +++ b/core/src/ru/deadsoftware/cavedroid/game/GameSaver.java @@ -5,7 +5,8 @@ import com.badlogic.gdx.files.FileHandle; 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.DropController; +import ru.deadsoftware.cavedroid.game.objects.drop.DropController; +import ru.deadsoftware.cavedroid.game.objects.container.ContainerController; import ru.deadsoftware.cavedroid.game.world.GameWorld; import javax.annotation.CheckForNull; @@ -24,11 +25,18 @@ public class GameSaver { @CheckForNull private DropController mDropController; @CheckForNull + private ContainerController mContainerController; + @CheckForNull private Block[][] mForeMap, mBackMap; - public Data(MobsController mobsController, DropController dropController, Block[][] foreMap, Block[][] backMap) { + public Data(MobsController mobsController, + DropController dropController, + ContainerController containerController, + Block[][] foreMap, + Block[][] backMap) { mMobsController = mobsController; mDropController = dropController; + mContainerController = containerController; mForeMap = foreMap; mBackMap = backMap; } @@ -47,6 +55,13 @@ public class GameSaver { return dropController; } + public ContainerController retrieveFurnaceController() { + assert mContainerController != null; + ContainerController containerController = mContainerController; + mContainerController = null; + return containerController; + } + public Block[][] retrieveForeMap() { assert mForeMap != null; Block[][] foreMap = mForeMap; @@ -62,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; } } @@ -183,10 +202,12 @@ public class GameSaver { int version = in.readInt(); DropController dropController; MobsController mobsController; + ContainerController containerController; if (SAVE_VERSION == version) { dropController = (DropController) in.readObject(); mobsController = (MobsController) in.readObject(); + containerController = (ContainerController) in.readObject(); } else { throw new Exception("version mismatch"); } @@ -201,7 +222,7 @@ public class GameSaver { throw new Exception("couldn't load"); } - return new Data(mobsController, dropController, foreMap, backMap); + return new Data(mobsController, dropController, containerController, foreMap, backMap); } catch (Exception e) { Gdx.app.error("GameSaver", e.getMessage()); } @@ -212,6 +233,7 @@ public class GameSaver { public static void save(MainConfig mainConfig, DropController dropController, MobsController mobsController, + ContainerController containerController, GameWorld gameWorld) { String folder = mainConfig.getGameFolder(); FileHandle file = Gdx.files.absolute(folder + "/saves/"); @@ -229,6 +251,7 @@ public class GameSaver { out.writeInt(SAVE_VERSION); out.writeObject(dropController); out.writeObject(mobsController); + out.writeObject(containerController); out.close(); saveDict(Gdx.files.absolute(folder + "/saves/dict"), dict); diff --git a/core/src/ru/deadsoftware/cavedroid/game/actions/PlaceBlockActionsModule.kt b/core/src/ru/deadsoftware/cavedroid/game/actions/PlaceBlockActionsModule.kt deleted file mode 100644 index f2c5a23..0000000 --- a/core/src/ru/deadsoftware/cavedroid/game/actions/PlaceBlockActionsModule.kt +++ /dev/null @@ -1,40 +0,0 @@ -package ru.deadsoftware.cavedroid.game.actions - -import dagger.Binds -import dagger.Module -import dagger.multibindings.IntoMap -import dagger.multibindings.StringKey -import ru.deadsoftware.cavedroid.game.GameScope -import ru.deadsoftware.cavedroid.game.actions.placeblock.IPlaceBlockAction -import ru.deadsoftware.cavedroid.game.actions.placeblock.PlaceBlockItemToBackgroundAction -import ru.deadsoftware.cavedroid.game.actions.placeblock.PlaceBlockItemToForegroundAction -import ru.deadsoftware.cavedroid.game.actions.placeblock.PlaceSlabAction - -@Module -class PlaceBlockActionsModule { - - @Binds - @IntoMap - @StringKey(PlaceBlockItemToForegroundAction.ACTION_KEY) - @GameScope - fun bindPlaceBlockItemToForegroundAction(action: PlaceBlockItemToForegroundAction): IPlaceBlockAction { - return action - } - - @Binds - @IntoMap - @StringKey(PlaceBlockItemToBackgroundAction.ACTION_KEY) - @GameScope - fun bindPlaceBlockItemToBackgroundAction(action: PlaceBlockItemToBackgroundAction): IPlaceBlockAction { - return action - } - - @Binds - @IntoMap - @StringKey(PlaceSlabAction.ACTION_KEY) - @GameScope - fun bindPlaceSlabAction(action: PlaceSlabAction): IPlaceBlockAction { - return action - } - -} \ No newline at end of file diff --git a/core/src/ru/deadsoftware/cavedroid/game/actions/UpdateBlockActionsModule.kt b/core/src/ru/deadsoftware/cavedroid/game/actions/UpdateBlockActionsModule.kt deleted file mode 100644 index 5dcfe0e..0000000 --- a/core/src/ru/deadsoftware/cavedroid/game/actions/UpdateBlockActionsModule.kt +++ /dev/null @@ -1,52 +0,0 @@ -package ru.deadsoftware.cavedroid.game.actions - -import dagger.Binds -import dagger.Module -import dagger.multibindings.IntoMap -import dagger.multibindings.StringKey -import ru.deadsoftware.cavedroid.game.GameScope -import ru.deadsoftware.cavedroid.game.actions.updateblock.* - -@Module -class UpdateBlockActionsModule { - - @Binds - @IntoMap - @StringKey(UpdateSandAction.BLOCK_KEY) - @GameScope - fun bindUpdateSandAction(action: UpdateSandAction): IUpdateBlockAction { - return action; - } - - @Binds - @IntoMap - @StringKey(UpdateGravelAction.BLOCK_KEY) - @GameScope - fun bindUpdateGravelAction(action: UpdateGravelAction): IUpdateBlockAction { - return action; - } - - @Binds - @IntoMap - @StringKey(UpdateRequiresBlockAction.ACTION_KEY) - @GameScope - fun bindUpdateRequiresBlockAction(action: UpdateRequiresBlockAction): IUpdateBlockAction { - return action; - } - - @Binds - @IntoMap - @StringKey(UpdateGrassAction.BLOCK_KEY) - @GameScope - fun bindUpdateGrassAction(action: UpdateGrassAction): IUpdateBlockAction { - return action; - } - - @Binds - @IntoMap - @StringKey(UpdateSnowedGrassAction.BLOCK_KEY) - @GameScope - fun bindUpdateSnowedGrassAction(action: UpdateSnowedGrassAction): IUpdateBlockAction { - return action; - } -} \ No newline at end of file diff --git a/core/src/ru/deadsoftware/cavedroid/game/actions/UseItemActionsModule.kt b/core/src/ru/deadsoftware/cavedroid/game/actions/UseItemActionsModule.kt deleted file mode 100644 index 0206d5f..0000000 --- a/core/src/ru/deadsoftware/cavedroid/game/actions/UseItemActionsModule.kt +++ /dev/null @@ -1,37 +0,0 @@ -package ru.deadsoftware.cavedroid.game.actions - -import dagger.Binds -import dagger.Module -import dagger.multibindings.IntoMap -import dagger.multibindings.StringKey -import ru.deadsoftware.cavedroid.game.GameScope -import ru.deadsoftware.cavedroid.game.actions.useitem.* - -@Module -class UseItemActionsModule { - - @Binds - @IntoMap - @StringKey(UseWaterBucketAction.ACTION_KEY) - @GameScope - fun bindUseWaterBucketAction(action: UseWaterBucketAction): IUseItemAction { - return action - } - - @Binds - @IntoMap - @StringKey(UseLavaBucketAction.ACTION_KEY) - @GameScope - fun bindUseLavaBucketAction(action: UseLavaBucketAction): IUseItemAction { - return action - } - - @Binds - @IntoMap - @StringKey(UseEmptyBucketAction.ACTION_KEY) - @GameScope - fun bindUseEmptyBucketAction(action: UseEmptyBucketAction): IUseItemAction { - return action - } - -} diff --git a/core/src/ru/deadsoftware/cavedroid/game/actions/placeblock/PlaceBlockItemToBackgroundAction.kt b/core/src/ru/deadsoftware/cavedroid/game/actions/placeblock/PlaceBlockItemToBackgroundAction.kt index fdfb61a..7258301 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/actions/placeblock/PlaceBlockItemToBackgroundAction.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/actions/placeblock/PlaceBlockItemToBackgroundAction.kt @@ -5,9 +5,11 @@ import ru.deadsoftware.cavedroid.game.GameScope import ru.deadsoftware.cavedroid.game.mobs.MobsController import ru.deadsoftware.cavedroid.game.model.item.Item import ru.deadsoftware.cavedroid.game.world.GameWorld +import ru.deadsoftware.cavedroid.misc.annotations.multibinding.BindPlaceBlockAction import javax.inject.Inject @GameScope +@BindPlaceBlockAction(stringKey = PlaceBlockItemToBackgroundAction.ACTION_KEY) class PlaceBlockItemToBackgroundAction @Inject constructor( private val gameWorld: GameWorld, private val gameItemsHolder: GameItemsHolder, diff --git a/core/src/ru/deadsoftware/cavedroid/game/actions/placeblock/PlaceBlockItemToForegroundAction.kt b/core/src/ru/deadsoftware/cavedroid/game/actions/placeblock/PlaceBlockItemToForegroundAction.kt index 22aafdd..ec249fb 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/actions/placeblock/PlaceBlockItemToForegroundAction.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/actions/placeblock/PlaceBlockItemToForegroundAction.kt @@ -5,9 +5,11 @@ import ru.deadsoftware.cavedroid.game.GameScope import ru.deadsoftware.cavedroid.game.mobs.MobsController import ru.deadsoftware.cavedroid.game.model.item.Item import ru.deadsoftware.cavedroid.game.world.GameWorld +import ru.deadsoftware.cavedroid.misc.annotations.multibinding.BindPlaceBlockAction import javax.inject.Inject @GameScope +@BindPlaceBlockAction(stringKey = PlaceBlockItemToForegroundAction.ACTION_KEY) class PlaceBlockItemToForegroundAction @Inject constructor( private val gameWorld: GameWorld, private val placeSlabAction: PlaceSlabAction, diff --git a/core/src/ru/deadsoftware/cavedroid/game/actions/placeblock/PlaceSlabAction.kt b/core/src/ru/deadsoftware/cavedroid/game/actions/placeblock/PlaceSlabAction.kt index 6ac94c9..00c62d7 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/actions/placeblock/PlaceSlabAction.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/actions/placeblock/PlaceSlabAction.kt @@ -6,9 +6,11 @@ import ru.deadsoftware.cavedroid.game.GameScope import ru.deadsoftware.cavedroid.game.mobs.MobsController import ru.deadsoftware.cavedroid.game.model.item.Item import ru.deadsoftware.cavedroid.game.world.GameWorld +import ru.deadsoftware.cavedroid.misc.annotations.multibinding.BindPlaceBlockAction import javax.inject.Inject @GameScope +@BindPlaceBlockAction(stringKey = PlaceSlabAction.ACTION_KEY) class PlaceSlabAction @Inject constructor( private val gameWorld: GameWorld, private val mobsController: MobsController, diff --git a/core/src/ru/deadsoftware/cavedroid/game/actions/updateblock/UpdateBedLeftAction.kt b/core/src/ru/deadsoftware/cavedroid/game/actions/updateblock/UpdateBedLeftAction.kt new file mode 100644 index 0000000..5507550 --- /dev/null +++ b/core/src/ru/deadsoftware/cavedroid/game/actions/updateblock/UpdateBedLeftAction.kt @@ -0,0 +1,28 @@ +package ru.deadsoftware.cavedroid.game.actions.updateblock + +import ru.deadsoftware.cavedroid.game.GameItemsHolder +import ru.deadsoftware.cavedroid.game.GameScope +import ru.deadsoftware.cavedroid.game.mobs.FallingGravel +import ru.deadsoftware.cavedroid.game.mobs.MobsController +import ru.deadsoftware.cavedroid.game.world.GameWorld +import ru.deadsoftware.cavedroid.misc.annotations.multibinding.BindUpdateBlockAction +import javax.inject.Inject + +@GameScope +@BindUpdateBlockAction(stringKey = UpdateBedLeftAction.BLOCK_KEY) +class UpdateBedLeftAction @Inject constructor( + private val gameWorld: GameWorld, + private val gameItemsHolder: GameItemsHolder, +) : IUpdateBlockAction { + + override fun update(x: Int, y: Int) { + val bedRight = gameItemsHolder.getBlock("bed_r") + if (gameWorld.getForeMap(x + 1, y) != bedRight) { + gameWorld.resetForeMap(x, y) + } + } + + companion object { + const val BLOCK_KEY = "bed_l" + } +} \ No newline at end of file diff --git a/core/src/ru/deadsoftware/cavedroid/game/actions/updateblock/UpdateBedRightAction.kt b/core/src/ru/deadsoftware/cavedroid/game/actions/updateblock/UpdateBedRightAction.kt new file mode 100644 index 0000000..42f551e --- /dev/null +++ b/core/src/ru/deadsoftware/cavedroid/game/actions/updateblock/UpdateBedRightAction.kt @@ -0,0 +1,28 @@ +package ru.deadsoftware.cavedroid.game.actions.updateblock + +import ru.deadsoftware.cavedroid.game.GameItemsHolder +import ru.deadsoftware.cavedroid.game.GameScope +import ru.deadsoftware.cavedroid.game.mobs.FallingGravel +import ru.deadsoftware.cavedroid.game.mobs.MobsController +import ru.deadsoftware.cavedroid.game.world.GameWorld +import ru.deadsoftware.cavedroid.misc.annotations.multibinding.BindUpdateBlockAction +import javax.inject.Inject + +@GameScope +@BindUpdateBlockAction(stringKey = UpdateBedRightAction.BLOCK_KEY) +class UpdateBedRightAction @Inject constructor( + private val gameWorld: GameWorld, + private val gameItemsHolder: GameItemsHolder, +) : IUpdateBlockAction { + + override fun update(x: Int, y: Int) { + val bedLeft = gameItemsHolder.getBlock("bed_l") + if (gameWorld.getForeMap(x - 1, y) != bedLeft) { + gameWorld.resetForeMap(x, y) + } + } + + companion object { + const val BLOCK_KEY = "bed_r" + } +} \ No newline at end of file diff --git a/core/src/ru/deadsoftware/cavedroid/game/actions/updateblock/UpdateGrassAction.kt b/core/src/ru/deadsoftware/cavedroid/game/actions/updateblock/UpdateGrassAction.kt index 27005b8..476235a 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/actions/updateblock/UpdateGrassAction.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/actions/updateblock/UpdateGrassAction.kt @@ -3,9 +3,11 @@ package ru.deadsoftware.cavedroid.game.actions.updateblock import ru.deadsoftware.cavedroid.game.GameItemsHolder import ru.deadsoftware.cavedroid.game.GameScope import ru.deadsoftware.cavedroid.game.world.GameWorld +import ru.deadsoftware.cavedroid.misc.annotations.multibinding.BindUpdateBlockAction import javax.inject.Inject @GameScope +@BindUpdateBlockAction(stringKey = UpdateGrassAction.BLOCK_KEY) class UpdateGrassAction @Inject constructor( private val gameWorld: GameWorld, private val mGameItemsHolder: GameItemsHolder, @@ -13,8 +15,12 @@ class UpdateGrassAction @Inject constructor( override fun update(x: Int, y: Int) { val blockOnTop = gameWorld.getForeMap(x, y - 1) - if (blockOnTop.collision || blockOnTop.isFluid()) { - gameWorld.setForeMap(x, y, mGameItemsHolder.getBlock("dirt")) + + val makesDirt = blockOnTop.params.hasCollision || blockOnTop.isFluid() + + when { + makesDirt -> gameWorld.setForeMap(x, y, mGameItemsHolder.getBlock("dirt")) + blockOnTop.params.key == "snow" -> gameWorld.setForeMap(x, y, mGameItemsHolder.getBlock("grass_snowed")) } } diff --git a/core/src/ru/deadsoftware/cavedroid/game/actions/updateblock/UpdateGravelAction.kt b/core/src/ru/deadsoftware/cavedroid/game/actions/updateblock/UpdateGravelAction.kt index 6cc026f..3c52418 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/actions/updateblock/UpdateGravelAction.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/actions/updateblock/UpdateGravelAction.kt @@ -4,9 +4,11 @@ import ru.deadsoftware.cavedroid.game.GameScope import ru.deadsoftware.cavedroid.game.mobs.FallingGravel import ru.deadsoftware.cavedroid.game.mobs.MobsController import ru.deadsoftware.cavedroid.game.world.GameWorld +import ru.deadsoftware.cavedroid.misc.annotations.multibinding.BindUpdateBlockAction import javax.inject.Inject @GameScope +@BindUpdateBlockAction(stringKey = UpdateGravelAction.BLOCK_KEY) class UpdateGravelAction @Inject constructor( private val gameWorld: GameWorld, private val mobsController: MobsController, diff --git a/core/src/ru/deadsoftware/cavedroid/game/actions/updateblock/UpdateRequiresBlockAction.kt b/core/src/ru/deadsoftware/cavedroid/game/actions/updateblock/UpdateRequiresBlockAction.kt index 57172a5..05d9863 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/actions/updateblock/UpdateRequiresBlockAction.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/actions/updateblock/UpdateRequiresBlockAction.kt @@ -2,9 +2,11 @@ package ru.deadsoftware.cavedroid.game.actions.updateblock import ru.deadsoftware.cavedroid.game.GameScope import ru.deadsoftware.cavedroid.game.world.GameWorld +import ru.deadsoftware.cavedroid.misc.annotations.multibinding.BindUpdateBlockAction import javax.inject.Inject @GameScope +@BindUpdateBlockAction(stringKey = UpdateRequiresBlockAction.ACTION_KEY) class UpdateRequiresBlockAction @Inject constructor( private val gameWorld: GameWorld, ) : IUpdateBlockAction { diff --git a/core/src/ru/deadsoftware/cavedroid/game/actions/updateblock/UpdateSandAction.kt b/core/src/ru/deadsoftware/cavedroid/game/actions/updateblock/UpdateSandAction.kt index 4a2b58e..ac1ff8a 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/actions/updateblock/UpdateSandAction.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/actions/updateblock/UpdateSandAction.kt @@ -4,9 +4,11 @@ import ru.deadsoftware.cavedroid.game.GameScope import ru.deadsoftware.cavedroid.game.mobs.FallingSand import ru.deadsoftware.cavedroid.game.mobs.MobsController import ru.deadsoftware.cavedroid.game.world.GameWorld +import ru.deadsoftware.cavedroid.misc.annotations.multibinding.BindUpdateBlockAction import javax.inject.Inject @GameScope +@BindUpdateBlockAction(stringKey = UpdateSandAction.BLOCK_KEY) class UpdateSandAction @Inject constructor( private val gameWorld: GameWorld, private val mobsController: MobsController, diff --git a/core/src/ru/deadsoftware/cavedroid/game/actions/updateblock/UpdateSnowedGrassAction.kt b/core/src/ru/deadsoftware/cavedroid/game/actions/updateblock/UpdateSnowedGrassAction.kt index 8b7f0e3..2cf5a57 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/actions/updateblock/UpdateSnowedGrassAction.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/actions/updateblock/UpdateSnowedGrassAction.kt @@ -3,9 +3,11 @@ package ru.deadsoftware.cavedroid.game.actions.updateblock import ru.deadsoftware.cavedroid.game.GameItemsHolder import ru.deadsoftware.cavedroid.game.GameScope import ru.deadsoftware.cavedroid.game.world.GameWorld +import ru.deadsoftware.cavedroid.misc.annotations.multibinding.BindUpdateBlockAction import javax.inject.Inject @GameScope +@BindUpdateBlockAction(stringKey = UpdateSnowedGrassAction.BLOCK_KEY) class UpdateSnowedGrassAction @Inject constructor( private val gameWorld: GameWorld, private val mGameItemsHolder: GameItemsHolder, @@ -13,8 +15,11 @@ class UpdateSnowedGrassAction @Inject constructor( override fun update(x: Int, y: Int) { val blockOnTop = gameWorld.getForeMap(x, y - 1) - if (blockOnTop.collision || blockOnTop.isFluid()) { - gameWorld.setForeMap(x, y, mGameItemsHolder.getBlock("dirt")) + val makesDirt = blockOnTop.params.hasCollision || blockOnTop.isFluid() + + when { + makesDirt -> gameWorld.setForeMap(x, y, mGameItemsHolder.getBlock("dirt")) + blockOnTop.params.key != "snow" -> gameWorld.setForeMap(x, y, mGameItemsHolder.getBlock("grass")) } } diff --git a/core/src/ru/deadsoftware/cavedroid/game/actions/useblock/IUseBlockAction.kt b/core/src/ru/deadsoftware/cavedroid/game/actions/useblock/IUseBlockAction.kt new file mode 100644 index 0000000..ddc70c5 --- /dev/null +++ b/core/src/ru/deadsoftware/cavedroid/game/actions/useblock/IUseBlockAction.kt @@ -0,0 +1,9 @@ +package ru.deadsoftware.cavedroid.game.actions.useblock + +import ru.deadsoftware.cavedroid.game.model.block.Block + +interface IUseBlockAction { + + fun perform(block: Block, x: Int, y: Int) + +} \ No newline at end of file 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 index 0000000..93684e7 --- /dev/null +++ b/core/src/ru/deadsoftware/cavedroid/game/actions/useblock/UseChestAction.kt @@ -0,0 +1,28 @@ +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 ru.deadsoftware.cavedroid.misc.annotations.multibinding.BindUseBlockAction +import javax.inject.Inject + +@GameScope +@BindUseBlockAction(stringKey = UseChestAction.KEY) +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 diff --git a/core/src/ru/deadsoftware/cavedroid/game/actions/useblock/UseCraftingTableAction.kt b/core/src/ru/deadsoftware/cavedroid/game/actions/useblock/UseCraftingTableAction.kt new file mode 100644 index 0000000..6d6c1e9 --- /dev/null +++ b/core/src/ru/deadsoftware/cavedroid/game/actions/useblock/UseCraftingTableAction.kt @@ -0,0 +1,22 @@ +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.ui.windows.GameWindowsManager +import ru.deadsoftware.cavedroid.misc.annotations.multibinding.BindUseBlockAction +import javax.inject.Inject + +@GameScope +@BindUseBlockAction(stringKey = UseCraftingTableAction.KEY) +class UseCraftingTableAction @Inject constructor( + private val gameWindowsManager: GameWindowsManager +) : IUseBlockAction { + + override fun perform(block: Block, x: Int, y: Int) { + gameWindowsManager.openCrafting() + } + + companion object { + const val KEY = "crafting_table" + } +} \ No newline at end of file diff --git a/core/src/ru/deadsoftware/cavedroid/game/actions/useblock/UseFurnaceAction.kt b/core/src/ru/deadsoftware/cavedroid/game/actions/useblock/UseFurnaceAction.kt new file mode 100644 index 0000000..0b8ba53 --- /dev/null +++ b/core/src/ru/deadsoftware/cavedroid/game/actions/useblock/UseFurnaceAction.kt @@ -0,0 +1,25 @@ +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.ui.windows.GameWindowsManager +import ru.deadsoftware.cavedroid.game.world.GameWorld +import ru.deadsoftware.cavedroid.misc.annotations.multibinding.BindUseBlockAction +import javax.inject.Inject + +@GameScope +@BindUseBlockAction(stringKey = UseFurnaceAction.KEY) +class UseFurnaceAction @Inject constructor( + private val gameWorld: GameWorld, + private val gameWindowsManager: GameWindowsManager, +) : IUseBlockAction { + + override fun perform(block: Block, x: Int, y: Int) { + val furnace = gameWorld.getForegroundFurnace(x, y) ?: gameWorld.getBackgroundFurnace(x, y) ?: return + gameWindowsManager.openFurnace(furnace) + } + + companion object { + const val KEY = "furnace" + } +} \ No newline at end of file diff --git a/core/src/ru/deadsoftware/cavedroid/game/actions/useitem/UseBedAction.kt b/core/src/ru/deadsoftware/cavedroid/game/actions/useitem/UseBedAction.kt new file mode 100644 index 0000000..f48115e --- /dev/null +++ b/core/src/ru/deadsoftware/cavedroid/game/actions/useitem/UseBedAction.kt @@ -0,0 +1,33 @@ +package ru.deadsoftware.cavedroid.game.actions.useitem + +import ru.deadsoftware.cavedroid.game.GameItemsHolder +import ru.deadsoftware.cavedroid.game.GameScope +import ru.deadsoftware.cavedroid.game.mobs.MobsController +import ru.deadsoftware.cavedroid.game.model.item.Item +import ru.deadsoftware.cavedroid.game.world.GameWorld +import ru.deadsoftware.cavedroid.misc.annotations.multibinding.BindUseItemAction +import javax.inject.Inject + +@GameScope +@BindUseItemAction(UseBedAction.ACTION_KEY) +class UseBedAction @Inject constructor( + private val gameWorld: GameWorld, + private val mobsController: MobsController, + private val gameItemsHolder: GameItemsHolder, +) : IUseItemAction { + + override fun perform(item: Item.Usable, x: Int, y: Int) { + val bedLeft = gameItemsHolder.getBlock("bed_l") + val bedRight = gameItemsHolder.getBlock("bed_r") + + if (gameWorld.canPlaceToForeground(x, y, bedLeft) && gameWorld.canPlaceToForeground(x + 1, y, bedRight)) { + gameWorld.placeToForeground(x, y, bedLeft) + gameWorld.placeToForeground(x + 1, y, bedRight) + mobsController.player.inventory.decreaseCurrentItemAmount() + } + } + + companion object { + const val ACTION_KEY = "use_bed_action" + } +} diff --git a/core/src/ru/deadsoftware/cavedroid/game/actions/useitem/UseEmptyBucketAction.kt b/core/src/ru/deadsoftware/cavedroid/game/actions/useitem/UseEmptyBucketAction.kt index 9f7c9f4..6992af7 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/actions/useitem/UseEmptyBucketAction.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/actions/useitem/UseEmptyBucketAction.kt @@ -6,9 +6,11 @@ import ru.deadsoftware.cavedroid.game.mobs.MobsController import ru.deadsoftware.cavedroid.game.model.block.Block import ru.deadsoftware.cavedroid.game.model.item.Item import ru.deadsoftware.cavedroid.game.world.GameWorld +import ru.deadsoftware.cavedroid.misc.annotations.multibinding.BindUseItemAction import javax.inject.Inject @GameScope +@BindUseItemAction(UseEmptyBucketAction.ACTION_KEY) class UseEmptyBucketAction @Inject constructor( private val gameWorld: GameWorld, private val mobsController: MobsController, @@ -22,6 +24,7 @@ class UseEmptyBucketAction @Inject constructor( } gameWorld.resetForeMap(x, y) + @Suppress("REDUNDANT_ELSE_IN_WHEN") val filled = when (foregroundBlock) { is Block.Lava -> gameItemsHolder.getItem("bucket_lava") is Block.Water -> gameItemsHolder.getItem("bucket_water") diff --git a/core/src/ru/deadsoftware/cavedroid/game/actions/useitem/UseLavaBucketAction.kt b/core/src/ru/deadsoftware/cavedroid/game/actions/useitem/UseLavaBucketAction.kt index 9659617..ec1e585 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/actions/useitem/UseLavaBucketAction.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/actions/useitem/UseLavaBucketAction.kt @@ -5,9 +5,11 @@ import ru.deadsoftware.cavedroid.game.GameScope import ru.deadsoftware.cavedroid.game.mobs.MobsController import ru.deadsoftware.cavedroid.game.model.item.Item import ru.deadsoftware.cavedroid.game.world.GameWorld +import ru.deadsoftware.cavedroid.misc.annotations.multibinding.BindUseItemAction import javax.inject.Inject @GameScope +@BindUseItemAction(UseLavaBucketAction.ACTION_KEY) class UseLavaBucketAction @Inject constructor( private val gameWorld: GameWorld, private val mobsController: MobsController, diff --git a/core/src/ru/deadsoftware/cavedroid/game/actions/useitem/UsePigSpawnEggAction.kt b/core/src/ru/deadsoftware/cavedroid/game/actions/useitem/UsePigSpawnEggAction.kt new file mode 100644 index 0000000..5eddc5e --- /dev/null +++ b/core/src/ru/deadsoftware/cavedroid/game/actions/useitem/UsePigSpawnEggAction.kt @@ -0,0 +1,31 @@ +package ru.deadsoftware.cavedroid.game.actions.useitem + +import ru.deadsoftware.cavedroid.game.GameItemsHolder +import ru.deadsoftware.cavedroid.game.GameScope +import ru.deadsoftware.cavedroid.game.mobs.MobsController +import ru.deadsoftware.cavedroid.game.mobs.Pig +import ru.deadsoftware.cavedroid.game.model.item.Item +import ru.deadsoftware.cavedroid.misc.annotations.multibinding.BindUseItemAction +import ru.deadsoftware.cavedroid.misc.utils.px +import javax.inject.Inject + +@GameScope +@BindUseItemAction(UsePigSpawnEggAction.ACTION_KEY) +class UsePigSpawnEggAction @Inject constructor( + private val mobsController: MobsController, + private val gameItemsHolder: GameItemsHolder, +) : IUseItemAction { + + override fun perform(item: Item.Usable, x: Int, y: Int) { + Pig(mobsController.player.cursorX.px, mobsController.player.cursorY.px) + .apply { + attachToController(mobsController) + } + + mobsController.player.decreaseCurrentItemCount(gameItemsHolder) + } + + companion object { + const val ACTION_KEY = "use_spawn_egg_pig" + } +} diff --git a/core/src/ru/deadsoftware/cavedroid/game/actions/useitem/UseWaterBucketAction.kt b/core/src/ru/deadsoftware/cavedroid/game/actions/useitem/UseWaterBucketAction.kt index 15e08fc..739ec28 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/actions/useitem/UseWaterBucketAction.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/actions/useitem/UseWaterBucketAction.kt @@ -5,9 +5,11 @@ import ru.deadsoftware.cavedroid.game.GameScope import ru.deadsoftware.cavedroid.game.mobs.MobsController import ru.deadsoftware.cavedroid.game.model.item.Item import ru.deadsoftware.cavedroid.game.world.GameWorld +import ru.deadsoftware.cavedroid.misc.annotations.multibinding.BindUseItemAction import javax.inject.Inject @GameScope +@BindUseItemAction(UseWaterBucketAction.ACTION_KEY) class UseWaterBucketAction @Inject constructor( private val gameWorld: GameWorld, private val mobsController: MobsController, diff --git a/core/src/ru/deadsoftware/cavedroid/game/debug/DebugInfoStringsProvider.kt b/core/src/ru/deadsoftware/cavedroid/game/debug/DebugInfoStringsProvider.kt index c8147d1..51dc335 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/debug/DebugInfoStringsProvider.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/debug/DebugInfoStringsProvider.kt @@ -3,7 +3,8 @@ 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.DropController +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 { @@ -20,15 +22,16 @@ class DebugInfoStringsProvider @Inject constructor( return listOf( "FPS: ${Gdx.graphics.framesPerSecond}", "X: ${player.mapX}", - "Y: ${gameWorld.height - player.upperMapY}", + "Y: ${player.upperMapY} (${gameWorld.height - player.upperMapY})", "CurX: ${player.cursorX}", "CurY: ${player.cursorY}", "Velocity: ${player.velocity}", "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[player.slot].item.params.key}", + "Hand: ${player.inventory.activeItem.item.params.key}", "Game mode: ${player.gameMode}", "Block damage: ${player.blockDamage}" ) diff --git a/core/src/ru/deadsoftware/cavedroid/game/input/IGameInputHandler.kt b/core/src/ru/deadsoftware/cavedroid/game/input/IGameInputHandler.kt index a8eaad1..2c5f118 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/input/IGameInputHandler.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/input/IGameInputHandler.kt @@ -1,6 +1,12 @@ package ru.deadsoftware.cavedroid.game.input import ru.deadsoftware.cavedroid.game.input.action.IGameInputAction +import ru.deadsoftware.cavedroid.game.input.action.KeyboardInputAction +import ru.deadsoftware.cavedroid.game.input.action.MouseInputAction + +interface IKeyboardInputHandler : IGameInputHandler + +interface IMouseInputHandler : IGameInputHandler interface IGameInputHandler { diff --git a/core/src/ru/deadsoftware/cavedroid/game/input/Joystick.kt b/core/src/ru/deadsoftware/cavedroid/game/input/Joystick.kt new file mode 100644 index 0000000..6cbc052 --- /dev/null +++ b/core/src/ru/deadsoftware/cavedroid/game/input/Joystick.kt @@ -0,0 +1,73 @@ +package ru.deadsoftware.cavedroid.game.input + +import com.badlogic.gdx.math.Vector2 +import com.badlogic.gdx.utils.TimeUtils + +class Joystick( + private val value: Float, +) { + + var active = false + private set + var centerX = 0f + private set + var centerY = 0f + private set + + var activeX = 0f + private set + var activeY = 0f + private set + + var pointer = 0 + private set + + private val stickVector = Vector2() + + private var activateTimeMs = 0L + + fun activate(touchX: Float, touchY: Float, pointer: Int) { + active = true + centerX = touchX + centerY = touchY + activateTimeMs = TimeUtils.millis() + this.pointer = pointer + } + + fun deactivate() { + active = false + } + + fun getVelocityVector(): Vector2 { + if (!active) { + return Vector2.Zero + } + return Vector2( + stickVector.x * value, + stickVector.y * value + ) + } + + fun updateState(touchX: Float, touchY: Float) { + if (!active) { + return + } + + stickVector.x = touchX - centerX + stickVector.y = touchY - centerY + stickVector.clamp(0f, RADIUS) + + activeX = centerX + stickVector.x + activeY = centerY + stickVector.y + + stickVector.x /= RADIUS + stickVector.y /= RADIUS + } + + companion object { + const val RADIUS = 48f + const val SIZE = RADIUS * 2 + const val STICK_SIZE = 32f + } + +} \ No newline at end of file diff --git a/core/src/ru/deadsoftware/cavedroid/game/input/KeyboardInputHandlersModule.kt b/core/src/ru/deadsoftware/cavedroid/game/input/KeyboardInputHandlersModule.kt deleted file mode 100644 index f590398..0000000 --- a/core/src/ru/deadsoftware/cavedroid/game/input/KeyboardInputHandlersModule.kt +++ /dev/null @@ -1,118 +0,0 @@ -package ru.deadsoftware.cavedroid.game.input - -import dagger.Binds -import dagger.Module -import dagger.multibindings.IntoSet -import ru.deadsoftware.cavedroid.game.GameScope -import ru.deadsoftware.cavedroid.game.input.action.KeyboardInputAction -import ru.deadsoftware.cavedroid.game.input.handler.keyboard.* - -@Module -object KeyboardInputHandlersModule { - - @Binds - @IntoSet - @GameScope - fun bindGoLeftKeyboardInputHandler(handler: GoLeftKeyboardInputHandler): IGameInputHandler { - return handler - } - - @Binds - @IntoSet - @GameScope - fun bindGoRightKeyboardInputHandler(handler: GoRightKeyboardInputHandler): IGameInputHandler { - return handler - } - - @Binds - @IntoSet - @GameScope - fun bindJumpKeyboardActionHandler(handler: JumpKeyboardInputHandler): IGameInputHandler { - return handler - } - - @Binds - @IntoSet - @GameScope - fun bindFlyUpKeyboardActionHandler(handler: FlyUpKeyboardInputHandler): IGameInputHandler { - return handler - } - - @Binds - @IntoSet - @GameScope - fun bindTurnOnFlyModeKeyboardActionHandler(handler: TurnOnFlyModeKeyboardInputHandler): IGameInputHandler { - return handler - } - - @Binds - @IntoSet - @GameScope - fun bindFlyDownKeyboardActionHandler(handler: FlyDownKeyboardInputHandler): IGameInputHandler { - return handler - } - - @Binds - @IntoSet - @GameScope - fun bindOpenInventoryKeyboardInputHandler(handler: OpenInventoryKeyboardInputHandler): IGameInputHandler { - return handler - } - - @Binds - @IntoSet - @GameScope - fun bindCloseGameWindowKeyboardInputHandler(handler: CloseGameWindowKeyboardInputHandler): IGameInputHandler { - return handler - } - - @Binds - @IntoSet - @GameScope - fun bindToggleDebugInfoKeyboardInputHandler(handler: ToggleDebugInfoKeyboardInputHandler): IGameInputHandler { - return handler - } - - @Binds - @IntoSet - @GameScope - fun bindToggleMinimapKeyboardInputHandler(handler: ToggleMinimapKeyboardInputHandler): IGameInputHandler { - return handler - } - - @Binds - @IntoSet - @GameScope - fun bindToggleGameModeKeyboardInputHandler(handler: ToggleGameModeKeyboardInputHandler): IGameInputHandler { - return handler - } - - @Binds - @IntoSet - @GameScope - fun bindPauseGameKeyboardInputHandler(handler: PauseGameKeyboardInputHandler): IGameInputHandler { - return handler - } - - @Binds - @IntoSet - @GameScope - fun bindToggleControlsModeKeyboardInputHandler(handler: ToggleControlsModeKeyboardInputHandler): IGameInputHandler { - return handler - } - - @Binds - @IntoSet - @GameScope - fun bindMoveCursorControlsModeKeyboardInputHandler(handler: MoveCursorControlsModeKeyboardInputHandler): IGameInputHandler { - return handler - } - - @Binds - @IntoSet - @GameScope - fun bindOpenCraftingKeyboardInputHandler(handler: OpenCraftingKeyboardInputHandler): IGameInputHandler { - return handler - } - -} \ No newline at end of file diff --git a/core/src/ru/deadsoftware/cavedroid/game/input/MouseInputHandlersModule.kt b/core/src/ru/deadsoftware/cavedroid/game/input/MouseInputHandlersModule.kt deleted file mode 100644 index 937b3e6..0000000 --- a/core/src/ru/deadsoftware/cavedroid/game/input/MouseInputHandlersModule.kt +++ /dev/null @@ -1,75 +0,0 @@ -package ru.deadsoftware.cavedroid.game.input - -import dagger.Binds -import dagger.Module -import dagger.multibindings.IntoSet -import ru.deadsoftware.cavedroid.game.GameScope -import ru.deadsoftware.cavedroid.game.input.action.MouseInputAction -import ru.deadsoftware.cavedroid.game.input.handler.mouse.* - -@Module -object MouseInputHandlersModule { - - @Binds - @IntoSet - @GameScope - fun bindCursorMouseInputHandler(handler: CursorMouseInputHandler): IGameInputHandler { - return handler - } - - @Binds - @IntoSet - @GameScope - fun bindHoldHotbarMouseInputHandler(handler: HotbarMouseInputHandler): IGameInputHandler { - return handler - } - - @Binds - @IntoSet - @GameScope - fun bindCloseGameWindowMouseActionHandler(handler: CloseGameWindowMouseInputHandler): IGameInputHandler { - return handler - } - - @Binds - @IntoSet - @GameScope - fun bindCreativeInventoryScrollMouseInputHandler(handler: CreativeInventoryScrollMouseInputHandler): IGameInputHandler { - return handler - } - - @Binds - @IntoSet - @GameScope - fun bindSelectCreativeInventoryItemMouseActionHandler(handler: SelectCreativeInventoryItemMouseInputHandler): IGameInputHandler { - return handler - } - - @Binds - @IntoSet - @GameScope - fun bindAttackMouseInputHandler(handler: AttackMouseInputHandler): IGameInputHandler { - return handler - } - - @Binds - @IntoSet - @GameScope - fun bindUseItemMouseInputActionHandler(handler: UseItemMouseInputHandler): IGameInputHandler { - return handler - } - - @Binds - @IntoSet - @GameScope - fun bindSelectSurvivalInventoryItemMouseInputHandler(handler: SelectSurvivalInventoryItemMouseInputHandler): IGameInputHandler { - return handler - } - - @Binds - @IntoSet - @GameScope - fun bindSelectCraftingInventoryItemMouseInputHandler(handler: SelectCraftingInventoryItemMouseInputHandler): IGameInputHandler { - return handler - } -} \ No newline at end of file diff --git a/core/src/ru/deadsoftware/cavedroid/game/input/action/keys/KeyboardInputActionKey.kt b/core/src/ru/deadsoftware/cavedroid/game/input/action/keys/KeyboardInputActionKey.kt index fb59efb..fd14fc4 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/input/action/keys/KeyboardInputActionKey.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/input/action/keys/KeyboardInputActionKey.kt @@ -5,11 +5,12 @@ sealed interface KeyboardInputActionKey { data object Left : KeyboardInputActionKey data object Right : KeyboardInputActionKey data object Down : KeyboardInputActionKey - - data object Jump : KeyboardInputActionKey + data object Up : KeyboardInputActionKey data object Crouch : KeyboardInputActionKey + data object DropItem : KeyboardInputActionKey + data object SwitchControlsMode : KeyboardInputActionKey data object OpenInventory : KeyboardInputActionKey @@ -20,5 +21,8 @@ sealed interface KeyboardInputActionKey { data object SpawnPig : KeyboardInputActionKey data object SwitchGameMode : KeyboardInputActionKey data object ShowMap : KeyboardInputActionKey - data object OpenCraft : KeyboardInputActionKey + + data class SelectHotbarSlot( + val slot: Int + ) : KeyboardInputActionKey } \ No newline at end of file diff --git a/core/src/ru/deadsoftware/cavedroid/game/input/action/keys/MouseInputActionKey.kt b/core/src/ru/deadsoftware/cavedroid/game/input/action/keys/MouseInputActionKey.kt index 5822760..3b2744f 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/input/action/keys/MouseInputActionKey.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/input/action/keys/MouseInputActionKey.kt @@ -4,12 +4,18 @@ sealed interface MouseInputActionKey { val touchUp: Boolean + sealed interface Touch : MouseInputActionKey { + val pointer: Int + } + data object None : MouseInputActionKey { override val touchUp: Boolean get() = throw IllegalAccessException("not applicable for mouse move action") } - data object Dragged : MouseInputActionKey { + data class Dragged( + override val pointer: Int + ) : Touch { override val touchUp: Boolean get() = throw IllegalAccessException("not applicable for mouse dragged action") } @@ -26,9 +32,10 @@ sealed interface MouseInputActionKey { override val touchUp: Boolean ) : MouseInputActionKey - data class Touch( - override val touchUp: Boolean - ) : MouseInputActionKey + data class Screen( + override val touchUp: Boolean, + override val pointer: Int, + ) : Touch data class Scroll( val amountX: Float, diff --git a/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/CloseGameWindowKeyboardInputHandler.kt b/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/CloseGameWindowKeyboardInputHandler.kt index 705f9aa..8bf9b1c 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/CloseGameWindowKeyboardInputHandler.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/CloseGameWindowKeyboardInputHandler.kt @@ -2,24 +2,26 @@ package ru.deadsoftware.cavedroid.game.input.handler.keyboard 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.IKeyboardInputHandler 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.DropController -import ru.deadsoftware.cavedroid.game.windows.GameWindowsManager +import ru.deadsoftware.cavedroid.game.objects.drop.DropController +import ru.deadsoftware.cavedroid.game.ui.windows.GameWindowsManager +import ru.deadsoftware.cavedroid.misc.annotations.multibinding.BindKeyboardInputHandler import javax.inject.Inject @GameScope +@BindKeyboardInputHandler class CloseGameWindowKeyboardInputHandler @Inject constructor( private val gameWindowsManager: GameWindowsManager, private val mobsController: MobsController, private val dropController: DropController, -) : IGameInputHandler { +) : IKeyboardInputHandler { override fun checkConditions(action: KeyboardInputAction): Boolean { return action.actionKey is KeyboardInputActionKey.OpenInventory && - action.isKeyDown && gameWindowsManager.getCurrentWindow() != GameUiWindow.NONE + !action.isKeyDown && gameWindowsManager.getCurrentWindow() != GameUiWindow.NONE } override fun handle(action: KeyboardInputAction) { diff --git a/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/DropItemKeyboardInputHandler.kt b/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/DropItemKeyboardInputHandler.kt new file mode 100644 index 0000000..e9c8eb0 --- /dev/null +++ b/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/DropItemKeyboardInputHandler.kt @@ -0,0 +1,51 @@ +package ru.deadsoftware.cavedroid.game.input.handler.keyboard + +import ru.deadsoftware.cavedroid.game.GameScope +import ru.deadsoftware.cavedroid.game.GameUiWindow +import ru.deadsoftware.cavedroid.game.input.IKeyboardInputHandler +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.model.item.Item +import ru.deadsoftware.cavedroid.game.objects.drop.Drop +import ru.deadsoftware.cavedroid.game.objects.drop.DropController +import ru.deadsoftware.cavedroid.game.ui.windows.GameWindowsManager +import ru.deadsoftware.cavedroid.misc.annotations.multibinding.BindKeyboardInputHandler +import javax.inject.Inject + +@GameScope +@BindKeyboardInputHandler +class DropItemKeyboardInputHandler @Inject constructor( + private val gameWindowsManager: GameWindowsManager, + private val mobsController: MobsController, + private val dropController: DropController, +) : IKeyboardInputHandler { + + override fun checkConditions(action: KeyboardInputAction): Boolean { + return action.actionKey is KeyboardInputActionKey.DropItem && + action.isKeyDown && gameWindowsManager.getCurrentWindow() == GameUiWindow.NONE && + !mobsController.player.inventory.activeItem.item.isNone() + } + + private fun createDrop(item: Item, playerX: Float, playerY: Float, amount: Int) { + dropController.addDrop( + /* x = */ playerX + ((DROP_DISTANCE - Drop.DROP_SIZE / 2) * mobsController.player.direction.basis), + /* y = */ playerY, + /* item = */ item, + /* count = */ amount + ) + } + + override fun handle(action: KeyboardInputAction) { + val player = mobsController.player + val currentItem = player.inventory.activeItem + val dropAmount = if (currentItem.item.isTool()) currentItem.amount else 1 + + createDrop(currentItem.item, player.x, player.y, dropAmount) + player.inventory.decreaseCurrentItemAmount(dropAmount) + } + + companion object { + const val DROP_DISTANCE = 20f + } +} \ No newline at end of file diff --git a/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/FlyDownKeyboardInputHandler.kt b/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/FlyDownKeyboardInputHandler.kt index 90347c4..ae5f4c3 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/FlyDownKeyboardInputHandler.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/FlyDownKeyboardInputHandler.kt @@ -2,18 +2,20 @@ package ru.deadsoftware.cavedroid.game.input.handler.keyboard import ru.deadsoftware.cavedroid.MainConfig import ru.deadsoftware.cavedroid.game.GameScope -import ru.deadsoftware.cavedroid.game.input.IGameInputHandler +import ru.deadsoftware.cavedroid.game.input.IKeyboardInputHandler 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.mobs.Player +import ru.deadsoftware.cavedroid.game.mobs.player.Player +import ru.deadsoftware.cavedroid.misc.annotations.multibinding.BindKeyboardInputHandler import javax.inject.Inject @GameScope +@BindKeyboardInputHandler class FlyDownKeyboardInputHandler @Inject constructor( private val mainConfig: MainConfig, private val mobsController: MobsController, -) : IGameInputHandler { +) : IKeyboardInputHandler { override fun checkConditions(action: KeyboardInputAction): Boolean { return action.actionKey is KeyboardInputActionKey.Down && diff --git a/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/FlyUpKeyboardInputHandler.kt b/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/FlyUpKeyboardInputHandler.kt index 2c6efc9..444fe09 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/FlyUpKeyboardInputHandler.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/FlyUpKeyboardInputHandler.kt @@ -2,21 +2,24 @@ package ru.deadsoftware.cavedroid.game.input.handler.keyboard import ru.deadsoftware.cavedroid.MainConfig import ru.deadsoftware.cavedroid.game.GameScope -import ru.deadsoftware.cavedroid.game.input.IGameInputHandler +import ru.deadsoftware.cavedroid.game.input.IKeyboardInputHandler 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.mobs.Player +import ru.deadsoftware.cavedroid.game.mobs.player.Player +import ru.deadsoftware.cavedroid.misc.annotations.multibinding.BindKeyboardInputHandler import javax.inject.Inject @GameScope +@BindKeyboardInputHandler class FlyUpKeyboardInputHandler @Inject constructor( private val mainConfig: MainConfig, private val mobsController: MobsController, -) : IGameInputHandler { +) : IKeyboardInputHandler { override fun checkConditions(action: KeyboardInputAction): Boolean { - return action.actionKey is KeyboardInputActionKey.Jump && + return action.actionKey is KeyboardInputActionKey.Up && + !mobsController.player.swim && mobsController.player.isFlyMode && (mobsController.player.controlMode == Player.ControlMode.WALK || !mainConfig.isTouch) } diff --git a/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/GoLeftKeyboardInputHandler.kt b/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/GoLeftKeyboardInputHandler.kt index 07ddb52..2b40d46 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/GoLeftKeyboardInputHandler.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/GoLeftKeyboardInputHandler.kt @@ -2,19 +2,21 @@ package ru.deadsoftware.cavedroid.game.input.handler.keyboard import ru.deadsoftware.cavedroid.MainConfig import ru.deadsoftware.cavedroid.game.GameScope -import ru.deadsoftware.cavedroid.game.input.IGameInputHandler +import ru.deadsoftware.cavedroid.game.input.IKeyboardInputHandler import ru.deadsoftware.cavedroid.game.input.action.KeyboardInputAction import ru.deadsoftware.cavedroid.game.input.action.keys.KeyboardInputActionKey import ru.deadsoftware.cavedroid.game.mobs.Mob import ru.deadsoftware.cavedroid.game.mobs.MobsController -import ru.deadsoftware.cavedroid.game.mobs.Player +import ru.deadsoftware.cavedroid.game.mobs.player.Player +import ru.deadsoftware.cavedroid.misc.annotations.multibinding.BindKeyboardInputHandler import javax.inject.Inject @GameScope +@BindKeyboardInputHandler class GoLeftKeyboardInputHandler @Inject constructor( private val mainConfig: MainConfig, private val mobsController: MobsController, -) : IGameInputHandler { +) : IKeyboardInputHandler { override fun checkConditions(action: KeyboardInputAction): Boolean { return action.actionKey is KeyboardInputActionKey.Left && diff --git a/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/GoRightKeyboardInputHandler.kt b/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/GoRightKeyboardInputHandler.kt index 8f8f038..ec38218 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/GoRightKeyboardInputHandler.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/GoRightKeyboardInputHandler.kt @@ -2,19 +2,21 @@ package ru.deadsoftware.cavedroid.game.input.handler.keyboard import ru.deadsoftware.cavedroid.MainConfig import ru.deadsoftware.cavedroid.game.GameScope -import ru.deadsoftware.cavedroid.game.input.IGameInputHandler +import ru.deadsoftware.cavedroid.game.input.IKeyboardInputHandler import ru.deadsoftware.cavedroid.game.input.action.KeyboardInputAction import ru.deadsoftware.cavedroid.game.input.action.keys.KeyboardInputActionKey import ru.deadsoftware.cavedroid.game.mobs.Mob import ru.deadsoftware.cavedroid.game.mobs.MobsController -import ru.deadsoftware.cavedroid.game.mobs.Player +import ru.deadsoftware.cavedroid.game.mobs.player.Player +import ru.deadsoftware.cavedroid.misc.annotations.multibinding.BindKeyboardInputHandler import javax.inject.Inject @GameScope +@BindKeyboardInputHandler class GoRightKeyboardInputHandler @Inject constructor( private val mainConfig: MainConfig, private val mobsController: MobsController -) : IGameInputHandler { +) : IKeyboardInputHandler { override fun checkConditions(action: KeyboardInputAction): Boolean { return action.actionKey is KeyboardInputActionKey.Right && diff --git a/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/JumpKeyboardInputHandler.kt b/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/JumpKeyboardInputHandler.kt index 1fbc9fb..bcacbf5 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/JumpKeyboardInputHandler.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/JumpKeyboardInputHandler.kt @@ -2,21 +2,23 @@ package ru.deadsoftware.cavedroid.game.input.handler.keyboard import ru.deadsoftware.cavedroid.MainConfig import ru.deadsoftware.cavedroid.game.GameScope -import ru.deadsoftware.cavedroid.game.input.IGameInputHandler +import ru.deadsoftware.cavedroid.game.input.IKeyboardInputHandler 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.mobs.Player +import ru.deadsoftware.cavedroid.game.mobs.player.Player +import ru.deadsoftware.cavedroid.misc.annotations.multibinding.BindKeyboardInputHandler import javax.inject.Inject @GameScope +@BindKeyboardInputHandler class JumpKeyboardInputHandler @Inject constructor( private val mainConfig: MainConfig, private val mobsController: MobsController, -) : IGameInputHandler { +) : IKeyboardInputHandler { override fun checkConditions(action: KeyboardInputAction): Boolean { - return action.actionKey is KeyboardInputActionKey.Jump && + return action.actionKey is KeyboardInputActionKey.Up && mobsController.player.canJump() && !mobsController.player.isFlyMode && action.isKeyDown && (mobsController.player.controlMode == Player.ControlMode.WALK || !mainConfig.isTouch) diff --git a/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/MoveCursorControlsModeKeyboardInputHandler.kt b/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/MoveCursorControlsModeKeyboardInputHandler.kt index ac82cb8..84c5b90 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/MoveCursorControlsModeKeyboardInputHandler.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/MoveCursorControlsModeKeyboardInputHandler.kt @@ -1,59 +1,45 @@ package ru.deadsoftware.cavedroid.game.input.handler.keyboard -import com.badlogic.gdx.math.MathUtils import ru.deadsoftware.cavedroid.MainConfig import ru.deadsoftware.cavedroid.game.GameScope -import ru.deadsoftware.cavedroid.game.input.IGameInputHandler +import ru.deadsoftware.cavedroid.game.input.IKeyboardInputHandler 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.mobs.Player +import ru.deadsoftware.cavedroid.game.mobs.player.Player import ru.deadsoftware.cavedroid.game.world.GameWorld +import ru.deadsoftware.cavedroid.misc.annotations.multibinding.BindKeyboardInputHandler import javax.inject.Inject @GameScope +@BindKeyboardInputHandler class MoveCursorControlsModeKeyboardInputHandler @Inject constructor( private val mainConfig: MainConfig, private val mobsController: MobsController, private val gameWorld: GameWorld, -) : IGameInputHandler { +) : IKeyboardInputHandler { override fun checkConditions(action: KeyboardInputAction): Boolean { return mainConfig.isTouch && mobsController.player.controlMode == Player.ControlMode.CURSOR && action.isKeyDown && (action.actionKey is KeyboardInputActionKey.Left || action.actionKey is KeyboardInputActionKey.Right || - action.actionKey is KeyboardInputActionKey.Jump || + action.actionKey is KeyboardInputActionKey.Up || action.actionKey is KeyboardInputActionKey.Down) } - private fun checkCursorBounds() { - val player = mobsController.player - if (player.gameMode == 0) { - val minCursorX = player.mapX - SURVIVAL_CURSOR_RANGE - val maxCursorX = player.mapX + SURVIVAL_CURSOR_RANGE - val minCursorY = player.middleMapY - SURVIVAL_CURSOR_RANGE - val maxCursorY = player.middleMapY + SURVIVAL_CURSOR_RANGE - - player.cursorX = MathUtils.clamp(player.cursorX, minCursorX, maxCursorX) - player.cursorY = MathUtils.clamp(player.cursorY, minCursorY, maxCursorY) - } - - player.cursorY = MathUtils.clamp(player.cursorY, 0, gameWorld.height - 1) - } - override fun handle(action: KeyboardInputAction) { val player = mobsController.player when (action.actionKey) { KeyboardInputActionKey.Left -> player.cursorX-- KeyboardInputActionKey.Right -> player.cursorX++ - KeyboardInputActionKey.Jump -> player.cursorY-- + KeyboardInputActionKey.Up -> player.cursorY-- KeyboardInputActionKey.Down -> player.cursorY++ else -> return } - checkCursorBounds() + player.checkCursorBounds(gameWorld); } companion object { diff --git a/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/OpenCraftingKeyboardInputHandler.kt b/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/OpenCraftingKeyboardInputHandler.kt deleted file mode 100644 index d2e333c..0000000 --- a/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/OpenCraftingKeyboardInputHandler.kt +++ /dev/null @@ -1,26 +0,0 @@ -package ru.deadsoftware.cavedroid.game.input.handler.keyboard - -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.KeyboardInputAction -import ru.deadsoftware.cavedroid.game.input.action.keys.KeyboardInputActionKey -import ru.deadsoftware.cavedroid.game.mobs.MobsController -import ru.deadsoftware.cavedroid.game.objects.DropController -import ru.deadsoftware.cavedroid.game.windows.GameWindowsManager -import javax.inject.Inject - -@GameScope -class OpenCraftingKeyboardInputHandler @Inject constructor( - private val gameWindowsManager: GameWindowsManager, -) : IGameInputHandler { - - override fun checkConditions(action: KeyboardInputAction): Boolean { - return action.actionKey is KeyboardInputActionKey.OpenCraft && - action.isKeyDown && gameWindowsManager.getCurrentWindow() == GameUiWindow.NONE - } - - override fun handle(action: KeyboardInputAction) { - gameWindowsManager.openCrafting() - } -} \ No newline at end of file diff --git a/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/OpenInventoryKeyboardInputHandler.kt b/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/OpenInventoryKeyboardInputHandler.kt index 0e2c11b..70ae158 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/OpenInventoryKeyboardInputHandler.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/OpenInventoryKeyboardInputHandler.kt @@ -2,22 +2,22 @@ package ru.deadsoftware.cavedroid.game.input.handler.keyboard 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.IKeyboardInputHandler 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.DropController -import ru.deadsoftware.cavedroid.game.windows.GameWindowsManager +import ru.deadsoftware.cavedroid.game.ui.windows.GameWindowsManager +import ru.deadsoftware.cavedroid.misc.annotations.multibinding.BindKeyboardInputHandler import javax.inject.Inject @GameScope +@BindKeyboardInputHandler class OpenInventoryKeyboardInputHandler @Inject constructor( private val gameWindowsManager: GameWindowsManager, -) : IGameInputHandler { +) : IKeyboardInputHandler { override fun checkConditions(action: KeyboardInputAction): Boolean { return action.actionKey is KeyboardInputActionKey.OpenInventory && - action.isKeyDown && gameWindowsManager.getCurrentWindow() == GameUiWindow.NONE + !action.isKeyDown && gameWindowsManager.getCurrentWindow() == GameUiWindow.NONE } override fun handle(action: KeyboardInputAction) { diff --git a/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/PauseGameKeyboardInputHandler.kt b/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/PauseGameKeyboardInputHandler.kt index 60a9edf..cedc78a 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/PauseGameKeyboardInputHandler.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/PauseGameKeyboardInputHandler.kt @@ -3,28 +3,40 @@ package ru.deadsoftware.cavedroid.game.input.handler.keyboard import ru.deadsoftware.cavedroid.MainConfig import ru.deadsoftware.cavedroid.game.GameSaver import ru.deadsoftware.cavedroid.game.GameScope -import ru.deadsoftware.cavedroid.game.input.IGameInputHandler +import ru.deadsoftware.cavedroid.game.GameUiWindow +import ru.deadsoftware.cavedroid.game.input.IKeyboardInputHandler 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.DropController +import ru.deadsoftware.cavedroid.game.objects.drop.DropController +import ru.deadsoftware.cavedroid.game.objects.container.ContainerController +import ru.deadsoftware.cavedroid.game.ui.windows.GameWindowsManager import ru.deadsoftware.cavedroid.game.world.GameWorld +import ru.deadsoftware.cavedroid.misc.annotations.multibinding.BindKeyboardInputHandler import javax.inject.Inject @GameScope +@BindKeyboardInputHandler class PauseGameKeyboardInputHandler @Inject constructor( private val mainConfig: MainConfig, private val dropController: DropController, private val mobsController: MobsController, private val gameWorld: GameWorld, -) : IGameInputHandler { + private val containerController: ContainerController, + private val gameWindowsManager: GameWindowsManager, +) : IKeyboardInputHandler { override fun checkConditions(action: KeyboardInputAction): Boolean { return action.actionKey is KeyboardInputActionKey.Pause && action.isKeyDown } override fun handle(action: KeyboardInputAction) { - GameSaver.save(mainConfig, dropController, mobsController, gameWorld) + if (gameWindowsManager.getCurrentWindow() != GameUiWindow.NONE) { + gameWindowsManager.closeWindow() + return + } + + GameSaver.save(mainConfig, dropController, mobsController, containerController, gameWorld) mainConfig.caveGame.quitGame() } } \ No newline at end of file diff --git a/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/SelectHotbarSlotKeyboardInputHandler.kt b/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/SelectHotbarSlotKeyboardInputHandler.kt new file mode 100644 index 0000000..d22cd94 --- /dev/null +++ b/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/SelectHotbarSlotKeyboardInputHandler.kt @@ -0,0 +1,26 @@ +package ru.deadsoftware.cavedroid.game.input.handler.keyboard + +import ru.deadsoftware.cavedroid.game.GameScope +import ru.deadsoftware.cavedroid.game.input.IKeyboardInputHandler +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.misc.annotations.multibinding.BindKeyboardInputHandler +import javax.inject.Inject + +@GameScope +@BindKeyboardInputHandler +class SelectHotbarSlotKeyboardInputHandler @Inject constructor( + private val mobsController: MobsController, +) : IKeyboardInputHandler { + + override fun checkConditions(action: KeyboardInputAction): Boolean { + return action.actionKey is KeyboardInputActionKey.SelectHotbarSlot && + action.isKeyDown + } + + override fun handle(action: KeyboardInputAction) { + mobsController.player.inventory.activeSlot = (action.actionKey as KeyboardInputActionKey.SelectHotbarSlot).slot + } + +} \ No newline at end of file diff --git a/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/StopSwimKeyboardInputHandler.kt b/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/StopSwimKeyboardInputHandler.kt new file mode 100644 index 0000000..d8c5acc --- /dev/null +++ b/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/StopSwimKeyboardInputHandler.kt @@ -0,0 +1,32 @@ +package ru.deadsoftware.cavedroid.game.input.handler.keyboard + +import ru.deadsoftware.cavedroid.MainConfig +import ru.deadsoftware.cavedroid.game.GameScope +import ru.deadsoftware.cavedroid.game.input.IKeyboardInputHandler +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.mobs.player.Player +import ru.deadsoftware.cavedroid.game.world.GameWorld +import ru.deadsoftware.cavedroid.misc.annotations.multibinding.BindKeyboardInputHandler +import javax.inject.Inject + +@GameScope +@BindKeyboardInputHandler +class StopSwimKeyboardInputHandler @Inject constructor( + private val mainConfig: MainConfig, + private val mobsController: MobsController, + private val gameWorld: GameWorld, +) : IKeyboardInputHandler { + + override fun checkConditions(action: KeyboardInputAction): Boolean { + return action.actionKey is KeyboardInputActionKey.Up && !action.isKeyDown && + mobsController.player.swim && + (mobsController.player.controlMode == Player.ControlMode.WALK || !mainConfig.isTouch) + } + + override fun handle(action: KeyboardInputAction) { + mobsController.player.swim = false + } + +} \ No newline at end of file diff --git a/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/SwimUpKeyboardInputHandler.kt b/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/SwimUpKeyboardInputHandler.kt new file mode 100644 index 0000000..20cc82e --- /dev/null +++ b/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/SwimUpKeyboardInputHandler.kt @@ -0,0 +1,38 @@ +package ru.deadsoftware.cavedroid.game.input.handler.keyboard + +import ru.deadsoftware.cavedroid.MainConfig +import ru.deadsoftware.cavedroid.game.GameScope +import ru.deadsoftware.cavedroid.game.input.IKeyboardInputHandler +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.mobs.player.Player +import ru.deadsoftware.cavedroid.game.world.GameWorld +import ru.deadsoftware.cavedroid.misc.annotations.multibinding.BindKeyboardInputHandler +import javax.inject.Inject + +@GameScope +@BindKeyboardInputHandler +class SwimUpKeyboardInputHandler @Inject constructor( + private val mainConfig: MainConfig, + private val mobsController: MobsController, + private val gameWorld: GameWorld, +) : IKeyboardInputHandler { + + private fun checkSwim(): Boolean { + return gameWorld.getForeMap(mobsController.player.mapX, mobsController.player.lowerMapY).isFluid() + } + + override fun checkConditions(action: KeyboardInputAction): Boolean { + return action.actionKey is KeyboardInputActionKey.Up && action.isKeyDown && + !mobsController.player.swim && + !mobsController.player.canJump() && + checkSwim() && !mobsController.player.isFlyMode && + (mobsController.player.controlMode == Player.ControlMode.WALK || !mainConfig.isTouch) + } + + override fun handle(action: KeyboardInputAction) { + mobsController.player.swim = true + } + +} \ No newline at end of file diff --git a/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/ToggleControlsModeKeyboardInputHandler.kt b/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/ToggleControlsModeKeyboardInputHandler.kt index 3deacbd..f8e0177 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/ToggleControlsModeKeyboardInputHandler.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/ToggleControlsModeKeyboardInputHandler.kt @@ -2,21 +2,23 @@ package ru.deadsoftware.cavedroid.game.input.handler.keyboard import ru.deadsoftware.cavedroid.MainConfig import ru.deadsoftware.cavedroid.game.GameScope -import ru.deadsoftware.cavedroid.game.input.IGameInputHandler +import ru.deadsoftware.cavedroid.game.input.IKeyboardInputHandler 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.mobs.Player +import ru.deadsoftware.cavedroid.game.mobs.player.Player +import ru.deadsoftware.cavedroid.misc.annotations.multibinding.BindKeyboardInputHandler import javax.inject.Inject @GameScope +@BindKeyboardInputHandler class ToggleControlsModeKeyboardInputHandler @Inject constructor( private val mainConfig: MainConfig, private val mobsController: MobsController, -) : IGameInputHandler { +) : IKeyboardInputHandler { override fun checkConditions(action: KeyboardInputAction): Boolean { - return action.actionKey is KeyboardInputActionKey.SwitchControlsMode && action.isKeyDown + return action.actionKey is KeyboardInputActionKey.SwitchControlsMode && !action.isKeyDown && mainConfig.isTouch } diff --git a/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/ToggleDebugInfoKeyboardInputHandler.kt b/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/ToggleDebugInfoKeyboardInputHandler.kt index 96bc21d..7cf08ed 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/ToggleDebugInfoKeyboardInputHandler.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/ToggleDebugInfoKeyboardInputHandler.kt @@ -2,15 +2,17 @@ package ru.deadsoftware.cavedroid.game.input.handler.keyboard import ru.deadsoftware.cavedroid.MainConfig import ru.deadsoftware.cavedroid.game.GameScope -import ru.deadsoftware.cavedroid.game.input.IGameInputHandler +import ru.deadsoftware.cavedroid.game.input.IKeyboardInputHandler import ru.deadsoftware.cavedroid.game.input.action.KeyboardInputAction import ru.deadsoftware.cavedroid.game.input.action.keys.KeyboardInputActionKey +import ru.deadsoftware.cavedroid.misc.annotations.multibinding.BindKeyboardInputHandler import javax.inject.Inject @GameScope +@BindKeyboardInputHandler class ToggleDebugInfoKeyboardInputHandler @Inject constructor( private val mainConfig: MainConfig -) : IGameInputHandler { +) : IKeyboardInputHandler { override fun checkConditions(action: KeyboardInputAction): Boolean { return action.actionKey is KeyboardInputActionKey.ShowDebug && action.isKeyDown diff --git a/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/ToggleGameModeKeyboardInputHandler.kt b/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/ToggleGameModeKeyboardInputHandler.kt index ef4e696..64a1116 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/ToggleGameModeKeyboardInputHandler.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/ToggleGameModeKeyboardInputHandler.kt @@ -1,16 +1,18 @@ package ru.deadsoftware.cavedroid.game.input.handler.keyboard import ru.deadsoftware.cavedroid.game.GameScope -import ru.deadsoftware.cavedroid.game.input.IGameInputHandler +import ru.deadsoftware.cavedroid.game.input.IKeyboardInputHandler 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.misc.annotations.multibinding.BindKeyboardInputHandler import javax.inject.Inject @GameScope +@BindKeyboardInputHandler class ToggleGameModeKeyboardInputHandler @Inject constructor( private val mobsController: MobsController -) : IGameInputHandler { +) : IKeyboardInputHandler { override fun checkConditions(action: KeyboardInputAction): Boolean { diff --git a/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/ToggleMinimapKeyboardInputHandler.kt b/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/ToggleMinimapKeyboardInputHandler.kt index d39dfdb..2cd6638 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/ToggleMinimapKeyboardInputHandler.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/ToggleMinimapKeyboardInputHandler.kt @@ -2,15 +2,17 @@ package ru.deadsoftware.cavedroid.game.input.handler.keyboard import ru.deadsoftware.cavedroid.MainConfig import ru.deadsoftware.cavedroid.game.GameScope -import ru.deadsoftware.cavedroid.game.input.IGameInputHandler +import ru.deadsoftware.cavedroid.game.input.IKeyboardInputHandler import ru.deadsoftware.cavedroid.game.input.action.KeyboardInputAction import ru.deadsoftware.cavedroid.game.input.action.keys.KeyboardInputActionKey +import ru.deadsoftware.cavedroid.misc.annotations.multibinding.BindKeyboardInputHandler import javax.inject.Inject @GameScope +@BindKeyboardInputHandler class ToggleMinimapKeyboardInputHandler @Inject constructor( private val mainConfig: MainConfig, -) : IGameInputHandler { +) : IKeyboardInputHandler { override fun checkConditions(action: KeyboardInputAction): Boolean { return action.actionKey is KeyboardInputActionKey.ShowMap && action.isKeyDown diff --git a/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/TurnOnFlyModeKeyboardInputHandler.kt b/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/TurnOnFlyModeKeyboardInputHandler.kt index 6a73a9b..43a7122 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/TurnOnFlyModeKeyboardInputHandler.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/input/handler/keyboard/TurnOnFlyModeKeyboardInputHandler.kt @@ -2,21 +2,24 @@ package ru.deadsoftware.cavedroid.game.input.handler.keyboard import ru.deadsoftware.cavedroid.MainConfig import ru.deadsoftware.cavedroid.game.GameScope -import ru.deadsoftware.cavedroid.game.input.IGameInputHandler +import ru.deadsoftware.cavedroid.game.input.IKeyboardInputHandler 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.mobs.Player +import ru.deadsoftware.cavedroid.game.mobs.player.Player +import ru.deadsoftware.cavedroid.misc.annotations.multibinding.BindKeyboardInputHandler import javax.inject.Inject @GameScope +@BindKeyboardInputHandler class TurnOnFlyModeKeyboardInputHandler @Inject constructor( private val mainConfig: MainConfig, private val mobsController: MobsController, -) : IGameInputHandler { +) : IKeyboardInputHandler { override fun checkConditions(action: KeyboardInputAction): Boolean { - return mobsController.player.gameMode == 1 && action.actionKey is KeyboardInputActionKey.Jump && + return mobsController.player.gameMode == 1 && action.actionKey is KeyboardInputActionKey.Up && + !mobsController.player.swim && !mobsController.player.isFlyMode && !mobsController.player.canJump() && action.isKeyDown && (mobsController.player.controlMode == Player.ControlMode.WALK || !mainConfig.isTouch) } diff --git a/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/AbstractInventoryItemsMouseInputHandler.kt b/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/AbstractInventoryItemsMouseInputHandler.kt new file mode 100644 index 0000000..3b925b0 --- /dev/null +++ b/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/AbstractInventoryItemsMouseInputHandler.kt @@ -0,0 +1,103 @@ +package ru.deadsoftware.cavedroid.game.input.handler.mouse + +import com.badlogic.gdx.graphics.g2d.TextureRegion +import ru.deadsoftware.cavedroid.game.GameItemsHolder +import ru.deadsoftware.cavedroid.game.GameUiWindow +import ru.deadsoftware.cavedroid.game.input.IMouseInputHandler +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.model.item.InventoryItem +import ru.deadsoftware.cavedroid.game.model.item.InventoryItem.Companion.isNoneOrNull +import ru.deadsoftware.cavedroid.game.ui.windows.GameWindowsManager +import ru.deadsoftware.cavedroid.game.ui.windows.inventory.AbstractInventoryWindow +import ru.deadsoftware.cavedroid.game.ui.windows.inventory.AbstractInventoryWindowWithCraftGrid + +abstract class AbstractInventoryItemsMouseInputHandler( + private val gameItemsHolder: GameItemsHolder, + private val gameWindowsManager: GameWindowsManager, + private val windowType: GameUiWindow, +) : IMouseInputHandler { + + protected abstract val windowTexture: TextureRegion + + override fun checkConditions(action: MouseInputAction): Boolean { + return gameWindowsManager.getCurrentWindow() == windowType && + isInsideWindow(action, windowTexture) && + (action.actionKey is MouseInputActionKey.Left || + action.actionKey is MouseInputActionKey.Right || + action.actionKey is MouseInputActionKey.Screen) + && (action.actionKey.touchUp || action.actionKey is MouseInputActionKey.Screen) + } + + protected fun updateCraftResult(window: AbstractInventoryWindowWithCraftGrid) { + window.craftResult = gameItemsHolder.craftItem(window.craftingItems.map(InventoryItem::item)) + ?: gameItemsHolder.fallbackItem.toInventoryItem() + } + + private fun reduceCraftItems(window: AbstractInventoryWindowWithCraftGrid) { + for (i in window.craftingItems.indices) { + if (window.craftingItems[i].amount > 1) { + window.craftingItems[i].amount-- + } else { + window.craftingItems[i] = gameItemsHolder.fallbackItem.toInventoryItem() + } + } + } + + protected fun handleInsidePlaceableCell( + action: MouseInputAction, + items: MutableList, + window: AbstractInventoryWindow, + index: Int + ) { + if (action.actionKey is MouseInputActionKey.Screen) { + if (!action.actionKey.touchUp) { + window.onLeftCLick(items, gameItemsHolder, index, action.actionKey.pointer) + } else { + if (action.actionKey.pointer == window.selectItemPointer) { + window.onLeftCLick(items, gameItemsHolder, index, action.actionKey.pointer) + } else { + window.onRightClick(items, gameItemsHolder, index) + } + } + } else if (action.actionKey is MouseInputActionKey.Left) { + window.onLeftCLick(items, gameItemsHolder, index) + } else { + window.onRightClick(items, gameItemsHolder, index) + } + } + + protected fun handleInsideCraftResultCell( + action: MouseInputAction, + items: MutableList, + window: AbstractInventoryWindow, + index: Int + ) { + val selectedItem = window.selectedItem + + if (!selectedItem.isNoneOrNull() && (selectedItem.item != items[index].item || + !selectedItem.canBeAdded(items[index].amount))) { + return + } + + if (!selectedItem.isNoneOrNull()) { + selectedItem.amount += items[index].amount + items[index] = gameItemsHolder.fallbackItem.toInventoryItem() + } else { + if (action.actionKey is MouseInputActionKey.Screen) { + if (!action.actionKey.touchUp) { + window.onLeftCLick(items, gameItemsHolder, index, action.actionKey.pointer) + } + } else if (action.actionKey is MouseInputActionKey.Left) { + window.onLeftCLick(items, gameItemsHolder, index) + } + } + + if (window is AbstractInventoryWindowWithCraftGrid) { + reduceCraftItems(window) + } + + } + +} \ No newline at end of file diff --git a/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/AttackMouseInputHandler.kt b/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/AttackMouseInputHandler.kt index a0bfa4c..52333eb 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/AttackMouseInputHandler.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/AttackMouseInputHandler.kt @@ -1,22 +1,24 @@ package ru.deadsoftware.cavedroid.game.input.handler.mouse +import ru.deadsoftware.cavedroid.misc.annotations.multibinding.BindMouseInputHandler 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.IMouseInputHandler import ru.deadsoftware.cavedroid.game.input.action.MouseInputAction import ru.deadsoftware.cavedroid.game.input.action.keys.MouseInputActionKey import ru.deadsoftware.cavedroid.game.input.isInsideHotbar import ru.deadsoftware.cavedroid.game.mobs.MobsController -import ru.deadsoftware.cavedroid.game.windows.GameWindowsManager +import ru.deadsoftware.cavedroid.game.ui.windows.GameWindowsManager import ru.deadsoftware.cavedroid.game.world.GameWorld import javax.inject.Inject @GameScope +@BindMouseInputHandler class AttackMouseInputHandler @Inject constructor( private val mobsController: MobsController, private val gameWorld: GameWorld, private val gameWindowsManager: GameWindowsManager -) : IGameInputHandler { +) : IMouseInputHandler { override fun checkConditions(action: MouseInputAction): Boolean { return gameWindowsManager.getCurrentWindow() == GameUiWindow.NONE && diff --git a/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/CloseGameWindowMouseInputHandler.kt b/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/CloseGameWindowMouseInputHandler.kt index e80ff47..4fb0879 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/CloseGameWindowMouseInputHandler.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/CloseGameWindowMouseInputHandler.kt @@ -1,33 +1,37 @@ package ru.deadsoftware.cavedroid.game.input.handler.mouse +import ru.deadsoftware.cavedroid.misc.annotations.multibinding.BindMouseInputHandler import com.badlogic.gdx.graphics.g2d.TextureRegion import ru.deadsoftware.cavedroid.game.GameScope import ru.deadsoftware.cavedroid.game.GameUiWindow -import ru.deadsoftware.cavedroid.game.windows.GameWindowsManager -import ru.deadsoftware.cavedroid.game.input.IGameInputHandler +import ru.deadsoftware.cavedroid.game.ui.windows.GameWindowsManager +import ru.deadsoftware.cavedroid.game.input.IMouseInputHandler 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.objects.DropController +import ru.deadsoftware.cavedroid.game.objects.drop.DropController import ru.deadsoftware.cavedroid.misc.Assets import javax.inject.Inject @GameScope +@BindMouseInputHandler class CloseGameWindowMouseInputHandler @Inject constructor( private val gameWindowsManager: GameWindowsManager, private val mobsController: MobsController, private val dropController: DropController, -) : IGameInputHandler { +) : IMouseInputHandler { private val creativeInventoryTexture get() = requireNotNull(Assets.textureRegions["creative"]) 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 && - (action.actionKey is MouseInputActionKey.Left || action.actionKey is MouseInputActionKey.Touch) && - !action.actionKey.touchUp && + (action.actionKey is MouseInputActionKey.Left || action.actionKey is MouseInputActionKey.Screen) && + action.actionKey.touchUp && !isInsideWindow(action, getCurrentWindowTexture()) } @@ -36,6 +40,8 @@ class CloseGameWindowMouseInputHandler @Inject constructor( GameUiWindow.CREATIVE_INVENTORY -> creativeInventoryTexture GameUiWindow.SURVIVAL_INVENTORY -> survivalInventoryTexture GameUiWindow.CRAFTING_TABLE -> craftingInventoryTexture + GameUiWindow.FURNACE -> furnaceInventoryTexture + GameUiWindow.CHEST -> chestInventoryTexture else -> throw UnsupportedOperationException("Cant close window ${window.name}") } } @@ -43,13 +49,12 @@ class CloseGameWindowMouseInputHandler @Inject constructor( override fun handle(action: MouseInputAction) { val selectedItem = gameWindowsManager.currentWindow?.selectedItem if (selectedItem != null) { - for (i in 1 .. selectedItem.amount) { dropController.addDrop( /* x = */ mobsController.player.x + (32f * mobsController.player.direction.basis), /* y = */ mobsController.player.y, - /* item = */ selectedItem.item + /* item = */ selectedItem.item, + /* count = */ selectedItem.amount, ) - } gameWindowsManager.currentWindow?.selectedItem = null } gameWindowsManager.closeWindow() diff --git a/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/CreativeInventoryScrollMouseInputHandler.kt b/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/CreativeInventoryScrollMouseInputHandler.kt index 01cc4e2..8acdb7e 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/CreativeInventoryScrollMouseInputHandler.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/CreativeInventoryScrollMouseInputHandler.kt @@ -1,12 +1,13 @@ package ru.deadsoftware.cavedroid.game.input.handler.mouse +import ru.deadsoftware.cavedroid.misc.annotations.multibinding.BindMouseInputHandler import com.badlogic.gdx.math.MathUtils import ru.deadsoftware.cavedroid.MainConfig import ru.deadsoftware.cavedroid.game.GameItemsHolder import ru.deadsoftware.cavedroid.game.GameScope import ru.deadsoftware.cavedroid.game.GameUiWindow -import ru.deadsoftware.cavedroid.game.windows.GameWindowsManager -import ru.deadsoftware.cavedroid.game.input.IGameInputHandler +import ru.deadsoftware.cavedroid.game.ui.windows.GameWindowsManager +import ru.deadsoftware.cavedroid.game.input.IMouseInputHandler import ru.deadsoftware.cavedroid.game.input.action.MouseInputAction import ru.deadsoftware.cavedroid.game.input.action.keys.MouseInputActionKey import ru.deadsoftware.cavedroid.game.input.isInsideWindow @@ -15,11 +16,12 @@ import javax.inject.Inject import kotlin.math.abs @GameScope +@BindMouseInputHandler class CreativeInventoryScrollMouseInputHandler @Inject constructor( private val mainConfig: MainConfig, private val gameWindowsManager: GameWindowsManager, private val gameItemsHolder: GameItemsHolder, -) : IGameInputHandler { +) : IMouseInputHandler { private val creativeInventoryTexture get() = requireNotNull(Assets.textureRegions["creative"]) @@ -34,12 +36,12 @@ class CreativeInventoryScrollMouseInputHandler @Inject constructor( } private fun checkStartDragConditions(action: MouseInputAction): Boolean { - return (action.actionKey is MouseInputActionKey.Touch) && + return (action.actionKey is MouseInputActionKey.Screen) && !action.actionKey.touchUp && !gameWindowsManager.isDragging } private fun checkEndDragConditions(action: MouseInputAction): Boolean { - return action.actionKey is MouseInputActionKey.Touch && + return action.actionKey is MouseInputActionKey.Screen && action.actionKey.touchUp && gameWindowsManager.isDragging } @@ -75,7 +77,7 @@ class CreativeInventoryScrollMouseInputHandler @Inject constructor( override fun handle(action: MouseInputAction) { when (action.actionKey) { - is MouseInputActionKey.Touch -> handleStartOrEndDrag(action) + is MouseInputActionKey.Screen -> handleStartOrEndDrag(action) is MouseInputActionKey.Dragged -> handleDrag(action) is MouseInputActionKey.Scroll -> handleScroll(action) else -> return diff --git a/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/CursorMouseInputHandler.kt b/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/CursorMouseInputHandler.kt index 54aacf2..c1f2af5 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/CursorMouseInputHandler.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/CursorMouseInputHandler.kt @@ -1,49 +1,48 @@ package ru.deadsoftware.cavedroid.game.input.handler.mouse +import ru.deadsoftware.cavedroid.misc.annotations.multibinding.BindMouseInputHandler import com.badlogic.gdx.math.MathUtils import ru.deadsoftware.cavedroid.MainConfig +import ru.deadsoftware.cavedroid.game.GameItemsHolder import ru.deadsoftware.cavedroid.game.GameScope -import ru.deadsoftware.cavedroid.game.input.IGameInputHandler +import ru.deadsoftware.cavedroid.game.GameUiWindow +import ru.deadsoftware.cavedroid.game.input.IMouseInputHandler import ru.deadsoftware.cavedroid.game.input.action.MouseInputAction import ru.deadsoftware.cavedroid.game.input.action.keys.MouseInputActionKey import ru.deadsoftware.cavedroid.game.mobs.Mob import ru.deadsoftware.cavedroid.game.mobs.MobsController -import ru.deadsoftware.cavedroid.game.mobs.Player +import ru.deadsoftware.cavedroid.game.mobs.player.Player import ru.deadsoftware.cavedroid.game.model.block.Block +import ru.deadsoftware.cavedroid.game.ui.TooltipManager +import ru.deadsoftware.cavedroid.game.ui.windows.GameWindowsConfigs +import ru.deadsoftware.cavedroid.game.ui.windows.GameWindowsManager import ru.deadsoftware.cavedroid.game.world.GameWorld +import ru.deadsoftware.cavedroid.misc.Assets import ru.deadsoftware.cavedroid.misc.utils.bl import ru.deadsoftware.cavedroid.misc.utils.px import javax.inject.Inject @GameScope +@BindMouseInputHandler class CursorMouseInputHandler @Inject constructor( private val mainConfig: MainConfig, private val mobsController: MobsController, private val gameWorld: GameWorld, -) : IGameInputHandler { + private val gameWindowsManager: GameWindowsManager, + private val gameItemsHolder: GameItemsHolder, + private val tooltipManager: TooltipManager, +) : IMouseInputHandler { private val player get() = mobsController.player + private val creativeInventoryTexture get() = requireNotNull(Assets.textureRegions["creative"]) + private val Block.isAutoselectable get() = !isNone() && params.hasCollision private fun GameWorld.isCurrentBlockAutoselectable() = getForeMap(player.cursorX, player.cursorY).isAutoselectable - private fun checkCursorBounds() { - if (player.gameMode == 0) { - val minCursorX = player.mapX - SURVIVAL_CURSOR_RANGE - val maxCursorX = player.mapX + SURVIVAL_CURSOR_RANGE - val minCursorY = player.middleMapY - SURVIVAL_CURSOR_RANGE - val maxCursorY = player.middleMapY + SURVIVAL_CURSOR_RANGE - - player.cursorX = MathUtils.clamp(player.cursorX, minCursorX, maxCursorX) - player.cursorY = MathUtils.clamp(player.cursorY, minCursorY, maxCursorY) - } - - player.cursorY = MathUtils.clamp(player.cursorY, 0, gameWorld.height - 1) - } - private fun setPlayerDirectionToCursor() { if (player.controlMode != Player.ControlMode.CURSOR) { return @@ -59,6 +58,7 @@ class CursorMouseInputHandler @Inject constructor( private fun handleWalkTouch() { player.cursorX = player.mapX + player.direction.basis player.cursorY = player.upperMapY + player.headRotation = 0f for (i in 1..2) { if (gameWorld.isCurrentBlockAutoselectable()) { @@ -73,7 +73,7 @@ class CursorMouseInputHandler @Inject constructor( } private fun getPlayerHeadRotation(mouseWorldX: Float, mouseWorldY: Float): Float { - val h = mouseWorldX - player.x + val h = mouseWorldX - (player.x + player.width / 2) val v = mouseWorldY - player.y return MathUtils.atan(v / h) * MathUtils.radDeg @@ -90,6 +90,33 @@ class CursorMouseInputHandler @Inject constructor( player.cursorY = worldY.bl player.headRotation = getPlayerHeadRotation(worldX, worldY) + + if (worldX < player.x + player.width / 2) { + player.setDir(Mob.Direction.LEFT) + } else { + player.setDir(Mob.Direction.RIGHT) + } + } + + private fun getCreativeTooltip(action: MouseInputAction): String? { + val creativeTexture = creativeInventoryTexture + val xOnGrid = (action.screenX - (action.cameraViewport.width / 2 - creativeTexture.regionWidth / 2 + + GameWindowsConfigs.Creative.itemsGridMarginLeft)) / + GameWindowsConfigs.Creative.itemsGridColWidth + val yOnGrid = (action.screenY - (action.cameraViewport.height / 2 - creativeTexture.regionHeight / 2 + + GameWindowsConfigs.Creative.itemsGridMarginTop)) / + GameWindowsConfigs.Creative.itemsGridRowHeight + + if (xOnGrid < 0 || xOnGrid >= GameWindowsConfigs.Creative.itemsInRow || + yOnGrid < 0 || yOnGrid >= GameWindowsConfigs.Creative.itemsInCol) { + return null + } + + val itemIndex = (gameWindowsManager.creativeScrollAmount * GameWindowsConfigs.Creative.itemsInRow + + (xOnGrid.toInt() + yOnGrid.toInt() * GameWindowsConfigs.Creative.itemsInRow)) + val item = gameItemsHolder.getItemFromCreativeInventory(itemIndex) + + return item.params.name } override fun checkConditions(action: MouseInputAction): Boolean { @@ -105,12 +132,19 @@ class CursorMouseInputHandler @Inject constructor( !mainConfig.isTouch -> handleMouse(action) } - checkCursorBounds() - setPlayerDirectionToCursor() + player.checkCursorBounds(gameWorld) + + if (player.controlMode == Player.ControlMode.WALK && mainConfig.isTouch) { + setPlayerDirectionToCursor() + } if (player.cursorX != pastCursorX || player.cursorY != pastCursorY) { player.blockDamage = 0f } + + if (gameWindowsManager.getCurrentWindow() == GameUiWindow.CREATIVE_INVENTORY) { + tooltipManager.showMouseTooltip(getCreativeTooltip(action).orEmpty()) + } } companion object { diff --git a/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/HotbarMouseInputHandler.kt b/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/HotbarMouseInputHandler.kt index 31827d2..6a66338 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/HotbarMouseInputHandler.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/HotbarMouseInputHandler.kt @@ -1,22 +1,30 @@ package ru.deadsoftware.cavedroid.game.input.handler.mouse +import ru.deadsoftware.cavedroid.misc.annotations.multibinding.BindMouseInputHandler import com.badlogic.gdx.utils.Timer import ru.deadsoftware.cavedroid.game.GameScope import ru.deadsoftware.cavedroid.game.GameUiWindow -import ru.deadsoftware.cavedroid.game.windows.GameWindowsManager -import ru.deadsoftware.cavedroid.game.input.IGameInputHandler +import ru.deadsoftware.cavedroid.game.ui.windows.GameWindowsManager +import ru.deadsoftware.cavedroid.game.input.IMouseInputHandler import ru.deadsoftware.cavedroid.game.input.action.MouseInputAction import ru.deadsoftware.cavedroid.game.input.action.keys.MouseInputActionKey +import ru.deadsoftware.cavedroid.game.input.handler.keyboard.DropItemKeyboardInputHandler.Companion.DROP_DISTANCE import ru.deadsoftware.cavedroid.game.input.isInsideHotbar import ru.deadsoftware.cavedroid.game.mobs.MobsController +import ru.deadsoftware.cavedroid.game.mobs.player.Player +import ru.deadsoftware.cavedroid.game.model.item.Item +import ru.deadsoftware.cavedroid.game.objects.drop.Drop +import ru.deadsoftware.cavedroid.game.objects.drop.DropController import ru.deadsoftware.cavedroid.misc.Assets import javax.inject.Inject @GameScope +@BindMouseInputHandler class HotbarMouseInputHandler @Inject constructor( private val gameWindowsManager: GameWindowsManager, private val mobsController: MobsController, -) : IGameInputHandler { + private val dropController: DropController, +) : IMouseInputHandler { private val hotbarTexture get() = requireNotNull(Assets.textureRegions["hotbar"]) @@ -24,7 +32,7 @@ class HotbarMouseInputHandler @Inject constructor( override fun checkConditions(action: MouseInputAction): Boolean { return buttonHoldTask?.isScheduled == true || - ((action.actionKey is MouseInputActionKey.Left || action.actionKey is MouseInputActionKey.Touch) + ((action.actionKey is MouseInputActionKey.Left || action.actionKey is MouseInputActionKey.Screen) && isInsideHotbar(action) || action.actionKey is MouseInputActionKey.Scroll) && gameWindowsManager.getCurrentWindow() == GameUiWindow.NONE @@ -35,15 +43,37 @@ class HotbarMouseInputHandler @Inject constructor( buttonHoldTask = null } - private fun handleHold() { - buttonHoldTask = null - gameWindowsManager.openInventory() + private fun createDrop(item: Item, playerX: Float, playerY: Float, amount: Int) { + dropController.addDrop( + /* x = */ playerX + ((DROP_DISTANCE - Drop.DROP_SIZE / 2) * mobsController.player.direction.basis), + /* y = */ playerY, + /* item = */ item, + /* count = */ amount + ) + } + + private fun getActionSlot(action: MouseInputAction): Int { + return ((action.screenX - + (action.cameraViewport.width / 2 - hotbarTexture.regionWidth / 2)) + / HOTBAR_CELL_WIDTH).toInt() + } + + private fun handleHold(action: MouseInputAction) { +// buttonHoldTask = null +// gameWindowsManager.openInventory() + val player = mobsController.player + val actionSlot = getActionSlot(action) + val currentItem = player.inventory.items[actionSlot] + val dropAmount = if (currentItem.item.isTool()) currentItem.amount else 1 + + createDrop(currentItem.item, player.x, player.y, dropAmount) + player.inventory.decreaseItemAmount(actionSlot, dropAmount) } private fun handleDown(action: MouseInputAction) { buttonHoldTask = object : Timer.Task() { override fun run() { - handleHold() + handleHold(action) } } @@ -51,21 +81,18 @@ class HotbarMouseInputHandler @Inject constructor( } private fun handleUp(action: MouseInputAction) { - mobsController.player.slot = - ((action.screenX - - (action.cameraViewport.width / 2 - hotbarTexture.regionWidth / 2)) - / HOTBAR_CELL_WIDTH).toInt() + mobsController.player.inventory.activeSlot = getActionSlot(action) } private fun handleScroll(action: MouseInputAction) { if (action.actionKey !is MouseInputActionKey.Scroll) { return } - mobsController.player.slot += action.actionKey.amountY.toInt() - if (mobsController.player.slot < 0) { - mobsController.player.slot = HOTBAR_ITEMS - 1 - } else if (mobsController.player.slot >= HOTBAR_ITEMS){ - mobsController.player.slot = 0 + mobsController.player.inventory.activeSlot += action.actionKey.amountY.toInt() + if (mobsController.player.inventory.activeSlot < 0) { + mobsController.player.inventory.activeSlot = Player.HOTBAR_SIZE - 1 + } else if (mobsController.player.inventory.activeSlot >= Player.HOTBAR_SIZE) { + mobsController.player.inventory.activeSlot = 0 } } @@ -74,7 +101,12 @@ class HotbarMouseInputHandler @Inject constructor( cancelHold() } - if (action.actionKey !is MouseInputActionKey.Left && action.actionKey !is MouseInputActionKey.Touch ) { + if (buttonHoldTask != null && buttonHoldTask?.isScheduled != true) { + buttonHoldTask = null + return + } + + if (action.actionKey !is MouseInputActionKey.Left && action.actionKey !is MouseInputActionKey.Screen) { if (action.actionKey is MouseInputActionKey.Scroll) { handleScroll(action) } @@ -91,7 +123,6 @@ class HotbarMouseInputHandler @Inject constructor( companion object { private const val TOUCH_HOLD_TIME_SEC = 0.5f private const val HOTBAR_CELL_WIDTH = 20 - private const val HOTBAR_ITEMS = 9 } } \ No newline at end of file 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 index 0000000..62a4836 --- /dev/null +++ b/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/SelectChestInventoryItemMouseInputHandler.kt @@ -0,0 +1,74 @@ +package ru.deadsoftware.cavedroid.game.input.handler.mouse + +import ru.deadsoftware.cavedroid.misc.annotations.multibinding.BindMouseInputHandler +import ru.deadsoftware.cavedroid.game.GameItemsHolder +import ru.deadsoftware.cavedroid.game.GameScope +import ru.deadsoftware.cavedroid.game.GameUiWindow +import ru.deadsoftware.cavedroid.game.input.action.MouseInputAction +import ru.deadsoftware.cavedroid.game.mobs.MobsController +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.misc.Assets +import javax.inject.Inject + +@GameScope +@BindMouseInputHandler +class SelectChestInventoryItemMouseInputHandler @Inject constructor( + private val gameWindowsManager: GameWindowsManager, + private val mobsController: MobsController, + private val gameItemsHolder: GameItemsHolder, +) : AbstractInventoryItemsMouseInputHandler(gameItemsHolder, gameWindowsManager, GameUiWindow.CHEST) { + + override val windowTexture get() = requireNotNull(Assets.textureRegions["chest"]) + + private fun handleInsideContentGrid(action: MouseInputAction, xOnGrid: Int, yOnGrid: Int) { + val window = gameWindowsManager.currentWindow as ChestInventoryWindow + val itemIndex = xOnGrid + yOnGrid * GameWindowsConfigs.Chest.contentsInRow + + handleInsidePlaceableCell(action, window.chest.items, window, itemIndex) + } + + private fun handleInsideInventoryGrid(action: MouseInputAction, xOnGrid: Int, yOnGrid: Int) { + val window = gameWindowsManager.currentWindow as ChestInventoryWindow + + var itemIndex = xOnGrid + yOnGrid * GameWindowsConfigs.Chest.itemsInRow + itemIndex += GameWindowsConfigs.Chest.hotbarCells + + if (itemIndex >= mobsController.player.inventory.size) { + itemIndex -= mobsController.player.inventory.size + } + + handleInsidePlaceableCell(action, mobsController.player.inventory.items, window, itemIndex) + } + + override fun handle(action: MouseInputAction) { + val texture = windowTexture + + val xOnWindow = action.screenX - (action.cameraViewport.width / 2 - texture.regionWidth / 2) + val yOnWindow = action.screenY - (action.cameraViewport.height / 2 - texture.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()) + } + } +} \ No newline at end of file diff --git a/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/SelectCraftingInventoryItemMouseInputHandler.kt b/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/SelectCraftingInventoryItemMouseInputHandler.kt index 7005a67..aefea54 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/SelectCraftingInventoryItemMouseInputHandler.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/SelectCraftingInventoryItemMouseInputHandler.kt @@ -1,110 +1,62 @@ package ru.deadsoftware.cavedroid.game.input.handler.mouse -import com.badlogic.gdx.Gdx +import ru.deadsoftware.cavedroid.misc.annotations.multibinding.BindMouseInputHandler 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.windows.GameWindowsConfigs -import ru.deadsoftware.cavedroid.game.windows.GameWindowsManager -import ru.deadsoftware.cavedroid.game.windows.inventory.CraftingInventoryWindow +import ru.deadsoftware.cavedroid.game.ui.windows.GameWindowsConfigs +import ru.deadsoftware.cavedroid.game.ui.windows.GameWindowsManager +import ru.deadsoftware.cavedroid.game.ui.windows.inventory.CraftingInventoryWindow import ru.deadsoftware.cavedroid.misc.Assets import javax.inject.Inject @GameScope +@BindMouseInputHandler class SelectCraftingInventoryItemMouseInputHandler @Inject constructor( private val gameWindowsManager: GameWindowsManager, private val mobsController: MobsController, private val gameItemsHolder: GameItemsHolder, -) : IGameInputHandler { +) : AbstractInventoryItemsMouseInputHandler(gameItemsHolder, gameWindowsManager, GameUiWindow.CRAFTING_TABLE) { - private val survivalWindowTexture get() = requireNotNull(Assets.textureRegions["survival"]) - - override fun checkConditions(action: MouseInputAction): Boolean { - return gameWindowsManager.getCurrentWindow() == GameUiWindow.CRAFTING_TABLE && - isInsideWindow(action, survivalWindowTexture) && - (action.actionKey is MouseInputActionKey.Left || action.actionKey is MouseInputActionKey.Right || action.actionKey is MouseInputActionKey.Touch) - && action.actionKey.touchUp - } - - private fun onLeftCLick(items: MutableList, window: CraftingInventoryWindow, index: Int) { - val selectedItem = window.selectedItem - val clickedItem = items[index] - - if (clickedItem != null && selectedItem != null && items[index]!!.item == selectedItem.item && - items[index]!!.amount + selectedItem.amount <= selectedItem.item.params.maxStack) { - items[index]!!.amount += selectedItem.amount - window.selectedItem = null - return - } - - val item = items[index] - items[index] = selectedItem ?: gameItemsHolder.fallbackItem.toInventoryItem() - window.selectedItem = item - } - - private fun onRightClick(items: MutableList, window: CraftingInventoryWindow, index: Int) { - val clickedItem = items[index] - val selectedItem = window.selectedItem - ?.takeIf { clickedItem == null || clickedItem.item.isNone() || it.item == items[index]!!.item && items[index]!!.amount + 1 < it.item.params.maxStack } - ?: return - - val newItem = selectedItem.item.toInventoryItem((clickedItem?.takeIf { !it.item.isNone() }?.amount ?: 0) + 1) - items[index] = newItem - selectedItem.amount -- - - if (selectedItem.amount <= 0) { - window.selectedItem = null - } - } + override val windowTexture get() = requireNotNull(Assets.textureRegions["crafting_table"]) private fun handleInsideInventoryGrid(action: MouseInputAction, xOnGrid: Int, yOnGrid: Int) { val window = gameWindowsManager.currentWindow as CraftingInventoryWindow - var itemIndex = ((xOnGrid.toInt() + yOnGrid.toInt() * GameWindowsConfigs.Crafting.itemsInRow)) + var itemIndex = xOnGrid + yOnGrid * GameWindowsConfigs.Crafting.itemsInRow itemIndex += GameWindowsConfigs.Crafting.hotbarCells - if (itemIndex >= 36) { - itemIndex -= 36 + if (itemIndex >= mobsController.player.inventory.size) { + itemIndex -= mobsController.player.inventory.size } - if (action.actionKey is MouseInputActionKey.Left || action.actionKey is MouseInputActionKey.Touch) { - onLeftCLick(mobsController.player.inventory, window, itemIndex) - } else { - onRightClick(mobsController.player.inventory, window, itemIndex) - } - - Gdx.app.debug( - TAG, - "selected item: ${window.selectedItem?.item?.params?.key ?: "null"}; index $itemIndex, grid ($xOnGrid;$yOnGrid)" - ) + handleInsidePlaceableCell(action, mobsController.player.inventory.items, window, itemIndex) } private fun handleInsideCraft(action: MouseInputAction, xOnCraft: Int, yOnCraft: Int) { val window = gameWindowsManager.currentWindow as CraftingInventoryWindow val index = xOnCraft + yOnCraft * GameWindowsConfigs.Crafting.craftGridSize - if (action.actionKey is MouseInputActionKey.Left || action.actionKey is MouseInputActionKey.Touch) { - onLeftCLick(window.craftingItems, window, index) - } else { - onRightClick(window.craftingItems, window, index) - } + handleInsidePlaceableCell(action, window.craftingItems, window, index) - window.craftResult = - gameItemsHolder.craftItem(window.craftingItems.map { it?.item ?: gameItemsHolder.fallbackItem }) + updateCraftResult(window) } - override fun handle(action: MouseInputAction) { - val survivalTexture = survivalWindowTexture + private fun handleInsideCraftResult(action: MouseInputAction) { val window = gameWindowsManager.currentWindow as CraftingInventoryWindow - val xOnWindow = action.screenX - (action.cameraViewport.width / 2 - survivalTexture.regionWidth / 2) - val yOnWindow = action.screenY - (action.cameraViewport.height / 2 - survivalTexture.regionHeight / 2) + handleInsideCraftResultCell(action, window.craftResultList, window, 0) + + updateCraftResult(window) + } + + override fun handle(action: MouseInputAction) { + val texture = windowTexture + + val xOnWindow = action.screenX - (action.cameraViewport.width / 2 - texture.regionWidth / 2) + val yOnWindow = action.screenY - (action.cameraViewport.height / 2 - texture.regionHeight / 2) val xOnGrid = (xOnWindow - GameWindowsConfigs.Crafting.itemsGridMarginLeft) / GameWindowsConfigs.Crafting.itemsGridColWidth @@ -132,30 +84,8 @@ class SelectCraftingInventoryItemMouseInputHandler @Inject constructor( } else if (isInsideCraftGrid) { handleInsideCraft(action, xOnCraft.toInt(), yOnCraft.toInt()) } else if (isInsideCraftResult) { - val selectedItem = window.selectedItem - if (selectedItem == null || selectedItem.item.isNone() || - (selectedItem.item == window.craftResult?.item && selectedItem.amount + (window.craftResult?.amount ?: 0) <= selectedItem.item.params.maxStack)) { - for (i in window.craftingItems.indices) { - if ((window.craftingItems[i]?.amount ?: 0) > 1) { - window.craftingItems[i]?.amount = window.craftingItems[i]?.amount!! - 1 - } else { - window.craftingItems[i] = null - } - } - if (selectedItem != null && !selectedItem.item.isNone()) { - selectedItem.amount += (window.craftResult?.amount ?: 0) - } else { - window.selectedItem = window.craftResult - } - window.craftResult = gameItemsHolder.craftItem(window.craftingItems - .map { it?.item ?: gameItemsHolder.fallbackItem }) - } + handleInsideCraftResult(action) } } - - companion object { - private const val TAG = "SelectCraftingInventoryItemMouseInputHandler" - - } } \ No newline at end of file diff --git a/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/SelectCreativeInventoryItemMouseInputHandler.kt b/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/SelectCreativeInventoryItemMouseInputHandler.kt index 7c587b6..976f443 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/SelectCreativeInventoryItemMouseInputHandler.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/SelectCreativeInventoryItemMouseInputHandler.kt @@ -1,31 +1,33 @@ package ru.deadsoftware.cavedroid.game.input.handler.mouse +import ru.deadsoftware.cavedroid.misc.annotations.multibinding.BindMouseInputHandler import ru.deadsoftware.cavedroid.game.GameItemsHolder import ru.deadsoftware.cavedroid.game.GameScope import ru.deadsoftware.cavedroid.game.GameUiWindow -import ru.deadsoftware.cavedroid.game.windows.GameWindowsManager -import ru.deadsoftware.cavedroid.game.input.IGameInputHandler +import ru.deadsoftware.cavedroid.game.ui.windows.GameWindowsManager +import ru.deadsoftware.cavedroid.game.input.IMouseInputHandler 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.windows.GameWindowsConfigs +import ru.deadsoftware.cavedroid.game.ui.windows.GameWindowsConfigs import ru.deadsoftware.cavedroid.misc.Assets import javax.inject.Inject @GameScope +@BindMouseInputHandler class SelectCreativeInventoryItemMouseInputHandler @Inject constructor( private val gameItemsHolder: GameItemsHolder, private val gameWindowsManager: GameWindowsManager, private val mobsController: MobsController, -) : IGameInputHandler { +) : IMouseInputHandler { private val creativeInventoryTexture get() = requireNotNull(Assets.textureRegions["creative"]) override fun checkConditions(action: MouseInputAction): Boolean { return gameWindowsManager.getCurrentWindow() == GameUiWindow.CREATIVE_INVENTORY && !gameWindowsManager.isDragging && - (action.actionKey is MouseInputActionKey.Left || action.actionKey is MouseInputActionKey.Touch) && + (action.actionKey is MouseInputActionKey.Left || action.actionKey is MouseInputActionKey.Screen) && action.actionKey.touchUp && isInsideWindow(action, creativeInventoryTexture) } @@ -46,13 +48,7 @@ class SelectCreativeInventoryItemMouseInputHandler @Inject constructor( val itemIndex = (gameWindowsManager.creativeScrollAmount * GameWindowsConfigs.Creative.itemsInRow + (xOnGrid.toInt() + yOnGrid.toInt() * GameWindowsConfigs.Creative.itemsInRow)) val item = gameItemsHolder.getItemFromCreativeInventory(itemIndex) - mobsController.player.inventory.reverse() - mobsController.player.inventory.add(item.toInventoryItem(amount = item.params.maxStack)) - mobsController.player.inventory.reverse() - - if (mobsController.player.inventory.size > 36) { - mobsController.player.inventory.dropLast(mobsController.player.inventory.size - 36) - } + mobsController.player.inventory.addItem(item) } } \ No newline at end of file diff --git a/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/SelectFurnaceInventoryItemMouseInputHandler.kt b/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/SelectFurnaceInventoryItemMouseInputHandler.kt new file mode 100644 index 0000000..eac8cfa --- /dev/null +++ b/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/SelectFurnaceInventoryItemMouseInputHandler.kt @@ -0,0 +1,102 @@ +package ru.deadsoftware.cavedroid.game.input.handler.mouse + +import ru.deadsoftware.cavedroid.misc.annotations.multibinding.BindMouseInputHandler +import ru.deadsoftware.cavedroid.game.GameItemsHolder +import ru.deadsoftware.cavedroid.game.GameScope +import ru.deadsoftware.cavedroid.game.GameUiWindow +import ru.deadsoftware.cavedroid.game.input.action.MouseInputAction +import ru.deadsoftware.cavedroid.game.mobs.MobsController +import ru.deadsoftware.cavedroid.game.model.item.InventoryItem.Companion.isNoneOrNull +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 +import ru.deadsoftware.cavedroid.misc.Assets +import javax.inject.Inject + +@GameScope +@BindMouseInputHandler +class SelectFurnaceInventoryItemMouseInputHandler @Inject constructor( + private val gameWindowsManager: GameWindowsManager, + private val mobsController: MobsController, + private val gameItemsHolder: GameItemsHolder, +) : AbstractInventoryItemsMouseInputHandler(gameItemsHolder, gameWindowsManager, GameUiWindow.FURNACE) { + + override val windowTexture get() = requireNotNull(Assets.textureRegions["furnace"]) + + private fun handleInsideInventoryGrid(action: MouseInputAction, xOnGrid: Int, yOnGrid: Int) { + val window = gameWindowsManager.currentWindow as FurnaceInventoryWindow + + var itemIndex = xOnGrid + yOnGrid * GameWindowsConfigs.Furnace.itemsInRow + itemIndex += GameWindowsConfigs.Furnace.hotbarCells + + if (itemIndex >= mobsController.player.inventory.size) { + itemIndex -= mobsController.player.inventory.size + } + + handleInsidePlaceableCell(action, mobsController.player.inventory.items, window, itemIndex) + } + + private fun handleInsideFuel(action: MouseInputAction) { + val window = gameWindowsManager.currentWindow as FurnaceInventoryWindow + + if (!window.selectedItem.isNoneOrNull() && window.selectedItem?.item?.params?.burningTimeMs == null) { + return + } + + handleInsidePlaceableCell(action, window.furnace.items, window, Furnace.FUEL_INDEX) + } + + private fun handleInsideInput(action: MouseInputAction) { + val window = gameWindowsManager.currentWindow as FurnaceInventoryWindow + + handleInsidePlaceableCell(action, window.furnace.items, window, Furnace.INPUT_INDEX) + } + + private fun handleInsideResult(action: MouseInputAction) { + val window = gameWindowsManager.currentWindow as FurnaceInventoryWindow + + handleInsideCraftResultCell(action, window.furnace.items, window, Furnace.RESULT_INDEX) + } + + override fun handle(action: MouseInputAction) { + val texture = windowTexture + + val xOnWindow = action.screenX - (action.cameraViewport.width / 2 - texture.regionWidth / 2) + val yOnWindow = action.screenY - (action.cameraViewport.height / 2 - texture.regionHeight / 2) + + val xOnGrid = (xOnWindow - GameWindowsConfigs.Furnace.itemsGridMarginLeft) / + GameWindowsConfigs.Furnace.itemsGridColWidth + val yOnGrid = (yOnWindow - GameWindowsConfigs.Furnace.itemsGridMarginTop) / + GameWindowsConfigs.Furnace.itemsGridRowHeight + + val isInsideInput = xOnWindow > GameWindowsConfigs.Furnace.smeltInputMarginLeft && + xOnWindow < GameWindowsConfigs.Furnace.smeltInputMarginLeft + GameWindowsConfigs.Furnace.itemsGridColWidth && + yOnWindow > GameWindowsConfigs.Furnace.smeltInputMarginTop && + yOnWindow < GameWindowsConfigs.Furnace.smeltInputMarginTop + GameWindowsConfigs.Furnace.itemsGridRowHeight + + val isInsideFuel = xOnWindow > GameWindowsConfigs.Furnace.smeltFuelMarginLeft && + xOnWindow < GameWindowsConfigs.Furnace.smeltFuelMarginLeft + GameWindowsConfigs.Furnace.itemsGridColWidth && + yOnWindow > GameWindowsConfigs.Furnace.smeltFuelMarginTop && + yOnWindow < GameWindowsConfigs.Furnace.smeltFuelMarginTop + GameWindowsConfigs.Furnace.itemsGridRowHeight + + val isInsideResult = xOnWindow > GameWindowsConfigs.Furnace.smeltResultOffsetX && + xOnWindow < GameWindowsConfigs.Furnace.smeltResultOffsetX + GameWindowsConfigs.Furnace.itemsGridColWidth && + yOnWindow > GameWindowsConfigs.Furnace.smeltResultOffsetY && + yOnWindow < GameWindowsConfigs.Furnace.smeltResultOffsetY + GameWindowsConfigs.Furnace.itemsGridRowHeight + + val isInsideInventoryGrid = xOnGrid >= 0 && xOnGrid < GameWindowsConfigs.Furnace.itemsInRow && + yOnGrid >= 0 && yOnGrid < GameWindowsConfigs.Furnace.itemsInCol + + if (isInsideInventoryGrid) { + handleInsideInventoryGrid(action, xOnGrid.toInt(), yOnGrid.toInt()) + } else if (isInsideFuel) { + handleInsideFuel(action) + } else if (isInsideInput) { + handleInsideInput(action) + } else if (isInsideResult) { + handleInsideResult(action) + } + + } +} \ No newline at end of file diff --git a/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/SelectSurvivalInventoryItemMouseInputHandler.kt b/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/SelectSurvivalInventoryItemMouseInputHandler.kt index 61e1b18..58687fc 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/SelectSurvivalInventoryItemMouseInputHandler.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/SelectSurvivalInventoryItemMouseInputHandler.kt @@ -1,110 +1,60 @@ package ru.deadsoftware.cavedroid.game.input.handler.mouse -import com.badlogic.gdx.Gdx +import ru.deadsoftware.cavedroid.misc.annotations.multibinding.BindMouseInputHandler 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.windows.GameWindowsConfigs -import ru.deadsoftware.cavedroid.game.windows.GameWindowsManager -import ru.deadsoftware.cavedroid.game.windows.inventory.SurvivalInventoryWindow +import ru.deadsoftware.cavedroid.game.ui.windows.GameWindowsConfigs +import ru.deadsoftware.cavedroid.game.ui.windows.GameWindowsManager +import ru.deadsoftware.cavedroid.game.ui.windows.inventory.SurvivalInventoryWindow import ru.deadsoftware.cavedroid.misc.Assets import javax.inject.Inject @GameScope +@BindMouseInputHandler class SelectSurvivalInventoryItemMouseInputHandler @Inject constructor( private val gameWindowsManager: GameWindowsManager, private val mobsController: MobsController, private val gameItemsHolder: GameItemsHolder, -) : IGameInputHandler { +) : AbstractInventoryItemsMouseInputHandler(gameItemsHolder, gameWindowsManager, GameUiWindow.SURVIVAL_INVENTORY) { - private val survivalWindowTexture get() = requireNotNull(Assets.textureRegions["survival"]) - - override fun checkConditions(action: MouseInputAction): Boolean { - return gameWindowsManager.getCurrentWindow() == GameUiWindow.SURVIVAL_INVENTORY && - isInsideWindow(action, survivalWindowTexture) && - (action.actionKey is MouseInputActionKey.Left || action.actionKey is MouseInputActionKey.Right || action.actionKey is MouseInputActionKey.Touch) - && action.actionKey.touchUp - } - - private fun onLeftCLick(items: MutableList, window: SurvivalInventoryWindow, index: Int) { - val selectedItem = window.selectedItem - val clickedItem = items[index] - - if (clickedItem != null && selectedItem != null && items[index]!!.item == selectedItem.item && - items[index]!!.amount + selectedItem.amount <= selectedItem.item.params.maxStack) { - items[index]!!.amount += selectedItem.amount - window.selectedItem = null - return - } - - val item = items[index] - items[index] = selectedItem ?: gameItemsHolder.fallbackItem.toInventoryItem() - window.selectedItem = item - } - - private fun onRightClick(items: MutableList, window: SurvivalInventoryWindow, index: Int) { - val clickedItem = items[index] - val selectedItem = window.selectedItem - ?.takeIf { clickedItem == null || clickedItem.item.isNone() || it.item == items[index]!!.item && items[index]!!.amount + 1 < it.item.params.maxStack } - ?: return - - val newItem = selectedItem.item.toInventoryItem((clickedItem?.takeIf { !it.item.isNone() }?.amount ?: 0) + 1) - items[index] = newItem - selectedItem.amount -- - - if (selectedItem.amount <= 0) { - window.selectedItem = null - } - } + override val windowTexture get() = requireNotNull(Assets.textureRegions["survival"]) private fun handleInsideInventoryGrid(action: MouseInputAction, xOnGrid: Int, yOnGrid: Int) { val window = gameWindowsManager.currentWindow as SurvivalInventoryWindow - var itemIndex = ((xOnGrid.toInt() + yOnGrid.toInt() * GameWindowsConfigs.Survival.itemsInRow)) + var itemIndex = xOnGrid + yOnGrid * GameWindowsConfigs.Survival.itemsInRow itemIndex += GameWindowsConfigs.Survival.hotbarCells - if (itemIndex >= 36) { - itemIndex -= 36 + if (itemIndex >= mobsController.player.inventory.size) { + itemIndex -= mobsController.player.inventory.size } - if (action.actionKey is MouseInputActionKey.Left || action.actionKey is MouseInputActionKey.Touch) { - onLeftCLick(mobsController.player.inventory, window, itemIndex) - } else { - onRightClick(mobsController.player.inventory, window, itemIndex) - } - - Gdx.app.debug( - TAG, - "selected item: ${window.selectedItem?.item?.params?.key ?: "null"}; index $itemIndex, grid ($xOnGrid;$yOnGrid)" - ) + handleInsidePlaceableCell(action, mobsController.player.inventory.items, window, itemIndex) } private fun handleInsideCraft(action: MouseInputAction, xOnCraft: Int, yOnCraft: Int) { val window = gameWindowsManager.currentWindow as SurvivalInventoryWindow val index = xOnCraft + yOnCraft * GameWindowsConfigs.Crafting.craftGridSize // this is crafting on purpose!! - if (action.actionKey is MouseInputActionKey.Left || action.actionKey is MouseInputActionKey.Touch) { - onLeftCLick(window.craftingItems, window, index) - } else { - onRightClick(window.craftingItems, window, index) - } + handleInsidePlaceableCell(action, window.craftingItems, window, index) - window.craftResult = - gameItemsHolder.craftItem(window.craftingItems.map { it?.item ?: gameItemsHolder.fallbackItem }) + updateCraftResult(window) } - override fun handle(action: MouseInputAction) { - val survivalTexture = survivalWindowTexture + private fun handleInsideCraftResult(action: MouseInputAction) { val window = gameWindowsManager.currentWindow as SurvivalInventoryWindow - val xOnWindow = action.screenX - (action.cameraViewport.width / 2 - survivalTexture.regionWidth / 2) - val yOnWindow = action.screenY - (action.cameraViewport.height / 2 - survivalTexture.regionHeight / 2) + handleInsideCraftResultCell(action, window.craftResultList, window, 0) + + updateCraftResult(window) + } + + override fun handle(action: MouseInputAction) { + val xOnWindow = action.screenX - (action.cameraViewport.width / 2 - windowTexture.regionWidth / 2) + val yOnWindow = action.screenY - (action.cameraViewport.height / 2 - windowTexture.regionHeight / 2) val xOnGrid = (xOnWindow - GameWindowsConfigs.Survival.itemsGridMarginLeft) / GameWindowsConfigs.Survival.itemsGridColWidth @@ -132,30 +82,8 @@ class SelectSurvivalInventoryItemMouseInputHandler @Inject constructor( } else if (isInsideCraftGrid) { handleInsideCraft(action, xOnCraft.toInt(), yOnCraft.toInt()) } else if (isInsideCraftResult) { - val selectedItem = window.selectedItem - if (selectedItem == null || selectedItem.item.isNone() || - (selectedItem.item == window.craftResult?.item && selectedItem.amount + (window.craftResult?.amount ?: 0) <= selectedItem.item.params.maxStack)) { - for (i in window.craftingItems.indices) { - if ((window.craftingItems[i]?.amount ?: 0) > 1) { - window.craftingItems[i]?.amount = window.craftingItems[i]?.amount!! - 1 - } else { - window.craftingItems[i] = null - } - } - if (selectedItem != null && !selectedItem.item.isNone()) { - selectedItem.amount += (window.craftResult?.amount ?: 0) - } else { - window.selectedItem = window.craftResult - } - window.craftResult = gameItemsHolder.craftItem(window.craftingItems - .map { it?.item ?: gameItemsHolder.fallbackItem }) - } + handleInsideCraftResult(action) } } - - companion object { - private const val TAG = "SelectSurvivalInventoryItemMouseInputHandler" - - } } \ No newline at end of file diff --git a/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/UseItemMouseInputHandler.kt b/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/UseItemMouseInputHandler.kt index e2d3f1d..541bba7 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/UseItemMouseInputHandler.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/input/handler/mouse/UseItemMouseInputHandler.kt @@ -1,5 +1,6 @@ package ru.deadsoftware.cavedroid.game.input.handler.mouse +import ru.deadsoftware.cavedroid.misc.annotations.multibinding.BindMouseInputHandler import com.badlogic.gdx.Gdx import com.badlogic.gdx.utils.Timer import ru.deadsoftware.cavedroid.game.GameScope @@ -7,23 +8,28 @@ import ru.deadsoftware.cavedroid.game.GameUiWindow import ru.deadsoftware.cavedroid.game.actions.placeToBackgroundAction import ru.deadsoftware.cavedroid.game.actions.placeToForegroundAction import ru.deadsoftware.cavedroid.game.actions.placeblock.IPlaceBlockAction +import ru.deadsoftware.cavedroid.game.actions.useblock.IUseBlockAction import ru.deadsoftware.cavedroid.game.actions.useitem.IUseItemAction -import ru.deadsoftware.cavedroid.game.input.IGameInputHandler +import ru.deadsoftware.cavedroid.game.input.IMouseInputHandler import ru.deadsoftware.cavedroid.game.input.action.MouseInputAction import ru.deadsoftware.cavedroid.game.input.action.keys.MouseInputActionKey import ru.deadsoftware.cavedroid.game.input.isInsideHotbar import ru.deadsoftware.cavedroid.game.mobs.MobsController import ru.deadsoftware.cavedroid.game.model.item.Item -import ru.deadsoftware.cavedroid.game.windows.GameWindowsManager +import ru.deadsoftware.cavedroid.game.ui.windows.GameWindowsManager +import ru.deadsoftware.cavedroid.game.world.GameWorld import javax.inject.Inject @GameScope +@BindMouseInputHandler class UseItemMouseInputHandler @Inject constructor( private val mobsController: MobsController, private val useItemActionMap: Map, private val placeBlockActionMap: Map, + private val useBlockActionMap: Map, private val gameWindowsManager: GameWindowsManager, -) : IGameInputHandler { + private val gameWorld: GameWorld, +) : IMouseInputHandler { private var buttonHoldTask: Timer.Task? = null @@ -43,13 +49,13 @@ class UseItemMouseInputHandler @Inject constructor( cancelHold() val player = mobsController.player - val item = player.currentItem.item + val item = player.inventory.activeItem.item player.startHitting(false) player.stopHitting() if (item is Item.Placeable) { placeBlockActionMap.placeToBackgroundAction( - item = player.currentItem.item as Item.Placeable, + item = item, x = player.cursorX, y = player.cursorY ) @@ -67,9 +73,23 @@ class UseItemMouseInputHandler @Inject constructor( Timer.schedule(buttonHoldTask, TOUCH_HOLD_TIME_SEC) } + private fun tryUseBlock() { + val block = gameWorld.getForeMap(mobsController.player.cursorX, mobsController.player.cursorY) + .takeIf { !it.isNone() } + ?: gameWorld.getBackMap(mobsController.player.cursorX, mobsController.player.cursorY) + .takeIf { !it.isNone() } + ?: return + + useBlockActionMap[block.params.key]?.perform( + block = block, + x = mobsController.player.cursorX, + y = mobsController.player.cursorY + ) + } + private fun handleUp(action: MouseInputAction) { val player = mobsController.player - val item = player.currentItem.item + val item = player.inventory.activeItem.item cancelHold() player.startHitting(false) @@ -84,6 +104,8 @@ class UseItemMouseInputHandler @Inject constructor( } else if (item is Item.Usable) { useItemActionMap[item.useActionKey]?.perform(item, player.cursorX, player.cursorY) ?: Gdx.app.error(TAG, "use item action ${item.useActionKey} not found"); + } else { + tryUseBlock() } } diff --git a/core/src/ru/deadsoftware/cavedroid/game/input/handler/touch/JoystickInputHandler.kt b/core/src/ru/deadsoftware/cavedroid/game/input/handler/touch/JoystickInputHandler.kt new file mode 100644 index 0000000..d717c18 --- /dev/null +++ b/core/src/ru/deadsoftware/cavedroid/game/input/handler/touch/JoystickInputHandler.kt @@ -0,0 +1,148 @@ +package ru.deadsoftware.cavedroid.game.input.handler.touch + +import ru.deadsoftware.cavedroid.misc.annotations.multibinding.BindMouseInputHandler +import com.badlogic.gdx.utils.TimeUtils +import ru.deadsoftware.cavedroid.MainConfig +import ru.deadsoftware.cavedroid.game.GameScope +import ru.deadsoftware.cavedroid.game.GameUiWindow +import ru.deadsoftware.cavedroid.game.input.* +import ru.deadsoftware.cavedroid.game.input.action.MouseInputAction +import ru.deadsoftware.cavedroid.game.input.action.keys.MouseInputActionKey +import ru.deadsoftware.cavedroid.game.mobs.Mob +import ru.deadsoftware.cavedroid.game.mobs.MobsController +import ru.deadsoftware.cavedroid.game.mobs.player.Player +import ru.deadsoftware.cavedroid.game.ui.windows.GameWindowsManager +import ru.deadsoftware.cavedroid.game.world.GameWorld +import javax.inject.Inject + +@GameScope +@BindMouseInputHandler +class JoystickInputHandler @Inject constructor( + private val mainConfig: MainConfig, + private val mobsController: MobsController, + private val gameWindowsManager: GameWindowsManager, + private val gameWorld: GameWorld, +) : IMouseInputHandler { + + private var activateTimeMs = 0L + private var cursorTimeoutMs = 100L + + private var active = false + set(value) { + if (!value) { + resetVelocity() + if (TimeUtils.timeSinceMillis(activateTimeMs) < 200L && + mobsController.player.controlMode != Player.ControlMode.CURSOR) { + mobsController.player.jump() + } + } else { + activateTimeMs = TimeUtils.millis() + } + field = value + } + + private fun resetVelocity() { + mobsController.player.velocity.x = 0f + + if (mobsController.player.isFlyMode) { + mobsController.player.velocity.y = 0f + } + } + + override fun checkConditions(action: MouseInputAction): Boolean { + return gameWindowsManager.getCurrentWindow() == GameUiWindow.NONE && + mainConfig.isTouch && +// mobsController.player.controlMode == Player.ControlMode.WALK && + mainConfig.joystick != null && + (action.actionKey is MouseInputActionKey.Touch) && + (action.actionKey.pointer == mainConfig.joystick?.pointer || !active) && + ((action.actionKey is MouseInputActionKey.Dragged) || + (action.screenX < action.cameraViewport.width / 2 && !action.actionKey.touchUp || active)) && + !(action.actionKey is MouseInputActionKey.Screen && isInsideHotbar(action)) + + } + + private fun handleTouchDown(action: MouseInputAction) { + val key = action.actionKey as MouseInputActionKey.Screen + mainConfig.joystick?.activate(action.screenX, action.screenY, key.pointer) ?: return + active = true + } + + private fun handleTouchUp(action: MouseInputAction) { + mainConfig.joystick?.deactivate() + active = false + } + + private fun handleCursor() { + val joystick = mainConfig.joystick ?: return + + if (TimeUtils.timeSinceMillis(cursorTimeoutMs) < 150L) { + return + } + + val pastCursorX = mobsController.player.cursorX + val pastCursorY = mobsController.player.cursorY + + if (Math.abs(joystick.activeX - joystick.centerX) >= Joystick.RADIUS / 2) { + mobsController.player.cursorX += if (joystick.activeX > joystick.centerX) 1 else -1 + cursorTimeoutMs = TimeUtils.millis() + } + + if (Math.abs(joystick.activeY - joystick.centerY) >= Joystick.RADIUS / 2) { + mobsController.player.cursorY += if (joystick.activeY > joystick.centerY) 1 else -1 + cursorTimeoutMs = TimeUtils.millis() + } + + mobsController.player.checkCursorBounds(gameWorld) + + if (mobsController.player.cursorX != pastCursorX || mobsController.player.cursorY != pastCursorY) { + mobsController.player.blockDamage = 0f + } + } + + private fun handleDragged() { + if (!active) { + return + } + + if (mobsController.player.controlMode == Player.ControlMode.CURSOR) { + handleCursor() + return + } + + val joystick = mainConfig.joystick ?: return + val joyVector = joystick.getVelocityVector() + + if (mobsController.player.isFlyMode) { + joyVector.scl(2f); + } + + mobsController.player.velocity.x = joyVector.x + + mobsController.player.setDir( + if (joyVector.x < 0) { + Mob.Direction.LEFT + } else { + Mob.Direction.RIGHT + } + ) + + if (mobsController.player.isFlyMode) { + mobsController.player.velocity.y = joyVector.y + } + } + + override fun handle(action: MouseInputAction) { + when (action.actionKey) { + is MouseInputActionKey.Dragged -> handleDragged() + else -> { + if (action.actionKey.touchUp) { + handleTouchUp(action) + } else { + handleTouchDown(action) + } + } + } + } + +} \ No newline at end of file diff --git a/core/src/ru/deadsoftware/cavedroid/game/input/mapper/KeyboardInputActionMapper.kt b/core/src/ru/deadsoftware/cavedroid/game/input/mapper/KeyboardInputActionMapper.kt index ca91f48..8d18d07 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/input/mapper/KeyboardInputActionMapper.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/input/mapper/KeyboardInputActionMapper.kt @@ -13,7 +13,7 @@ class KeyboardInputActionMapper @Inject constructor() { val actionKey = when (key) { Input.Keys.A, Input.Keys.LEFT -> KeyboardInputActionKey.Left Input.Keys.D, Input.Keys.RIGHT -> KeyboardInputActionKey.Right - Input.Keys.W, Input.Keys.SPACE -> KeyboardInputActionKey.Jump + Input.Keys.W, Input.Keys.SPACE -> KeyboardInputActionKey.Up Input.Keys.S -> KeyboardInputActionKey.Down Input.Keys.E -> KeyboardInputActionKey.OpenInventory @@ -25,7 +25,17 @@ class KeyboardInputActionMapper @Inject constructor() { Input.Keys.GRAVE -> KeyboardInputActionKey.SwitchGameMode Input.Keys.M -> KeyboardInputActionKey.ShowMap - Input.Keys.T -> KeyboardInputActionKey.OpenCraft + Input.Keys.Q -> KeyboardInputActionKey.DropItem + + Input.Keys.NUM_1 -> KeyboardInputActionKey.SelectHotbarSlot(0) + Input.Keys.NUM_2 -> KeyboardInputActionKey.SelectHotbarSlot(1) + Input.Keys.NUM_3 -> KeyboardInputActionKey.SelectHotbarSlot(2) + Input.Keys.NUM_4 -> KeyboardInputActionKey.SelectHotbarSlot(3) + Input.Keys.NUM_5 -> KeyboardInputActionKey.SelectHotbarSlot(4) + Input.Keys.NUM_6 -> KeyboardInputActionKey.SelectHotbarSlot(5) + Input.Keys.NUM_7 -> KeyboardInputActionKey.SelectHotbarSlot(6) + Input.Keys.NUM_8 -> KeyboardInputActionKey.SelectHotbarSlot(7) + Input.Keys.NUM_9 -> KeyboardInputActionKey.SelectHotbarSlot(8) else -> null } diff --git a/core/src/ru/deadsoftware/cavedroid/game/input/mapper/MouseInputActionMapper.kt b/core/src/ru/deadsoftware/cavedroid/game/input/mapper/MouseInputActionMapper.kt index 254cee2..5ef450a 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/input/mapper/MouseInputActionMapper.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/input/mapper/MouseInputActionMapper.kt @@ -19,9 +19,10 @@ class MouseInputActionMapper @Inject constructor( mouseY: Float, cameraViewport: Rectangle, button: Int, - touchUp: Boolean + touchUp: Boolean, + pointer: Int, ): MouseInputAction? { - val actionKey = mapActionKey(button, touchUp) ?: return null + val actionKey = mapActionKey(button, touchUp, pointer) ?: return null return MouseInputAction( screenX = getScreenX(mouseX), @@ -35,11 +36,12 @@ class MouseInputActionMapper @Inject constructor( mouseX: Float, mouseY: Float, cameraViewport: Rectangle, + pointer: Int, ): MouseInputAction { return MouseInputAction( screenX = getScreenX(mouseX), screenY = getScreenY(mouseY), - actionKey = MouseInputActionKey.Dragged, + actionKey = MouseInputActionKey.Dragged(pointer), cameraViewport = cameraViewport, ) } @@ -59,12 +61,12 @@ class MouseInputActionMapper @Inject constructor( ) } - private fun mapActionKey(button: Int, touchUp: Boolean): MouseInputActionKey? { + private fun mapActionKey(button: Int, touchUp: Boolean, pointer: Int): MouseInputActionKey? { return when (button) { Input.Buttons.LEFT -> MouseInputActionKey.Left(touchUp) Input.Buttons.RIGHT -> MouseInputActionKey.Right(touchUp) Input.Buttons.MIDDLE -> MouseInputActionKey.Middle(touchUp) - -1 -> MouseInputActionKey.Touch(touchUp) + -1 -> MouseInputActionKey.Screen(touchUp, pointer) else -> null } } diff --git a/core/src/ru/deadsoftware/cavedroid/game/mobs/FallingGravel.java b/core/src/ru/deadsoftware/cavedroid/game/mobs/FallingGravel.java index 641ffe5..2ad4287 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/mobs/FallingGravel.java +++ b/core/src/ru/deadsoftware/cavedroid/game/mobs/FallingGravel.java @@ -40,7 +40,7 @@ public class FallingGravel extends Mob { } @Override - public void ai(GameWorld gameWorld, GameItemsHolder gameItemsHolder, float delta) { + public void ai(GameWorld gameWorld, GameItemsHolder gameItemsHolder, MobsController mobsController, float delta) { if (mVelocity.isZero()) { gameWorld.setForeMap(getMapX(), getUpperMapY(), gameItemsHolder.getBlock("gravel")); kill(); @@ -51,6 +51,11 @@ public class FallingGravel extends Mob { public void changeDir() { } + @Override + public void damage(int damage) { + // no-op + } + @Override public void draw(SpriteBatch spriteBatch, float x, float y, float delta) { @CheckForNull final Texture texture = Assets.blockTextures.get("gravel"); diff --git a/core/src/ru/deadsoftware/cavedroid/game/mobs/FallingSand.java b/core/src/ru/deadsoftware/cavedroid/game/mobs/FallingSand.java index f41da96..970ff53 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/mobs/FallingSand.java +++ b/core/src/ru/deadsoftware/cavedroid/game/mobs/FallingSand.java @@ -41,7 +41,7 @@ public class FallingSand extends Mob { } @Override - public void ai(GameWorld gameWorld, GameItemsHolder gameItemsHolder, float delta) { + public void ai(GameWorld gameWorld, GameItemsHolder gameItemsHolder, MobsController mobsController, float delta) { if (mVelocity.isZero()) { gameWorld.setForeMap(getMapX(), getUpperMapY(), gameItemsHolder.getBlock("sand")); kill(); @@ -52,6 +52,11 @@ public class FallingSand extends Mob { public void changeDir() { } + @Override + public void damage(int damage) { + // no-op + } + @Override public void draw(SpriteBatch spriteBatch, float x, float y, float delta) { @CheckForNull final Texture texture = Assets.blockTextures.get("sand"); diff --git a/core/src/ru/deadsoftware/cavedroid/game/mobs/Mob.java b/core/src/ru/deadsoftware/cavedroid/game/mobs/Mob.java index 415ef30..62ddc50 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/mobs/Mob.java +++ b/core/src/ru/deadsoftware/cavedroid/game/mobs/Mob.java @@ -1,13 +1,16 @@ package ru.deadsoftware.cavedroid.game.mobs; import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.math.MathUtils; import com.badlogic.gdx.math.Rectangle; import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.utils.Timer; import ru.deadsoftware.cavedroid.game.GameItemsHolder; import ru.deadsoftware.cavedroid.game.world.GameWorld; +import javax.annotation.CheckForNull; import java.io.Serializable; /** @@ -15,6 +18,11 @@ import java.io.Serializable; */ public abstract class Mob extends Rectangle implements Serializable { + private static final float DAMAGE_TINT_TIMEOUT_S = 0.5f; + private static final Color DAMAGE_TINT_COLOR = new Color(0xff8080ff); + + private static final float HIT_RANGE = 8f; + protected static int ANIMATION_SPEED = 360; public enum Type { @@ -51,6 +59,14 @@ public abstract class Mob extends Rectangle implements Serializable { } } + private class ResetTakeDamageTask extends Timer.Task { + + @Override + public void run() { + mTakingDamage = false; + } + } + protected Vector2 mVelocity; protected Type mType; protected int mAnimDelta = ANIMATION_SPEED; @@ -64,6 +80,9 @@ public abstract class Mob extends Rectangle implements Serializable { private final int mMaxHealth; private int mHealth; + private transient boolean mTakingDamage = false; + @CheckForNull private transient ResetTakeDamageTask mResetTakeDamageTask = null; + /** * @param x in pixels * @param y in pixels @@ -99,17 +118,21 @@ public abstract class Mob extends Rectangle implements Serializable { } protected final void updateAnimation(float delta) { - if (mVelocity.x != 0f || Math.abs(mAnim) > mAnimDelta * delta) { - mAnim += mAnimDelta * delta; + final float velocityMultiplier = (Math.abs(getVelocity().x) / getSpeed()); + final float animMultiplier = (velocityMultiplier == 0f ? 1f : velocityMultiplier) * delta; + final float maxAnim = 60f * (velocityMultiplier == 0f ? 1f : velocityMultiplier); + + if (mVelocity.x != 0f || Math.abs(mAnim) > mAnimDelta * animMultiplier) { + mAnim += mAnimDelta * animMultiplier; } else { mAnim = 0; } - if (mAnim > 60f) { - mAnim = 60f; + if (mAnim > maxAnim) { + mAnim = maxAnim; mAnimDelta = -ANIMATION_SPEED; - } else if (mAnim < -60f) { - mAnim = -60f; + } else if (mAnim < -maxAnim) { + mAnim = -maxAnim; mAnimDelta = ANIMATION_SPEED; } @@ -257,6 +280,8 @@ public abstract class Mob extends Rectangle implements Serializable { mHealth -= damage; checkHealth(); + + setTakingDamage(true); } public void heal(int heal) { @@ -273,9 +298,35 @@ public abstract class Mob extends Rectangle implements Serializable { checkHealth(); } + public Rectangle getHitBox() { + return new Rectangle(x - HIT_RANGE, y - HIT_RANGE, width + HIT_RANGE, height + HIT_RANGE); + } + + public boolean isTakingDamage() { + return mTakingDamage; + } + + public void setTakingDamage(boolean takingDamage) { + mTakingDamage = takingDamage; + + if (takingDamage) { + if (mResetTakeDamageTask != null && mResetTakeDamageTask.isScheduled()) { + mResetTakeDamageTask.cancel(); + } else if (mResetTakeDamageTask == null) { + mResetTakeDamageTask = new ResetTakeDamageTask(); + } + + Timer.schedule(mResetTakeDamageTask, DAMAGE_TINT_TIMEOUT_S); + } + } + + protected Color getTintColor() { + return isTakingDamage() ? DAMAGE_TINT_COLOR : Color.WHITE; + } + public abstract void draw(SpriteBatch spriteBatch, float x, float y, float delta); - public abstract void ai(GameWorld gameWorld, GameItemsHolder gameItemsHolder, float delta); + public abstract void ai(GameWorld gameWorld, GameItemsHolder gameItemsHolder, MobsController mobsController, float delta); public abstract void changeDir(); diff --git a/core/src/ru/deadsoftware/cavedroid/game/mobs/MobsController.kt b/core/src/ru/deadsoftware/cavedroid/game/mobs/MobsController.kt index 0ec111b..158d22a 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/mobs/MobsController.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/mobs/MobsController.kt @@ -2,18 +2,22 @@ package ru.deadsoftware.cavedroid.game.mobs import ru.deadsoftware.cavedroid.game.GameItemsHolder import ru.deadsoftware.cavedroid.game.GameScope +import ru.deadsoftware.cavedroid.game.mobs.player.Player +import ru.deadsoftware.cavedroid.game.ui.TooltipManager import java.io.Serializable import java.util.* import javax.inject.Inject @GameScope class MobsController @Inject constructor( - gameItemsHolder: GameItemsHolder + gameItemsHolder: GameItemsHolder, + tooltipManager: TooltipManager, ) : Serializable { private val _mobs = LinkedList() - val player: Player = Player(gameItemsHolder) + val player: Player = + Player(gameItemsHolder, tooltipManager) val mobs: List get() = _mobs diff --git a/core/src/ru/deadsoftware/cavedroid/game/mobs/Pig.kt b/core/src/ru/deadsoftware/cavedroid/game/mobs/Pig.kt index b55f429..68c457e 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/mobs/Pig.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/mobs/Pig.kt @@ -27,8 +27,18 @@ class Pig(x: Float, y: Float) : Mob(x, y, WIDTH, HEIGHT, randomDir(), Type.MOB, override fun jump() { velocity.y = JUMP_VELOCITY } - - override fun ai(world: GameWorld, gameItemsHolder: GameItemsHolder, delta: Float) { + + override fun damage(damage: Int) { + super.damage(damage) + + if (damage > 0) { + if (canJump()) { + jump() + } + } + } + + override fun ai(world: GameWorld, gameItemsHolder: GameItemsHolder, mobsController: MobsController, delta: Float) { if (MathUtils.randomBoolean(delta)) { if (velocity.x != 0f) { velocity.x = 0f @@ -45,19 +55,19 @@ class Pig(x: Float, y: Float) : Mob(x, y, WIDTH, HEIGHT, randomDir(), Type.MOB, val rightLegX = x + getRightLegRelativeX(direction) val legY = y + getLegsRelativeY() - spriteBatch.drawSprite(getBackgroundLeg(), leftLegX, legY, -anim) - spriteBatch.drawSprite(getBackgroundLeg(), rightLegX, legY, -anim) - spriteBatch.drawSprite(getBody(direction), x, y) - spriteBatch.drawSprite(getForegroundLeg(), leftLegX, legY, anim) - spriteBatch.drawSprite(getForegroundLeg(), rightLegX, legY, anim) + spriteBatch.drawSprite(getBackgroundLeg(), leftLegX, legY, -anim, tint = tintColor) + spriteBatch.drawSprite(getBackgroundLeg(), rightLegX, legY, -anim, tint = tintColor) + spriteBatch.drawSprite(getBody(direction), x, y, tint = tintColor) + spriteBatch.drawSprite(getForegroundLeg(), leftLegX, legY, anim, tint = tintColor) + spriteBatch.drawSprite(getForegroundLeg(), rightLegX, legY, anim, tint = tintColor) } private companion object { private const val WIDTH = 25f private const val HEIGHT = 18f - private const val SPEED = 69.072f + private const val SPEED = 48f private const val JUMP_VELOCITY = -133.332f - private const val MAX_HEALTH = 10; + private const val MAX_HEALTH = 10 } } \ No newline at end of file diff --git a/core/src/ru/deadsoftware/cavedroid/game/mobs/player/Inventory.kt b/core/src/ru/deadsoftware/cavedroid/game/mobs/player/Inventory.kt new file mode 100644 index 0000000..3012d66 --- /dev/null +++ b/core/src/ru/deadsoftware/cavedroid/game/mobs/player/Inventory.kt @@ -0,0 +1,136 @@ +package ru.deadsoftware.cavedroid.game.mobs.player + +import ru.deadsoftware.cavedroid.game.GameItemsHolder +import ru.deadsoftware.cavedroid.game.model.item.InventoryItem +import ru.deadsoftware.cavedroid.game.model.item.Item +import ru.deadsoftware.cavedroid.game.objects.drop.Drop +import ru.deadsoftware.cavedroid.game.ui.TooltipManager +import java.io.Serializable + +class Inventory( + val size: Int, + val hotbarSize: Int, + gameItemsHolder: GameItemsHolder, + tooltipManager: TooltipManager, +) : Serializable { + + @Suppress("UNNECESSARY_LATEINIT") + @Transient + private lateinit var tooltipManager: TooltipManager + + @Suppress("UNNECESSARY_LATEINIT") + @Transient + private lateinit var fallbackItem: InventoryItem + + init { + fallbackItem = gameItemsHolder.fallbackItem.toInventoryItem() + this.tooltipManager = tooltipManager + + if (size < 0 || hotbarSize < 0 || hotbarSize > size) { + throw IllegalArgumentException("Invalid inventory sizes: hotbarSize=$hotbarSize; size=$size") + } + } + + private val _items = Array(size) { InventoryItem(gameItemsHolder.fallbackItem) } + + val items get() = _items.asList() as MutableList + + val hotbarItems get() = items.subList(0, hotbarSize) + + var activeSlot = 0 + set(value) { + if (value in 0 ..< hotbarSize) { + field = value + showCurrentItemTooltip() + } + } + + fun showCurrentItemTooltip() { + tooltipManager.showHotbarTooltip(activeItem.item.params.name) + } + + val activeItem get() = _items[activeSlot] + + fun initItems(gameItemsHolder: GameItemsHolder, tooltipManager: TooltipManager) { + this.tooltipManager = tooltipManager + fallbackItem = gameItemsHolder.fallbackItem.toInventoryItem() + _items.forEach { item -> + item.init(gameItemsHolder) + } + } + + private fun getItemPickSlot(drop: Drop): Int { + val item = drop.item + + for (i in _items.indices) { + val inventoryItem = _items[i] + + if (item == inventoryItem.item && inventoryItem.canBeAdded()) { + return i + } + } + + for (i in _items.indices) { + val inventoryItem = _items[i] + + if (inventoryItem.item.isNone()) { + return i + } + } + + return -1 + } + + fun canPickItem(drop: Drop): Boolean { + return getItemPickSlot(drop) >= 0 + } + + fun pickDrop(drop: Drop) { + val slot = getItemPickSlot(drop).takeIf { it >= 0 } ?: return + val inventoryItem = _items[slot] + + if (inventoryItem.item == drop.item) { + if (inventoryItem.canBeAdded(drop.amount)) { + inventoryItem.add(drop.amount) + drop.pickedUp = true + } else { + val addCount = inventoryItem.item.params.maxStack - inventoryItem.amount + inventoryItem.add(addCount) + drop.subtract(addCount) + pickDrop(drop) + } + } else { + _items[slot] = drop.item.toInventoryItem(drop.amount) + if (slot == activeSlot) { + showCurrentItemTooltip() + } + drop.pickedUp = true + } + } + + fun addItem(item: Item) { + _items.copyInto( + destination = _items, + destinationOffset = 1, + startIndex = 0, + endIndex = size - 1 + ) + + _items[0] = item.toInventoryItem(item.params.maxStack) + showCurrentItemTooltip() + } + + @JvmOverloads + fun decreaseItemAmount(slot: Int, count: Int = 1) { + val item = _items[slot] + item.subtract(count) + if (item.amount <= 0) { + _items[slot] = fallbackItem + } + } + + @JvmOverloads + fun decreaseCurrentItemAmount(count: Int = 1) { + decreaseItemAmount(activeSlot, count) + } +} \ No newline at end of file diff --git a/core/src/ru/deadsoftware/cavedroid/game/mobs/Player.java b/core/src/ru/deadsoftware/cavedroid/game/mobs/player/Player.java similarity index 70% rename from core/src/ru/deadsoftware/cavedroid/game/mobs/Player.java rename to core/src/ru/deadsoftware/cavedroid/game/mobs/player/Player.java index 0e8af6e..8ea87c1 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/mobs/Player.java +++ b/core/src/ru/deadsoftware/cavedroid/game/mobs/player/Player.java @@ -1,34 +1,41 @@ -package ru.deadsoftware.cavedroid.game.mobs; +package ru.deadsoftware.cavedroid.game.mobs.player; import com.badlogic.gdx.graphics.g2d.Sprite; import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.math.MathUtils; import com.badlogic.gdx.math.Vector2; import ru.deadsoftware.cavedroid.game.GameItemsHolder; +import ru.deadsoftware.cavedroid.game.mobs.Mob; +import ru.deadsoftware.cavedroid.game.mobs.MobsController; 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.objects.Drop; +import ru.deadsoftware.cavedroid.game.objects.drop.Drop; +import ru.deadsoftware.cavedroid.game.objects.drop.DropController; +import ru.deadsoftware.cavedroid.game.ui.TooltipManager; import ru.deadsoftware.cavedroid.game.world.GameWorld; import ru.deadsoftware.cavedroid.misc.Assets; import ru.deadsoftware.cavedroid.misc.utils.SpriteOrigin; import ru.deadsoftware.cavedroid.misc.utils.SpriteUtilsKt; import javax.annotation.CheckForNull; -import java.util.ArrayList; public class Player extends Mob { private static final float SPEED = 69.072f; private static final float JUMP_VELOCITY = -133.332f; - private static final int MAX_HEALTH = 20; + private static final int SURVIVAL_CURSOR_RANGE = 4; + + public static final int MAX_HEALTH = 20; + public static final int INVENTORY_SIZE = 36; + public static final int HOTBAR_SIZE = 9; private boolean hitting = false, hittingWithDamage = false; private float hitAnim = 0f; private float hitAnimDelta = ANIMATION_SPEED; - public final ArrayList inventory; - public int slot; + public final Inventory inventory; + public int gameMode; public boolean swim; public float headRotation = 0f; @@ -47,26 +54,16 @@ public class Player extends Mob { CURSOR } - public Player(GameItemsHolder gameItemsHolder) { + public Player(GameItemsHolder gameItemsHolder, TooltipManager tooltipManager) { super(0, 0, 4, 30, randomDir(), Type.MOB, MAX_HEALTH); - inventory = new ArrayList<>(36); - for (int i = 0; i < 36; i++) { - inventory.add(gameItemsHolder.getFallbackItem().toInventoryItem()); - } + inventory = new Inventory(INVENTORY_SIZE, HOTBAR_SIZE, gameItemsHolder, tooltipManager); swim = false; } - public void initInventory(GameItemsHolder gameItemsHolder) { - for (InventoryItem invItem : inventory) { - invItem.init(gameItemsHolder); - } + public void initInventory(GameItemsHolder gameItemsHolder, TooltipManager tooltipManager) { + inventory.initItems(gameItemsHolder, tooltipManager); } - @CheckForNull - public Item inventory(int i) { - return inventory.get(i).getItem(); - } - public void respawn(GameWorld gameWorld, GameItemsHolder itemsHolder) { Vector2 pos = getSpawnPoint(gameWorld, itemsHolder); this.x = pos.x; @@ -80,34 +77,17 @@ public class Player extends Mob { if (gameMode == 1) { return; } - getCurrentItem().setAmount(getCurrentItem().getAmount() - 1); - if (getCurrentItem().getAmount() <= 0) { + + final InventoryItem item = inventory.getActiveItem(); + item.subtract(); + if (item.getAmount() <= 0) { setCurrentInventorySlotItem(gameItemsHolder.getFallbackItem()); } } - public InventoryItem getCurrentItem() { - return inventory.get(slot); - } - - public void pickUpDrop(Drop drop) { - for (InventoryItem invItem : inventory) { - if (!invItem.getItem().isTool() - && invItem.getItem() == drop.getItem() - && invItem.getAmount() < invItem.getItem().getParams().getMaxStack()) { - invItem.setAmount(invItem.getAmount() + 1); - drop.setPickedUp(true); - return; - } - } + public void dropCurrentItem(DropController dropController) { + final InventoryItem activeItem = inventory.getActiveItem(); - for (int i = 0; i < inventory.size(); i++) { - if (inventory(i) == null || inventory(i).getParams().getKey().equals(GameItemsHolder.FALLBACK_ITEM_KEY)) { - inventory.set(i, drop.getItem().toInventoryItem()); - drop.setPickedUp(true); - break; - } - } } private Vector2 getSpawnPoint(GameWorld gameWorld, GameItemsHolder itemsHolder) { @@ -144,7 +124,7 @@ public class Player extends Mob { } public void setCurrentInventorySlotItem(Item item) { - inventory.set(slot, item.toInventoryItem()); + inventory.getItems().set(inventory.getActiveSlot(), item.toInventoryItem()); } @Override @@ -154,9 +134,47 @@ public class Player extends Mob { @Override public void jump() { + if (!canJump()) { + if (gameMode == 1) { + if (isFlyMode()) { + setFlyMode(false); + } else { + getVelocity().y = 0f; + setFlyMode(true); + } + } + return; + } mVelocity.y = JUMP_VELOCITY; } + private boolean checkBlockCanBeHit(Block block) { + return !block.isNone() && block.getParams().getHitPoints() >= 0; + } + + /** + * @return true if any mob fas hit + */ + private boolean hitMobs(GameItemsHolder gameItemsHolder, MobsController mobsController) { + if (!hitting || !hittingWithDamage) { + return false; + } + + boolean result = false; + for (Mob mob : mobsController.getMobs()) { + if (overlaps(mob.getHitBox())) { + final Item activeItem = inventory.getActiveItem().getItem(); + final Item.Tool tool = activeItem.isTool() ? (Item.Tool) activeItem : null; + if (tool != null) { + decreaseCurrentItemCount(gameItemsHolder); + } + result = true; + mob.damage(MathUtils.floor(tool != null ? tool.getMobDamageMultiplier() : 1)); + } + } + return result; + } + private void hitBlock(GameWorld gameWorld, GameItemsHolder gameItemsHolder) { if (!hitting || !hittingWithDamage) { return; @@ -165,15 +183,20 @@ public class Player extends Mob { final Block foregroundBlock = gameWorld.getForeMap(cursorX, cursorY); final Block backgroundBlock = gameWorld.getBackMap(cursorX, cursorY); - if ((!foregroundBlock.isNone() && foregroundBlock.getParams().getHitPoints() >= 0) || - (foregroundBlock.isNone() && !backgroundBlock.isNone() && backgroundBlock.getParams().getHitPoints() >= 0)) { + + if ((checkBlockCanBeHit(foregroundBlock)) || + (foregroundBlock.isNone() && checkBlockCanBeHit(backgroundBlock))) { if (gameMode == 0) { - if (!foregroundBlock.isNone() && blockDamage >= foregroundBlock.getParams().getHitPoints()) { - gameWorld.destroyForeMap(cursorX, cursorY); - blockDamage = 0; - } else if (!backgroundBlock.isNone() && blockDamage >= backgroundBlock.getParams().getHitPoints()) { - gameWorld.destroyBackMap(cursorX, cursorY); - blockDamage = 0; + if (!foregroundBlock.isNone()) { + if (blockDamage >= foregroundBlock.getParams().getHitPoints()) { + gameWorld.destroyForeMap(cursorX, cursorY); + blockDamage = 0; + } + } else if (!backgroundBlock.isNone()) { + if (blockDamage >= backgroundBlock.getParams().getHitPoints()) { + gameWorld.destroyBackMap(cursorX, cursorY); + blockDamage = 0; + } } } else { if (!foregroundBlock.isNone()) { @@ -189,9 +212,14 @@ public class Player extends Mob { } @Override - public void ai(GameWorld gameWorld, GameItemsHolder gameItemsHolder, float delta) { + public void ai(GameWorld gameWorld, GameItemsHolder gameItemsHolder, MobsController mobsController, float delta) { updateAnimation(delta); - hitBlock(gameWorld, gameItemsHolder); + + if (!hitMobs(gameItemsHolder, mobsController)) { + hitBlock(gameWorld, gameItemsHolder); + } else { + stopHitting(); + } if (gameMode == 1) { return; @@ -201,9 +229,9 @@ public class Player extends Mob { final Block backgroundBlock = gameWorld.getBackMap(cursorX, cursorY); @CheckForNull final Block target; - if (!foregroundBlock.isNone() && foregroundBlock.getParams().getHitPoints() >= 0) { + if (checkBlockCanBeHit(foregroundBlock)) { target = foregroundBlock; - } else if (!backgroundBlock.isNone() && backgroundBlock.getParams().getHitPoints() >= 0) { + } else if (checkBlockCanBeHit(backgroundBlock)) { target = backgroundBlock; } else { target = null; @@ -212,7 +240,7 @@ public class Player extends Mob { final boolean canHitBlock = target != null; float multiplier = 1f; - final Item currentItem = inventory.get(slot).getItem(); + final Item currentItem = inventory.getActiveItem().getItem(); if (currentItem instanceof Item.Tool && canHitBlock) { if (target.getParams().getToolType() == currentItem.getClass() && ((Item.Tool)currentItem).getLevel() >= target.getParams().getToolLevel()) { @@ -253,8 +281,22 @@ public class Player extends Mob { super.heal(heal); } + public void checkCursorBounds(GameWorld gameWorld) { + if (gameMode == 0) { + int minCursorX = getMapX() - SURVIVAL_CURSOR_RANGE; + int maxCursorX = getMapX() + SURVIVAL_CURSOR_RANGE; + int minCursorY = getMiddleMapY() - SURVIVAL_CURSOR_RANGE; + int maxCursorY = getMiddleMapY() + SURVIVAL_CURSOR_RANGE; + + cursorX = MathUtils.clamp(cursorX, minCursorX, maxCursorX); + cursorY = MathUtils.clamp(cursorY, minCursorY, maxCursorY); + } + + cursorY = MathUtils.clamp(cursorY, 0, gameWorld.getHeight() - 1); + } + private void drawItem(SpriteBatch spriteBatch, float x, float y, float anim) { - final Item item = inventory(slot); + final Item item = inventory.getActiveItem().getItem(); if (item == null || item.isNone()) { return; @@ -372,6 +414,13 @@ public class Player extends Mob { frontHandAnim = -rightHandAnim; } + backHand.setColor(getTintColor()); + backLeg.setColor(getTintColor()); + frontLeg.setColor(getTintColor()); + head.setColor(getTintColor()); + body.setColor(getTintColor()); + frontHand.setColor(getTintColor()); + SpriteUtilsKt.drawSprite(spriteBatch, backHand, x + 2, y + 8, backHandAnim); if (looksLeft()) { diff --git a/core/src/ru/deadsoftware/cavedroid/game/model/block/Block.kt b/core/src/ru/deadsoftware/cavedroid/game/model/block/Block.kt index 76c6ac5..fa99bfd 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/model/block/Block.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/model/block/Block.kt @@ -20,14 +20,14 @@ sealed class Block { val spriteWidth: Float get() = 16f - params.spriteMargins.left - params.spriteMargins.right val spriteHeight: Float get() = 16f - params.spriteMargins.top - params.spriteMargins.bottom - private var animation: Array? = null + protected var animation: Array? = null private var _sprite: Sprite? = null get() { return animation?.get(currentAnimationFrame) ?: field } - val sprite: Sprite + open val sprite: Sprite get() = requireNotNull(_sprite) { "null sprite for block '${params.key}'" } private val currentAnimationFrame: Int @@ -111,6 +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 @@ -125,6 +140,8 @@ sealed class Block { ) } + sealed class Container() : Block() + data class None( override val params: CommonBlockParams ) : Block() @@ -133,6 +150,41 @@ sealed class Block { override val params: CommonBlockParams, ) : Block() + data class Furnace( + override val params: CommonBlockParams, + ): Container() { + + override val sprite: Sprite + get() = getSprite(false) + + private fun getSprite(isActive: Boolean): Sprite { + return animation?.let { animation -> + if (isActive) { + animation[1] + } else { + animation[0] + } + } ?: sprite + } + + fun draw(spriter: SpriteBatch, x: Float, y: Float, isActive: Boolean) { + getSprite(isActive).apply { + setBounds( + /* x = */ x + params.spriteMargins.left, + /* y = */ y + params.spriteMargins.top, + /* width = */ spriteWidth, + /* height = */ spriteHeight + ) + draw(spriter) + } + } + + } + + data class Chest( + override val params: CommonBlockParams + ): Container() + data class Slab( override val params: CommonBlockParams, val fullBlockKey: String, diff --git a/core/src/ru/deadsoftware/cavedroid/game/model/block/CommonBlockParams.kt b/core/src/ru/deadsoftware/cavedroid/game/model/block/CommonBlockParams.kt index e98f1be..369f752 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/model/block/CommonBlockParams.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/model/block/CommonBlockParams.kt @@ -4,7 +4,6 @@ import com.badlogic.gdx.graphics.Texture import ru.deadsoftware.cavedroid.game.model.item.Item data class CommonBlockParams( - @Deprecated("numeric id's will be removed") val id: Int?, val key: String, val collisionMargins: BlockMargins, val hitPoints: Int, diff --git a/core/src/ru/deadsoftware/cavedroid/game/model/craft/CraftingRecipe.kt b/core/src/ru/deadsoftware/cavedroid/game/model/craft/CraftingRecipe.kt index eebe13f..c8b2a86 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/model/craft/CraftingRecipe.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/model/craft/CraftingRecipe.kt @@ -4,7 +4,7 @@ import ru.deadsoftware.cavedroid.game.model.item.InventoryItem import ru.deadsoftware.cavedroid.game.model.item.Item data class CraftingRecipe( - val input: List, + val input: List, val output: CraftingResult ) diff --git a/core/src/ru/deadsoftware/cavedroid/game/model/dto/BlockDto.kt b/core/src/ru/deadsoftware/cavedroid/game/model/dto/BlockDto.kt index c6065b7..69b1f18 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/model/dto/BlockDto.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/model/dto/BlockDto.kt @@ -5,7 +5,6 @@ import kotlinx.serialization.Serializable @Serializable data class BlockDto( - @Deprecated("numeric ids will be removed") @SerialName("id") val id: Int? = null, @SerialName("left") val left: Int = 0, @SerialName("top") val top: Int = 0, @SerialName("right") val right: Int = 0, diff --git a/core/src/ru/deadsoftware/cavedroid/game/model/dto/ItemDto.kt b/core/src/ru/deadsoftware/cavedroid/game/model/dto/ItemDto.kt index fe28e64..373db46 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/model/dto/ItemDto.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/model/dto/ItemDto.kt @@ -5,7 +5,6 @@ import kotlinx.serialization.Serializable @Serializable data class ItemDto( - @Deprecated("numeric ids will be removed") @SerialName("id") val id: Int? = null, @SerialName("name") val name: String, @SerialName("type") val type: String = "normal", @SerialName("texture") val texture: String, @@ -18,4 +17,7 @@ data class ItemDto( @SerialName("bottom_slab_block") val bottomSlabBlock: String? = null, @SerialName("tool_level") val toolLevel: Int? = null, @SerialName("max_stack") val maxStack: Int = 64, + @SerialName("tint") val tint: String? = null, + @SerialName("burning_time") val burningTime: Long? = null, + @SerialName("smelt_product") val smeltProduct: String? = null, ) diff --git a/core/src/ru/deadsoftware/cavedroid/game/model/item/CommonItemParams.kt b/core/src/ru/deadsoftware/cavedroid/game/model/item/CommonItemParams.kt index 291cfb8..00af08b 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/model/item/CommonItemParams.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/model/item/CommonItemParams.kt @@ -3,9 +3,10 @@ package ru.deadsoftware.cavedroid.game.model.item import ru.deadsoftware.cavedroid.misc.utils.SpriteOrigin data class CommonItemParams( - @Deprecated("numeric id's will be removed") val id: Int?, val key: String, val name: String, val inHandSpriteOrigin: SpriteOrigin, val maxStack: Int, + val burningTimeMs: Long?, + val smeltProductKey: String?, ) \ No newline at end of file diff --git a/core/src/ru/deadsoftware/cavedroid/game/model/item/InventoryItem.kt b/core/src/ru/deadsoftware/cavedroid/game/model/item/InventoryItem.kt index 6c15983..3cd406b 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/model/item/InventoryItem.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/model/item/InventoryItem.kt @@ -9,26 +9,68 @@ import ru.deadsoftware.cavedroid.misc.utils.drawSprite import ru.deadsoftware.cavedroid.misc.utils.drawString import ru.deadsoftware.cavedroid.misc.utils.px import java.io.Serializable +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.contract class InventoryItem @JvmOverloads constructor( val itemKey: String, - var amount: Int = 1, + _amount: Int = 1, ) : Serializable { + var amount = _amount + set(value) { + field = if (value < 0) { + 0 + } else { + value + } + } + @Transient - lateinit var item: Item - private set + private var _item: Item? = null + + var item: Item + get() { + requireNotNull(_item) { "_item is null" } + return _item.takeIf { amount > 0 } ?: throw IllegalArgumentException("Accessing item with zero amount") + } + private set (value) { + _item = value + } @JvmOverloads - constructor(_item: Item, amount: Int = 1) : this(_item.params.key, amount) { - item = _item + constructor(item: Item, amount: Int = 1) : this(item.params.key, amount) { + _item = item } fun init(gameItemsHolder: GameItemsHolder) { - if (this::item.isInitialized) { + if (_item != null) { return } - item = gameItemsHolder.getItem(itemKey) + _item = gameItemsHolder.getItem(itemKey) + } + + @JvmOverloads + fun add(count: Int = 1) { + if (count > 0 && Int.MAX_VALUE - count < amount) { + throw IllegalArgumentException("$amount + $count exceeds Int.MAX_VALUE") + } + + amount += count + } + + @JvmOverloads + fun subtract(count: Int = 1) { + if (count < 0) { + throw IllegalArgumentException("Can't subtract negative amount") + } + + add(-count) + } + + @JvmOverloads + fun canBeAdded(count: Int = 1): Boolean { + return amount + count <= item.params.maxStack } private fun drawAmountText(spriteBatch: SpriteBatch, text: String, x: Float, y: Float) { @@ -58,7 +100,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 @@ -87,4 +131,12 @@ class InventoryItem @JvmOverloads constructor( } } + companion object { + + @OptIn(ExperimentalContracts::class) + fun InventoryItem?.isNoneOrNull(): Boolean { + contract { returns(false) implies(this@isNoneOrNull != null) } + return this?.item == null || this.item.isNone() + } + } } diff --git a/core/src/ru/deadsoftware/cavedroid/game/model/item/Item.kt b/core/src/ru/deadsoftware/cavedroid/game/model/item/Item.kt index 1e6755a..bf2a55c 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/model/item/Item.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/model/item/Item.kt @@ -46,8 +46,8 @@ sealed class Item { } fun isUsable(): Boolean { - contract { returns(true) implies (this@Item is Placeable) } - return this is Placeable + contract { returns(true) implies (this@Item is Usable) } + return this is Usable } @JvmOverloads @@ -66,10 +66,6 @@ sealed class Item { abstract val level: Int } - sealed class Usable : Item() { - abstract val useActionKey: String - } - sealed class Placeable : Item() { abstract val block: BlockModel override val sprite: Sprite get() = block.sprite @@ -82,6 +78,12 @@ sealed class Item { get() = throw IllegalAccessException("Trying to get sprite of None") } + data class Usable( + override val params: CommonItemParams, + override val sprite: Sprite, + val useActionKey: String + ) : Item() + data class Block( override val params: CommonItemParams, override val block: BlockModel @@ -134,11 +136,5 @@ sealed class Item { override val blockDamageMultiplier: Float, override val level: Int, ) : Tool() - - data class Bucket( - override val params: CommonItemParams, - override val sprite: Sprite, - override val useActionKey: String - ) : Usable() } \ No newline at end of file diff --git a/core/src/ru/deadsoftware/cavedroid/game/model/mapper/BlockMapper.kt b/core/src/ru/deadsoftware/cavedroid/game/model/mapper/BlockMapper.kt index 85d8cb7..1b641ed 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/model/mapper/BlockMapper.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/model/mapper/BlockMapper.kt @@ -23,6 +23,8 @@ class BlockMapper @Inject constructor( "water" -> Water(commonBlockParams, requireNotNull(dto.state)) "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) } @@ -30,7 +32,6 @@ class BlockMapper @Inject constructor( private fun mapCommonParams(key: String, dto: BlockDto): CommonBlockParams { return CommonBlockParams( - id = dto.id, key = key, collisionMargins = BlockMargins( left = dto.left, diff --git a/core/src/ru/deadsoftware/cavedroid/game/model/mapper/ItemMapper.kt b/core/src/ru/deadsoftware/cavedroid/game/model/mapper/ItemMapper.kt index b951f26..a0949a0 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/model/mapper/ItemMapper.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/model/mapper/ItemMapper.kt @@ -11,6 +11,7 @@ import ru.deadsoftware.cavedroid.game.model.item.Item.* import ru.deadsoftware.cavedroid.misc.Assets import ru.deadsoftware.cavedroid.misc.utils.AssetLoader import ru.deadsoftware.cavedroid.misc.utils.SpriteOrigin +import ru.deadsoftware.cavedroid.misc.utils.colorFromHexString import javax.inject.Inject @Reusable @@ -23,7 +24,7 @@ class ItemMapper @Inject constructor( return when (dto.type) { "normal" -> Normal(params, requireNotNull(loadSprite(dto))) - "bucket" -> Bucket(params, requireNotNull(loadSprite(dto)), requireNotNull(dto.actionKey)) + "usable" -> Usable(params, requireNotNull(loadSprite(dto)), requireNotNull(dto.actionKey)) "shovel" -> Shovel(params, requireNotNull(loadSprite(dto)), dto.mobDamageMultiplier, dto.blockDamageMultiplier, requireNotNull(dto.toolLevel)) "sword" -> Sword(params, requireNotNull(loadSprite(dto)), dto.mobDamageMultiplier, dto.blockDamageMultiplier, requireNotNull(dto.toolLevel)) "pickaxe" -> Pickaxe(params, requireNotNull(loadSprite(dto)), dto.mobDamageMultiplier, dto.blockDamageMultiplier, requireNotNull(dto.toolLevel)) @@ -38,7 +39,6 @@ class ItemMapper @Inject constructor( private fun mapCommonParams(key: String, dto: ItemDto): CommonItemParams { return CommonItemParams( - id = dto.id, key = key, name = dto.name, inHandSpriteOrigin = SpriteOrigin( @@ -46,6 +46,8 @@ class ItemMapper @Inject constructor( y = dto.origin_y, ), maxStack = dto.maxStack, + burningTimeMs = dto.burningTime, + smeltProductKey = dto.smeltProduct, ) } @@ -56,7 +58,12 @@ class ItemMapper @Inject constructor( val texture = Assets.resolveItemTexture(assetLoader, dto.texture) return Sprite(texture) - .apply { flip(false, true) } + .apply { + flip(false, true) + dto.tint?.let { + color = colorFromHexString(it) + } + } } } \ No newline at end of file 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 index 0000000..be820bc --- /dev/null +++ b/core/src/ru/deadsoftware/cavedroid/game/objects/container/Chest.kt @@ -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 index 0000000..1e13c64 --- /dev/null +++ b/core/src/ru/deadsoftware/cavedroid/game/objects/container/Container.kt @@ -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 + + @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 index 0000000..3facb6f --- /dev/null +++ b/core/src/ru/deadsoftware/cavedroid/game/objects/container/ContainerController.kt @@ -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() + + 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) { + 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 diff --git a/core/src/ru/deadsoftware/cavedroid/game/objects/container/Furnace.kt b/core/src/ru/deadsoftware/cavedroid/game/objects/container/Furnace.kt new file mode 100644 index 0000000..1a75e89 --- /dev/null +++ b/core/src/ru/deadsoftware/cavedroid/game/objects/container/Furnace.kt @@ -0,0 +1,146 @@ +package ru.deadsoftware.cavedroid.game.objects.container + +import com.badlogic.gdx.Gdx +import com.badlogic.gdx.math.MathUtils +import com.badlogic.gdx.utils.TimeUtils +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 + +class Furnace(gameItemsHolder: GameItemsHolder) : Container(SIZE, gameItemsHolder) { + + var fuel: InventoryItem + get() = items[FUEL_INDEX] + set(value) { + items[FUEL_INDEX] = value + } + + var input: InventoryItem + get() = items[INPUT_INDEX] + set(value) { + items[INPUT_INDEX] = value + } + + var result: InventoryItem + get() = items[RESULT_INDEX] + set(value) { + items[RESULT_INDEX] = value + } + + val isActive: Boolean get() = currentFuel != null + + @Transient + var currentFuel: Item? = null + set(value) { + currentFuelKey = value?.params?.key + field = value + } + + var currentFuelKey: String? = null + + private var startBurnTimeMs = 0L + private var smeltStarTimeMs = 0L + + var burnProgress = 0f + private set(value) { + field = MathUtils.clamp(value, 0f, 1f) + } + var smeltProgress = 0f + private set(value) { + field = MathUtils.clamp(value, 0f, 1f) + } + + fun init(gameItemsHolder: GameItemsHolder) { + currentFuel = currentFuelKey?.let { gameItemsHolder.getItem(it) } + 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 && + (!fuel.isNoneOrNull() || burnProgress > 0f) + } + + 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 + } + + override fun update(gameItemsHolder: GameItemsHolder) { + if (currentFuel?.isNone() == true) { + currentFuel = null + } + + currentFuel?.let { curFuel -> + val burningTimeMs = curFuel.params.burningTimeMs ?: run { + Gdx.app.error(TAG, "Burning item has no burning time. Item : ${curFuel.params.key}") + return + } + + if (TimeUtils.timeSinceMillis(startBurnTimeMs).toDouble() / burningTimeMs >= 0.01) { + burnProgress += 0.01f + startBurnTimeMs = TimeUtils.millis() + } + + } + + if (currentFuel?.isNone() == false && burnProgress >= 1f) { + if (canSmelt()) { + startBurning(gameItemsHolder) + } else { + currentFuel = null + burnProgress = 0f + smeltProgress = 0f + } + } + + if (!canSmelt()) { + return + } + if (currentFuel == null && !fuel.isNoneOrNull()) { + startBurning(gameItemsHolder) + smeltStarTimeMs = startBurnTimeMs + smeltProgress = 0f + } + + if ((TimeUtils.timeSinceMillis(smeltStarTimeMs).toDouble() / SMELTING_TIME_MS) >= 0.01) { + smeltProgress += 0.01f + smeltStarTimeMs = TimeUtils.millis() + } + + if (isActive && smeltProgress >= 1f) { + val productKey = requireNotNull(input.item.params.smeltProductKey) + val res = gameItemsHolder.getItem(productKey) + if (result.isNoneOrNull()) { + result = res.toInventoryItem() + } else { + result.add() + } + input.subtract() + if (input.amount <= 0) { + input = gameItemsHolder.fallbackItem.toInventoryItem() + } + smeltStarTimeMs = TimeUtils.millis() + smeltProgress = 0f + } + } + + companion object { + private const val SIZE = 3 + private const val TAG = "Furnace" + + const val FUEL_INDEX = 0 + const val INPUT_INDEX = 1 + const val RESULT_INDEX = 2 + + const val SMELTING_TIME_MS = 10000L + } + +} \ No newline at end of file diff --git a/core/src/ru/deadsoftware/cavedroid/game/objects/Drop.kt b/core/src/ru/deadsoftware/cavedroid/game/objects/drop/Drop.kt similarity index 72% rename from core/src/ru/deadsoftware/cavedroid/game/objects/Drop.kt rename to core/src/ru/deadsoftware/cavedroid/game/objects/drop/Drop.kt index 151e486..edb3c81 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/objects/Drop.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/objects/drop/Drop.kt @@ -1,4 +1,4 @@ -package ru.deadsoftware.cavedroid.game.objects +package ru.deadsoftware.cavedroid.game.objects.drop import com.badlogic.gdx.math.Intersector import com.badlogic.gdx.math.Rectangle @@ -6,16 +6,21 @@ import com.badlogic.gdx.math.Vector2 import ru.deadsoftware.cavedroid.game.GameItemsHolder import ru.deadsoftware.cavedroid.game.model.item.Item -class Drop( +class Drop @JvmOverloads constructor( x: Float, y: Float, _item: Item, + _amount: Int = 1, ) : Rectangle(x, y, DROP_SIZE, DROP_SIZE) { + var amount: Int = _amount + private set + val itemKey = _item.params.key val velocity = getInitialVelocity() var pickedUp = false + @Suppress("UNNECESSARY_LATEINIT") @Transient lateinit var item: Item private set @@ -37,6 +42,15 @@ class Drop( return Intersector.overlaps(magnetArea, rectangle) } + @JvmOverloads + fun subtract(count: Int = 1) { + if (count < 0) { + throw IllegalArgumentException("Can't subtract negative amount") + } + + amount -= count + } + private fun getMagnetArea(): Rectangle { return Rectangle( /* x = */ x - MAGNET_DISTANCE, @@ -47,9 +61,9 @@ class Drop( } companion object { - private const val MAGNET_DISTANCE = 16f + private const val MAGNET_DISTANCE = 8f - const val MAGNET_VELOCITY = 128f + const val MAGNET_VELOCITY = 256f const val DROP_SIZE = 8f private fun getInitialVelocity(): Vector2 = Vector2(0f, -1f) diff --git a/core/src/ru/deadsoftware/cavedroid/game/objects/DropController.java b/core/src/ru/deadsoftware/cavedroid/game/objects/drop/DropController.java similarity index 59% rename from core/src/ru/deadsoftware/cavedroid/game/objects/DropController.java rename to core/src/ru/deadsoftware/cavedroid/game/objects/drop/DropController.java index 798a84c..0213c97 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/objects/DropController.java +++ b/core/src/ru/deadsoftware/cavedroid/game/objects/drop/DropController.java @@ -1,7 +1,9 @@ -package ru.deadsoftware.cavedroid.game.objects; +package ru.deadsoftware.cavedroid.game.objects.drop; +import org.jetbrains.annotations.NotNull; import ru.deadsoftware.cavedroid.game.GameItemsHolder; import ru.deadsoftware.cavedroid.game.GameScope; +import ru.deadsoftware.cavedroid.game.model.item.InventoryItem; import ru.deadsoftware.cavedroid.game.model.item.Item; import javax.inject.Inject; @@ -23,14 +25,24 @@ public class DropController implements Serializable { } public void initDrops(GameItemsHolder gameItemsHolder) { - mDrops.forEach((drop) -> drop.initItem(gameItemsHolder)); + for (Drop drop : mDrops) { + drop.initItem(gameItemsHolder); + } } public void addDrop(float x, float y, Item item) { + addDrop(x, y, item, 1); + } + + public void addDrop(float x, float y, Item item, int count) { if (item.isNone()) { return; } - mDrops.add(new Drop(x, y, item)); + mDrops.add(new Drop(x, y, item, count)); + } + + public void addDrop(float x, float y, @NotNull InventoryItem invItem) { + addDrop(x, y, invItem.getItem(), invItem.getAmount()); } public int getSize() { @@ -38,7 +50,9 @@ public class DropController implements Serializable { } public void forEach(Callback callback) { - mDrops.forEach(callback::run); + for (Drop drop : mDrops) { + callback.run(drop); + } } public Iterator getIterator() { diff --git a/core/src/ru/deadsoftware/cavedroid/game/render/BackgroundBlocksRenderer.kt b/core/src/ru/deadsoftware/cavedroid/game/render/BackgroundBlocksRenderer.kt index aae4f98..0d34540 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/render/BackgroundBlocksRenderer.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/render/BackgroundBlocksRenderer.kt @@ -8,10 +8,12 @@ import com.badlogic.gdx.math.Rectangle import ru.deadsoftware.cavedroid.game.GameScope import ru.deadsoftware.cavedroid.game.mobs.MobsController import ru.deadsoftware.cavedroid.game.world.GameWorld +import ru.deadsoftware.cavedroid.misc.annotations.multibinding.BindRenderer import ru.deadsoftware.cavedroid.misc.utils.forEachBlockInArea import javax.inject.Inject @GameScope +@BindRenderer class BackgroundBlocksRenderer @Inject constructor( gameWorld: GameWorld, mobsController: MobsController diff --git a/core/src/ru/deadsoftware/cavedroid/game/render/BlocksRenderer.kt b/core/src/ru/deadsoftware/cavedroid/game/render/BlocksRenderer.kt index 378ed7b..68af67b 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/render/BlocksRenderer.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/render/BlocksRenderer.kt @@ -2,7 +2,6 @@ package ru.deadsoftware.cavedroid.game.render import com.badlogic.gdx.graphics.g2d.Sprite import com.badlogic.gdx.graphics.g2d.SpriteBatch -import com.badlogic.gdx.graphics.g2d.TextureRegion import com.badlogic.gdx.graphics.glutils.ShapeRenderer import com.badlogic.gdx.math.MathUtils import com.badlogic.gdx.math.Rectangle @@ -87,7 +86,11 @@ abstract class BlocksRenderer( if (foregroundBlock.canSeeThrough && !backgroundBlock.isNone()) { val drawX = x.px - viewport.x val drawY = y.px - viewport.y - backgroundBlock.draw(spriteBatch, drawX, drawY) + if (backgroundBlock is Block.Furnace) { + backgroundBlock.draw(spriteBatch, drawX, drawY, gameWorld.getBackgroundFurnace(x, y)?.isActive ?: false) + } else { + backgroundBlock.draw(spriteBatch, drawX, drawY) + } } } @@ -97,7 +100,12 @@ abstract class BlocksRenderer( if (!foregroundBlock.isNone() && foregroundBlock.params.isBackground == background) { val drawX = x.px - viewport.x val drawY = y.px - viewport.y - foregroundBlock.draw(spriteBatch, drawX, drawY) + + if (foregroundBlock is Block.Furnace) { + foregroundBlock.draw(spriteBatch, drawX, drawY, gameWorld.getForegroundFurnace(x, y)?.isActive ?: false) + } else { + foregroundBlock.draw(spriteBatch, drawX, drawY) + } } } diff --git a/core/src/ru/deadsoftware/cavedroid/game/render/DebugRenderer.kt b/core/src/ru/deadsoftware/cavedroid/game/render/DebugRenderer.kt index 03f6253..0fa2756 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/render/DebugRenderer.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/render/DebugRenderer.kt @@ -10,7 +10,7 @@ import ru.deadsoftware.cavedroid.game.debug.DebugInfoStringsProvider import ru.deadsoftware.cavedroid.game.mobs.MobsController import ru.deadsoftware.cavedroid.game.model.block.Block import ru.deadsoftware.cavedroid.game.world.GameWorld -import ru.deadsoftware.cavedroid.misc.Assets +import ru.deadsoftware.cavedroid.misc.annotations.multibinding.BindRenderer import ru.deadsoftware.cavedroid.misc.utils.bl import ru.deadsoftware.cavedroid.misc.utils.drawString import ru.deadsoftware.cavedroid.misc.utils.forEachBlockInArea @@ -18,6 +18,7 @@ import ru.deadsoftware.cavedroid.misc.utils.px import javax.inject.Inject @GameScope +@BindRenderer class DebugRenderer @Inject constructor( private val mainConfig: MainConfig, private val gameWorld: GameWorld, diff --git a/core/src/ru/deadsoftware/cavedroid/game/render/DropsRenderer.kt b/core/src/ru/deadsoftware/cavedroid/game/render/DropsRenderer.kt index a17bd61..d1fc65a 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/render/DropsRenderer.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/render/DropsRenderer.kt @@ -4,14 +4,16 @@ import com.badlogic.gdx.graphics.g2d.SpriteBatch import com.badlogic.gdx.graphics.glutils.ShapeRenderer import com.badlogic.gdx.math.Rectangle import ru.deadsoftware.cavedroid.game.GameScope -import ru.deadsoftware.cavedroid.game.objects.DropController +import ru.deadsoftware.cavedroid.game.objects.drop.DropController import ru.deadsoftware.cavedroid.game.world.GameWorld +import ru.deadsoftware.cavedroid.misc.annotations.multibinding.BindRenderer import ru.deadsoftware.cavedroid.misc.utils.cycledInsideWorld import ru.deadsoftware.cavedroid.misc.utils.drawSprite import ru.deadsoftware.cavedroid.misc.utils.px import javax.inject.Inject @GameScope +@BindRenderer class DropsRenderer @Inject constructor( private val dropController: DropController, private val gameWorld: GameWorld, diff --git a/core/src/ru/deadsoftware/cavedroid/game/render/ForegroundBlocksRenderer.kt b/core/src/ru/deadsoftware/cavedroid/game/render/ForegroundBlocksRenderer.kt index ef8be71..8353b0b 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/render/ForegroundBlocksRenderer.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/render/ForegroundBlocksRenderer.kt @@ -6,10 +6,12 @@ import com.badlogic.gdx.math.Rectangle import ru.deadsoftware.cavedroid.game.GameScope import ru.deadsoftware.cavedroid.game.mobs.MobsController import ru.deadsoftware.cavedroid.game.world.GameWorld +import ru.deadsoftware.cavedroid.misc.annotations.multibinding.BindRenderer import ru.deadsoftware.cavedroid.misc.utils.forEachBlockInArea import javax.inject.Inject @GameScope +@BindRenderer class ForegroundBlocksRenderer @Inject constructor( gameWorld: GameWorld, mobsController: MobsController diff --git a/core/src/ru/deadsoftware/cavedroid/game/render/HudRenderer.kt b/core/src/ru/deadsoftware/cavedroid/game/render/HudRenderer.kt index b3f8990..b6b22ae 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/render/HudRenderer.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/render/HudRenderer.kt @@ -5,16 +5,22 @@ import com.badlogic.gdx.graphics.glutils.ShapeRenderer import com.badlogic.gdx.math.Rectangle import ru.deadsoftware.cavedroid.game.GameScope import ru.deadsoftware.cavedroid.game.mobs.MobsController -import ru.deadsoftware.cavedroid.game.mobs.Player.ControlMode +import ru.deadsoftware.cavedroid.game.mobs.player.Player +import ru.deadsoftware.cavedroid.game.mobs.player.Player.ControlMode +import ru.deadsoftware.cavedroid.game.ui.TooltipManager import ru.deadsoftware.cavedroid.game.world.GameWorld import ru.deadsoftware.cavedroid.misc.Assets +import ru.deadsoftware.cavedroid.misc.annotations.multibinding.BindRenderer +import ru.deadsoftware.cavedroid.misc.utils.drawString import ru.deadsoftware.cavedroid.misc.utils.px import javax.inject.Inject @GameScope +@BindRenderer class HudRenderer @Inject constructor( private val gameWorld: GameWorld, private val mobsController: MobsController, + private val tooltipManager: TooltipManager, ) : IGameRenderer { override val renderLayer = RENDER_LAYER @@ -23,6 +29,7 @@ class HudRenderer @Inject constructor( private val hotbarTexture get() = requireNotNull(Assets.textureRegions[HOTBAR_KEY]) private val hotbarSelectorTexture get() = requireNotNull(Assets.textureRegions[HOTBAR_SELECTOR_KEY]) private val wholeHeartTexture get() = requireNotNull(Assets.textureRegions[WHOLE_HEART_KEY]) + private val emptyHeartTexture get() = requireNotNull(Assets.textureRegions[EMPTY_HEART_KEY]) private val halfHeartTexture get() = requireNotNull(Assets.textureRegions[HALF_HEART_KEY]) private fun drawCursor(spriteBatch: SpriteBatch, viewport: Rectangle) { @@ -45,19 +52,29 @@ class HudRenderer @Inject constructor( } val wholeHeart = wholeHeartTexture + val halfHeart = halfHeartTexture + val emptyHeart = emptyHeartTexture + + val totalHearts = Player.MAX_HEALTH / 2 val wholeHearts = player.health / 2 - for (i in 0.. if (item.item.isNone()) { return@forEachIndexed @@ -77,7 +94,7 @@ class HudRenderer @Inject constructor( spriteBatch.draw( /* region = */ hotbarSelectorTexture, /* x = */ hotbarX - HotbarSelectorConfig.horizontalPadding - + mobsController.player.slot * (HotbarConfig.itemSeparatorWidth + HotbarConfig.itemSlotSpace), + + mobsController.player.inventory.activeSlot * (HotbarConfig.itemSeparatorWidth + HotbarConfig.itemSlotSpace), /* y = */ -HotbarSelectorConfig.verticalPadding ) } @@ -90,6 +107,15 @@ class HudRenderer @Inject constructor( drawHealth(spriteBatch, hotbarX, hotbarTexture.regionHeight.toFloat()) drawHotbarSelector(spriteBatch, hotbarX) drawHotbarItems(spriteBatch, shapeRenderer, hotbarX) + + val tooltip = tooltipManager.currentHotbarTooltip + if (tooltip.isNotBlank()) { + spriteBatch.drawString( + str = tooltip, + x = viewport.width / 2 - Assets.getStringWidth(tooltip) / 2, + y = hotbarTexture.regionHeight.toFloat() + ) + } } override fun draw(spriteBatch: SpriteBatch, shapeRenderer: ShapeRenderer, viewport: Rectangle, delta: Float) { @@ -105,6 +131,7 @@ class HudRenderer @Inject constructor( private const val HOTBAR_SELECTOR_KEY = "hotbar_selector" private const val WHOLE_HEART_KEY = "heart_whole" private const val HALF_HEART_KEY = "heart_half" + private const val EMPTY_HEART_KEY = "heart_empty" private data object HotbarConfig { const val horizontalMargin = 3f diff --git a/core/src/ru/deadsoftware/cavedroid/game/render/MobsRenderer.kt b/core/src/ru/deadsoftware/cavedroid/game/render/MobsRenderer.kt index 6d388bb..52ac971 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/render/MobsRenderer.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/render/MobsRenderer.kt @@ -7,11 +7,13 @@ 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.world.GameWorld +import ru.deadsoftware.cavedroid.misc.annotations.multibinding.BindRenderer import ru.deadsoftware.cavedroid.misc.utils.cycledInsideWorld import ru.deadsoftware.cavedroid.misc.utils.px import javax.inject.Inject @GameScope +@BindRenderer class MobsRenderer @Inject constructor( private val mobsController: MobsController, private val gameWorld: GameWorld, diff --git a/core/src/ru/deadsoftware/cavedroid/game/render/RenderModule.kt b/core/src/ru/deadsoftware/cavedroid/game/render/RenderModule.kt deleted file mode 100644 index 9ae3b46..0000000 --- a/core/src/ru/deadsoftware/cavedroid/game/render/RenderModule.kt +++ /dev/null @@ -1,59 +0,0 @@ -package ru.deadsoftware.cavedroid.game.render - -import dagger.Binds -import dagger.Module -import dagger.multibindings.IntoSet -import ru.deadsoftware.cavedroid.game.GameScope - -@Module -object RenderModule { - - @Binds - @IntoSet - @GameScope - fun bindBackGroundBlocksRenderer(renderer: BackgroundBlocksRenderer): IGameRenderer = renderer - - @Binds - @IntoSet - @GameScope - fun bindForegroundBlocksRenderer(renderer: ForegroundBlocksRenderer): IGameRenderer = renderer - - @Binds - @IntoSet - @GameScope - fun bindMobsRenderer(renderer: MobsRenderer): IGameRenderer = renderer - - @Binds - @IntoSet - @GameScope - fun bindDropsRenderer(renderer: DropsRenderer): IGameRenderer = renderer - - @Binds - @IntoSet - @GameScope - fun bindHudRenderer(renderer: HudRenderer): IGameRenderer = renderer - - @Binds - @IntoSet - @GameScope - fun bindWindowsRenderer(renderer: WindowsRenderer): IGameRenderer = renderer - - @Binds - @IntoSet - @GameScope - fun bindTouchControlsRenderer(renderer: TouchControlsRenderer): IGameRenderer = renderer - - @Binds - @IntoSet - @GameScope - fun bindDebugRenderer(renderer: DebugRenderer): IGameRenderer = renderer - -// @Provides -// @GameScope -// fun provideGameRenderers(renderers: Set<@JvmSuppressWildcards IGameRenderer>): List { -// return renderers.asSequence() -// .sortedWith(Comparator.comparingInt(IGameRenderer::renderLayer)) -// .toList() -// } - -} diff --git a/core/src/ru/deadsoftware/cavedroid/game/render/TouchControlsRenderer.kt b/core/src/ru/deadsoftware/cavedroid/game/render/TouchControlsRenderer.kt index 5c95d69..f2198aa 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/render/TouchControlsRenderer.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/render/TouchControlsRenderer.kt @@ -6,15 +6,19 @@ import com.badlogic.gdx.math.Rectangle import ru.deadsoftware.cavedroid.MainConfig import ru.deadsoftware.cavedroid.game.GameScope import ru.deadsoftware.cavedroid.game.GameUiWindow +import ru.deadsoftware.cavedroid.game.input.Joystick import ru.deadsoftware.cavedroid.game.mobs.MobsController -import ru.deadsoftware.cavedroid.game.mobs.Player.ControlMode -import ru.deadsoftware.cavedroid.game.windows.GameWindowsManager +import ru.deadsoftware.cavedroid.game.mobs.player.Player.ControlMode +import ru.deadsoftware.cavedroid.game.ui.windows.GameWindowsManager import ru.deadsoftware.cavedroid.misc.Assets +import ru.deadsoftware.cavedroid.misc.annotations.multibinding.BindRenderer import ru.deadsoftware.cavedroid.misc.utils.ArrayMapExtensions.component1 import ru.deadsoftware.cavedroid.misc.utils.ArrayMapExtensions.component2 +import ru.deadsoftware.cavedroid.misc.utils.drawSprite import javax.inject.Inject @GameScope +@BindRenderer class TouchControlsRenderer @Inject constructor( private val mainConfig: MainConfig, private val mobsController: MobsController, @@ -25,6 +29,26 @@ class TouchControlsRenderer @Inject constructor( private val shadeTexture get() = Assets.textureRegions[SHADE_KEY] + private fun drawJoystick(spriteBatch: SpriteBatch) { + val joystick = mainConfig.joystick?.takeIf { it.active } ?: return + + spriteBatch.drawSprite( + sprite = Assets.joyBackground, + x = joystick.centerX - Joystick.RADIUS, + y = joystick.centerY - Joystick.RADIUS, + width = Joystick.SIZE, + height = Joystick.SIZE + ) + + spriteBatch.drawSprite( + sprite = Assets.joyStick, + x = joystick.activeX - Joystick.STICK_SIZE / 2, + y = joystick.activeY - Joystick.STICK_SIZE / 2, + width = Joystick.STICK_SIZE, + height = Joystick.STICK_SIZE + ) + } + override fun draw(spriteBatch: SpriteBatch, shapeRenderer: ShapeRenderer, viewport: Rectangle, delta: Float) { if (!mainConfig.isTouch || gameWindowsManager.getCurrentWindow() != GameUiWindow.NONE) { return @@ -48,6 +72,8 @@ class TouchControlsRenderer @Inject constructor( val altKeyRect = touchControlsMap.get("alt").rect spriteBatch.draw(shadeTexture, altKeyRect.x, altKeyRect.y, altKeyRect.width, altKeyRect.height) } + + drawJoystick(spriteBatch) } companion object { diff --git a/core/src/ru/deadsoftware/cavedroid/game/render/WindowsRenderer.kt b/core/src/ru/deadsoftware/cavedroid/game/render/WindowsRenderer.kt index 2fa093f..945bb1e 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/render/WindowsRenderer.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/render/WindowsRenderer.kt @@ -6,18 +6,20 @@ 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.SurvivalWindowRenderer -import ru.deadsoftware.cavedroid.game.windows.GameWindowsManager +import ru.deadsoftware.cavedroid.game.render.windows.* +import ru.deadsoftware.cavedroid.game.ui.windows.GameWindowsManager +import ru.deadsoftware.cavedroid.misc.annotations.multibinding.BindRenderer import javax.inject.Inject @GameScope +@BindRenderer class WindowsRenderer @Inject constructor( private val creativeWindowRenderer: CreativeWindowRenderer, private val survivalWindowRenderer: SurvivalWindowRenderer, private val craftingWindowRenderer: CraftingWindowRenderer, private val gameWindowsManager: GameWindowsManager, + private val furnaceWindowRenderer: FurnaceWindowRenderer, + private val chestWindowRenderer: ChestWindowRenderer, ) : IGameRenderer { override val renderLayer get() = RENDER_LAYER @@ -27,6 +29,8 @@ class WindowsRenderer @Inject constructor( GameUiWindow.CREATIVE_INVENTORY -> creativeWindowRenderer.draw(spriteBatch, shapeRenderer, viewport, delta) 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 index 0000000..78178bc --- /dev/null +++ b/core/src/ru/deadsoftware/cavedroid/game/render/windows/ChestWindowRenderer.kt @@ -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 diff --git a/core/src/ru/deadsoftware/cavedroid/game/render/windows/CraftingWindowRenderer.kt b/core/src/ru/deadsoftware/cavedroid/game/render/windows/CraftingWindowRenderer.kt index 3b08ed7..6772282 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/render/windows/CraftingWindowRenderer.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/render/windows/CraftingWindowRenderer.kt @@ -10,9 +10,9 @@ import ru.deadsoftware.cavedroid.game.GameScope 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.windows.GameWindowsConfigs -import ru.deadsoftware.cavedroid.game.windows.GameWindowsManager -import ru.deadsoftware.cavedroid.game.windows.inventory.CraftingInventoryWindow +import ru.deadsoftware.cavedroid.game.ui.windows.GameWindowsConfigs +import ru.deadsoftware.cavedroid.game.ui.windows.GameWindowsManager +import ru.deadsoftware.cavedroid.game.ui.windows.inventory.CraftingInventoryWindow import ru.deadsoftware.cavedroid.misc.Assets import javax.inject.Inject @@ -42,7 +42,7 @@ class CraftingWindowRenderer @Inject constructor( shapeRenderer = shapeRenderer, gridX = windowX + GameWindowsConfigs.Crafting.itemsGridMarginLeft, gridY = windowY + GameWindowsConfigs.Crafting.itemsGridMarginTop, - items = mobsController.player.inventory.asSequence() + items = mobsController.player.inventory.items.asSequence() .drop(GameWindowsConfigs.Crafting.hotbarCells) .take(GameWindowsConfigs.Crafting.itemsInCol * GameWindowsConfigs.Crafting.itemsInRow) .asIterable(), @@ -56,7 +56,7 @@ class CraftingWindowRenderer @Inject constructor( shapeRenderer = shapeRenderer, gridX = windowX + GameWindowsConfigs.Crafting.itemsGridMarginLeft, gridY = windowY + windowTexture.regionHeight - GameWindowsConfigs.Crafting.hotbarOffsetFromBottom, - items = mobsController.player.inventory.asSequence() + items = mobsController.player.inventory.items.asSequence() .take(GameWindowsConfigs.Crafting.hotbarCells) .asIterable(), itemsInRow = GameWindowsConfigs.Crafting.hotbarCells, diff --git a/core/src/ru/deadsoftware/cavedroid/game/render/windows/CreativeWindowRenderer.kt b/core/src/ru/deadsoftware/cavedroid/game/render/windows/CreativeWindowRenderer.kt index 4c43600..6bfac42 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/render/windows/CreativeWindowRenderer.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/render/windows/CreativeWindowRenderer.kt @@ -6,11 +6,11 @@ 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.windows.GameWindowsManager +import ru.deadsoftware.cavedroid.game.ui.windows.GameWindowsManager 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.windows.GameWindowsConfigs +import ru.deadsoftware.cavedroid.game.ui.windows.GameWindowsConfigs import ru.deadsoftware.cavedroid.misc.Assets import javax.inject.Inject import kotlin.math.min @@ -69,7 +69,7 @@ class CreativeWindowRenderer @Inject constructor( shapeRenderer = shapeRenderer, gridX = windowX + GameWindowsConfigs.Creative.itemsGridMarginLeft, gridY = windowY + creativeWindow.regionHeight - GameWindowsConfigs.Creative.playerInventoryOffsetFromBottom, - items = mobsController.player.inventory.asSequence().take(GameWindowsConfigs.Creative.invItems).asIterable(), + items = mobsController.player.inventory.items.asSequence().take(GameWindowsConfigs.Creative.invItems).asIterable(), itemsInRow = GameWindowsConfigs.Creative.invItems, cellWidth = GameWindowsConfigs.Creative.itemsGridColWidth, cellHeight = GameWindowsConfigs.Creative.itemsGridRowHeight, diff --git a/core/src/ru/deadsoftware/cavedroid/game/render/windows/FurnaceWindowRenderer.kt b/core/src/ru/deadsoftware/cavedroid/game/render/windows/FurnaceWindowRenderer.kt new file mode 100644 index 0000000..3037009 --- /dev/null +++ b/core/src/ru/deadsoftware/cavedroid/game/render/windows/FurnaceWindowRenderer.kt @@ -0,0 +1,137 @@ +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.Rectangle +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.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.FurnaceInventoryWindow +import ru.deadsoftware.cavedroid.misc.Assets +import ru.deadsoftware.cavedroid.misc.utils.drawSprite +import ru.deadsoftware.cavedroid.misc.utils.withScissors +import javax.inject.Inject + +@GameScope +class FurnaceWindowRenderer @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 furnaceWindowTexture get() = requireNotNull(Assets.textureRegions[FURNACE_WINDOW_KEY]) + + + override fun draw(spriteBatch: SpriteBatch, shapeRenderer: ShapeRenderer, viewport: Rectangle, delta: Float) { + val windowTexture = furnaceWindowTexture + + val window = gameWindowsManager.currentWindow as FurnaceInventoryWindow + + 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.Furnace.itemsGridMarginLeft, + gridY = windowY + GameWindowsConfigs.Furnace.itemsGridMarginTop, + items = mobsController.player.inventory.items.asSequence() + .drop(GameWindowsConfigs.Furnace.hotbarCells) + .take(GameWindowsConfigs.Furnace.itemsInCol * GameWindowsConfigs.Furnace.itemsInRow) + .asIterable(), + itemsInRow = GameWindowsConfigs.Furnace.itemsInRow, + cellWidth = GameWindowsConfigs.Furnace.itemsGridColWidth, + cellHeight = GameWindowsConfigs.Furnace.itemsGridRowHeight, + ) + + drawItemsGrid( + spriteBatch = spriteBatch, + shapeRenderer = shapeRenderer, + gridX = windowX + GameWindowsConfigs.Furnace.itemsGridMarginLeft, + gridY = windowY + windowTexture.regionHeight - GameWindowsConfigs.Furnace.hotbarOffsetFromBottom, + items = mobsController.player.inventory.items.asSequence() + .take(GameWindowsConfigs.Furnace.hotbarCells) + .asIterable(), + itemsInRow = GameWindowsConfigs.Furnace.hotbarCells, + cellWidth = GameWindowsConfigs.Furnace.itemsGridColWidth, + cellHeight = GameWindowsConfigs.Furnace.itemsGridRowHeight, + ) + + window.furnace.fuel?.draw( + spriteBatch = spriteBatch, + shapeRenderer = shapeRenderer, + x = windowX + GameWindowsConfigs.Furnace.smeltFuelMarginLeft, + y = windowY + GameWindowsConfigs.Furnace.smeltFuelMarginTop + ) + + window.furnace.input?.draw( + spriteBatch = spriteBatch, + shapeRenderer = shapeRenderer, + x = windowX + GameWindowsConfigs.Furnace.smeltInputMarginLeft, + y = windowY + GameWindowsConfigs.Furnace.smeltInputMarginTop + ) + + window.furnace.result?.draw( + spriteBatch = spriteBatch, + shapeRenderer = shapeRenderer, + x = windowX + GameWindowsConfigs.Furnace.smeltResultOffsetX, + y = windowY + GameWindowsConfigs.Furnace.smeltResultOffsetY + ) + + if (window.furnace.isActive) { + val burn = GameWindowsConfigs.Furnace.fuelBurnHeight * window.furnace.burnProgress + + spriteBatch.withScissors( + mainConfig = mainConfig, + x = windowX + GameWindowsConfigs.Furnace.fuelBurnMarginLeft, + y = windowY + GameWindowsConfigs.Furnace.fuelBurnMarginTop + burn, + width = Assets.furnaceBurn.width, + height = GameWindowsConfigs.Furnace.fuelBurnHeight, + ) { + spriteBatch.drawSprite( + sprite = Assets.furnaceBurn, + x = windowX + GameWindowsConfigs.Furnace.fuelBurnMarginLeft, + y = windowY + GameWindowsConfigs.Furnace.fuelBurnMarginTop + ) + } + + if (window.furnace.canSmelt()) { + val progress = GameWindowsConfigs.Furnace.progressWidth * window.furnace.smeltProgress + + spriteBatch.withScissors( + mainConfig = mainConfig, + x = windowX + GameWindowsConfigs.Furnace.progressMarginLeft, + y = windowY + GameWindowsConfigs.Furnace.progressMarginTop, + width = progress, + height = Assets.furnaceProgress.height + ) { + spriteBatch.drawSprite( + sprite = Assets.furnaceProgress, + x = windowX + GameWindowsConfigs.Furnace.progressMarginLeft, + y = windowY + GameWindowsConfigs.Furnace.progressMarginTop, + ) + } + } + } + + 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 FURNACE_WINDOW_KEY = "furnace" + } +} \ No newline at end of file diff --git a/core/src/ru/deadsoftware/cavedroid/game/render/windows/SurvivalWindowRenderer.kt b/core/src/ru/deadsoftware/cavedroid/game/render/windows/SurvivalWindowRenderer.kt index 56df2ca..7ee3b27 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/render/windows/SurvivalWindowRenderer.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/render/windows/SurvivalWindowRenderer.kt @@ -12,9 +12,9 @@ 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.windows.GameWindowsConfigs -import ru.deadsoftware.cavedroid.game.windows.GameWindowsManager -import ru.deadsoftware.cavedroid.game.windows.inventory.SurvivalInventoryWindow +import ru.deadsoftware.cavedroid.game.ui.windows.GameWindowsConfigs +import ru.deadsoftware.cavedroid.game.ui.windows.GameWindowsManager +import ru.deadsoftware.cavedroid.game.ui.windows.inventory.SurvivalInventoryWindow import ru.deadsoftware.cavedroid.misc.Assets import javax.inject.Inject import kotlin.math.atan @@ -78,7 +78,7 @@ class SurvivalWindowRenderer @Inject constructor( shapeRenderer = shapeRenderer, gridX = windowX + GameWindowsConfigs.Survival.itemsGridMarginLeft, gridY = windowY + GameWindowsConfigs.Survival.itemsGridMarginTop, - items = mobsController.player.inventory.asSequence() + items = mobsController.player.inventory.items.asSequence() .drop(GameWindowsConfigs.Survival.hotbarCells) .take(GameWindowsConfigs.Survival.itemsInCol * GameWindowsConfigs.Survival.itemsInRow) .asIterable(), @@ -92,7 +92,7 @@ class SurvivalWindowRenderer @Inject constructor( shapeRenderer = shapeRenderer, gridX = windowX + GameWindowsConfigs.Survival.itemsGridMarginLeft, gridY = windowY + windowTexture.regionHeight - GameWindowsConfigs.Survival.hotbarOffsetFromBottom, - items = mobsController.player.inventory.asSequence() + items = mobsController.player.inventory.items.asSequence() .take(GameWindowsConfigs.Survival.hotbarCells) .asIterable(), itemsInRow = GameWindowsConfigs.Survival.hotbarCells, diff --git a/core/src/ru/deadsoftware/cavedroid/game/ui/TooltipManager.kt b/core/src/ru/deadsoftware/cavedroid/game/ui/TooltipManager.kt new file mode 100644 index 0000000..a8f5a9b --- /dev/null +++ b/core/src/ru/deadsoftware/cavedroid/game/ui/TooltipManager.kt @@ -0,0 +1,41 @@ +package ru.deadsoftware.cavedroid.game.ui + +import com.badlogic.gdx.utils.Timer +import ru.deadsoftware.cavedroid.MainConfig +import ru.deadsoftware.cavedroid.game.GameScope +import javax.inject.Inject + +@GameScope +class TooltipManager @Inject constructor( + private val mainConfig: MainConfig +) { + + private val resetTask = object : Timer.Task() { + override fun run() { + currentHotbarTooltip = "" + } + } + + var currentHotbarTooltip: String = "" + private set + + var currentMouseTooltip: String = "" + private set + + fun showHotbarTooltip(tooltip: String) { + currentHotbarTooltip = tooltip + if (resetTask.isScheduled) { + resetTask.cancel() + } + Timer.schedule(resetTask, TOOLTIP_TIME_S) + } + + fun showMouseTooltip(tooltip: String) { + currentMouseTooltip = tooltip + } + + companion object { + private const val TOOLTIP_TIME_S = 2f + } + +} \ No newline at end of file diff --git a/core/src/ru/deadsoftware/cavedroid/game/windows/GameWindowsConfigs.kt b/core/src/ru/deadsoftware/cavedroid/game/ui/windows/GameWindowsConfigs.kt similarity index 55% rename from core/src/ru/deadsoftware/cavedroid/game/windows/GameWindowsConfigs.kt rename to core/src/ru/deadsoftware/cavedroid/game/ui/windows/GameWindowsConfigs.kt index a6cff63..2f1d264 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/windows/GameWindowsConfigs.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/ui/windows/GameWindowsConfigs.kt @@ -1,4 +1,4 @@ -package ru.deadsoftware.cavedroid.game.windows +package ru.deadsoftware.cavedroid.game.ui.windows object GameWindowsConfigs { data object Creative { @@ -67,7 +67,58 @@ object GameWindowsConfigs { const val craftOffsetX = 30f const val craftOffsetY = 18f - const val craftResultOffsetX = 128f + const val craftResultOffsetX = 124f const val craftResultOffsetY = 36f } + + data object Furnace { + const val itemsGridMarginLeft = 8f + const val itemsGridMarginTop = 84f + + const val itemsGridRowHeight = 18f + const val itemsGridColWidth = 18f + + const val itemsInRow = 9 + const val itemsInCol = 5 + + const val hotbarOffsetFromBottom = 24f + const val hotbarCells = 9 + + const val smeltInputMarginLeft = 56f + const val smeltInputMarginTop = 18f + + const val smeltFuelMarginLeft = 56f + const val smeltFuelMarginTop = 54f + + const val smeltResultOffsetX = 116f + const val smeltResultOffsetY = 36f + + const val fuelBurnMarginLeft = 56f + const val fuelBurnMarginTop = 36f + const val fuelBurnHeight = 14f + + const val progressMarginLeft = 79f + 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 diff --git a/core/src/ru/deadsoftware/cavedroid/game/ui/windows/GameWindowsManager.kt b/core/src/ru/deadsoftware/cavedroid/game/ui/windows/GameWindowsManager.kt new file mode 100644 index 0000000..8d32f94 --- /dev/null +++ b/core/src/ru/deadsoftware/cavedroid/game/ui/windows/GameWindowsManager.kt @@ -0,0 +1,63 @@ +package ru.deadsoftware.cavedroid.game.ui.windows + +import ru.deadsoftware.cavedroid.game.GameItemsHolder +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.container.Furnace +import ru.deadsoftware.cavedroid.game.ui.TooltipManager +import ru.deadsoftware.cavedroid.game.ui.windows.inventory.* +import javax.inject.Inject + +@GameScope +class GameWindowsManager @Inject constructor( + private val tooltipManager: TooltipManager, + private val mobsController: MobsController, + private val dropController: DropController, + private val gameItemsHolder: GameItemsHolder, +) { + + var creativeScrollAmount = 0 + var isDragging = false + + var currentWindow: AbstractInventoryWindow? = null + + @JvmName("getCurrentWindowType") + fun getCurrentWindow(): GameUiWindow { + return currentWindow?.type ?: GameUiWindow.NONE + } + + fun openInventory() { + if (mobsController.player.gameMode == 1) { + currentWindow = CreativeInventoryWindow() + } else { + currentWindow = SurvivalInventoryWindow(gameItemsHolder) + } + } + + fun openFurnace(furnace: Furnace) { + currentWindow = FurnaceInventoryWindow(furnace) + } + + fun openChest(chest: Chest) { + currentWindow = ChestInventoryWindow(chest) + } + + fun openCrafting() { + currentWindow = CraftingInventoryWindow(gameItemsHolder) + } + + fun closeWindow() { + (currentWindow as? AbstractInventoryWindowWithCraftGrid)?.let { window -> + window.craftingItems.forEach { item -> + dropController.addDrop(mobsController.player.x, mobsController.player.y, item) + } + } + + currentWindow = null + tooltipManager.showMouseTooltip("") + } + +} \ No newline at end of file diff --git a/core/src/ru/deadsoftware/cavedroid/game/ui/windows/inventory/AbstractInventoryWindow.kt b/core/src/ru/deadsoftware/cavedroid/game/ui/windows/inventory/AbstractInventoryWindow.kt new file mode 100644 index 0000000..ed15bac --- /dev/null +++ b/core/src/ru/deadsoftware/cavedroid/game/ui/windows/inventory/AbstractInventoryWindow.kt @@ -0,0 +1,81 @@ +package ru.deadsoftware.cavedroid.game.ui.windows.inventory + +import com.badlogic.gdx.math.MathUtils +import ru.deadsoftware.cavedroid.game.GameItemsHolder +import ru.deadsoftware.cavedroid.game.GameUiWindow +import ru.deadsoftware.cavedroid.game.model.item.InventoryItem +import ru.deadsoftware.cavedroid.game.model.item.InventoryItem.Companion.isNoneOrNull + +abstract class AbstractInventoryWindow { + + abstract val type: GameUiWindow + + abstract var selectedItem: InventoryItem? + + var selectItemPointer: Int = -1 + + fun onLeftCLick( + items: MutableList, + gameItemsHolder: GameItemsHolder, + index: Int, + pointer: Int = -1 + ) { + if (selectedItem != null && + selectedItem?.item?.isNone() != true && + pointer >= 0 && selectItemPointer >= 0 && + pointer != selectItemPointer + ) { + return + } + + val clickedItem = items[index] + + selectedItem?.let { selectedItem -> + if (!clickedItem.isNoneOrNull() && items[index].item == selectedItem.item && + items[index].amount + selectedItem.amount <= selectedItem.item.params.maxStack + ) { + items[index].amount += selectedItem.amount + this@AbstractInventoryWindow.selectedItem = null + selectItemPointer = -1 + return + } + } + + val item = items[index] + items[index] = selectedItem ?: gameItemsHolder.fallbackItem.toInventoryItem() + selectedItem = item + selectItemPointer = pointer + } + + fun onRightClick(items: MutableList, gameItemsHolder: GameItemsHolder, index: Int) { + val clickedItem = items[index] + val selectedItem = selectedItem + + if (selectedItem.isNoneOrNull() && !clickedItem.isNoneOrNull()) { + val half = InventoryItem(clickedItem.item, MathUtils.ceil(clickedItem.amount.toFloat() / 2f)) + this.selectedItem = half + clickedItem.subtract(half.amount) + if (clickedItem.amount == 0) { + items[index] = gameItemsHolder.fallbackItem.toInventoryItem() + } + return + } + + if (selectedItem == null || + (!clickedItem.isNoneOrNull() && selectedItem.item != clickedItem.item) || + !clickedItem.canBeAdded()) { + return + } + + val newItem = selectedItem.item.toInventoryItem( + (clickedItem.takeIf { !it.item.isNone() }?.amount ?: 0) + 1 + ) + items[index] = newItem + selectedItem.amount-- + + if (selectedItem.amount <= 0) { + this@AbstractInventoryWindow.selectedItem = null + } + } + +} \ No newline at end of file diff --git a/core/src/ru/deadsoftware/cavedroid/game/ui/windows/inventory/AbstractInventoryWindowWithCraftGrid.kt b/core/src/ru/deadsoftware/cavedroid/game/ui/windows/inventory/AbstractInventoryWindowWithCraftGrid.kt new file mode 100644 index 0000000..066ca37 --- /dev/null +++ b/core/src/ru/deadsoftware/cavedroid/game/ui/windows/inventory/AbstractInventoryWindowWithCraftGrid.kt @@ -0,0 +1,24 @@ +package ru.deadsoftware.cavedroid.game.ui.windows.inventory + +import ru.deadsoftware.cavedroid.game.GameItemsHolder +import ru.deadsoftware.cavedroid.game.model.item.InventoryItem + +abstract class AbstractInventoryWindowWithCraftGrid( + gameItemsHolder: GameItemsHolder, +) : AbstractInventoryWindow() { + + private val _items = Array(10) { gameItemsHolder.fallbackItem.toInventoryItem() } + + val items get() = _items.asList() + + val craftingItems get() = items.subList(0, 9) as MutableList + + val craftResultList get() = items.subList(9, 10) as MutableList + + var craftResult: InventoryItem + get() = craftResultList[0] + set(value) { + craftResultList[0] = value + } + +} \ No newline at end of file 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 index 0000000..6f4a4fe --- /dev/null +++ b/core/src/ru/deadsoftware/cavedroid/game/ui/windows/inventory/ChestInventoryWindow.kt @@ -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 diff --git a/core/src/ru/deadsoftware/cavedroid/game/ui/windows/inventory/CraftingInventoryWindow.kt b/core/src/ru/deadsoftware/cavedroid/game/ui/windows/inventory/CraftingInventoryWindow.kt new file mode 100644 index 0000000..cd7c0ff --- /dev/null +++ b/core/src/ru/deadsoftware/cavedroid/game/ui/windows/inventory/CraftingInventoryWindow.kt @@ -0,0 +1,14 @@ +package ru.deadsoftware.cavedroid.game.ui.windows.inventory + +import ru.deadsoftware.cavedroid.game.GameItemsHolder +import ru.deadsoftware.cavedroid.game.GameUiWindow +import ru.deadsoftware.cavedroid.game.model.item.InventoryItem + +class CraftingInventoryWindow( + gameItemsHolder: GameItemsHolder +) : AbstractInventoryWindowWithCraftGrid(gameItemsHolder) { + + override val type = GameUiWindow.CRAFTING_TABLE + + override var selectedItem: InventoryItem? = null +} \ No newline at end of file diff --git a/core/src/ru/deadsoftware/cavedroid/game/ui/windows/inventory/CreativeInventoryWindow.kt b/core/src/ru/deadsoftware/cavedroid/game/ui/windows/inventory/CreativeInventoryWindow.kt new file mode 100644 index 0000000..a38fd29 --- /dev/null +++ b/core/src/ru/deadsoftware/cavedroid/game/ui/windows/inventory/CreativeInventoryWindow.kt @@ -0,0 +1,11 @@ +package ru.deadsoftware.cavedroid.game.ui.windows.inventory + +import ru.deadsoftware.cavedroid.game.GameUiWindow +import ru.deadsoftware.cavedroid.game.model.item.InventoryItem + +class CreativeInventoryWindow() : AbstractInventoryWindow() { + + override val type = GameUiWindow.CREATIVE_INVENTORY + + override var selectedItem: InventoryItem? = null +} \ No newline at end of file diff --git a/core/src/ru/deadsoftware/cavedroid/game/ui/windows/inventory/FurnaceInventoryWindow.kt b/core/src/ru/deadsoftware/cavedroid/game/ui/windows/inventory/FurnaceInventoryWindow.kt new file mode 100644 index 0000000..42f7038 --- /dev/null +++ b/core/src/ru/deadsoftware/cavedroid/game/ui/windows/inventory/FurnaceInventoryWindow.kt @@ -0,0 +1,15 @@ +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.Furnace + +class FurnaceInventoryWindow( + val furnace: Furnace, +) : AbstractInventoryWindow() { + + override val type = GameUiWindow.FURNACE + + override var selectedItem: InventoryItem? = null + +} \ No newline at end of file diff --git a/core/src/ru/deadsoftware/cavedroid/game/ui/windows/inventory/SurvivalInventoryWindow.kt b/core/src/ru/deadsoftware/cavedroid/game/ui/windows/inventory/SurvivalInventoryWindow.kt new file mode 100644 index 0000000..ce250fc --- /dev/null +++ b/core/src/ru/deadsoftware/cavedroid/game/ui/windows/inventory/SurvivalInventoryWindow.kt @@ -0,0 +1,14 @@ +package ru.deadsoftware.cavedroid.game.ui.windows.inventory + +import ru.deadsoftware.cavedroid.game.GameItemsHolder +import ru.deadsoftware.cavedroid.game.GameUiWindow +import ru.deadsoftware.cavedroid.game.model.item.InventoryItem + +class SurvivalInventoryWindow( + gameItemsHolder: GameItemsHolder +) : AbstractInventoryWindowWithCraftGrid(gameItemsHolder) { + + override val type = GameUiWindow.SURVIVAL_INVENTORY + + override var selectedItem: InventoryItem? = null +} \ No newline at end of file diff --git a/core/src/ru/deadsoftware/cavedroid/game/windows/GameWindowsManager.kt b/core/src/ru/deadsoftware/cavedroid/game/windows/GameWindowsManager.kt deleted file mode 100644 index b07f1fd..0000000 --- a/core/src/ru/deadsoftware/cavedroid/game/windows/GameWindowsManager.kt +++ /dev/null @@ -1,46 +0,0 @@ -package ru.deadsoftware.cavedroid.game.windows - -import ru.deadsoftware.cavedroid.MainConfig -import ru.deadsoftware.cavedroid.game.GameScope -import ru.deadsoftware.cavedroid.game.GameUiWindow -import ru.deadsoftware.cavedroid.game.mobs.MobsController -import ru.deadsoftware.cavedroid.game.model.item.InventoryItem -import ru.deadsoftware.cavedroid.game.windows.inventory.AbstractInventoryWindow -import ru.deadsoftware.cavedroid.game.windows.inventory.CraftingInventoryWindow -import ru.deadsoftware.cavedroid.game.windows.inventory.CreativeInventoryWindow -import ru.deadsoftware.cavedroid.game.windows.inventory.SurvivalInventoryWindow -import javax.inject.Inject - -@GameScope -class GameWindowsManager @Inject constructor( - private val mainConfig: MainConfig, - private val mobsController: MobsController, -) { - - var creativeScrollAmount = 0 - var isDragging = false - - var currentWindow: AbstractInventoryWindow? = null - - @JvmName("getCurrentWindowType") - fun getCurrentWindow(): GameUiWindow { - return currentWindow?.type ?: GameUiWindow.NONE - } - - fun openInventory() { - if (mobsController.player.gameMode == 1) { - currentWindow = CreativeInventoryWindow(GameUiWindow.CREATIVE_INVENTORY) - } else { - currentWindow = SurvivalInventoryWindow(GameUiWindow.SURVIVAL_INVENTORY) - } - } - - fun openCrafting() { - currentWindow = CraftingInventoryWindow(GameUiWindow.CRAFTING_TABLE) - } - - fun closeWindow() { - currentWindow = null - } - -} \ No newline at end of file diff --git a/core/src/ru/deadsoftware/cavedroid/game/windows/inventory/AbstractInventoryWindow.kt b/core/src/ru/deadsoftware/cavedroid/game/windows/inventory/AbstractInventoryWindow.kt deleted file mode 100644 index 0660604..0000000 --- a/core/src/ru/deadsoftware/cavedroid/game/windows/inventory/AbstractInventoryWindow.kt +++ /dev/null @@ -1,12 +0,0 @@ -package ru.deadsoftware.cavedroid.game.windows.inventory - -import ru.deadsoftware.cavedroid.game.GameUiWindow -import ru.deadsoftware.cavedroid.game.model.item.InventoryItem - -abstract class AbstractInventoryWindow { - - abstract val type: GameUiWindow - - abstract var selectedItem: InventoryItem? - -} \ No newline at end of file diff --git a/core/src/ru/deadsoftware/cavedroid/game/windows/inventory/CraftingInventoryWindow.kt b/core/src/ru/deadsoftware/cavedroid/game/windows/inventory/CraftingInventoryWindow.kt deleted file mode 100644 index 03808f1..0000000 --- a/core/src/ru/deadsoftware/cavedroid/game/windows/inventory/CraftingInventoryWindow.kt +++ /dev/null @@ -1,15 +0,0 @@ -package ru.deadsoftware.cavedroid.game.windows.inventory - -import ru.deadsoftware.cavedroid.game.GameUiWindow -import ru.deadsoftware.cavedroid.game.model.item.InventoryItem - -class CraftingInventoryWindow( - override val type: GameUiWindow, -) : AbstractInventoryWindow() { - - override var selectedItem: InventoryItem? = null - - val craftingItems = MutableList(9) { null } - - var craftResult: InventoryItem? = null -} \ No newline at end of file diff --git a/core/src/ru/deadsoftware/cavedroid/game/windows/inventory/CreativeInventoryWindow.kt b/core/src/ru/deadsoftware/cavedroid/game/windows/inventory/CreativeInventoryWindow.kt deleted file mode 100644 index 5f72243..0000000 --- a/core/src/ru/deadsoftware/cavedroid/game/windows/inventory/CreativeInventoryWindow.kt +++ /dev/null @@ -1,10 +0,0 @@ -package ru.deadsoftware.cavedroid.game.windows.inventory - -import ru.deadsoftware.cavedroid.game.GameUiWindow -import ru.deadsoftware.cavedroid.game.model.item.InventoryItem - -class CreativeInventoryWindow( - override val type: GameUiWindow, -) : AbstractInventoryWindow() { - override var selectedItem: InventoryItem? = null -} \ No newline at end of file diff --git a/core/src/ru/deadsoftware/cavedroid/game/windows/inventory/SurvivalInventoryWindow.kt b/core/src/ru/deadsoftware/cavedroid/game/windows/inventory/SurvivalInventoryWindow.kt deleted file mode 100644 index 4eeba3c..0000000 --- a/core/src/ru/deadsoftware/cavedroid/game/windows/inventory/SurvivalInventoryWindow.kt +++ /dev/null @@ -1,15 +0,0 @@ -package ru.deadsoftware.cavedroid.game.windows.inventory - -import ru.deadsoftware.cavedroid.game.GameUiWindow -import ru.deadsoftware.cavedroid.game.model.item.InventoryItem - -class SurvivalInventoryWindow( - override val type: GameUiWindow, -) : AbstractInventoryWindow() { - - override var selectedItem: InventoryItem? = null - - val craftingItems = MutableList(9) { null } - - var craftResult: InventoryItem? = null -} \ No newline at end of file diff --git a/core/src/ru/deadsoftware/cavedroid/game/world/GameWorld.java b/core/src/ru/deadsoftware/cavedroid/game/world/GameWorld.java index f2fd27d..05a7d5f 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/world/GameWorld.java +++ b/core/src/ru/deadsoftware/cavedroid/game/world/GameWorld.java @@ -1,14 +1,19 @@ package ru.deadsoftware.cavedroid.game.world; +import com.badlogic.gdx.math.MathUtils; import kotlin.Pair; import ru.deadsoftware.cavedroid.game.GameItemsHolder; import ru.deadsoftware.cavedroid.game.GameScope; import ru.deadsoftware.cavedroid.game.mobs.MobsController; +import ru.deadsoftware.cavedroid.game.mobs.Pig; 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.DropController; +import ru.deadsoftware.cavedroid.game.objects.container.Container; +import ru.deadsoftware.cavedroid.game.objects.drop.DropController; +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; @@ -17,26 +22,32 @@ 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 ContainerController mContainerController; private final int mWidth; private final int mHeight; private final Block[][] mForeMap; private final Block[][] mBackMap; - private final WorldGeneratorConfig mWorldConfig = WorldGeneratorConfig.Companion.getDefault(); + private final WorldGeneratorConfig mWorldConfig = WorldGeneratorConfig.Companion.getDefault(); @Inject public GameWorld(DropController dropController, MobsController mobsController, GameItemsHolder gameItemsHolder, + ContainerController containerController, @CheckForNull Block[][] foreMap, @CheckForNull Block[][] backMap) { mDropController = dropController; mMobsController = mobsController; mGameItemsHolder = gameItemsHolder; + mContainerController = containerController; boolean isNewGame = foreMap == null || backMap == null; @@ -46,6 +57,7 @@ public class GameWorld { Pair maps = new GameWorldGenerator(mWorldConfig, mGameItemsHolder).generate(); mForeMap = maps.getFirst(); mBackMap = maps.getSecond(); + spawnInitialMobs(); mMobsController.getPlayer().respawn(this, mGameItemsHolder); } else { mForeMap = foreMap; @@ -97,23 +109,43 @@ public class GameWorld { private Block getMap(int x, int y, int layer) { Block map = mGameItemsHolder.getFallbackBlock(); - try { - x = transformX(x); - map = (layer == 0) ? mForeMap[x][y] : mBackMap[x][y]; - } catch (ArrayIndexOutOfBoundsException ignored) { + + if (y < 0 || y >= getHeight()) { + return map; + } + + x = transformX(x); + + if (x < 0 || x >= getWidth()) { + return map; } + + map = (layer == 0) ? mForeMap[x][y] : mBackMap[x][y]; + return map; } private void setMap(int x, int y, int layer, Block value) { - try { - x = transformX(x); - if (layer == 0) { - mForeMap[x][y] = value; - } else { - mBackMap[x][y] = value; - } - } catch (ArrayIndexOutOfBoundsException ignored) { + if (y < 0 || y >= getHeight()) { + return; + } + + x = transformX(x); + + if (x < 0 || x >= getWidth()) { + return; + } + + mContainerController.destroyContainer(x, y, layer, false); + + if (value.isContainer()) { + mContainerController.addContainer(x, y, layer, (Class) value.getClass()); + } + + if (layer == 0) { + mForeMap[x][y] = value; + } else { + mBackMap[x][y] = value; } } @@ -127,19 +159,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) { @@ -147,15 +179,19 @@ 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 canPlaceToForeground(int x, int y, Block value) { + return !hasForeAt(x, y) || value == mGameItemsHolder.getFallbackBlock() || !getForeMap(x, y).hasCollision(); } public boolean placeToForeground(int x, int y, Block value) { - if (!hasForeAt(x, y) || value == mGameItemsHolder.getFallbackBlock() || !getForeMap(x, y).hasCollision()) { + if (canPlaceToForeground(x, y, value)) { setForeMap(x, y, value); return true; } else if (value instanceof Block.Slab && isSameSlab(value, getForeMap(x, y))) { @@ -167,7 +203,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"))) { + (!value.isTransparent() || value == mGameItemsHolder.getBlock("glass") || value.isChest() || value.isSlab())) { setBackMap(x, y, value); return true; } @@ -175,23 +211,41 @@ public class GameWorld { } private void playerDurateTool() { - final InventoryItem playerCurrentItem = mMobsController.getPlayer().getCurrentItem(); - if (mMobsController.getPlayer().getCurrentItem().getItem().isTool()) { + final InventoryItem playerCurrentItem = mMobsController.getPlayer().inventory.getActiveItem(); + if (playerCurrentItem.getItem().isTool()) { mMobsController.getPlayer().decreaseCurrentItemCount(mGameItemsHolder); } } private boolean shouldDrop(Block block) { - final Item item = mMobsController.getPlayer().getCurrentItem().getItem(); - int toolLevel = item.isTool() ? ((Item.Tool)item).getLevel() : 0; + final Item item = mMobsController.getPlayer().inventory.getActiveItem().getItem(); + int toolLevel = item.isTool() ? ((Item.Tool) item).getLevel() : 0; if (item.isTool() && block.getParams().getToolType() != item.getClass()) { toolLevel = 0; } return toolLevel >= block.getParams().getToolLevel(); } + private void spawnInitialMobs() { + for (int x = 0; x < getWidth(); x++) { + int y = 0; + while (y < getWorldConfig().getSeaLevel()) { + if (getForeMap(x, y) == mGameItemsHolder.getBlock("grass")) { + if (MathUtils.randomBoolean(.125f)) { + mMobsController.addMob(new Pig(MeasureUnitsUtilsKt.getPx(x), MeasureUnitsUtilsKt.getPx(y))); + } + break; + } + y++; + } + } + } + public void destroyForeMap(int x, int y) { Block block = getForeMap(x, y); + if (block.isContainer()) { + mContainerController.destroyContainer(x, y, FOREGROUND_Z, true); + } 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())); @@ -207,6 +261,9 @@ public class GameWorld { public void destroyBackMap(int x, int y) { Block block = getBackMap(x, y); + if (block.isContainer()) { + mContainerController.destroyContainer(x, y, BACKGROUND_Z, true); + } 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())); @@ -215,4 +272,43 @@ public class GameWorld { playerDurateTool(); 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) { + @CheckForNull + final Container container = getForegroundContainer(x, y); + + if (container instanceof Furnace) { + return (Furnace) container; + } + + return null; + } + + @CheckForNull + public Furnace getBackgroundFurnace(int x, int y) { + @CheckForNull + final Container container = getBackgroundContainer(x, y); + + if (container instanceof Furnace) { + return (Furnace) container; + } + + return null; + } } \ No newline at end of file diff --git a/core/src/ru/deadsoftware/cavedroid/game/world/GameWorldFluidsLogicControllerTask.java b/core/src/ru/deadsoftware/cavedroid/game/world/GameWorldFluidsLogicControllerTask.java deleted file mode 100644 index 416721f..0000000 --- a/core/src/ru/deadsoftware/cavedroid/game/world/GameWorldFluidsLogicControllerTask.java +++ /dev/null @@ -1,223 +0,0 @@ -package ru.deadsoftware.cavedroid.game.world; - -import com.badlogic.gdx.utils.Timer; -import ru.deadsoftware.cavedroid.game.GameItemsHolder; -import ru.deadsoftware.cavedroid.game.GameScope; -import ru.deadsoftware.cavedroid.game.mobs.MobsController; -import ru.deadsoftware.cavedroid.game.model.block.Block; - -import javax.annotation.CheckForNull; -import javax.inject.Inject; -import java.util.*; - -@GameScope -public class GameWorldFluidsLogicControllerTask extends Timer.Task { - - public static final float FLUID_UPDATE_INTERVAL_SEC = 0.25f; - - private short mUpdateTick = 0; - - private final GameWorld mGameWorld; - private final MobsController mMobsController; - private final GameItemsHolder mGameItemsHolder; - - private final Map, List> mFluidStatesMap; - - private final class UpdateCommand { - final Runnable command; - final int priority; - - private UpdateCommand(int priority, Runnable command) { - this.priority = priority; - this.command = command; - } - - private UpdateCommand(Block block, int x, int y, int priority) { - this(priority, () -> mGameWorld.setForeMap(x, y, block)); - } - - private UpdateCommand(Block.Fluid fluid, int x, int y) { - this(fluid, x, y, ((5 -fluid.getState() )+ 1) * (fluid.isLava() ? 2 : 1)); - } - - private int getPriority() { - return priority; - } - - private void exec() { - command.run(); - } - } - - private final PriorityQueue mUpdateQueue - = new PriorityQueue<>(Comparator.comparingInt(UpdateCommand::getPriority)); - - @Inject - GameWorldFluidsLogicControllerTask(GameWorld gameWorld, - MobsController mobsController, - GameItemsHolder gameItemsHolder) { - mGameWorld = gameWorld; - mMobsController = mobsController; - mGameItemsHolder = gameItemsHolder; - - final List waters = mGameItemsHolder.getBlocksByType(Block.Water.class); - waters.sort(Comparator.comparingInt(Block.Water::getState)); - - final List lavas = mGameItemsHolder.getBlocksByType(Block.Lava.class); - lavas.sort(Comparator.comparingInt(Block.Lava::getState)); - - mFluidStatesMap = new HashMap<>(); - mFluidStatesMap.put(Block.Water.class, waters); - mFluidStatesMap.put(Block.Lava.class, lavas); - } - - @CheckForNull - private List getFluidStateList(Block.Fluid fluid) { - return mFluidStatesMap.get(fluid.getClass()); - } - - private int getCurrentStateIndex(Block.Fluid fluid) { - @CheckForNull final List stateList = getFluidStateList(fluid); - - if (stateList == null) { - return -1; - } - - return stateList.indexOf(fluid); - } - - @CheckForNull - private Block.Fluid getNextStateBlock(Block.Fluid fluid) { - @CheckForNull final List stateList = getFluidStateList(fluid); - - if (stateList == null) { - return null; - } - - int currentState = stateList.indexOf(fluid); - - if (currentState < 0) { - return null; - } - - int nextState = currentState + 1; - - if (nextState == 1) { - nextState++; - } - - if (nextState < stateList.size()) { - return stateList.get(nextState); - } - - return null; - } - - private boolean noFluidNearby(int x, int y) { - return !mGameWorld.getForeMap(x, y - 1).isFluid() && - (!mGameWorld.getForeMap(x - 1, y).isFluid() || ((Block.Fluid)mGameWorld.getForeMap(x - 1, y)).getState() >= ((Block.Fluid)mGameWorld.getForeMap(x, y)).getState()) && - (!mGameWorld.getForeMap(x + 1, y).isFluid() || ((Block.Fluid)mGameWorld.getForeMap(x + 1, y)).getState() >= ((Block.Fluid)mGameWorld.getForeMap(x, y)).getState()); - } - - private boolean drainFluid(int x, int y) { - final Block block = mGameWorld.getForeMap(x, y); - - if (!(block instanceof Block.Fluid fluid)) { - return true; - } - - if (fluid.getState() > 0) { - if (noFluidNearby(x, y)) { - @CheckForNull final Block.Fluid nextState = getNextStateBlock(fluid); - if (nextState == null) { - mUpdateQueue.offer(new UpdateCommand(-1, () -> mGameWorld.resetForeMap(x, y))); - return true; - } - - mUpdateQueue.offer(new UpdateCommand(nextState, x, y)); - } - } - return false; - } - - private boolean fluidCanFlowThere(Block.Fluid fluid, Block targetBlock) { - return targetBlock == mGameItemsHolder.getFallbackBlock() || - (!targetBlock.getParams().getHasCollision() && !targetBlock.isFluid()) || - (fluid.getClass() == targetBlock.getClass() && fluid.getState() < ((Block.Fluid)targetBlock).getState()); - } - - private void flowFluidTo(Block.Fluid currentFluid, int x, int y, Block.Fluid nextStateFluid) { - final Block targetBlock = mGameWorld.getForeMap(x, y); - - if (fluidCanFlowThere(currentFluid, targetBlock)) { - mUpdateQueue.offer(new UpdateCommand(nextStateFluid, x, y)); - } else if (currentFluid.isWater() && targetBlock.isLava()) { - if (((Block.Lava)targetBlock).getState() > 0) { - mUpdateQueue.offer(new UpdateCommand(100, () -> mGameWorld.setForeMap(x, y, mGameItemsHolder.getBlock("cobblestone")))); - } else { - mUpdateQueue.offer(new UpdateCommand(300, () -> mGameWorld.setForeMap(x, y, mGameItemsHolder.getBlock("obsidian")))); - } - } else if (currentFluid.isLava() && targetBlock.isWater()) { - mUpdateQueue.offer(new UpdateCommand(200, () -> mGameWorld.setForeMap(x, y, mGameItemsHolder.getBlock("stone")))); - } - } - - private void flowFluid(int x, int y) { - Block.Fluid fluid = (Block.Fluid) mGameWorld.getForeMap(x, y); - @CheckForNull final List stateList = getFluidStateList(fluid); - - if (stateList == null) { - return; - } - - if (fluid.getState() < stateList.size() - 1 && mGameWorld.getForeMap(x, y + 1).hasCollision()) { - @CheckForNull Block.Fluid nextState = getNextStateBlock(fluid); - - if (nextState == null) { - return; - } - - flowFluidTo(fluid, x - 1, y, nextState); - flowFluidTo(fluid, x + 1, y, nextState); - } else { - flowFluidTo(fluid, x, y + 1, stateList.get(1)); - } - - } - - private void updateFluids(int x, int y) { - final Block block = mGameWorld.getForeMap(x, y); - if (!block.isFluid() || (block.isLava() && mUpdateTick % 2 == 0)) { - return; - } - if (drainFluid(x, y)) { - return; - } - flowFluid(x, y); - } - - private void fluidUpdater() { - int midScreen = (int) mMobsController.getPlayer().x / 16; - for (int y = mGameWorld.getHeight() - 1; y >= 0; y--) { - for (int x = 0; x <= Math.min(mGameWorld.getWidth() / 2, 32); x++) { - updateFluids(midScreen + x, y); - updateFluids(midScreen - x, y); - } - } - - while (!mUpdateQueue.isEmpty()) { - final UpdateCommand command = mUpdateQueue.poll(); - command.exec(); - } - } - - @Override - public void run() { - if (mUpdateTick < 0xFF) { - mUpdateTick ++; - } else { - mUpdateTick = 0; - } - fluidUpdater(); - } -} diff --git a/core/src/ru/deadsoftware/cavedroid/game/world/GameWorldFluidsLogicControllerTask.kt b/core/src/ru/deadsoftware/cavedroid/game/world/GameWorldFluidsLogicControllerTask.kt new file mode 100644 index 0000000..d0f4eaa --- /dev/null +++ b/core/src/ru/deadsoftware/cavedroid/game/world/GameWorldFluidsLogicControllerTask.kt @@ -0,0 +1,189 @@ +package ru.deadsoftware.cavedroid.game.world + +import com.badlogic.gdx.utils.Timer +import ru.deadsoftware.cavedroid.game.GameItemsHolder +import ru.deadsoftware.cavedroid.game.GameScope +import ru.deadsoftware.cavedroid.game.mobs.MobsController +import ru.deadsoftware.cavedroid.game.model.block.Block +import ru.deadsoftware.cavedroid.misc.utils.bl +import java.util.PriorityQueue +import javax.inject.Inject +import kotlin.math.min +import kotlin.reflect.KClass + +@GameScope +class GameWorldFluidsLogicControllerTask @Inject constructor( + private val gameWorld: GameWorld, + private val mobsController: MobsController, + private val gameItemsHolder: GameItemsHolder, +) : Timer.Task() { + + private var updateTick: Short = 0; + + private val fluidStatesMap = mutableMapOf, List>() + + private val updateQueue = PriorityQueue(16) { c1, c2 -> + c1.priority.compareTo(c2.priority) + } + + init { + val waters = gameItemsHolder.getBlocksByType(Block.Water::class.java) + .sortedBy(Block.Water::state) + val lavas = gameItemsHolder.getBlocksByType(Block.Lava::class.java) + .sortedBy(Block.Lava::state) + + fluidStatesMap[Block.Water::class] = waters + fluidStatesMap[Block.Lava::class] = lavas + } + + private fun getNextStateBlock(fluid: Block.Fluid): Block.Fluid? { + val stateList = fluidStatesMap[fluid::class] ?: return null + val currentState = stateList.indexOf(fluid) + .takeIf { it >= 0 } ?: return null + + var nextState = currentState + 1 + + if (nextState == 1) { + nextState++ + } + + if (nextState < stateList.size) { + return stateList[nextState] + } + + return null + } + + private fun noFluidNearby(x: Int, y: Int): Boolean { + val current = gameWorld.getForeMap(x, y) + + if (current !is Block.Fluid) { + throw IllegalArgumentException("block at $x;$y is not a fluid") + } + + val onTop = gameWorld.getForeMap(x, y - 1) + val onLeft = gameWorld.getForeMap(x - 1, y) + val onRight = gameWorld.getForeMap(x + 1, y) + + return !onTop.isFluid() && + (onLeft !is Block.Fluid || onLeft.state >= current.state) && + (onRight !is Block.Fluid || onRight.state >= current.state) + } + + private fun drainFluid(x: Int, y: Int): Boolean { + val fluid = (gameWorld.getForeMap(x, y) as? Block.Fluid) + ?: return true + + if (fluid.state > 0) { + if (noFluidNearby(x, y)) { + val nexState = getNextStateBlock(fluid) + if (nexState == null) { + updateQueue.offer(UpdateCommand(-1) { gameWorld.resetForeMap(x, y) }) + return true + } + updateQueue.offer(UpdateCommand(nexState, x, y)) + } + } + + return false + } + + private fun fluidCanFlowThere(fluid: Block.Fluid, targetBlock: Block): Boolean { + return targetBlock.isNone() || + (!targetBlock.params.hasCollision && !targetBlock.isFluid()) || + (fluid::class == targetBlock::class && fluid.state < (targetBlock as Block.Fluid).state) + } + + private fun flowFluidTo(currentFluid: Block.Fluid, x: Int, y: Int, nextStateFluid: Block.Fluid) { + val targetBlock = gameWorld.getForeMap(x, y) + + val command = when { + fluidCanFlowThere(currentFluid, targetBlock) -> UpdateCommand(nextStateFluid, x, y) + + currentFluid.isWater() && targetBlock is Block.Lava && targetBlock.state > 0 -> + UpdateCommand(100) { gameWorld.setForeMap(x, y, gameItemsHolder.getBlock("cobblestone")) } + + currentFluid.isWater() && targetBlock.isLava() -> + UpdateCommand(100) { gameWorld.setForeMap(x, y, gameItemsHolder.getBlock("obsidian")) } + + currentFluid.isLava() && targetBlock.isWater() -> + UpdateCommand(200) { gameWorld.setForeMap(x, y, gameItemsHolder.getBlock("stone")) } + + else -> null + } + + command?.let(updateQueue::offer) + } + + private fun flowFluid(x: Int, y: Int) { + val fluid = gameWorld.getForeMap(x, y) as Block.Fluid + val stateList = fluidStatesMap[fluid::class] ?: return + + if (fluid.state < stateList.lastIndex && gameWorld.getForeMap(x, y + 1).params.hasCollision) { + val nextState = getNextStateBlock(fluid) ?: return + + flowFluidTo(fluid, x - 1, y, nextState) + flowFluidTo(fluid, x + 1, y, nextState) + } else { + flowFluidTo(fluid, x, y + 1, stateList[1]) + } + } + + fun updateFluids(x: Int, y: Int) { + val block = gameWorld.getForeMap(x, y) + if (!block.isFluid() || (block.isLava() && updateTick % 2 == 0)) { + return + } + + if (drainFluid(x, y)) { + return + } + + flowFluid(x, y) + } + + private fun fluidUpdater() { + val midScreen = mobsController.player.x.bl + + for (y in gameWorld.height - 1 downTo 0) { + for (x in 0 ..< min(gameWorld.width / 2, 32)) { + updateFluids(midScreen + x, y) + updateFluids(midScreen - x, y) + } + } + + while (!updateQueue.isEmpty()) { + updateQueue.poll().exec() + } + } + + override fun run() { + if (updateTick < 0xFF) { + updateTick++ + } else { + updateTick = 1 + } + + fluidUpdater() + } + + private inner class UpdateCommand( + val priority: Int, + val command: Runnable + ) { + + constructor(block: Block, x: Int, y: Int, priority: Int) : + this(priority, Runnable { gameWorld.setForeMap(x, y, block) }) + + constructor(fluid: Block.Fluid, x: Int, y: Int) : + this(fluid, x, y, ((5 - fluid.state) + 1) * (if (fluid.isLava()) 2 else 1)) + + fun exec() = command.run() + + } + + companion object { + const val FLUID_UPDATE_INTERVAL_SEC = 0.25f + } + +} \ No newline at end of file diff --git a/core/src/ru/deadsoftware/cavedroid/game/world/GameWorldGenerator.kt b/core/src/ru/deadsoftware/cavedroid/game/world/GameWorldGenerator.kt index e00a0ea..004a56b 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/world/GameWorldGenerator.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/world/GameWorldGenerator.kt @@ -72,12 +72,17 @@ class GameWorldGenerator( val bedrock = gameItemsHolder.getBlock("bedrock") val dirt = gameItemsHolder.getBlock("dirt") val stone = gameItemsHolder.getBlock("stone") + val snow = gameItemsHolder.getBlock("snow") foreMap[x][surfaceHeight] = grass foreMap[x][config.height - 1] = bedrock backMap[x][surfaceHeight] = grass backMap[x][config.height - 1] = bedrock + if (surfaceHeight - 1 < config.seaLevel) { + foreMap[x][surfaceHeight - 1] = snow + } + for (y in min(surfaceHeight + 1, config.seaLevel) ..< config.height - 1) { if (y <= surfaceHeight) { backMap[x][y] = dirt @@ -90,6 +95,13 @@ class GameWorldGenerator( } backMap[x][y] = foreMap[x][y] } + + val plant = random.nextInt(100) + if (surfaceHeight < config.seaLevel) { + if (plant < 10) { + generateSpruce(x) + } + } } private fun plainsBiome(x: Int) { @@ -222,6 +234,37 @@ class GameWorldGenerator( } } + private fun generateSpruce(x: Int) { + val log = gameItemsHolder.getBlock("log_spruce") + val leaves = gameItemsHolder.getBlock("leaves_spruce") + val h = heights[x] - 1 + val treeH = random.nextInt(7, 9) + val height = max(0, h - treeH) + + val top = height - 1 + if (top >= 0) { + foreMap[x][top] = leaves + backMap[x][top] = leaves + } + + for (x1 in max(0, x - 1) .. min(config.width - 1, x + 1)) { + val y = height + foreMap[x1][y] = leaves + backMap[x1][y] = leaves + } + + for (y in 1..2) { + for (x1 in max(0, x - y) .. min(config.width - 1, x + y)) { + foreMap[x1][height + 1 + y] = leaves + backMap[x1][height + 1 + y] = leaves + } + } + + for (y in h downTo height) { + backMap[x][y] = log + } + } + private fun generateTallGrass(x: Int) { val tallGrass = gameItemsHolder.getBlock(plainsPlants.random(random)) val h = heights[x] - 1 diff --git a/core/src/ru/deadsoftware/cavedroid/game/world/GameWorldMobDamageControllerTask.kt b/core/src/ru/deadsoftware/cavedroid/game/world/GameWorldMobDamageControllerTask.kt index 8dc39b9..f016c67 100644 --- a/core/src/ru/deadsoftware/cavedroid/game/world/GameWorldMobDamageControllerTask.kt +++ b/core/src/ru/deadsoftware/cavedroid/game/world/GameWorldMobDamageControllerTask.kt @@ -24,7 +24,10 @@ class GameWorldMobDamageControllerTask @Inject constructor( val foregroundBlock = gameWorld.getForeMap(x, y) val backgroundBlock = gameWorld.getBackMap(x, y) - mob.damage(max(foregroundBlock.params.damage, backgroundBlock.params.damage)) + val damage = max(foregroundBlock.params.damage, backgroundBlock.params.damage) + if (damage > 0) { + mob.damage(damage) + } } } diff --git a/core/src/ru/deadsoftware/cavedroid/menu/MenuProc.java b/core/src/ru/deadsoftware/cavedroid/menu/MenuProc.java index 6accb57..aa3888a 100644 --- a/core/src/ru/deadsoftware/cavedroid/menu/MenuProc.java +++ b/core/src/ru/deadsoftware/cavedroid/menu/MenuProc.java @@ -5,13 +5,15 @@ import com.badlogic.gdx.utils.ObjectMap; import ru.deadsoftware.cavedroid.CaveGame; import ru.deadsoftware.cavedroid.MainConfig; import ru.deadsoftware.cavedroid.menu.objects.Button; -import ru.deadsoftware.cavedroid.menu.submenus.Menu; -import ru.deadsoftware.cavedroid.menu.submenus.MenuMain; -import ru.deadsoftware.cavedroid.menu.submenus.MenuNewGame; +import ru.deadsoftware.cavedroid.menu.submenus.*; import ru.deadsoftware.cavedroid.misc.Renderer; import javax.inject.Inject; +import java.lang.reflect.Method; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + import static ru.deadsoftware.cavedroid.misc.Assets.*; @MenuScope @@ -30,6 +32,10 @@ public class MenuProc extends Renderer { mMainConfig.getCaveGame().loadGame(); } + public void optionsClicked() { + mCurrentMenu = mMenuOptions; + } + public void quitClicked() { Gdx.app.exit(); } @@ -45,20 +51,24 @@ public class MenuProc extends Renderer { public void backClicked() { mCurrentMenu = mMenuMain; } + + public void setPreference(String key, Object value) { + mMainConfig.setPreference(key, value.toString()); + } } private final MainConfig mMainConfig; private final MenuMain mMenuMain; private final MenuNewGame mMenuNewGame; + private final MenuOptions mMenuOptions; private Menu mCurrentMenu; @Inject public MenuProc( MainConfig mainConfig, - MenuMain.Factory menuMainFactory, - MenuNewGame.Factory menuNewGameFactory + MenusFactory menusFactory ) { super(mainConfig.getWidth(), mainConfig.getHeight()); @@ -66,18 +76,42 @@ public class MenuProc extends Renderer { Input menuInput = new Input(); - mMenuMain = menuMainFactory.get(getWidth(), getHeight(), this::drawButton, menuInput); - mMenuNewGame = menuNewGameFactory.get(getWidth(), getHeight(), this::drawButton, menuInput); + mMenuMain = menusFactory.getMainMenu(getWidth(), getHeight(), this::drawButton, menuInput); + mMenuNewGame = menusFactory.getMenuNewGame(getWidth(), getHeight(), this::drawButton, menuInput); + mMenuOptions = menusFactory.getMenuOptions(getWidth(), getHeight(), this::drawButton, menuInput); mCurrentMenu = mMenuMain; } + private String processVariables(String raw) { + final Pattern pattern = Pattern.compile("%%([A-Za-z]+)%%", Pattern.CASE_INSENSITIVE); + final Matcher matcher = pattern.matcher(raw); + while (matcher.find()) { + for (int i = 0; i < matcher.groupCount(); i++) { + try { + final String group = matcher.group(i); + final String name = group.replaceAll("%%", ""); + final Method method = mMainConfig.getClass().getMethod(name); + final String value = method.invoke(mMainConfig).toString(); + raw = raw.replace(group, value); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + } + + return raw; + } + private void drawButton(Button button) { spriter.draw(textureRegions.get("button_" + button.getType()), button.getX(), button.getY()); setFontColor(255, 255, 255); - drawString(button.getLabel(), - (button.getX() + button.getWidth() / 2) - (float) getStringWidth(button.getLabel()) / 2, - (button.getY() + button.getHeight() / 2) - (float) getStringHeight(button.getLabel()) / 2); + + String label = processVariables(button.getLabel()); + + drawString(label, + (button.getX() + button.getWidth() / 2) - (float) getStringWidth(label) / 2, + (button.getY() + button.getHeight() / 2) - (float) getStringHeight(label) / 2); } @Override diff --git a/core/src/ru/deadsoftware/cavedroid/menu/objects/BooleanOptionButton.kt b/core/src/ru/deadsoftware/cavedroid/menu/objects/BooleanOptionButton.kt new file mode 100644 index 0000000..56329d5 --- /dev/null +++ b/core/src/ru/deadsoftware/cavedroid/menu/objects/BooleanOptionButton.kt @@ -0,0 +1,29 @@ +package ru.deadsoftware.cavedroid.menu.objects + +import ru.deadsoftware.cavedroid.MainConfig + +class BooleanOptionButton( + private val mainConfig: MainConfig, + private val optionKey: String, + private val defaultValue: Boolean, + label: String, + x: Int, + y: Int, + type: Int, +) : Button( + label, + x, + y, + type, + { + val current = (mainConfig.getPreference(optionKey)?.toBooleanStrictOrNull()) ?: defaultValue + mainConfig.setPreference(optionKey, (!current).toString()) + } +) { + + override fun getLabel(): String { + val value = (mainConfig.getPreference(optionKey)?.toBooleanStrictOrNull()) ?: defaultValue + return super.getLabel().replace("%%value%%", value.toString()) + } + +} \ No newline at end of file diff --git a/core/src/ru/deadsoftware/cavedroid/menu/submenus/Menu.java b/core/src/ru/deadsoftware/cavedroid/menu/submenus/Menu.java index 587d0f6..7e793b7 100644 --- a/core/src/ru/deadsoftware/cavedroid/menu/submenus/Menu.java +++ b/core/src/ru/deadsoftware/cavedroid/menu/submenus/Menu.java @@ -1,13 +1,16 @@ package ru.deadsoftware.cavedroid.menu.submenus; +import com.badlogic.gdx.Application; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.files.FileHandle; import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.graphics.g2d.TextureRegion; import com.badlogic.gdx.utils.ArrayMap; import com.badlogic.gdx.utils.JsonValue; +import kotlin.text.StringsKt; import ru.deadsoftware.cavedroid.MainConfig; import ru.deadsoftware.cavedroid.menu.MenuProc; +import ru.deadsoftware.cavedroid.menu.objects.BooleanOptionButton; import ru.deadsoftware.cavedroid.menu.objects.Button; import ru.deadsoftware.cavedroid.menu.objects.ButtonEventListener; import ru.deadsoftware.cavedroid.menu.objects.ButtonRenderer; @@ -76,13 +79,27 @@ public abstract class Menu { JsonValue json = Assets.jsonReader.parse(jsonFile); int y = (int) mHeight / 4; for (JsonValue key = json.child(); key != null; key = key.next(), y += Button.HEIGHT + 10) { - buttons.put(key.name(), - new Button(Assets.getStringFromJson(key, "label", ""), - (int) mWidth / 2 - Button.WIDTH / 2, - Assets.getIntFromJson(key, "y", y), - Assets.getIntFromJson(key, "type", Button.NORMAL), - eventListeners.containsKey(key.name()) ? eventListeners.get(key.name()) : () -> { - })); + + if (Gdx.app.getType() == Application.ApplicationType.Android && + !Assets.getBooleanFromJson(key, "visible_on_android", true)) { + continue; + } + + String optionType = Assets.getStringFromJson(key, "option_type", ""); + String label = Assets.getStringFromJson(key, "label", ""); + int x = (int) mWidth / 2 - Button.WIDTH / 2; + int type = Assets.getIntFromJson(key, "type", Button.NORMAL); + String defaultValue = Assets.getStringFromJson(key, "default_value", ""); + + + Button button = switch (optionType) { + case "boolean" -> + new BooleanOptionButton(mMainConfig, key.name(), Boolean.parseBoolean(defaultValue), label, x, y, type); + default -> + new Button(label, x, y, type, eventListeners.containsKey(key.name()) ? eventListeners.get(key.name()) : () -> {}); + }; + + buttons.put(key.name(), button); } } diff --git a/core/src/ru/deadsoftware/cavedroid/menu/submenus/MenuMain.java b/core/src/ru/deadsoftware/cavedroid/menu/submenus/MenuMain.java index f71183a..6a40fc5 100644 --- a/core/src/ru/deadsoftware/cavedroid/menu/submenus/MenuMain.java +++ b/core/src/ru/deadsoftware/cavedroid/menu/submenus/MenuMain.java @@ -28,6 +28,7 @@ public class MenuMain extends Menu { HashMap map = new HashMap<>(); map.put("new_game", mMenuInput::newGameClicked); map.put("load_game", mMenuInput::loadGameClicked); + map.put("options", mMenuInput::optionsClicked); map.put("quit", mMenuInput::quitClicked); return map; } diff --git a/core/src/ru/deadsoftware/cavedroid/menu/submenus/MenuOptions.kt b/core/src/ru/deadsoftware/cavedroid/menu/submenus/MenuOptions.kt new file mode 100644 index 0000000..7cc8a90 --- /dev/null +++ b/core/src/ru/deadsoftware/cavedroid/menu/submenus/MenuOptions.kt @@ -0,0 +1,27 @@ +package ru.deadsoftware.cavedroid.menu.submenus + +import ru.deadsoftware.cavedroid.MainConfig +import ru.deadsoftware.cavedroid.menu.MenuProc +import ru.deadsoftware.cavedroid.menu.objects.ButtonEventListener +import ru.deadsoftware.cavedroid.menu.objects.ButtonRenderer +import ru.deadsoftware.cavedroid.misc.utils.AssetLoader + +class MenuOptions( + width: Float, + height: Float, + buttonRenderer: ButtonRenderer, + mainConfig: MainConfig, + menuInput: MenuProc.Input, + assetLoader: AssetLoader, +) : Menu(width, height, buttonRenderer, mainConfig, menuInput, assetLoader) { + + override fun getButtonEventListeners(): HashMap { + val map = HashMap() + map["back"] = ButtonEventListener { mMenuInput.backClicked() } + return map + } + + override fun initButtons() { + loadButtonsFromJson(mAssetLoader.getAssetHandle("json/menu_options_buttons.json")) + } +} \ No newline at end of file diff --git a/core/src/ru/deadsoftware/cavedroid/menu/submenus/MenusFactory.kt b/core/src/ru/deadsoftware/cavedroid/menu/submenus/MenusFactory.kt new file mode 100644 index 0000000..e31a9ad --- /dev/null +++ b/core/src/ru/deadsoftware/cavedroid/menu/submenus/MenusFactory.kt @@ -0,0 +1,43 @@ +package ru.deadsoftware.cavedroid.menu.submenus + +import ru.deadsoftware.cavedroid.MainConfig +import ru.deadsoftware.cavedroid.menu.MenuProc +import ru.deadsoftware.cavedroid.menu.MenuScope +import ru.deadsoftware.cavedroid.menu.objects.ButtonRenderer +import ru.deadsoftware.cavedroid.misc.utils.AssetLoader +import javax.inject.Inject + +@MenuScope +class MenusFactory @Inject constructor( + private val mainConfig: MainConfig, + private val assetLoader: AssetLoader, +) { + + fun getMainMenu( + width: Float, + height: Float, + buttonRenderer: ButtonRenderer, + menuInput: MenuProc.Input, + ): MenuMain { + return MenuMain(width, height, buttonRenderer, mainConfig, menuInput, assetLoader) + } + + fun getMenuNewGame( + width: Float, + height: Float, + buttonRenderer: ButtonRenderer, + menuInput: MenuProc.Input, + ): MenuNewGame { + return MenuNewGame(width, height, buttonRenderer, mainConfig, menuInput, assetLoader) + } + + fun getMenuOptions( + width: Float, + height: Float, + buttonRenderer: ButtonRenderer, + menuInput: MenuProc.Input, + ): MenuOptions { + return MenuOptions(width, height, buttonRenderer, mainConfig, menuInput, assetLoader) + } + +} \ No newline at end of file diff --git a/core/src/ru/deadsoftware/cavedroid/misc/Assets.java b/core/src/ru/deadsoftware/cavedroid/misc/Assets.java index b7fd03e..893414b 100644 --- a/core/src/ru/deadsoftware/cavedroid/misc/Assets.java +++ b/core/src/ru/deadsoftware/cavedroid/misc/Assets.java @@ -41,9 +41,17 @@ public class Assets { public static Map blockTextures = new HashMap<>(); public static Map itemTextures = new HashMap<>(); + public static Sprite joyBackground; + public static Sprite joyStick; + + public static Sprite furnaceBurn; + public static Sprite furnaceProgress; + public static void dispose() { minecraftFont.dispose(); - loadedTextures.forEach(Texture::dispose); + for (Texture texture : loadedTextures) { + texture.dispose(); + } loadedTextures.clear(); } @@ -73,14 +81,14 @@ public class Assets { for (int i = 0; i < sprite.length; i++) { for (int j = 0; j < sprite[i].length; j++) { sprite[i][j] = flippedSprite(loadTexture( - assetLoader.getAssetHandle("mobs/" + mob + "/" + i + "_" + j + ".png"))); + assetLoader.getAssetHandle("pp/mobs/" + mob + "/" + i + "_" + j + ".png"))); sprite[i][j].setOrigin(sprite[i][j].getWidth() / 2, 0); } } } private static void loadBlockDamage(AssetLoader assetLoader) { - final Texture blockDamageTexture = loadTexture(assetLoader.getAssetHandle("break.png")); + final Texture blockDamageTexture = loadTexture(assetLoader.getAssetHandle("pp/break.png")); for (int i = 0; i < BLOCK_DAMAGE_STAGES; i++) { blockDamageSprites[i] = new Sprite(flippedRegion(blockDamageTexture, i * 16, 0, 16, 16)); } @@ -100,9 +108,10 @@ public class Assets { JsonValue json = jsonReader.parse(assetLoader.getAssetHandle("json/texture_regions.json")); for (JsonValue file = json.child(); file != null; file = file.next()) { Texture texture = loadTexture(assetLoader.getAssetHandle(file.name() + ".png")); + final String[] pathSegments = file.name().split("/"); + final String name = pathSegments[pathSegments.length - 1]; if (file.size == 0) { - textureRegions.put(file.name(), - flippedRegion(texture, 0, 0, texture.getWidth(), texture.getHeight())); + textureRegions.put(name, flippedRegion(texture, 0, 0, texture.getWidth(), texture.getHeight())); } else { for (JsonValue key = file.child(); key != null; key = key.next()) { int x = getIntFromJson(key, "x", 0); @@ -165,11 +174,11 @@ public class Assets { } public static Texture resolveItemTexture(AssetLoader assetLoader, String textureName) { - return resolveTexture(assetLoader, textureName, "textures/items", itemTextures); + return resolveTexture(assetLoader, textureName, "pp/textures/items", itemTextures); } public static Texture resolveBlockTexture(AssetLoader assetLoader, String textureName) { - return resolveTexture(assetLoader, textureName, "textures/blocks", blockTextures); + return resolveTexture(assetLoader, textureName, "pp/textures/blocks", blockTextures); } private static void loadAllPngsFromDirInto(FileHandle dir, Map loadInto) { @@ -179,15 +188,25 @@ public class Assets { } private static void loadItems(AssetLoader assetLoader) { - final FileHandle itemsDir = assetLoader.getAssetHandle("textures/items"); + final FileHandle itemsDir = assetLoader.getAssetHandle("pp/textures/items"); loadAllPngsFromDirInto(itemsDir, itemTextures); } private static void loadBlocks(AssetLoader assetLoader) { - final FileHandle blocksDir = assetLoader.getAssetHandle("textures/blocks"); + final FileHandle blocksDir = assetLoader.getAssetHandle("pp/textures/blocks"); loadAllPngsFromDirInto(blocksDir, blockTextures); } + private static void loadJoystick(AssetLoader assetLoader) { + joyStick = new Sprite(loadTexture(assetLoader.getAssetHandle("joy_stick.png"))); + joyBackground = new Sprite(loadTexture(assetLoader.getAssetHandle("joy_background.png"))); + } + + private static void loadFurnace(AssetLoader assetLoader) { + furnaceBurn = new Sprite(textureRegions.get("furnace_burn")); + furnaceProgress = new Sprite(textureRegions.get("furnace_progress")); + } + public static void load(final AssetLoader assetLoader) { loadMob(assetLoader, playerSprite, "char"); loadMob(assetLoader, pigSprite, "pig"); @@ -196,9 +215,12 @@ public class Assets { loadBlocks(assetLoader); loadItems(assetLoader); loadTouchButtonsFromJSON(assetLoader); + loadJoystick(assetLoader); + loadFurnace(assetLoader); setPlayerHeadOrigin(); minecraftFont = new BitmapFont(assetLoader.getAssetHandle("font.fnt"), true); minecraftFont.getData().setScale(.375f); + minecraftFont.setUseIntegerPositions(false); } /** diff --git a/core/src/ru/deadsoftware/cavedroid/misc/annotations/multibinding/BindKeyboardInputHandler.kt b/core/src/ru/deadsoftware/cavedroid/misc/annotations/multibinding/BindKeyboardInputHandler.kt new file mode 100644 index 0000000..558dc96 --- /dev/null +++ b/core/src/ru/deadsoftware/cavedroid/misc/annotations/multibinding/BindKeyboardInputHandler.kt @@ -0,0 +1,11 @@ +package ru.deadsoftware.cavedroid.misc.annotations.multibinding + +import ru.deadsoftware.cavedroid.game.input.IKeyboardInputHandler +import ru.fredboy.automultibind.annotations.BindsIntoSet + +@BindsIntoSet( + interfaceClass = IKeyboardInputHandler::class, + modulePackage = MultibindingConfig.GENERATED_MODULES_PACKAGE, + moduleName = "KeyboardInputHandlersModule" +) +annotation class BindKeyboardInputHandler \ No newline at end of file diff --git a/core/src/ru/deadsoftware/cavedroid/misc/annotations/multibinding/BindMouseInputHandler.kt b/core/src/ru/deadsoftware/cavedroid/misc/annotations/multibinding/BindMouseInputHandler.kt new file mode 100644 index 0000000..af9b608 --- /dev/null +++ b/core/src/ru/deadsoftware/cavedroid/misc/annotations/multibinding/BindMouseInputHandler.kt @@ -0,0 +1,11 @@ +package ru.deadsoftware.cavedroid.misc.annotations.multibinding + +import ru.deadsoftware.cavedroid.game.input.IMouseInputHandler +import ru.fredboy.automultibind.annotations.BindsIntoSet + +@BindsIntoSet( + interfaceClass = IMouseInputHandler::class, + modulePackage = MultibindingConfig.GENERATED_MODULES_PACKAGE, + moduleName = "MouseInputHandlersModule" +) +annotation class BindMouseInputHandler \ No newline at end of file diff --git a/core/src/ru/deadsoftware/cavedroid/misc/annotations/multibinding/BindPlaceBlockAction.kt b/core/src/ru/deadsoftware/cavedroid/misc/annotations/multibinding/BindPlaceBlockAction.kt new file mode 100644 index 0000000..89f2dd0 --- /dev/null +++ b/core/src/ru/deadsoftware/cavedroid/misc/annotations/multibinding/BindPlaceBlockAction.kt @@ -0,0 +1,11 @@ +package ru.deadsoftware.cavedroid.misc.annotations.multibinding + +import ru.deadsoftware.cavedroid.game.actions.placeblock.IPlaceBlockAction +import ru.fredboy.automultibind.annotations.BindsIntoMapStringKey + +@BindsIntoMapStringKey( + interfaceClass = IPlaceBlockAction::class, + modulePackage = MultibindingConfig.GENERATED_MODULES_PACKAGE, + moduleName = "PlaceBlockActionsModule" +) +annotation class BindPlaceBlockAction(val stringKey: String) diff --git a/core/src/ru/deadsoftware/cavedroid/misc/annotations/multibinding/BindRenderer.kt b/core/src/ru/deadsoftware/cavedroid/misc/annotations/multibinding/BindRenderer.kt new file mode 100644 index 0000000..c1d96a9 --- /dev/null +++ b/core/src/ru/deadsoftware/cavedroid/misc/annotations/multibinding/BindRenderer.kt @@ -0,0 +1,11 @@ +package ru.deadsoftware.cavedroid.misc.annotations.multibinding + +import ru.deadsoftware.cavedroid.game.render.IGameRenderer +import ru.fredboy.automultibind.annotations.BindsIntoSet + +@BindsIntoSet( + interfaceClass = IGameRenderer::class, + modulePackage = MultibindingConfig.GENERATED_MODULES_PACKAGE, + moduleName = "RenderModule" +) +annotation class BindRenderer diff --git a/core/src/ru/deadsoftware/cavedroid/misc/annotations/multibinding/BindUpdateBlockAction.kt b/core/src/ru/deadsoftware/cavedroid/misc/annotations/multibinding/BindUpdateBlockAction.kt new file mode 100644 index 0000000..310d69e --- /dev/null +++ b/core/src/ru/deadsoftware/cavedroid/misc/annotations/multibinding/BindUpdateBlockAction.kt @@ -0,0 +1,11 @@ +package ru.deadsoftware.cavedroid.misc.annotations.multibinding + +import ru.deadsoftware.cavedroid.game.actions.updateblock.IUpdateBlockAction +import ru.fredboy.automultibind.annotations.BindsIntoMapStringKey + +@BindsIntoMapStringKey( + interfaceClass = IUpdateBlockAction::class, + modulePackage = MultibindingConfig.GENERATED_MODULES_PACKAGE, + moduleName = "UpdateBlockActionsModule" +) +annotation class BindUpdateBlockAction(val stringKey: String) \ No newline at end of file diff --git a/core/src/ru/deadsoftware/cavedroid/misc/annotations/multibinding/BindUseBlockAction.kt b/core/src/ru/deadsoftware/cavedroid/misc/annotations/multibinding/BindUseBlockAction.kt new file mode 100644 index 0000000..46353ca --- /dev/null +++ b/core/src/ru/deadsoftware/cavedroid/misc/annotations/multibinding/BindUseBlockAction.kt @@ -0,0 +1,11 @@ +package ru.deadsoftware.cavedroid.misc.annotations.multibinding + +import ru.deadsoftware.cavedroid.game.actions.useblock.IUseBlockAction +import ru.fredboy.automultibind.annotations.BindsIntoMapStringKey + +@BindsIntoMapStringKey( + interfaceClass = IUseBlockAction::class, + modulePackage = MultibindingConfig.GENERATED_MODULES_PACKAGE, + moduleName = "UseBlockActionsModule" +) +annotation class BindUseBlockAction(val stringKey: String) diff --git a/core/src/ru/deadsoftware/cavedroid/misc/annotations/multibinding/BindUseItemAction.kt b/core/src/ru/deadsoftware/cavedroid/misc/annotations/multibinding/BindUseItemAction.kt new file mode 100644 index 0000000..7f17bfc --- /dev/null +++ b/core/src/ru/deadsoftware/cavedroid/misc/annotations/multibinding/BindUseItemAction.kt @@ -0,0 +1,11 @@ +package ru.deadsoftware.cavedroid.misc.annotations.multibinding + +import ru.deadsoftware.cavedroid.game.actions.useitem.IUseItemAction +import ru.fredboy.automultibind.annotations.BindsIntoMapStringKey + +@BindsIntoMapStringKey( + interfaceClass = IUseItemAction::class, + modulePackage = MultibindingConfig.GENERATED_MODULES_PACKAGE, + moduleName = "UseItemActionsModule" +) +annotation class BindUseItemAction(val stringKey: String) diff --git a/core/src/ru/deadsoftware/cavedroid/misc/annotations/multibinding/MultibindingConfig.kt b/core/src/ru/deadsoftware/cavedroid/misc/annotations/multibinding/MultibindingConfig.kt new file mode 100644 index 0000000..12427bd --- /dev/null +++ b/core/src/ru/deadsoftware/cavedroid/misc/annotations/multibinding/MultibindingConfig.kt @@ -0,0 +1,5 @@ +package ru.deadsoftware.cavedroid.misc.annotations.multibinding + +data object MultibindingConfig { + const val GENERATED_MODULES_PACKAGE = "ru.deadsoftware.cavedroid.generated.module" +} \ No newline at end of file diff --git a/core/src/ru/deadsoftware/cavedroid/misc/utils/MeasureUnitsUtils.kt b/core/src/ru/deadsoftware/cavedroid/misc/utils/MeasureUnitsUtils.kt index ecf1ce0..24103e7 100644 --- a/core/src/ru/deadsoftware/cavedroid/misc/utils/MeasureUnitsUtils.kt +++ b/core/src/ru/deadsoftware/cavedroid/misc/utils/MeasureUnitsUtils.kt @@ -15,4 +15,4 @@ val Int.px get() = this * 16f /** * Converts this value in PIXELS into blocks */ -val Float.bl get() = MathUtils.floor(this / 16) \ No newline at end of file +val Float.bl get() = MathUtils.floor(this / 16f) \ No newline at end of file diff --git a/core/src/ru/deadsoftware/cavedroid/misc/utils/RenderingUtils.kt b/core/src/ru/deadsoftware/cavedroid/misc/utils/RenderingUtils.kt index 8976c99..917f69b 100644 --- a/core/src/ru/deadsoftware/cavedroid/misc/utils/RenderingUtils.kt +++ b/core/src/ru/deadsoftware/cavedroid/misc/utils/RenderingUtils.kt @@ -1,9 +1,12 @@ package ru.deadsoftware.cavedroid.misc.utils +import com.badlogic.gdx.Gdx import com.badlogic.gdx.graphics.Color +import com.badlogic.gdx.graphics.GL20 import com.badlogic.gdx.graphics.g2d.GlyphLayout import com.badlogic.gdx.graphics.g2d.SpriteBatch import com.badlogic.gdx.math.Rectangle +import ru.deadsoftware.cavedroid.MainConfig import ru.deadsoftware.cavedroid.misc.Assets private fun Rectangle.shifted(shift: Float) = Rectangle(x + shift, y, width, height) @@ -69,3 +72,27 @@ fun colorFromHexString(hex: String): Color { rgba = (rgba shl 8) or 0xFF return Color(rgba) } + +fun SpriteBatch.withScissors( + mainConfig: MainConfig, + x: Float, + y: Float, + width: Float, + height: Float, + block: () -> Unit +) { + val scaleX = Gdx.graphics.width / mainConfig.width + val scaleY = Gdx.graphics.height / mainConfig.height + + flush() + Gdx.gl.glEnable(GL20.GL_SCISSOR_TEST) + Gdx.gl.glScissor( + /* x = */ (x * scaleX).toInt(), + /* y = */ ((mainConfig.height - y - height) * scaleY).toInt(), + /* width = */ (width * scaleX).toInt(), + /* height = */ (height * scaleY).toInt() + ) + block.invoke() + flush() + Gdx.gl.glDisable(GL20.GL_SCISSOR_TEST) +} diff --git a/core/src/ru/deadsoftware/cavedroid/misc/utils/SpriteUtils.kt b/core/src/ru/deadsoftware/cavedroid/misc/utils/SpriteUtils.kt index 7b75e38..a26c5b9 100644 --- a/core/src/ru/deadsoftware/cavedroid/misc/utils/SpriteUtils.kt +++ b/core/src/ru/deadsoftware/cavedroid/misc/utils/SpriteUtils.kt @@ -1,5 +1,6 @@ package ru.deadsoftware.cavedroid.misc.utils +import com.badlogic.gdx.graphics.Color import com.badlogic.gdx.graphics.g2d.Sprite import com.badlogic.gdx.graphics.g2d.SpriteBatch @@ -14,14 +15,20 @@ fun SpriteBatch.drawSprite( rotation: Float = 0f, width: Float = sprite.regionWidth.toFloat(), height: Float = sprite.regionHeight.toFloat(), + tint: Color? = null, ) { + val oldColor = sprite.color + sprite.setPosition(x, y) sprite.setSize(width, height) sprite.rotation = rotation + tint?.let(sprite::setColor) + sprite.draw(this) sprite.setSize(sprite.regionWidth.toFloat(), sprite.regionHeight.toFloat()) sprite.rotation = 0f + sprite.color = oldColor } fun Sprite.applyOrigin(origin: SpriteOrigin) { diff --git a/core/src/ru/deadsoftware/cavedroid/prefs/PreferencesStore.kt b/core/src/ru/deadsoftware/cavedroid/prefs/PreferencesStore.kt new file mode 100644 index 0000000..edc9517 --- /dev/null +++ b/core/src/ru/deadsoftware/cavedroid/prefs/PreferencesStore.kt @@ -0,0 +1,9 @@ +package ru.deadsoftware.cavedroid.prefs + +interface PreferencesStore { + + fun getPreference(key: String): String? + + fun setPreference(key: String, value: String?) + +} diff --git a/desktop/build.gradle b/desktop/build.gradle index 70a63ba..9127345 100644 --- a/desktop/build.gradle +++ b/desktop/build.gradle @@ -1,16 +1,19 @@ plugins { + id 'java-library' id 'kotlin' id 'org.jetbrains.kotlin.plugin.serialization' version "$kotlinVersion" } -sourceCompatibility = 17 -sourceSets.main.java.srcDirs = [ "src/" ] +java.targetCompatibility = JavaVersion.VERSION_17 +java.sourceCompatibility = JavaVersion.VERSION_1_8 + +sourceSets.main.java.srcDirs = ["src/"] sourceSets.main.resources.srcDirs = ["../android/assets"] project.ext.mainClassName = "ru.deadsoftware.cavedroid.desktop.DesktopLauncher" project.ext.assetsDir = new File("../android/assets") -task run(dependsOn: classes, type: JavaExec) { +task run(dependsOn: build, type: JavaExec) { main = project.mainClassName classpath = sourceSets.main.runtimeClasspath standardInput = System.in @@ -19,7 +22,7 @@ task run(dependsOn: classes, type: JavaExec) { args "--debug" } -task runTouch(dependsOn: classes, type: JavaExec) { +task runTouch(dependsOn: build, type: JavaExec) { main = project.mainClassName classpath = sourceSets.main.runtimeClasspath standardInput = System.in @@ -28,25 +31,20 @@ task runTouch(dependsOn: classes, type: JavaExec) { args "--touch", "--debug" } -task debug(dependsOn: classes, type: JavaExec) { - main = project.mainClassName - classpath = sourceSets.main.runtimeClasspath - standardInput = System.in - workingDir = project.assetsDir - ignoreExitValue = true as JavaExecSpec - debug = true -} - -task dist(type: Jar) { +task dist(dependsOn: build, type: Jar) { duplicatesStrategy = DuplicatesStrategy.EXCLUDE manifest { attributes 'Main-Class': project.mainClassName } from { - configurations.compileClasspath.collect { it.isDirectory() ? it : zipTree(it) } + configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } } with jar } - -dist.dependsOn classes \ No newline at end of file +dependencies { + implementation project(":core") + implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:$kotlinSerializationVersion" + api "com.badlogicgames.gdx:gdx-backend-lwjgl3:$gdxVersion" + api "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-desktop" +} diff --git a/desktop/src/ru/deadsoftware/cavedroid/desktop/DesktopLauncher.java b/desktop/src/ru/deadsoftware/cavedroid/desktop/DesktopLauncher.java index fe78235..5903920 100644 --- a/desktop/src/ru/deadsoftware/cavedroid/desktop/DesktopLauncher.java +++ b/desktop/src/ru/deadsoftware/cavedroid/desktop/DesktopLauncher.java @@ -8,7 +8,8 @@ import ru.deadsoftware.cavedroid.CaveGame; class DesktopLauncher { public static void main(String[] arg) { Lwjgl3ApplicationConfiguration config = new Lwjgl3ApplicationConfiguration(); - config.setWindowIcon(Files.FileType.Internal, "icons/icon256.png", "icons/icon128.png"); + config.setWindowIcon(Files.FileType.Internal, + "icons/icon512.png", "icons/icon256.png", "icons/icon128.png"); config.setTitle("CaveDroid"); config.setWindowedMode(960, 540); config.useVsync(true); @@ -34,7 +35,8 @@ class DesktopLauncher { } } - CaveGame caveGame = new CaveGame(System.getProperty("user.home") + "/.cavedroid", touch, assetsPath); + CaveGame caveGame = new CaveGame(System.getProperty("user.home") + "/.cavedroid", touch, + new DesktopPreferencesStore(), assetsPath); caveGame.setDebug(debug); new Lwjgl3Application(caveGame, config); diff --git a/desktop/src/ru/deadsoftware/cavedroid/desktop/DesktopPreferencesStore.kt b/desktop/src/ru/deadsoftware/cavedroid/desktop/DesktopPreferencesStore.kt new file mode 100644 index 0000000..03591bb --- /dev/null +++ b/desktop/src/ru/deadsoftware/cavedroid/desktop/DesktopPreferencesStore.kt @@ -0,0 +1,18 @@ +package ru.deadsoftware.cavedroid.desktop + +import ru.deadsoftware.cavedroid.prefs.PreferencesStore +import java.util.prefs.Preferences + +class DesktopPreferencesStore : PreferencesStore { + + private val prefs = Preferences.userNodeForPackage(DesktopPreferencesStore::class.java) + + override fun getPreference(key: String): String? { + return prefs.get(key, null) + } + + override fun setPreference(key: String, value: String?) { + prefs.put(key, value) + } + +} \ No newline at end of file diff --git a/make-release.sh b/make-release.sh index 5e3f71a..23acc64 100755 --- a/make-release.sh +++ b/make-release.sh @@ -5,7 +5,7 @@ if [[ ! $1 ]]; then exit fi -./require_clean_work_tree "$0" +./require-clean-work-tree.sh "$0" || exit 1 release_dir="release-$1" diff --git a/require-celan-work-tree.sh b/require-clean-work-tree.sh old mode 100644 new mode 100755 similarity index 100% rename from require-celan-work-tree.sh rename to require-clean-work-tree.sh diff --git a/settings.gradle b/settings.gradle index 77ae463..99367df 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1,2 @@ -include 'desktop', 'android', 'core' \ No newline at end of file +include 'desktop', 'android', 'core' +