diff --git a/.editorconfig b/.editorconfig index 6effc03c5..48902f6ed 100644 --- a/.editorconfig +++ b/.editorconfig @@ -8,14 +8,35 @@ charset = utf-8 [**.java] indent_style = tab indent_size = tab +ij_smart_tabs = true tab_width = 4 -ij_java_imports_layout = *,|,javax.**,|,java.**,|,$* +ij_java_imports_layout = *, |, javax.**, |, java.**, |, $* ij_java_packages_to_use_import_on_demand = unset ij_java_class_count_to_use_import_on_demand = 99999999 ij_java_names_count_to_use_import_on_demand = 99999999 ij_java_use_single_class_imports = true ij_java_insert_inner_class_imports = false ij_java_layout_static_imports_separately = true +ij_java_space_before_array_initializer_left_brace = true +ij_java_block_comment_add_space = true +ij_java_line_comment_add_space = true +ij_java_space_after_closing_angle_bracket_in_type_argument = true +ij_java_space_before_annotation_array_initializer_left_brace = true +ij_java_spaces_within_array_initializer_braces = true +ij_java_spaces_within_braces = true +ij_java_doc_add_blank_line_after_description = false +ij_java_doc_keep_empty_lines = true +ij_java_doc_indent_on_continuation = true +ij_java_doc_do_not_wrap_if_one_line = true +ij_java_keep_simple_blocks_in_one_line = true +ij_java_keep_simple_classes_in_one_line = true +ij_java_keep_simple_lambdas_in_one_line = true +ij_java_keep_simple_methods_in_one_line = true +ij_java_method_annotation_wrap = on_every_item +ij_java_field_annotation_wrap = on_every_item +ij_java_do_not_wrap_after_single_annotation = false +ij_java_do_not_wrap_after_single_annotation_in_parameter = true +ij_java_indent_case_from_switch = true [**.json] indent_style = space diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 50ae616dc..9a69af588 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -12,6 +12,7 @@ A clear and concise description of what the bug is. **To Reproduce** Steps to reproduce the behavior: + 1. Go to '...' 2. Click on '....' 3. See error @@ -23,8 +24,9 @@ A clear and concise description of what you expected to happen. If applicable, add screenshots to help explain your problem. **Desktop (please complete the following information):** - - OS: [e.g. Windows] - - Game version [e.g. 2.0.7] + +- OS: [e.g. Windows] +- Game version [e.g. 2.0.7] **Additional context** Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 000000000..bd9a33111 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: false +contact_links: + - name: Question + url: https://github.com/MinicraftPlus/minicraft-plus-revived/discussions + about: Ask a question diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md deleted file mode 100644 index c4c57ea96..000000000 --- a/.github/ISSUE_TEMPLATE/question.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -name: Question -about: Ask a question -title: Question -labels: Question -assignees: '' - ---- - -**What the question is about?** -A brief description of what you wanted to ask. Ex. I don't know how can I [...] - -**Additional context** -Add any other context or screenshots about the question here. diff --git a/.github/workflows/autobuild.yml b/.github/workflows/autobuild.yml index 631cf6746..9bff81a7e 100644 --- a/.github/workflows/autobuild.yml +++ b/.github/workflows/autobuild.yml @@ -1,36 +1,33 @@ name: Nightly build on: schedule: - - cron: '0 0 * * *' + - cron: '0 0 * * *' workflow_dispatch: - + jobs: gradle: strategy: matrix: - os: [ubuntu-latest] + os: [ ubuntu-latest ] runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v3 - - uses: actions/setup-java@v3 - with: - distribution: temurin - java-version: 8 - - - name: Setup Gradle - uses: gradle/gradle-build-action@v2.4.2 - - - name: Execute Gradle build - run: ./gradlew build - - - uses: "dciborow/action-github-releases@v1.0.1" - with: - repo_token: "${{ secrets.GITHUB_TOKEN }}" - prerelease: true - title: "Nightly (breaking)" - generate_release_notes: true - files: | - LICENSE - ChangeLog.md - build/libs/**.jar - + - uses: actions/checkout@v3 + - uses: actions/setup-java@v3 + with: + distribution: temurin + java-version: 8 + + - name: Setup Gradle + uses: gradle/gradle-build-action@v2.4.2 + + - name: Execute Gradle build + run: ./gradlew build + + - uses: actions/upload-artifact@v3.1.2 + with: + name: "Nightly release" + path: | + LICENSE + ChangeLog.md + build/libs/**.jar + if-no-files-found: error diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index c1d66f49d..a0fefaba5 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -37,36 +37,36 @@ jobs: # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support steps: - - name: Checkout repository - uses: actions/checkout@v3 + - name: Checkout repository + uses: actions/checkout@v3 - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v2 - with: - languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - - # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs - # queries: security-extended,security-and-quality + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. - - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild - uses: github/codeql-action/autobuild@v2 + # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs + # queries: security-extended,security-and-quality - # ℹ️ Command-line programs to run using the OS shell. - # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun - # If the Autobuild fails above, remove it and uncomment the following three lines. - # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v2 - # - run: | - # echo "Run, Build Application using script" - # ./location_of_script_within_repo/buildscript.sh + # ℹ️ Command-line programs to run using the OS shell. + # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + # If the Autobuild fails above, remove it and uncomment the following three lines. + # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. + + # - run: | + # echo "Run, Build Application using script" + # ./location_of_script_within_repo/buildscript.sh + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index c003ebe5b..8349d4ae4 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -1,18 +1,25 @@ -name: publish -on: [workflow_dispatch] # Manual trigger +name: Publish package to GitHub Packages +on: + release: + types: [created] jobs: - build: - strategy: - matrix: - java: [ 8-jdk ] - runs-on: ubuntu-20.04 - container: - image: eclipse-temurin:${{ matrix.java }} - options: --user root + publish: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write steps: - - uses: actions/checkout@v1 - - uses: gradle/wrapper-validation-action@v1 - - run: ./gradlew publish --stacktrace + - uses: actions/checkout@v4 + - uses: actions/setup-java@v3 + with: + java-version: '8' + distribution: 'oracle' + - name: Validate Gradle wrapper + uses: gradle/wrapper-validation-action@ccb4328a959376b642e027874838f60f8e596de3 + - name: Publish package + uses: gradle/gradle-build-action@749f47bda3e44aa060e82d7b3ef7e40d953bd629 + with: + arguments: publish env: - MAVEN_PUBLISH_TOKEN: ${{ secrets.MAVEN_PUBLISH_TOKEN }} - MAVEN_PUBLISH_USERNAME: ${{ secrets.MAVEN_PUBLISH_USERNAME }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GITHUB_ACTOR: ${{ secrets.GITHUB_ACTOR }} diff --git a/.gitignore b/.gitignore index 7537dea4e..05b77b506 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ +# dev savedir folder +run/ + # Compiled class file *.class diff --git a/ChangeLog.md b/ChangeLog.md index e2a8c6884..14a3d4f46 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -7,16 +7,42 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html), but some sections are changed to compliant this project. +## [2.2.1] + +### Additions + +* Added ornate wood tiles + +### Changes + +* Disabled hardware acceleration by default +* Hardware acceleration is now a toggle in settings +* Screenshots will now be the size of the rendered view within the window +* Updated localization + +### Removals + +* Removed argument flag `--no-hardware-acceleration` +* Removed screenshot size setting + +### Fixes + +* Optimized light source rendering +* Optimized calculations +* Fixed the texture on stone hoe + ## [2.2.0] ### Additions -* Added a quest system -* Added tutorial -* Added obsidian knight as the second boss +* Added quest system +* Added tutorials +* Added obsidian knight as the second boss (Air Wizard II replacement) * Added limitation to inventories * Added limitation to stackable items -* Added four new debug arguments - `--debug-log-time`, `--debug-log-thread`, `--debug-log-trace`, `--debug-filelog-full` +* Added seven new debug arguments: + `--debug-log-time`, `--debug-log-thread`, `--debug-log-trace`, `--debug-filelog-full`, `--debug-level`, `--debug-locale`, `--debug-unloc-tracing` +* Added a new argument for disabling hardware acceleration - `--no-hardware-acceleration` * Added a toggle for HUD display * Added a toggle for simplified effect display * Added a new menu for creative mode @@ -25,17 +51,17 @@ but some sections are changed to compliant this project. * Added a crash handler and a better look of dialog. * Added a simple ability for screenshots * Added dynamic for sounds -* Added sand particle for sand +* ReAdded sand footprint particle for sand * Added characters to the font (`ÀÂÄÈÎÌÏÒÙÛÝ*«»£$&€§ªº`) * Added world-wide seed * Added controller support * Added on-screen keyboard -* Added logo splash screen * Added glass bottle and made potions return glass bottles when used -* Added dyes (#445) -* Added coloured sheep (#445) -* Added ability to dye sheep and beds (#445) -* Cow and sheep now graze on grasses +* Added a trigger to auto-enable hardware acceleration +* Added support for lower-cased letters +* Added item description menu +* Added fences +* Added editable signs ### Changes @@ -46,15 +72,29 @@ but some sections are changed to compliant this project. * If the application flag `--savedir` is present, '.playminicraft/mods/Minecraft Plus' will no longer be appended * Updated all ore-related and metal-related textures * Made the parent display render in the background -* Made recipies unlockable +* Made recipes unlockable * Made you reobtain your old clothes when putting on new clothing +* Made you reobtain empty bottles when a bottle of potion is consumed * Made languages fallback to English * Improved the tile place indicator * Overhauled debugging actions +* Overhauled the farming system +* Changed the languaging setting menu +* Optimized CPU usage +* Reduced food stamina cost +* Made some strings lower-cased +* Updated spawning and despawning conditions +* Iron and gold now require 3 ores instead of 4 for crafting +* Renamed `assets/books/story_guide.txt` to `assets/books/game_guide.txt` +* Updated `assets/books/game_guide.txt` and `assets/books/instructions.txt` +* Sand footprints are now more accurately placed +* Optimized rendering +* Increased death chest despawn timer as follows: + Easy: 450 secs, Normal: 300 secs, Hard: 150 secs ### Removals -* Removed stepped sand texture +* None (compared to 2.1.3) ### Fixes @@ -62,6 +102,11 @@ but some sections are changed to compliant this project. * Fixed rendering positioning problem of color code styled texts * Fixed lights disappearing when out of screen * Fixed animals and items destroying plants +* Fixed various old world loading crashes, including migration to the new destination +* Fixed possible crash when Air Wizard is not loaded +* Fixed minor loading bugs to dungeon chests +* Fixed performance issue in WaterTile ticking +* Fixed majority of audio issues ## [2.1.3] @@ -400,7 +445,11 @@ but some sections are changed to compliant this project. > * Added an Iron Lantern at the entrance of the purple dungeon [2.2.0]: https://github.com/MinicraftPlus/minicraft-plus-revived/compare/v2.1.3...HEAD + [2.1.3]: https://github.com/MinicraftPlus/minicraft-plus-revived/compare/v2.1.2...v2.1.3 + [2.1.2]: https://github.com/MinicraftPlus/minicraft-plus-revived/compare/v2.1.1...v2.1.2 + [2.1.1]: https://github.com/MinicraftPlus/minicraft-plus-revived/compare/v2.1.0...v2.1.1 + [2.1.0]: https://github.com/MinicraftPlus/minicraft-plus-revived/compare/v2.0.7...v2.1.0 diff --git a/Credits.md b/Credits.md index 2d13f6ee4..d4e3b7333 100644 --- a/Credits.md +++ b/Credits.md @@ -1,16 +1,21 @@ ## Credits + Original game by Markus "Notch" Persson. ### Former maintainers + * David.b * Dillyg10 * Chris J * afyber +* Makkkkus ### Current maintainer -* Makkkkus + +* Litorom1 ### Code contributions from + * A.L.I.C.E * BenCheung0422 * Christoffer Holmesland @@ -21,11 +26,13 @@ Original game by Markus "Notch" Persson. * rocketedsocks ### Art contributions from + * TheBigEye * JamesTDG * Geek_Joystick ### Localisation contributions from + * A.L.I.C.E * Christoffer Holmesland * GladfanIsHere diff --git a/README.md b/README.md index 4d00c10c3..eb4b80914 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,28 @@ +[![Nightly build](https://github.com/MinicraftPlus/minicraft-plus-revived/actions/workflows/autobuild.yml/badge.svg?branch=main)](https://github.com/MinicraftPlus/minicraft-plus-revived/actions/workflows/autobuild.yml) +[![CodeQL](https://github.com/MinicraftPlus/minicraft-plus-revived/actions/workflows/codeql-analysis.yml/badge.svg?branch=main)](https://github.com/MinicraftPlus/minicraft-plus-revived/actions/workflows/codeql-analysis.yml) + # Minicraft+ + ![Minicraft+](https://user-images.githubusercontent.com/37084190/138313821-75ac3112-7044-45c1-bdbb-d89f2333c2c0.png) -Minicraft+ is an overhaul mod of Minicraft, a game made by Markus "Notch" Persson in the Ludum Dare 22 contest. To learn more about Minicraft take a look at [playminicraft.com](https://www.playminicraft.com), talk to the community at our [Discord](https://discord.me/minicraft), or check out our [Fandom Wiki](https://minicraft.fandom.com/wiki/Minicraft_Wiki). +Minicraft+ is an overhaul mod of Minicraft, a game made by Markus "Notch" Persson in the Ludum Dare 22 contest. To learn +more about Minicraft take a look at [playminicraft.com](https://www.playminicraft.com), talk to the community at +our [Discord](https://discord.me/minicraft), or check out +our [wiki.gg Wiki](https://minicraft.wiki.gg/wiki/). -Check the [releases](https://github.com/minicraftplus/minicraft-plus-revived/releases) page to download the latest version, or older versions. +Check the [releases](https://github.com/minicraftplus/minicraft-plus-revived/releases) page to download the latest +version, or older versions. ## Major features + * Four new gamemodes - * Creative - * Hardcore - * Score - * Survival + * Creative + * Hardcore + * Score + * Survival * Saving and loading -* Multiplayer mode and an account system (Now supported by [El-Virus](https://www.github.com/ElVir-Software/minicraft-plus-online)) +* Multiplayer mode and an account system (Now supported + by [El-Virus](https://www.github.com/ElVir-Software/minicraft-plus-online)) * More mobs * Personal crafting menu * Beds @@ -29,25 +39,40 @@ Check the [releases](https://github.com/minicraftplus/minicraft-plus-revived/rel * Support for several languages * and many, many more! +## System Prerequisites + +Our game only supports Windows, MacOS and Linux. Furthermore, newer platform versions are required for controllers. + +For Java, you may check out [system requirements for Java](https://www.java.com/en/download/help/sysreq.html). + ## Current goals and ideas -Take a look at the [ideas](ideas/) folder or the [issues](https://github.com/minicraftplus/minicraft-plus-revived/issues) page. + +Take a look at the [ideas](ideas/) folder or +the [issues](https://github.com/minicraftplus/minicraft-plus-revived/issues) page. ## Getting the game and run the game -Head over [releases](https://github.com/minicraftplus/minicraft-plus-revived/releases) and find the latest version of Minicraft+. -There, you can find an file called `minicraft_plus.jar`. Click the file, and after you have downloaded the file, you must double-click the file in downloads folder to open it. -You must first confirm that you have [Java](https://www.java.com/en/download/) (at least version 8) installed on your computer. + +Head over [releases](https://github.com/minicraftplus/minicraft-plus-revived/releases) and find the latest version of +Minicraft+. +There, you can find an file called `minicraft_plus.jar`. Click the file, and after you have downloaded the file, you +must double-click the file in downloads folder to open it. +You must first confirm that you have [Java](https://www.java.com/en/download/) (at least version 8) installed on your +computer. ## Localization -This project is running with an external localization platform called POEditor. You can contribute localization by clicking the image below! -[![Minicraft+ POEditor Stats](https://raw.githubusercontent.com/BenCheung0422/MinicraftPlus-POEditor-Stats/main/docs/poeditor_stats.svg)](https://poeditor.com/join/project/xvtwoWhNXe) +This project is running with an external localization platform called Lokalise. You can now [head over Lokalise to contribute localization](https://app.lokalise.com/public/42925017655336d50b3007.03067253/)! ## How to build/run in development + Because this project uses a build tool called gradle it is very easy to build or run the project from the source code. 1. Download the source code by clicking the green code button, and download it as a ZIP. 2. Extract the contents of the folder. -3. Open command prompt and enter `cd [folder_location]`, this will open the folder in the command prompt. -4. Type `gradlew run` or `gradlew build` to run or build the program. This might take some time. If on unix, add "./" to the front. - 1. If you built the project, the jar file is found in `build/libs` - 2. If you get an error screaming that you're missing java. You need to [set up](https://confluence.atlassian.com/doc/setting-the-java_home-variable-in-windows-8895.html) your JAVA_HOME environment variable, or download a JDK if you haven't already. +3. Open command prompt and enter `cd `, this will open the folder in the command prompt. +4. Type `gradlew run` or `gradlew build` to run or build the program. This might take some time. If on unix, add "./" to + the front. If on Windows using an IDE or Windows Powershell, add ".\" to the front. + 1. If you built the project, the jar file is found in `build/libs` + 2. If you get an error screaming that you're missing java. You need + to [set up](https://confluence.atlassian.com/doc/setting-the-java_home-variable-in-windows-8895.html) your + JAVA_HOME environment variable, or download a JDK if you haven't already. diff --git a/build.gradle b/build.gradle index 8911d1700..01be4c064 100644 --- a/build.gradle +++ b/build.gradle @@ -1,11 +1,12 @@ plugins { id 'application' + id 'maven-publish' } allprojects { apply plugin: "java" - version = "2.2.0-dev3" + version = "2.2.1-dev1" sourceCompatibility = 8 [compileJava, compileTestJava]*.options*.encoding = 'UTF-8' @@ -94,13 +95,26 @@ jar { from files(sourceSets.main.output.classesDirs) from files(sourceSets.main.output.resourcesDir) - from { configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }} + from { configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } } +} + +publishing { + repositories { + maven { + name = "GitHubPackages" + url = "https://maven.pkg.github.com/MinicraftPlus/minicraft-plus-revived" + credentials { + username = System.getenv("GITHUB_ACTOR") + password = System.getenv("GITHUB_TOKEN") + } + } + } } // Don't override if we're building a tar package. -tasks.withType(Tar){ +tasks.withType(Tar) { duplicatesStrategy = DuplicatesStrategy.EXCLUDE } -tasks.withType(Zip){ +tasks.withType(Zip) { duplicatesStrategy = DuplicatesStrategy.INCLUDE } diff --git a/ideas/ideas for new additions.txt b/ideas/ideas for new additions.txt index a9e5284ea..cc8f0ee87 100644 --- a/ideas/ideas for new additions.txt +++ b/ideas/ideas for new additions.txt @@ -5,9 +5,9 @@ New Potions?? [ ] Ragdoll potion: Allows you to control other mobs, but not other players. ++++ Additions -[ ] Add signs. So, when you walk over them, a message is displayed! +[X] Add signs. So, when you walk over them, a message is displayed! [ ] Add maps. Possible crafting recipe: bones and leather. One for each level on the smallest world size, and progressively more maps should be needed otherwise. Should I make the maps lock to "chuck" sort of locations, or always make the center the current location, where possible? It could work by having a mini-map in the upper-left whenever the map is the active item, and there is no menu open. -[ ] Bone meal to make trees grow. Though I might make something else that has the same functionality, instead. +[X] Bone meal to make trees grow. Though I might make something else that has the same functionality, instead. [ ] Tipped/Enchanted Arrows [ ] Fire [ ] Flint N' Steel @@ -17,7 +17,7 @@ Additions [ ] Milk & bad status effects. [ ] Boats; though I don't see them being *too* useful without infinite terrain and vast oceans... ++++ -[ ] add controller support +[X] Add controller support [ ] Make beds colorable [ ] Add world backup option, that user can select a download location. Then maybe... pack to zip? Also, I'll need to make a "restore" feature, and unzip it, so this could get complicated... [X] Custom skins diff --git a/settings.gradle b/settings.gradle index ed6c13faa..0360f2e6a 100644 --- a/settings.gradle +++ b/settings.gradle @@ -4,6 +4,6 @@ include "common" include "client" include "server" -rootProject.children.each {project -> +rootProject.children.each { project -> project.projectDir = new File(settingsDir, "src/${project.name}") } diff --git a/src/client/java/minicraft/core/Action.java b/src/client/java/minicraft/core/Action.java index 4b931e34b..520187682 100644 --- a/src/client/java/minicraft/core/Action.java +++ b/src/client/java/minicraft/core/Action.java @@ -2,7 +2,7 @@ @FunctionalInterface public interface Action { - + void act(); - + } diff --git a/src/client/java/minicraft/core/CrashHandler.java b/src/client/java/minicraft/core/CrashHandler.java index 15157c31e..6da80acaa 100644 --- a/src/client/java/minicraft/core/CrashHandler.java +++ b/src/client/java/minicraft/core/CrashHandler.java @@ -28,10 +28,18 @@ import java.util.concurrent.Future; public class CrashHandler { - public static void crashHandle(Thread thread, Throwable throwable) { crashHandle(throwable); } - public static void crashHandle(Throwable throwable) { crashHandle(throwable, new ErrorInfo(true)); } - /** This handles application crashing errors by giving notification to the user clearly.
- * The user can only exit the program. */ + public static void crashHandle(Thread thread, Throwable throwable) { + crashHandle(throwable); + } + + public static void crashHandle(Throwable throwable) { + crashHandle(throwable, new ErrorInfo(true)); + } + + /** + * This handles application crashing errors by giving notification to the user clearly.
+ * The user can only exit the program. + */ public static void crashHandle(Throwable throwable, ErrorInfo info) { Logging.CRASHHANDLER.error(throwable); @@ -45,7 +53,8 @@ public static void crashHandle(Throwable throwable, ErrorInfo info) { if (GraphicsEnvironment.isHeadless() && ping != null) { try { ping.get(); - } catch (Exception ignored) {} + } catch (Exception ignored) { + } return; } @@ -100,11 +109,19 @@ public static void crashHandle(Throwable throwable, ErrorInfo info) { System.exit(info.type.exitCode); } - public static void errorHandle(Throwable throwable) { errorHandle(throwable, new ErrorInfo()); } - public static void errorHandle(Throwable throwable, ErrorInfo info) { errorHandle(throwable, info, null); } - /** This handles application crashing errors by giving notification to the user clearly.
+ public static void errorHandle(Throwable throwable) { + errorHandle(throwable, new ErrorInfo()); + } + + public static void errorHandle(Throwable throwable, ErrorInfo info) { + errorHandle(throwable, info, null); + } + + /** + * This handles application crashing errors by giving notification to the user clearly.
* The user can ignore the error, continue handling the error or exit the program (only in serious errors or error reports). - * @param handling The handling function of the error. */ + * @param handling The handling function of the error. + */ public static void errorHandle(Throwable throwable, ErrorInfo info, @Nullable Action handling) { throwable.printStackTrace(); @@ -118,7 +135,8 @@ public static void errorHandle(Throwable throwable, ErrorInfo info, @Nullable Ac if (GraphicsEnvironment.isHeadless() && ping != null) { try { ping.get(); - } catch (Exception ignored) {} + } catch (Exception ignored) { + } return; } @@ -161,13 +179,18 @@ public static void errorHandle(Throwable throwable, ErrorInfo info, @Nullable Ac dialog.setVisible(true); // Shows the dialog. } - /** Getting the stack trace display component. */ + /** + * Getting the stack trace display component. + */ private static JScrollPane getErrorScrollPane(String stackTrace) { JTextArea errorDisplay = new JTextArea(stackTrace); errorDisplay.setEditable(false); return new JScrollPane(errorDisplay); } - /** Getting the panel for crashing handling dialog. */ + + /** + * Getting the panel for crashing handling dialog. + */ private static JPanel getCrashPanel(ErrorInfo info, JScrollPane errorPane, JDialog dialog, String stackTrace) { JPanel panel = new JPanel(new BorderLayout()); panel.add(errorPane); @@ -190,6 +213,7 @@ private static JPanel getCrashPanel(ErrorInfo info, JScrollPane errorPane, JDial panel.add(buttonPanel, BorderLayout.SOUTH); return panel; } + private static JPanel getErrorPanel(ErrorInfo info, JScrollPane errorPane, JDialog dialog, String stackTrace, Action callback, Future> ping) { JPanel panel = new JPanel(new BorderLayout()); panel.add(errorPane); @@ -249,13 +273,31 @@ public static class ErrorInfo { public final String message; public final boolean serious; - public ErrorInfo() { this(false); } - public ErrorInfo(boolean crashing) { this(crashing ? "General Application Crash" : "General Application Error", - crashing ? ErrorType.DEFAULT : ErrorType.REPORT); } - public ErrorInfo(String topic) { this(topic, ErrorType.DEFAULT); } - public ErrorInfo(String topic, ErrorType type) { this(topic, type, type.exitCode != 0); } - public ErrorInfo(String topic, ErrorType type, boolean serious) { this(topic, type, serious, null); } - public ErrorInfo(String topic, ErrorType type, String message) { this(topic, type, type.exitCode < 0, message); } + public ErrorInfo() { + this(false); + } + + public ErrorInfo(boolean crashing) { + this(crashing ? "General Application Crash" : "General Application Error", + crashing ? ErrorType.DEFAULT : ErrorType.REPORT); + } + + public ErrorInfo(String topic) { + this(topic, ErrorType.DEFAULT); + } + + public ErrorInfo(String topic, ErrorType type) { + this(topic, type, type.exitCode != 0); + } + + public ErrorInfo(String topic, ErrorType type, boolean serious) { + this(topic, type, serious, null); + } + + public ErrorInfo(String topic, ErrorType type, String message) { + this(topic, type, type.exitCode < 0, message); + } + public ErrorInfo(String topic, ErrorType type, boolean serious, String message) { this.title = topic; this.type = type; @@ -263,17 +305,21 @@ public ErrorInfo(String topic, ErrorType type, boolean serious, String message) this.serious = serious; } - /** The error types. Add more types when needed. */ + /** + * The error types. Add more types when needed. + */ public static enum ErrorType { - DEFAULT (-1, "Unhandled error"), - UNEXPECTED (-2, "Unexpected error"), - UNHANDLEABLE (-3, "Unhandleable error"), - SERIOUS (1, "Serious error"), - HANDLED (0, "Handled error"), - REPORT (0, "Error report"), + DEFAULT(-1, "Unhandled error"), + UNEXPECTED(-2, "Unexpected error"), + UNHANDLEABLE(-3, "Unhandleable error"), + SERIOUS(1, "Serious error"), + HANDLED(0, "Handled error"), + REPORT(0, "Error report"), ; - /** The exit codes are referring to https://www.techiedelight.com/exit-codes-java-system-exit-method/ */ + /** + * The exit codes are referring to https://www.techiedelight.com/exit-codes-java-system-exit-method/ + */ public final int exitCode; public final String name; diff --git a/src/client/java/minicraft/core/Game.java b/src/client/java/minicraft/core/Game.java index 8fc3f1e7a..f2a97ab69 100644 --- a/src/client/java/minicraft/core/Game.java +++ b/src/client/java/minicraft/core/Game.java @@ -4,7 +4,6 @@ import minicraft.core.io.Settings; import minicraft.core.io.Sound; import minicraft.entity.mob.Player; -import minicraft.gfx.Screen; import minicraft.level.Level; import minicraft.level.tile.Tiles; import minicraft.network.Analytics; @@ -21,11 +20,12 @@ import java.util.List; public class Game { - protected Game() {} // Can't instantiate the Game class. + protected Game() { + } // Can't instantiate the Game class. public static final String NAME = "Minicraft Plus"; // This is the name on the application window. - public static final Version VERSION = new Version("2.2.0-dev3"); + public static final Version VERSION = new Version("2.2.1-dev1"); public static InputHandler input; // Input used in Game, Player, and just about all the *Menu classes. public static Player player; @@ -37,13 +37,18 @@ protected Game() {} // Can't instantiate the Game class. // DISPLAY static Display currentDisplay = null; static final ArrayDeque displayQuery = new ArrayDeque<>(); + public static void setDisplay(@Nullable Display display) { if (display == null) displayQuery.clear(); else displayQuery.add(display); } - public static void exitDisplay() { exitDisplay(1); } + + public static void exitDisplay() { + exitDisplay(1); + } + public static void exitDisplay(int depth) { if (depth < 1) return; // There is nothing needed to exit. if (displayQuery.isEmpty()) { @@ -61,11 +66,16 @@ public static void exitDisplay(int depth) { displayQuery.add(parent); } } + @Nullable - public static Display getDisplay() { return displayQuery.isEmpty() ? null : displayQuery.peekLast(); } + public static Display getDisplay() { + return displayQuery.isEmpty() ? null : displayQuery.peekLast(); + } // GAMEMODE - public static boolean isMode(String mode) { return ((String)Settings.get("mode")).equalsIgnoreCase(mode); } + public static boolean isMode(String mode) { + return ((String) Settings.get("mode")).equalsIgnoreCase(mode); + } // LEVEL public static Level[] levels = new Level[6]; // This array stores the different levels. @@ -76,7 +86,10 @@ public static void exitDisplay(int depth) { static boolean gameOver = false; // If the player wins this is set to true. static boolean running = true; - public static void quit() { running = false; } + + public static void quit() { + running = false; + } public static void main(String[] args) { @@ -87,6 +100,11 @@ public static void main(String[] args) { Analytics.GameStartup.ping(); + new Load(true, true); // This loads basic saved preferences. + // Reference: https://stackoverflow.com/a/13832805 + if ((boolean) Settings.get("hwa")) System.setProperty("sun.java2d.opengl", "true"); + MAX_FPS = (int) Settings.get("fps"); // DO NOT put this above. + input = new InputHandler(Renderer.canvas); ResourcePackDisplay.initPacks(); @@ -103,8 +121,7 @@ public static void main(String[] args) { World.resetGame(); // "half"-starts a new game, to set up initial variables player.eid = 0; - new Load(true); // This loads any saved preferences. - MAX_FPS = (int) Settings.get("fps"); // DO NOT put this above. + new Load(true, false); // This loads any saved preferences. // Update fullscreen frame if Updater.FULLSCREEN was updated previously if (Updater.FULLSCREEN) { diff --git a/src/client/java/minicraft/core/Initializer.java b/src/client/java/minicraft/core/Initializer.java index 8b6281d10..de2c99e44 100644 --- a/src/client/java/minicraft/core/Initializer.java +++ b/src/client/java/minicraft/core/Initializer.java @@ -21,7 +21,8 @@ import java.io.IOException; public class Initializer extends Game { - private Initializer() {} + private Initializer() { + } /** * Reference to actual frame, also it may be null. @@ -29,13 +30,19 @@ private Initializer() {} static JFrame frame; static int fra, tik; // These store the number of frames and ticks in the previous second; used for fps, at least. - public static JFrame getFrame() { return frame; } - public static int getCurFps() { return fra; } + public static JFrame getFrame() { + return frame; + } + + public static int getCurFps() { + return fra; + } static void parseArgs(String[] args) { // Parses command line arguments @Nullable String saveDir = null; + boolean enableHardwareAcceleration = true; for (int i = 0; i < args.length; i++) { if (args[i].equalsIgnoreCase("--savedir") && i + 1 < args.length) { i++; @@ -63,10 +70,11 @@ static void parseArgs(String[] args) { FileHandler.determineGameDir(saveDir); } - /** This is the main loop that runs the game. It: - * -keeps track of the amount of time that has passed - * -fires the ticks needed to run the game - * -fires the command to render out the screen. + /** + * This is the main loop that runs the game. It: + * -keeps track of the amount of time that has passed + * -fires the ticks needed to run the game + * -fires the command to render out the screen. */ static void run() { long lastTick = System.nanoTime(); @@ -104,7 +112,8 @@ static void run() { //noinspection BusyWait Thread.sleep((long) Math.floor(timeToWait / 1E6), (int) ((timeToWait - Math.floor(timeToWait)) % 1E6)); } - } catch (InterruptedException ignored) {} + } catch (InterruptedException ignored) { + } if (System.currentTimeMillis() - lastTimer1 > 1000) { //updates every 1 second long interval = System.currentTimeMillis() - lastTimer1; @@ -148,12 +157,25 @@ public void componentResized(ComponentEvent e) { }); frame.addWindowListener(new WindowListener() { - public void windowActivated(WindowEvent e) {} - public void windowDeactivated(WindowEvent e) {} - public void windowIconified(WindowEvent e) {} - public void windowDeiconified(WindowEvent e) {} - public void windowOpened(WindowEvent e) {} - public void windowClosed(WindowEvent e) { Logging.GAMEHANDLER.debug("Window closed"); } + public void windowActivated(WindowEvent e) { + } + + public void windowDeactivated(WindowEvent e) { + } + + public void windowIconified(WindowEvent e) { + } + + public void windowDeiconified(WindowEvent e) { + } + + public void windowOpened(WindowEvent e) { + } + + public void windowClosed(WindowEvent e) { + Logging.GAMEHANDLER.debug("Window closed"); + } + public void windowClosing(WindowEvent e) { Logging.GAMEHANDLER.info("Window closing"); quit(); @@ -161,7 +183,9 @@ public void windowClosing(WindowEvent e) { }); } - /** Launching the main window. */ + /** + * Launching the main window. + */ static void launchWindow() { frame.setVisible(true); frame.requestFocus(); @@ -171,9 +195,8 @@ static void launchWindow() { /** * Provides a String representation of the provided Throwable's stack trace * that is extracted via PrintStream. - * * @param throwable Throwable/Exception from which stack trace is to be - * extracted. + * extracted. * @return String with provided Throwable's stack trace. */ public static String getExceptionTrace(final Throwable throwable) { diff --git a/src/client/java/minicraft/core/Renderer.java b/src/client/java/minicraft/core/Renderer.java index 01e024f4e..8d92bab9d 100644 --- a/src/client/java/minicraft/core/Renderer.java +++ b/src/client/java/minicraft/core/Renderer.java @@ -23,21 +23,24 @@ import minicraft.item.PotionType; import minicraft.item.ToolItem; import minicraft.item.ToolType; +import minicraft.item.WateringCanItem; import minicraft.level.Level; import minicraft.screen.LoadingDisplay; import minicraft.screen.Menu; import minicraft.screen.QuestsDisplay; import minicraft.screen.RelPos; +import minicraft.screen.SignDisplayMenu; import minicraft.screen.TutorialDisplayHandler; import minicraft.screen.entry.ListEntry; import minicraft.screen.entry.StringEntry; +import minicraft.util.Logging; import minicraft.util.Quest; import minicraft.util.Quest.QuestSeries; import javax.imageio.ImageIO; import java.awt.Canvas; -import java.awt.Graphics; +import java.awt.Graphics2D; import java.awt.geom.AffineTransform; import java.awt.image.AffineTransformOp; import java.awt.image.BufferStrategy; @@ -67,11 +70,12 @@ private Renderer() { static Canvas canvas = new Canvas(); private static BufferedImage image; // Creates an image to be displayed on the screen. - private static Screen lightScreen; // Creates a front screen to render the darkness in caves (Fog of war). public static boolean readyToRenderGameplay = false; public static boolean showDebugInfo = false; + public static SignDisplayMenu signDisplayMenu = null; + private static Ellipsis ellipsis = new SmoothEllipsis(new TickUpdater()); private static int potionRenderOffset = 0; @@ -82,12 +86,12 @@ public static MinicraftImage loadDefaultSkinSheet() { MinicraftImage skinsSheet; try { // These set the sprites to be used. - skinsSheet = new MinicraftImage(ImageIO.read(Objects.requireNonNull(Game.class.getResourceAsStream("/resources/textures/skins.png")))); + skinsSheet = MinicraftImage.createDefaultCompatible(ImageIO.read(Objects.requireNonNull(Game.class.getResourceAsStream("/resources/textures/skins.png")))); } catch (NullPointerException e) { // If a provided InputStream has no name. (in practice meaning it cannot be found.) CrashHandler.crashHandle(e, new ErrorInfo("Sprite Sheet Not Found", ErrorInfo.ErrorType.UNEXPECTED, true, "A sprite sheet was not found.")); return null; - } catch (IOException | IllegalArgumentException e) { + } catch (IOException | IllegalArgumentException | MinicraftImage.MinicraftImageDimensionIncompatibleException e) { // If there is an error reading the file. CrashHandler.crashHandle(e, new ErrorInfo("Sprite Sheet Could Not be Loaded", ErrorInfo.ErrorType.UNEXPECTED, true, "Could not load a sprite sheet.")); return null; @@ -97,11 +101,10 @@ public static MinicraftImage loadDefaultSkinSheet() { } public static void initScreen() { - screen = new Screen(); - lightScreen = new Screen(); - image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB); - screen.pixels = ((DataBufferInt) image.getRaster().getDataBuffer()).getData(); + screen = new Screen(image); + //lightScreen = new Screen(); + hudSheet = new LinkedSprite(SpriteType.Gui, "hud"); canvas.createBufferStrategy(3); @@ -114,6 +117,8 @@ public static void initScreen() { public static void render() { if (screen == null) return; // No point in this if there's no gui... :P + screen.clear(0); + if (readyToRenderGameplay) { renderLevel(); if (player.renderGUI) renderGui(); @@ -127,8 +132,13 @@ public static void render() { BufferStrategy bs = canvas.getBufferStrategy(); // Creates a buffer strategy to determine how the graphics should be buffered. - Graphics g = bs.getDrawGraphics(); // Gets the graphics in which java draws the picture - g.fillRect(0, 0, canvas.getWidth(), canvas.getHeight()); // Draws a rect to fill the whole window (to cover last?) + Graphics2D g = (Graphics2D) bs.getDrawGraphics(); // Gets the graphics in which java draws the picture + g.clearRect(0, 0, canvas.getWidth(), canvas.getHeight()); // Draws a rect to fill the whole window (to cover last?) + + + + // Flushes the screen to the renderer. + screen.flush(); // Scale the pixels. int ww = getWindowSize().width; @@ -159,21 +169,14 @@ public static void render() { count++; } - try { // https://stackoverflow.com/a/4216635 - int w = image.getWidth(); - int h = image.getHeight(); - BufferedImage before = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB); - before.getRaster().setRect(image.getData()); - int scale = (Integer) Settings.get("screenshot"); - // BufferedImage after = BigBufferedImage.create(scale * w, scale * h, BufferedImage.TYPE_INT_RGB); - AffineTransform at = new AffineTransform(); - at.scale(scale, scale); // Setting the scaling. - AffineTransformOp scaleOp = new AffineTransformOp(at, AffineTransformOp.TYPE_BICUBIC); - - // Use this solution without larger scales which use up a lot memory. - // With scale 20, up to around 360MB overall RAM use. - BufferedImage after = scaleOp.filter(before, null); - ImageIO.write(after, "png", file); + try { + // A blank image as same as the canvas + BufferedImage img = new BufferedImage(canvas.getWidth(), canvas.getHeight(), BufferedImage.TYPE_INT_RGB); + Graphics2D g2d = img.createGraphics(); + g2d.drawImage(image, xOffset, yOffset, ww, hh, null); // The same invoke as the one on canvas graphics + g2d.dispose(); + ImageIO.write(img, "png", file); + Logging.PLAYER.info("Saved screenshot as {}.", file.getName()); } catch (IOException e) { CrashHandler.errorHandle(e); } @@ -193,8 +196,8 @@ private static void renderLevel() { // Stop scrolling if the screen is at the ... if (xScroll < 0) xScroll = 0; // ...Left border. if (yScroll < 0) yScroll = 0; // ...Top border. - if (xScroll > level.w * 16 - Screen.w) xScroll = level.w * 16 - Screen.w; // ...Right border. - if (yScroll > level.h * 16 - Screen.h) yScroll = level.h * 16 - Screen.h; // ...Bottom border. + if (xScroll > (level.w << 4) - Screen.w) xScroll = (level.w << 4) - Screen.w; // ...Right border. + if (yScroll > (level.h << 4) - Screen.h) yScroll = (level.h << 4) - Screen.h; // ...Bottom border. if (currentLevel > 3) { // If the current level is higher than 3 (which only the sky level (and dungeon) is) MinicraftImage cloud = spriteLinker.getSheet(SpriteType.Tile, "cloud_background"); for (int y = 0; y < 28; y++) @@ -209,10 +212,9 @@ private static void renderLevel() { // This creates the darkness in the caves if ((currentLevel != 3 || Updater.tickCount < Updater.dayLength / 4 || Updater.tickCount > Updater.dayLength / 2) && !isMode("minicraft.settings.mode.creative")) { - lightScreen.clear(0); // This doesn't mean that the pixel will be black; it means that the pixel will be DARK, by default; lightScreen is about light vs. dark, not necessarily a color. The light level it has is compared with the minimum light values in dither to decide whether to leave the cell alone, or mark it as "dark", which will do different things depending on the game level and time of day. int brightnessMultiplier = player.potioneffects.containsKey(PotionType.Light) ? 12 : 8; // Brightens all light sources by a factor of 1.5 when the player has the Light potion effect. (8 above is normal) - level.renderLight(lightScreen, xScroll, yScroll, brightnessMultiplier); // Finds (and renders) all the light from objects (like the player, lanterns, and lava). - screen.overlay(lightScreen, currentLevel, xScroll, yScroll); // Overlays the light screen over the main screen. + level.renderLight(screen, xScroll, yScroll, brightnessMultiplier); // Finds (and renders) all the light from objects (like the player, lanterns, and lava). + screen.overlay(currentLevel, xScroll, yScroll); // Overlays the light screen over the main screen. } } @@ -324,6 +326,15 @@ private static void renderGui() { Font.drawBackground(dura + "%", screen, 164, Screen.h - 16, Color.get(1, 255 - green, green, 0)); } + // WATERING CAN CONTAINER STATUS + if (player.activeItem instanceof WateringCanItem) { + // Draws the text + WateringCanItem tin = (WateringCanItem) player.activeItem; + int dura = tin.content * 100 / tin.CAPACITY; + int green = (int) (dura * 2.55f); // Let duration show as normal. + Font.drawBackground(dura + "%", screen, 164, Screen.h - 16, Color.get(1, 255 - green, green, 0)); + } + // This renders the potions overlay if (player.showpotioneffects && player.potioneffects.size() > 0) { @@ -411,6 +422,7 @@ private static void renderGui() { TutorialDisplayHandler.render(screen); renderQuestsDisplay(); + if (signDisplayMenu != null) signDisplayMenu.render(screen); renderDebugInfo(); } @@ -435,7 +447,7 @@ public static void renderBossbar(int length, String title) { } } - screen.render(x - 5 , y , 0, ACTIVE_BOSSBAR, 0, hudSheet.getSheet()); // right corner + screen.render(x - 5, y, 0, ACTIVE_BOSSBAR, 0, hudSheet.getSheet()); // right corner for (int bx = 0; bx < bar_length; bx++) { for (int by = 0; by < 1; by++) { @@ -457,10 +469,10 @@ private static void renderQuestsDisplay() { for (Quest q : quests) { QuestSeries series = q.getSeries(); - questsShown.add(!expanding? - new StringEntry(Localization.getLocalized(q.key), Color.WHITE, false): + questsShown.add(!expanding ? + new StringEntry(Localization.getLocalized(q.key), Color.WHITE, false) : new StringEntry(q.shouldAllCriteriaBeCompleted() && q.getTotalNumCriteria() > 1 ? - String.format("%s (%d/%d)", Localization.getLocalized(series.key), q.getNumCriteriaCompleted(), q.getTotalNumCriteria()) : + String.format("%s (%d/%d)", Localization.getLocalized(series.key), q.getNumCriteriaCompleted(), q.getTotalNumCriteria()) : Localization.getLocalized(series.key), Color.WHITE, false) ); @@ -492,8 +504,8 @@ private static void renderDebugInfo() { info.add((Updater.normSpeed * Updater.gamespeed) + " tps"); info.add("walk spd: " + player.moveSpeed); - info.add("X: " + (player.x / 16) + "-" + (player.x % 16)); - info.add("Y: " + (player.y / 16) + "-" + (player.y % 16)); + info.add("X: " + (player.x >> 4) + "-" + (player.x % 16)); + info.add("Y: " + (player.y >> 4) + "-" + (player.y % 16)); if (levels[currentLevel] != null) info.add("Tile: " + levels[currentLevel].getTile(player.x >> 4, player.y >> 4).name); if (isMode("minicraft.settings.mode.score")) info.add("Score: " + player.getScore()); diff --git a/src/client/java/minicraft/core/Updater.java b/src/client/java/minicraft/core/Updater.java index 391d94314..c0355e0f9 100644 --- a/src/client/java/minicraft/core/Updater.java +++ b/src/client/java/minicraft/core/Updater.java @@ -2,6 +2,7 @@ import minicraft.core.io.Localization; import minicraft.core.io.Settings; +import minicraft.core.io.Sound; import minicraft.entity.furniture.Bed; import minicraft.entity.mob.Player; import minicraft.level.Level; @@ -20,7 +21,8 @@ import java.awt.GraphicsDevice; public class Updater extends Game { - private Updater() {} + private Updater() { + } // TIME AND TICKS @@ -31,8 +33,8 @@ private Updater() {} public static int tickCount = 0; // The number of ticks since the beginning of the game day. static int time = 0; // Facilites time of day / sunlight. public static final int dayLength = 64800; // This value determines how long one game day is. - public static final int sleepEndTime = dayLength/8; // This value determines when the player "wakes up" in the morning. - public static final int sleepStartTime = dayLength/2+dayLength/8; // This value determines when the player allowed to sleep. + public static final int sleepEndTime = dayLength / 8; // This value determines when the player "wakes up" in the morning. + public static final int sleepStartTime = dayLength / 2 + dayLength / 8; // This value determines when the player allowed to sleep. //public static int noon = 32400; // This value determines when the sky switches from getting lighter to getting darker. public static int gameTime = 0; // This stores the total time (number of ticks) you've been playing your @@ -56,10 +58,10 @@ private Updater() {} public static int screenshot = 0; // Counter for screenshot queries. public enum Time { - Morning (0), - Day (dayLength/4), - Evening (dayLength/2), - Night (dayLength/4*3); + Morning(0), + Day(dayLength / 4), + Evening(dayLength / 2), + Night(dayLength / 4 * 3); public int tickTime; @@ -91,20 +93,12 @@ static void updateFullscreen() { // In the end, calls menu.tick() if there's a menu, or level.tick() if no menu. public static void tick() { - // Quick Level change: move the player for -1, or 1 levels - if (isMode("minicraft.settings.mode.creative") && input.getKey("SHIFT-S").clicked ) { - Game.setDisplay(new LevelTransitionDisplay(-1)); - - } else if (isMode("minicraft.settings.mode.creative") && input.getKey("SHIFT-W").clicked ){ - Game.setDisplay(new LevelTransitionDisplay(1)); - } - - if (input.getKey("FULLSCREEN").clicked) { + if (input.getMappedKey("FULLSCREEN").isClicked()) { Updater.FULLSCREEN = !Updater.FULLSCREEN; Updater.updateFullscreen(); } - if (input.getKey("screenshot").clicked) { + if (input.getMappedKey("screenshot").isClicked()) { screenshot++; } @@ -126,7 +120,10 @@ public static void tick() { // assert curDisplay == prevDisplay; currentDisplay = displayQuery.peek(); assert currentDisplay != null; - currentDisplay.init(prevDisplay); + if (prevDisplay.getParent() == currentDisplay) + prevDisplay.onExit(); + else + currentDisplay.init(prevDisplay); } Level level = levels[currentLevel]; @@ -148,7 +145,7 @@ public static void tick() { } // Auto-save tick; marks when to do autosave. - if(!paused) + if (!paused) asTick++; if (asTick > astime) { if ((boolean) Settings.get("autosave") && !gameOver && player.health > 0) { @@ -160,7 +157,7 @@ public static void tick() { } // Increment tickCount if the game is not paused - if (!paused) setTime(tickCount+1); + if (!paused) setTime(tickCount + 1); // SCORE MODE ONLY @@ -175,6 +172,8 @@ public static void tick() { if (updateNoteTick) notetick++; + Sound.tick(); + // This is the general action statement thing! Regulates menus, mostly. if (!Renderer.canvas.hasFocus()) { input.releaseAll(); @@ -215,13 +214,21 @@ public static void tick() { Tile.tickCount++; } - if (currentDisplay == null && input.getKey("F3").clicked) { // Shows debug info in upper-left + if (currentDisplay == null && input.getMappedKey("F3").isClicked()) { // Shows debug info in upper-left Renderer.showDebugInfo = !Renderer.showDebugInfo; } // For debugging only { - if (input.getKey("F3-L").clicked) { + // Quick Level change: move the player for -1, or 1 levels + if (isMode("minicraft.settings.mode.creative") && input.getMappedKey("SHIFT-S").isClicked()) { + Game.setDisplay(new LevelTransitionDisplay(-1)); + + } else if (isMode("minicraft.settings.mode.creative") && input.getMappedKey("SHIFT-W").isClicked()) { + Game.setDisplay(new LevelTransitionDisplay(1)); + } + + if (input.getMappedKey("F3-L").isClicked()) { // Print all players on all levels, and their coordinates. Logging.WORLD.info("Printing players on all levels."); for (Level value : levels) { @@ -231,57 +238,58 @@ public static void tick() { } // Host-only cheats. - if (input.getKey("F3-T-1").clicked) changeTimeOfDay(Time.Morning); - if (input.getKey("F3-T-2").clicked) changeTimeOfDay(Time.Day); - if (input.getKey("F3-T-3").clicked) changeTimeOfDay(Time.Evening); - if (input.getKey("F3-T-4").clicked) changeTimeOfDay(Time.Night); + if (input.getMappedKey("F3-T-1").isClicked()) changeTimeOfDay(Time.Morning); + if (input.getMappedKey("F3-T-2").isClicked()) changeTimeOfDay(Time.Day); + if (input.getMappedKey("F3-T-3").isClicked()) changeTimeOfDay(Time.Evening); + if (input.getMappedKey("F3-T-4").isClicked()) changeTimeOfDay(Time.Night); - String prevMode = (String)Settings.get("mode"); - if (input.getKey("F3-F4-2").clicked) { + String prevMode = (String) Settings.get("mode"); + if (input.getMappedKey("F3-F4-2").isClicked()) { Settings.set("mode", "minicraft.settings.mode.creative"); Logging.WORLDNAMED.trace("Game mode changed from {} into {}.", prevMode, "minicraft.settings.mode.creative"); } - if (input.getKey("F3-F4-1").clicked) { + if (input.getMappedKey("F3-F4-1").isClicked()) { Settings.set("mode", "minicraft.settings.mode.survival"); Logging.WORLDNAMED.trace("Game mode changed from {} into {}.", prevMode, "minicraft.settings.mode.survival"); } - if (input.getKey("F3-F4-3").clicked) { + if (input.getMappedKey("F3-F4-3").isClicked()) { Settings.set("mode", "minicraft.settings.mode.score"); Logging.WORLDNAMED.trace("Game mode changed from {} into {}.", prevMode, "minicraft.settings.mode.score"); } - if (isMode("minicraft.settings.mode.score") && input.getKey("F3-SHIFT-T").clicked) { + if (isMode("minicraft.settings.mode.score") && input.getMappedKey("F3-SHIFT-T").isClicked()) { scoreTime = normSpeed * 5; // 5 seconds } float prevSpeed = gamespeed; - if (input.getKey("F3-S-0").clicked) { + if (input.getMappedKey("F3-S-0").isClicked()) { gamespeed = 1; Logging.WORLDNAMED.trace("Tick speed reset from {} into 1.", prevSpeed); } - if (input.getKey("F3-S-equals").clicked) { + if (input.getMappedKey("F3-S-equals").isClicked()) { if (gamespeed < 1) gamespeed *= 2; - else if (normSpeed*gamespeed < 2000) gamespeed++; + else if (normSpeed * gamespeed < 2000) gamespeed++; Logging.WORLDNAMED.trace("Tick speed increased from {} into {}.", prevSpeed, gamespeed); } - if (input.getKey("F3-S-minus").clicked) { + if (input.getMappedKey("F3-S-minus").isClicked()) { if (gamespeed > 1) gamespeed--; - else if (normSpeed*gamespeed > 5) gamespeed /= 2; + else if (normSpeed * gamespeed > 5) gamespeed /= 2; Logging.WORLDNAMED.trace("Tick speed decreased from {} into {}.", prevSpeed, gamespeed); } - if (input.getKey("F3-h").clicked) player.health--; - if (input.getKey("F3-b").clicked) player.hunger--; + if (input.getMappedKey("F3-h").isClicked()) player.health--; + if (input.getMappedKey("F3-b").isClicked()) player.hunger--; - if (input.getKey("F3-M-0").clicked) player.moveSpeed = 1; - if (input.getKey("F3-M-equals").clicked) player.moveSpeed++; - if (input.getKey("F3-M-minus").clicked && player.moveSpeed > 1) player.moveSpeed--; // -= 0.5D; + if (input.getMappedKey("F3-M-0").isClicked()) player.moveSpeed = 1; + if (input.getMappedKey("F3-M-equals").isClicked()) player.moveSpeed++; + if (input.getMappedKey("F3-M-minus").isClicked() && player.moveSpeed > 1) + player.moveSpeed--; // -= 0.5D; - if (input.getKey("F3-u").clicked) { - levels[currentLevel].setTile(player.x>>4, player.y>>4, Tiles.get("Stairs Up")); + if (input.getMappedKey("F3-u").isClicked()) { + levels[currentLevel].setTile(player.x >> 4, player.y >> 4, Tiles.get("Stairs Up")); } - if (input.getKey("F3-d").clicked) { - levels[currentLevel].setTile(player.x>>4, player.y>>4, Tiles.get("Stairs Down")); + if (input.getMappedKey("F3-d").isClicked()) { + levels[currentLevel].setTile(player.x >> 4, player.y >> 4, Tiles.get("Stairs Down")); } } // End debug only cond. } // End "menu-null" conditional @@ -308,6 +316,7 @@ public static void setTime(int ticks) { public static void changeTimeOfDay(Time t) { setTime(t.tickTime); } + // This one works too. public static void changeTimeOfDay(int t) { Time[] times = Time.values(); @@ -322,10 +331,13 @@ public static Time getTime() { return times[time]; } - /** This adds a notification to all player games. */ + /** + * This adds a notification to all player games. + */ public static void notifyAll(String msg) { notifyAll(msg, 0); } + public static void notifyAll(String msg, int notetick) { msg = Localization.getLocalized(msg); notifications.add(msg); diff --git a/src/client/java/minicraft/core/World.java b/src/client/java/minicraft/core/World.java index 4e5a2aa8d..c46195c54 100644 --- a/src/client/java/minicraft/core/World.java +++ b/src/client/java/minicraft/core/World.java @@ -11,6 +11,7 @@ import minicraft.screen.LoadingDisplay; import minicraft.screen.PlayerDeathDisplay; import minicraft.screen.QuestsDisplay; +import minicraft.screen.SignDisplay; import minicraft.screen.TutorialDisplayHandler; import minicraft.screen.WorldGenDisplay; import minicraft.screen.WorldSelectDisplay; @@ -22,9 +23,10 @@ import java.util.Random; public class World extends Game { - private World() {} + private World() { + } - public static final int[] idxToDepth = {-3, -2, -1, 0, 1, -4}; /// This is to map the level depths to each level's index in Game's levels array. This must ALWAYS be the same length as the levels array, of course. + public static final int[] idxToDepth = { -3, -2, -1, 0, 1, -4 }; /// This is to map the level depths to each level's index in Game's levels array. This must ALWAYS be the same length as the levels array, of course. public static final int minLevelDepth, maxLevelDepth; static int worldSize = 128; // The size of the world @@ -44,7 +46,7 @@ private World() {} static { int min, max; min = max = idxToDepth[0]; - for (int depth: idxToDepth) { + for (int depth : idxToDepth) { if (depth < min) min = depth; if (depth > max) @@ -54,7 +56,9 @@ private World() {} maxLevelDepth = max; } - /** This is for a contained way to find the index in the levels array of a level, based on it's depth. This is also helpful because add a new level in the future could change this. */ + /** + * This is for a contained way to find the index in the levels array of a level, based on it's depth. This is also helpful because add a new level in the future could change this. + */ public static int lvlIdx(int depth) { if (depth > maxLevelDepth) return lvlIdx(minLevelDepth); if (depth < minLevelDepth) return lvlIdx(maxLevelDepth); @@ -65,8 +69,13 @@ public static int lvlIdx(int depth) { } - /** This method is used when respawning, and by initWorld to reset the vars. It does not generate any new terrain. */ - public static void resetGame() { resetGame(true); } + /** + * This method is used when respawning, and by initWorld to reset the vars. It does not generate any new terrain. + */ + public static void resetGame() { + resetGame(true); + } + public static void resetGame(boolean keepPlayer) { Logging.WORLD.debug("Resetting..."); playerDeadTime = 0; @@ -91,7 +100,8 @@ public static void resetGame(boolean keepPlayer) { } } - /** This method is used to create a brand new world, or to load an existing one from a file. + /** + * This method is used to create a brand new world, or to load an existing one from a file. * For the loading screen updates to work, it it assumed that *this* is called by a thread *other* than the one rendering the current *menu*. **/ public static void initWorld() { // This is a full reset; everything. @@ -134,8 +144,8 @@ public static void resetGame(boolean keepPlayer) { Logging.WORLD.trace("Generating level " + i + "..."); - LoadingDisplay.setMessage(Level.getDepthString(i)); - levels[lvlIdx(i)] = new Level(worldSize, worldSize, random.nextLong(), i, levels[lvlIdx(i+1)], !WorldSelectDisplay.hasLoadedWorld()); + LoadingDisplay.setMessage(Level.getDepthString(i), false); + levels[lvlIdx(i)] = new Level(worldSize, worldSize, random.nextLong(), i, levels[lvlIdx(i + 1)], !WorldSelectDisplay.hasLoadedWorld()); LoadingDisplay.progress(loadingInc); } @@ -150,29 +160,44 @@ public static void resetGame(boolean keepPlayer) { CraftingDisplay.resetRecipeUnlocks(); TutorialDisplayHandler.reset(true); AdvancementElement.resetRecipeUnlockingElements(); + SignDisplay.resetSignTexts(); } Renderer.readyToRenderGameplay = true; + Renderer.signDisplayMenu = null; + PlayerDeathDisplay.shouldRespawn = true; Logging.WORLD.trace("World initialized."); } - public static long getWorldSeed() { return seed; } - public static void setWorldSeed(long seed) { World.seed = seed; } + public static long getWorldSeed() { + return seed; + } + + public static void setWorldSeed(long seed) { + World.seed = seed; + } + + /** + * This method is called when you interact with stairs, this will give you the transition effect. While changeLevel(int) just changes the level. + */ + public static void scheduleLevelChange(int dir) { + scheduleLevelChange(dir, null); + } - /** This method is called when you interact with stairs, this will give you the transition effect. While changeLevel(int) just changes the level. */ - public static void scheduleLevelChange(int dir) { scheduleLevelChange(dir, null); } public static void scheduleLevelChange(int dir, @Nullable Action changeAction) { onChangeAction = changeAction; pendingLevelChange = dir; } - /** This method changes the level that the player is currently on. + /** + * This method changes the level that the player is currently on. * It takes 1 integer variable, which is used to tell the game which direction to go. * For example, 'changeLevel(1)' will make you go up a level, - while 'changeLevel(-1)' will make you go down a level. */ + * while 'changeLevel(-1)' will make you go down a level. + */ public static void changeLevel(int dir) { if (onChangeAction != null) { onChangeAction.act(); @@ -182,7 +207,7 @@ public static void changeLevel(int dir) { levels[currentLevel].remove(player); // Removes the player from the current level. int nextLevel = currentLevel + dir; - if (nextLevel <= -1) nextLevel = levels.length-1; // Fix accidental level underflow + if (nextLevel <= -1) nextLevel = levels.length - 1; // Fix accidental level underflow if (nextLevel >= levels.length) nextLevel = 0; // Fix accidental level overflow Logging.WORLD.trace("Setting level from {} to {}", currentLevel, nextLevel); currentLevel = nextLevel; @@ -206,6 +231,11 @@ public static void onWorldExits() { lastWorldExitTime = System.currentTimeMillis(); } - public static long getLastWorldExitTime() { return lastWorldExitTime; } - public static long getLastWorldEnterTime() { return lastWorldEnterTime; } + public static long getLastWorldExitTime() { + return lastWorldExitTime; + } + + public static long getLastWorldEnterTime() { + return lastWorldEnterTime; + } } diff --git a/src/client/java/minicraft/core/io/ClipboardHandler.java b/src/client/java/minicraft/core/io/ClipboardHandler.java index 0fa75b5fc..1eb898945 100644 --- a/src/client/java/minicraft/core/io/ClipboardHandler.java +++ b/src/client/java/minicraft/core/io/ClipboardHandler.java @@ -13,36 +13,37 @@ public final class ClipboardHandler implements ClipboardOwner { - @Override - public void lostOwnership(Clipboard clipboard, Transferable contents) { } + @Override + public void lostOwnership(Clipboard clipboard, Transferable contents) { + } /** * Give the system clipboard data. */ - public void setClipboardContents(String string) { - StringSelection stringSelection = new StringSelection(string); - Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); - clipboard.setContents(stringSelection, this); - } + public void setClipboardContents(String string) { + StringSelection stringSelection = new StringSelection(string); + Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); + clipboard.setContents(stringSelection, this); + } /** * Get the string from the system clipboard data. * @return A string with the contents. */ public String getClipboardContents() { - Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); - Transferable contents = clipboard.getContents(null); + Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); + Transferable contents = clipboard.getContents(null); - String result = ""; + String result = ""; - if ((contents != null) && contents.isDataFlavorSupported(DataFlavor.stringFlavor)) { - try { - result = (String) contents.getTransferData(DataFlavor.stringFlavor); - } catch (UnsupportedFlavorException | IOException ex) { + if ((contents != null) && contents.isDataFlavorSupported(DataFlavor.stringFlavor)) { + try { + result = (String) contents.getTransferData(DataFlavor.stringFlavor); + } catch (UnsupportedFlavorException | IOException ex) { CrashHandler.errorHandle(ex); - } - } + } + } - return result; - } + return result; + } } diff --git a/src/client/java/minicraft/core/io/FileHandler.java b/src/client/java/minicraft/core/io/FileHandler.java index a831c3160..2423da2d1 100644 --- a/src/client/java/minicraft/core/io/FileHandler.java +++ b/src/client/java/minicraft/core/io/FileHandler.java @@ -26,7 +26,8 @@ import java.util.stream.Stream; public class FileHandler extends Game { - private FileHandler() {} + private FileHandler() { + } public static final int REPLACE_EXISTING = 0; public static final int RENAME_COPY = 1; @@ -57,7 +58,6 @@ private FileHandler() {} * If saveDir is not null, use it as the game directory. Otherwise use the default path. *

* If the default path is used, check if old default path exists and if so move it to the new path. - * * @param saveDir Value from --savedir argument. Null if it was not set. */ public static void determineGameDir(@Nullable String saveDir) { @@ -99,11 +99,11 @@ public static void determineGameDir(@Nullable String saveDir) { } public static String getSystemGameDir() { - return systemGameDir; + return systemGameDir; } public static String getLocalGameDir() { - return localGameDir; + return localGameDir; } private static void deleteFolder(File top) { @@ -133,12 +133,13 @@ else if (ifExisting == RENAME_COPY) { newFilename = newFilename.substring(0, newFilename.lastIndexOf(".")); do { newFilename += "(Old)"; - } while(new File(newFilename).exists()); + } while (new File(newFilename).exists()); newFilename += Save.extension; } } Path newFile = new File(newFilename).toPath(); + newFile.getParent().toFile().mkdirs(); try { Files.copy(file, newFile, StandardCopyOption.REPLACE_EXISTING); } catch (IOException ex) { @@ -146,12 +147,15 @@ else if (ifExisting == RENAME_COPY) { } return FileVisitResult.CONTINUE; } + public FileVisitResult preVisitDirectory(Path p, BasicFileAttributes bfa) { return FileVisitResult.CONTINUE; } + public FileVisitResult postVisitDirectory(Path p, IOException ex) { return FileVisitResult.CONTINUE; } + public FileVisitResult visitFileFailed(Path p, IOException ex) { return FileVisitResult.CONTINUE; } @@ -179,7 +183,7 @@ public static ArrayList listAssets() { ArrayList names = new ArrayList<>(); try (Stream paths = Files.walk(path)) { Path finalPath = path; - paths.forEach(p -> names.add(finalPath.getParent().relativize(p).toString().replace('\\', '/')+ + paths.forEach(p -> names.add(finalPath.getParent().relativize(p).toString().replace('\\', '/') + (p.toFile().isDirectory() ? "/" : ""))); return names; } catch (IOException e) { @@ -203,7 +207,7 @@ private static ArrayList listResourcesUsingIDE() { Path folderPath = Paths.get(fUrl.toURI()); Files.walk(folderPath) - .forEach(p -> { + .forEach(p -> { names.add(folderPath.relativize(p).toString().replace('\\', '/') + (p.toFile().isDirectory() ? "/" : "")); }); diff --git a/src/client/java/minicraft/core/io/InputHandler.java b/src/client/java/minicraft/core/io/InputHandler.java index d24b53c37..0123050d9 100644 --- a/src/client/java/minicraft/core/io/InputHandler.java +++ b/src/client/java/minicraft/core/io/InputHandler.java @@ -1,5 +1,6 @@ package minicraft.core.io; +import com.badlogic.gdx.utils.SharedLibraryLoadRuntimeException; import com.studiohartman.jamepad.ControllerAxis; import com.studiohartman.jamepad.ControllerButton; import com.studiohartman.jamepad.ControllerIndex; @@ -14,43 +15,45 @@ import java.awt.event.KeyListener; import java.lang.reflect.Field; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.Map.Entry; import java.util.Stack; +import java.util.function.Predicate; public class InputHandler implements KeyListener { /** - This class handles key presses; this also implements MouseListener... but I have no idea why. - It's not used in any way. Ever. As far as I know. Anyway, here are a few tips about this class: - - -This class must instantiated to be used; and it's pretty much always called "input" in the code. - - -The keys are stored in two arrays, one for physical keyboard keys(called "keyboard"), and one for "keys" you make-up (called "keymap") to represent different actions ("virtual keys", you could say). - - -All the Keys in the keyboard array are generated automatically as you ask for them in the code (if they don't already exist), so there's no need to define anything in the keyboard array here. - --Note: this shouldn't matter, but keys that are not asked for or defined as values here in keymap will be ignored when it comes to key presses. - - -All the "virtual keys" in keymap "map" to a Key object in the keyboard array; that is to say, - keymap contains a HashMap of string keys, to string values. The keys are the names of the actions, - and the values are the names of the keyboard keys you physically press to do them. - - -To get whether a key is pressed or not, use input.getKey("key"), where "key" is the name of the key, either physical or virtual. If virtual, all it does is then fetch the corrosponding key from keyboard anyway; but it allows one to change the controls while still making the same key requests in the code. - - -If you want to have multiple possibilities at once when it comes to which key to press to do something, you can! just put a "|" between the mappings. For example, say you wanted both "wasd" and arrow key controls to work, at the same time. How you do this is in the construstor below, where it says "keymap.put(" UP, DOWN, LEFT, and RIGHT. - - -This class supports modifier keys as inputs. To specify a "compound" key (one using modifiders), write "MOD1-MOD2-KEY", that is, "SHIFT-ALT-D" or "ALT-F", with a "-" between the keys. ALWAYS put the actual trigger key last, after all modifiers (the modifiers are: shift, ctrl, and alt). - - --All the magic happens in the getKey() method: If the String keyname input has hyphens("-"), then it's a compound key, and it splits it up between the hyphens. Then, it compares which modifiers are currently being pressed, and which are being requested. Then, a Key object is created, which if the modifiers match, reflects the non-modifier key's "down" and "clicked" values; otherwise they're both false. - --If a key with no hyph is requested, it skips most of that and just gives you the Key, generating it if needed. - - */ + * This class handles key presses; this also implements MouseListener... but I have no idea why. + * It's not used in any way. Ever. As far as I know. Anyway, here are a few tips about this class: + *

+ * -This class must instantiated to be used; and it's pretty much always called "input" in the code. + *

+ * -The keys are stored in two arrays, one for physical keyboard keys(called "keyboard"), and one for "keys" you make-up (called "keymap") to represent different actions ("virtual keys", you could say). + *

+ * -All the Keys in the keyboard array are generated automatically as you ask for them in the code (if they don't already exist), so there's no need to define anything in the keyboard array here. + * --Note: this shouldn't matter, but keys that are not asked for or defined as values here in keymap will be ignored when it comes to key presses. + *

+ * -All the "virtual keys" in keymap "map" to a Key object in the keyboard array; that is to say, + * keymap contains a HashMap of string keys, to string values. The keys are the names of the actions, + * and the values are the names of the keyboard keys you physically press to do them. + *

+ * -To get whether a key is pressed or not, use input.getKey("key"), where "key" is the name of the key, either physical or virtual. If virtual, all it does is then fetch the corrosponding key from keyboard anyway; but it allows one to change the controls while still making the same key requests in the code. + *

+ * -If you want to have multiple possibilities at once when it comes to which key to press to do something, you can! just put a "|" between the mappings. For example, say you wanted both "wasd" and arrow key controls to work, at the same time. How you do this is in the construstor below, where it says "keymap.put(" UP, DOWN, LEFT, and RIGHT. + *

+ * -This class supports modifier keys as inputs. To specify a "compound" key (one using modifiders), write "MOD1-MOD2-KEY", that is, "SHIFT-ALT-D" or "ALT-F", with a "-" between the keys. ALWAYS put the actual trigger key last, after all modifiers (the modifiers are: shift, ctrl, and alt). + *

+ * --All the magic happens in the getKey() method: If the String keyname input has hyphens("-"), then it's a compound key, and it splits it up between the hyphens. Then, it compares which modifiers are currently being pressed, and which are being requested. Then, a Key object is created, which if the modifiers match, reflects the non-modifier key's "down" and "clicked" values; otherwise they're both false. + * --If a key with no hyph is requested, it skips most of that and just gives you the Key, generating it if needed. + */ public String keyToChange = null; // This is used when listening to change key bindings. private String keyChanged = null; // This is used when listening to change key bindings. private boolean overwrite = false; - private ControllerManager controllerManager = new ControllerManager(); + private final boolean controllersSupported; + private ControllerManager controllerManager; private ControllerIndex controllerIndex; // Please prevent getting button states directly from this object. private HashMap controllerButtonBooleanMapJust = new HashMap<>(); private HashMap controllerButtonBooleanMap = new HashMap<>(); @@ -62,20 +65,22 @@ public String getChangedKey() { } private static HashMap keyNames = new HashMap<>(); + static { Field[] keyEventFields = KeyEvent.class.getFields(); ArrayList keyConstants = new ArrayList<>(); - for (Field field: keyEventFields) { + for (Field field : keyEventFields) { if (field.getName().contains("VK_") && (field.getType().getName().equals(int.class.getName()))) keyConstants.add(field); } - for (Field keyConst: keyConstants) { + for (Field keyConst : keyConstants) { String name = keyConst.getName(); name = name.substring(3); // Removes the "VK_" try { - keyNames.put(((Integer)keyConst.get(0)), name); - } catch(IllegalAccessException ignored) {} + keyNames.put(((Integer) keyConst.get(0)), name); + } catch (IllegalAccessException ignored) { + } } // For compatibility becuase I'm lazy. :P @@ -84,7 +89,7 @@ public String getChangedKey() { } private HashMap keymap; // The symbolic map of actions to physical key names. - private HashMap keyboard; // The actual map of key names to Key objects. + private HashMap keyboard; // The actual map of key names to Key objects. private String lastKeyTyped = ""; // Used for things like typing world names. private String keyTypedBuffer = ""; // Used to store the last key typed before putting it into the main var during tick(). @@ -102,19 +107,28 @@ public InputHandler() { } // I'm not entirely sure if this is necessary... but it doesn't hurt. - keyboard.put("SHIFT", new Key(true)); - keyboard.put("CTRL", new Key(true)); - keyboard.put("ALT", new Key(true)); + keyboard.put("SHIFT", new PhysicalKey(true)); + keyboard.put("CTRL", new PhysicalKey(true)); + keyboard.put("ALT", new PhysicalKey(true)); - controllerManager.initSDLGamepad(); - controllerIndex = controllerManager.getControllerIndex(0); - controllerManager.update(); + boolean controllerInit = false; try { - Logging.CONTROLLER.debug("Controller Detected: " + controllerManager.getControllerIndex(0).getName()); - } catch (ControllerUnpluggedException e) { - Logging.CONTROLLER.debug("No Controllers Detected, moving on."); + controllerManager = new ControllerManager(); + controllerManager.initSDLGamepad(); + controllerIndex = controllerManager.getControllerIndex(0); + controllerManager.update(); + try { + Logging.CONTROLLER.debug("Controller Detected: " + controllerManager.getControllerIndex(0).getName()); + } catch (ControllerUnpluggedException e) { + Logging.CONTROLLER.debug("No Controllers Detected, moving on."); + } + controllerInit = true; + } catch (IllegalStateException | SharedLibraryLoadRuntimeException | UnsatisfiedLinkError e) { + Logging.CONTROLLER.error(e, "Controllers are not support, being disabled."); } + controllersSupported = controllerInit; } + public InputHandler(Component inputSource) { this(); inputSource.addKeyListener(this); // Add key listener to game @@ -164,6 +178,7 @@ private void initKeyMap() { // The button mapping should not be modifiable. private final HashMap buttonMap = new HashMap<>(); + private void initButtonMap() { buttonMap.put("MOVE-UP", ControllerButton.DPAD_UP); buttonMap.put("MOVE-DOWN", ControllerButton.DPAD_DOWN); @@ -196,27 +211,33 @@ public void resetKeyBindings() { initKeyMap(); } - /** Processes each key one by one, in keyboard. */ + /** + * Processes each key one by one, in keyboard. + */ public void tick() { lastKeyTyped = keyTypedBuffer; keyTypedBuffer = ""; + inputMask = null; synchronized ("lock") { - for (Key key: keyboard.values()) + for (PhysicalKey key : keyboard.values()) key.tick(); // Call tick() for each key. } lastInputActivityListener.tick(); // Also update the controller button state. - for (ControllerButton btn : ControllerButton.values()) { - try { - controllerButtonBooleanMapJust.put(btn, controllerIndex.isButtonJustPressed(btn)); - } catch (ControllerUnpluggedException e) { - controllerButtonBooleanMapJust.put(btn, false); - } try { - controllerButtonBooleanMap.put(btn, controllerIndex.isButtonPressed(btn)); - } catch (ControllerUnpluggedException e) { - controllerButtonBooleanMap.put(btn, false); + if (controllersSupported) { + for (ControllerButton btn : ControllerButton.values()) { + try { + controllerButtonBooleanMapJust.put(btn, controllerIndex.isButtonJustPressed(btn)); + } catch (ControllerUnpluggedException e) { + controllerButtonBooleanMapJust.put(btn, false); + } + try { + controllerButtonBooleanMap.put(btn, controllerIndex.isButtonPressed(btn)); + } catch (ControllerUnpluggedException e) { + controllerButtonBooleanMap.put(btn, false); + } } } @@ -225,34 +246,61 @@ public void tick() { } // The Key class. - public static class Key { + public static abstract class Key { + public abstract boolean isDown(); + + public abstract boolean isClicked(); + + public String toString() { // For debugging + return "down:" + isDown() + "; clicked:" + isClicked(); + } + } + + private static class PhysicalKey extends Key { // presses = how many times the Key has been pressed. // absorbs = how many key presses have been processed. private int presses, absorbs; // down = if the key is currently physically being held down. // clicked = if the key is still being processed at the current tick. - public boolean down, clicked; + protected boolean down, clicked; // sticky = true if presses reaches 3, and the key continues to be held down. private boolean sticky; - boolean stayDown; + protected boolean stayDown; - public Key() { this(false); } - public Key(boolean stayDown) { + public PhysicalKey() { + this(false); + } + + public PhysicalKey(boolean stayDown) { this.stayDown = stayDown; } - /** toggles the key down or not down. */ + @Override + public boolean isDown() { + return down; + } + + @Override + public boolean isClicked() { + return clicked; + } + + /** + * toggles the key down or not down. + */ public void toggle(boolean pressed) { down = pressed; // Set down to the passed in value; the if statement is probably unnecessary... if (pressed && !sticky) presses++; // Add to the number of total presses. } - /** Processes the key presses. */ + /** + * Processes the key presses. + */ public void tick() { if (absorbs < presses) { // If there are more key presses to process... absorbs++; // Process them! - if(presses - absorbs > 3) absorbs = presses - 3; + if (presses - absorbs > 3) absorbs = presses - 3; clicked = true; // Make clicked true, since key presses are still being processed. } else { // All key presses so far for this key have been processed. if (!sticky) sticky = presses > 3; @@ -279,9 +327,66 @@ public String toString() { } } - /** This is used to stop all of the actions when the game is out of focus. */ + private static class CompoundedKey extends Key { + private final HashSet keys; + + public CompoundedKey(Collection keys) { + this.keys = new HashSet<>(keys); + } + + @Override + public boolean isDown() { // All keys down. + return keys.stream().allMatch(Key::isDown); + } + + @Override + public boolean isClicked() { // If the whole key binding is clicked, then the all keys must be down and at least one of these is/are just clicked. + return isDown() && keys.stream().anyMatch(Key::isClicked); + } + } + + private static class ORKey extends Key { + private final HashSet keys; + + public ORKey(Collection keys) { + this.keys = new HashSet<>(keys); + } + + @Override + public boolean isDown() { + return keys.stream().anyMatch(Key::isDown); + } + + @Override + public boolean isClicked() { + return keys.stream().anyMatch(Key::isClicked); + } + } + + private static final Predicate maskAll = k -> true; + private static final Key keyMask = new Key() { + @Override + public boolean isDown() { + return false; + } + + @Override + public boolean isClicked() { + return false; + } + }; + private @Nullable Predicate inputMask = null; + + public void maskInput(@Nullable Predicate filter) { + if (filter == null) filter = maskAll; + inputMask = inputMask == null ? filter : inputMask.and(filter); + } + + /** + * This is used to stop all of the actions when the game is out of focus. + */ public void releaseAll() { - for (Key key: keyboard.values().toArray(new Key[0])) { + for (PhysicalKey key : keyboard.values()) { key.release(); } } @@ -292,7 +397,9 @@ public void setKey(String keymapKey, String keyboardKey) { keymap.put(keymapKey, keyboardKey); } - /** Simply returns the mapped value of key in keymap. */ + /** + * Simply returns the mapped value of key in keymap. + */ public String getMapping(String actionKey) { actionKey = actionKey.toUpperCase(); if (lastInputActivityListener.lastButtonActivityTimestamp > lastInputActivityListener.lastKeyActivityTimestamp) { @@ -331,31 +438,53 @@ public int getLastInputType() { } /// THIS is pretty much the only way you want to be interfacing with this class; it has all the auto-create and protection functions and such built-in. - public Key getKey(String keytext) { return getKey(keytext, true); } - private Key getKey(String keytext, boolean getFromMap) { - // If the passed-in key is blank, or null, then return null. - if (keytext == null || keytext.length() == 0) return new Key(); + // For mapped keys + public Key getMappedKey(String keyText) { + keyText = keyText.toUpperCase(java.util.Locale.ENGLISH); // Prevent errors due to improper "casing" + synchronized ("lock") { + // If the passed-in key equals one in keymap, then replace it with its match, a key in keyboard. + if (keymap.containsKey(keyText)) // If false, we assume that keytext is a physical key. + keyText = keymap.get(keyText); // Converts action name to physical key name + } - keytext = keytext.toUpperCase(java.util.Locale.ENGLISH); // Prevent errors due to improper "casing" + if (keyText.contains("|")) { + /// Multiple key possibilities exist for this action; so, combine the results of each one! + ArrayList keys = new ArrayList<>(); + for (String keyposs : keyText.split("\\|")) { // String.split() uses regex, and "|" is a special character, so it must be escaped; but the backslash must be passed in, so it needs escaping. + // It really does combine using "or": + keys.add(getMappedKey(keyposs)); + } + return new ORKey(keys); + } + + // Complex compound key binding support. + HashSet keys = new HashSet<>(); synchronized ("lock") { - if(getFromMap) { // If false, we assume that keytext is a physical key. - // If the passed-in key equals one in keymap, then replace it with it's match, a key in keyboard. - if (keymap.containsKey(keytext)) - keytext = keymap.get(keytext); // Converts action name to physical key name + String[] split = keyText.split("\\+"); + for (String s : split) { + keys.add(getKey(keymap.getOrDefault(s, s))); } } + //if(key.clicked && Game.debug) System.out.println("Processed key: " + keytext + " is clicked; tickNum=" + ticks); + return new CompoundedKey(keys); // Return the Key object. + } + + // Physical keys only + private Key getKey(String keytext) { + // If the passed-in key is blank, or null, then return null. + if (keytext == null || keytext.isEmpty()) return keyMask; + + keytext = keytext.toUpperCase(java.util.Locale.ENGLISH); // Prevent errors due to improper "casing" + if (keytext.contains("|")) { /// Multiple key possibilities exist for this action; so, combine the results of each one! - Key key = new Key(); - for (String keyposs: keytext.split("\\|")) { // String.split() uses regex, and "|" is a special character, so it must be escaped; but the backslash must be passed in, so it needs escaping. - Key aKey = getKey(keyposs, false); // This time, do NOT attempt to fetch from keymap. - + ArrayList keys = new ArrayList<>(); + for (String keyposs : keytext.split("\\|")) { // String.split() uses regex, and "|" is a special character, so it must be escaped; but the backslash must be passed in, so it needs escaping. // It really does combine using "or": - key.down = key.down || aKey.down; - key.clicked = key.clicked || aKey.clicked; + keys.add(getKey(keyposs)); } - return key; + return new ORKey(keys); } // Complex compound key binding support. @@ -364,10 +493,11 @@ private Key getKey(String keytext, boolean getFromMap) { String[] split = keytext.split("-"); for (String s : split) { if (keyboard.containsKey(s)) - keys.add(keyboard.get(s)); // Gets the key object from keyboard, if if exists. + // Gets the key object from keyboard, if it exists. + keys.add(inputMask == null || !inputMask.test(s) ? keyboard.get(s) : keyMask); else { // If the specified key does not yet exist in keyboard, then create a new Key, and put it there. - Key key = new Key(); // Make new key + PhysicalKey key = new PhysicalKey(); // Make new key keyboard.put(s, key); // Add it to keyboard keys.add(key); @@ -376,17 +506,11 @@ private Key getKey(String keytext, boolean getFromMap) { } } - //if(key.clicked && Game.debug) System.out.println("Processed key: " + keytext + " is clicked; tickNum=" + ticks); + // Returns the key itself if there is only one key. + if (keys.size() == 1) return keys.iterator().next(); - Key key = new Key(); - key.down = true; // The set is not empty, so this will not be returned directly. - key.clicked = false; - return keys.stream().reduce(key, (k0, k1) -> { - k0.down = k0.down && k1.down; // All keys down. - // If the whole key binding is clicked, then the all keys must be down and at least one of these is/are just clicked. - k0.clicked = k0.down && (k0.clicked || k1.clicked); - return k0; - }); // Return the Key object. + //if(key.clicked && Game.debug) System.out.println("Processed key: " + keytext + " is clicked; tickNum=" + ticks); + return new CompoundedKey(keys); // Return the Key object. } /// This method provides a way to press physical keys without actually generating a key event. @@ -400,7 +524,7 @@ public ArrayList getAllPressedKeys() { ArrayList keyList = new ArrayList<>(keyboard.size()); synchronized ("lock") { - for (Entry entry : keyboard.entrySet()) { + for (Entry entry : keyboard.entrySet()) { if (entry.getValue().down) { keyList.add(entry.getKey()); } @@ -411,14 +535,14 @@ public ArrayList getAllPressedKeys() { } /// This gets a key from key text, w/o adding to the key list. - private Key getPhysKey(String keytext) { + private PhysicalKey getPhysKey(String keytext) { keytext = keytext.toUpperCase(); if (keyboard.containsKey(keytext)) return keyboard.get(keytext); else { //System.out.println("UNKNOWN KEYBOARD KEY: " + keytext); // it's okay really; was just checking - return new Key(); // Won't matter where I'm calling it. + return new PhysicalKey(); // Won't matter where I'm calling it. } } @@ -438,8 +562,8 @@ private void toggle(int keycode, boolean pressed) { //System.out.println("Interpreted key press: " + keytext); //System.out.println("Toggling " + keytext + " key (keycode " + keycode + ") to "+pressed+"."); - if( pressed && keyToChange != null && !isMod(keytext) ) { - keymap.put(keyToChange, ( overwrite ? "" : keymap.get(keyToChange) + "|" ) + getCurModifiers() + keytext); + if (pressed && keyToChange != null && !isMod(keytext)) { + keymap.put(keyToChange, (overwrite ? "" : keymap.get(keyToChange) + "|") + getCurModifiers() + keytext); keyChanged = keyToChange; keyToChange = null; return; @@ -486,16 +610,18 @@ private static boolean isMod(String keyname) { } private String getCurModifiers() { - return (getKey("ctrl").down ? "CTRL-" : "") + - (getKey("alt").down ? "ALT-" : "") + - (getKey("shift").down ? "SHIFT-" : ""); + return (getKey("ctrl").isDown() ? "CTRL-" : "") + + (getKey("alt").isDown() ? "ALT-" : "") + + (getKey("shift").isDown() ? "SHIFT-" : ""); } - /** Used by Save.java, to save user key preferences. */ + /** + * Used by Save.java, to save user key preferences. + */ public String[] getKeyPrefs() { ArrayList keystore = new ArrayList<>(); // Make a list for keys - for (String keyname: keymap.keySet()) // Go though each mapping + for (String keyname : keymap.keySet()) // Go though each mapping keystore.add(keyname + ";" + keymap.get(keyname)); // Add the mapping values as one string, seperated by a semicolon. return keystore.toArray(new String[0]); // Return the array of encoded key preferences. @@ -513,51 +639,73 @@ public void addKeyBinding(String actionKey) { } /// Event methods, many to satisfy interface requirements... - public void keyPressed(KeyEvent ke) { toggle(ke.getExtendedKeyCode(), true); } - public void keyReleased(KeyEvent ke) { toggle(ke.getExtendedKeyCode(), false); } + public void keyPressed(KeyEvent ke) { + toggle(ke.getExtendedKeyCode(), true); + } + + public void keyReleased(KeyEvent ke) { + toggle(ke.getExtendedKeyCode(), false); + } + public void keyTyped(KeyEvent ke) { // Stores the last character typed keyTypedBuffer = String.valueOf(ke.getKeyChar()); } - private static final String control = "\\p{Print}"; // Should match only printable characters. + private static final String control = "[\\p{Print}\n]+"; // Should match only printable characters. public String addKeyTyped(String typing, @Nullable String pattern) { + return handleBackspaceChars(getKeysTyped(typing, pattern)); + } + + /** This returns a raw format of the keys typed, i.e. {@code \b} are not handled here. */ + public String getKeysTyped(@Nullable String pattern) { return getKeysTyped(null, pattern, true); } + public String getKeysTyped(@Nullable String typing, @Nullable String pattern) { return getKeysTyped(typing, pattern, false); } + public String getKeysTyped(@Nullable String typing, @Nullable String pattern, boolean multiline) { + StringBuilder typed = typing == null ? new StringBuilder() : new StringBuilder(typing); if (lastKeyTyped.length() > 0) { - String letter = lastKeyTyped; + for (char letter : lastKeyTyped.toCharArray()) { + String letterString = String.valueOf(letter); + if (letter == '\b' || letterString.matches(control) && (letter != '\n' || multiline) && (pattern == null || letterString.matches(pattern))) + typed.append(letter); + } lastKeyTyped = ""; - if ( letter.matches(control) && (pattern == null || letter.matches(pattern)) || letter.equals("\b") ) - typing += letter; } + return typed.toString(); + } + + public static String handleBackspaceChars(String typing) { return handleBackspaceChars(typing, false); } + /** + * This handles and erases backspace control characters {@code \b} from the given string. + * Evaluation to backspace characters stops if no more characters are in front of them. + * @param keepUnevaluated {@code true} if intending to keep the unhandled backspace characters in the returned string; + * otherwise, those characters are removed even that they are not evaluated. + */ + public static String handleBackspaceChars(String typing, boolean keepUnevaluated) { // Erasing characters by \b. Reference: https://stackoverflow.com/a/30174028 Stack stack = new Stack<>(); // for-each character in the string for (int i = 0; i < typing.length(); i++) { char c = typing.charAt(i); - - // push if it's not a backspace - if (c != '\b') { - stack.push(c); - // else pop if possible - } else if (!stack.empty()) { + if (c == '\b' && !stack.empty() && stack.peek() != '\b') { // pop if the last char exists and is not \b stack.pop(); + } else if (c != '\b' || keepUnevaluated) { + stack.push(c); } } // convert stack to string StringBuilder builder = new StringBuilder(stack.size()); - for (Character c : stack) { builder.append(c); } - typing = builder.toString(); - return typing; + return builder.toString(); } public boolean anyControllerConnected() { - return controllerManager.getNumControllers() > 0; + return controllersSupported && controllerManager.getNumControllers() > 0; } public boolean buttonPressed(ControllerButton button) { @@ -580,12 +728,12 @@ public ArrayList getAllPressedButtons() { public boolean inputPressed(String mapping) { mapping = mapping.toUpperCase(java.util.Locale.ENGLISH); - return getKey(mapping).clicked || (buttonMap.containsKey(mapping) && buttonPressed(buttonMap.get(mapping))); + return getMappedKey(mapping).isClicked() || (buttonMap.containsKey(mapping) && buttonPressed(buttonMap.get(mapping))); } public boolean inputDown(String mapping) { mapping = mapping.toUpperCase(java.util.Locale.ENGLISH); - return getKey(mapping).down || (buttonMap.containsKey(mapping) && buttonDown(buttonMap.get(mapping))); + return getMappedKey(mapping).isDown() || (buttonMap.containsKey(mapping) && buttonDown(buttonMap.get(mapping))); } /** @@ -593,43 +741,49 @@ public boolean inputDown(String mapping) { * This will return false if the controller doesn't support vibration or if SDL was unable to start * vibration (maybe the controller doesn't support left/right vibration, maybe it was unplugged in the * middle of trying, etc...) - * * @param leftMagnitude The speed for the left motor to vibrate (this should be between 0 and 1) * @param rightMagnitude The speed for the right motor to vibrate (this should be between 0 and 1) * @return Whether or not the controller was able to be vibrated (i.e. if haptics are supported) or controller not connected. */ public boolean controllerVibration(float leftMagnitude, float rightMagnitude, int duration_ms) { - try { - return controllerIndex.doVibration(leftMagnitude, rightMagnitude, duration_ms); - } catch (ControllerUnpluggedException ignored) { - return false; - } + if (controllersSupported) { + try { + return controllerIndex.doVibration(leftMagnitude, rightMagnitude, duration_ms); + } catch (ControllerUnpluggedException ignored) { + return false; + } + } else return false; } private int leftTriggerCooldown = 0; private int rightTriggerCooldown = 0; public boolean leftTriggerPressed() { - try { - if (leftTriggerCooldown == 0 && controllerIndex.getAxisState(ControllerAxis.TRIGGERLEFT) > 0.5) { - leftTriggerCooldown = 8; - return true; - } else + if (controllersSupported) { + try { + if (leftTriggerCooldown == 0 && controllerIndex.getAxisState(ControllerAxis.TRIGGERLEFT) > 0.5) { + leftTriggerCooldown = 8; + return true; + } else + return false; + } catch (ControllerUnpluggedException e) { return false; - } catch (ControllerUnpluggedException e) { - return false; - } + } + } else return false; } + public boolean rightTriggerPressed() { - try { - if (rightTriggerCooldown == 0 && controllerIndex.getAxisState(ControllerAxis.TRIGGERRIGHT) > 0.5) { - rightTriggerCooldown = 8; - return true; - } else + if (controllersSupported) { + try { + if (rightTriggerCooldown == 0 && controllerIndex.getAxisState(ControllerAxis.TRIGGERRIGHT) > 0.5) { + rightTriggerCooldown = 8; + return true; + } else + return false; + } catch (ControllerUnpluggedException e) { return false; - } catch (ControllerUnpluggedException e) { - return false; - } + } + } else return false; } private class LastInputActivityListener { diff --git a/src/client/java/minicraft/core/io/Localization.java b/src/client/java/minicraft/core/io/Localization.java index 019aa243a..737d8712a 100644 --- a/src/client/java/minicraft/core/io/Localization.java +++ b/src/client/java/minicraft/core/io/Localization.java @@ -39,12 +39,14 @@ public static String getLocalized(String key, Object... arguments) { try { Double.parseDouble(key); return key; // This is a number; don't try to localize it - } catch(NumberFormatException ignored) {} + } catch (NumberFormatException ignored) { + } String localString = localization.get(key); if (localString == null) { - if (!knownUnlocalizedStrings.containsKey(selectedLocale)) knownUnlocalizedStrings.put(selectedLocale, new HashSet<>()); + if (!knownUnlocalizedStrings.containsKey(selectedLocale)) + knownUnlocalizedStrings.put(selectedLocale, new HashSet<>()); if (!knownUnlocalizedStrings.get(selectedLocale).contains(key)) { Logger.tag("LOC").trace(unlocalizedStringTracing ? new Throwable("Tracing") : null, "{}: '{}' is unlocalized.", selectedLocale.toLanguageTag(), key); knownUnlocalizedStrings.get(selectedLocale).add(key); @@ -62,7 +64,9 @@ public static String getLocalized(String key, Object... arguments) { * Gets the currently selected locale. * @return A locale object. */ - public static Locale getSelectedLocale() { return selectedLocale; } + public static Locale getSelectedLocale() { + return selectedLocale; + } /** * Get the currently selected locale, but as a full name without the country code. @@ -78,7 +82,9 @@ public static LocaleInformation getSelectedLanguage() { * @return A list of locales. */ @NotNull - public static LocaleInformation[] getLocales() { return localeInfo.values().toArray(new LocaleInformation[0]); } + public static LocaleInformation[] getLocales() { + return localeInfo.values().toArray(new LocaleInformation[0]); + } /** * Changes the selected language and loads it. @@ -88,7 +94,10 @@ public static LocaleInformation getSelectedLanguage() { public static void changeLanguage(@NotNull String newLanguage) { changeLanguage(Locale.forLanguageTag(newLanguage)); } - /** @see #changeLanguage(String) */ + + /** + * @see #changeLanguage(String) + */ public static void changeLanguage(@NotNull Locale newLanguage) { selectedLocale = newLanguage; loadLanguage(); diff --git a/src/client/java/minicraft/core/io/Settings.java b/src/client/java/minicraft/core/io/Settings.java index ce0c92622..e3dfdde31 100644 --- a/src/client/java/minicraft/core/io/Settings.java +++ b/src/client/java/minicraft/core/io/Settings.java @@ -15,7 +15,6 @@ public final class Settings { static { options.put("fps", new RangeEntry("minicraft.settings.fps", 10, 300, getDefaultRefreshRate())); // Has to check if the game is running in a headless mode. If it doesn't set the fps to 60 - options.put("screenshot", new ArrayEntry<>("minicraft.settings.screenshot_scale", 1, 2, 5, 10, 15, 20)); // The magnification of screenshot. I would want to see ultimate sized. options.put("diff", new ArrayEntry<>("minicraft.settings.difficulty", "minicraft.settings.difficulty.easy", "minicraft.settings.difficulty.normal", "minicraft.settings.difficulty.hard")); options.get("diff").setSelection(1); options.put("mode", new ArrayEntry<>("minicraft.settings.mode", "minicraft.settings.mode.survival", "minicraft.settings.mode.creative", "minicraft.settings.mode.hardcore", "minicraft.settings.mode.score")); @@ -26,15 +25,17 @@ public final class Settings { options.put("sound", new BooleanEntry("minicraft.settings.sound", true)); options.put("autosave", new BooleanEntry("minicraft.settings.autosave", true)); + // For Windows, OpenGL hardware acceleration is disabled by default + options.put("hwa", new BooleanEntry("minicraft.settings.opengl_hwa", !FileHandler.OS.contains("windows"))); options.put("size", new ArrayEntry<>("minicraft.settings.size", 128, 256, 512)); options.put("theme", new ArrayEntry<>("minicraft.settings.theme", "minicraft.settings.theme.normal", "minicraft.settings.theme.forest", "minicraft.settings.theme.desert", "minicraft.settings.theme.plain", "minicraft.settings.theme.hell")); options.put("type", new ArrayEntry<>("minicraft.settings.type", "minicraft.settings.type.island", "minicraft.settings.type.box", "minicraft.settings.type.mountain", "minicraft.settings.type.irregular")); // TODO localize these labels - options.put("tutorials", new BooleanEntry("Tutorials", false)); - options.put("quests", new BooleanEntry("Quests", false)); - options.put("showquests", new BooleanEntry("Quests Panel", true)); + options.put("tutorials", new BooleanEntry("minicraft.settings.tutorials", false)); + options.put("quests", new BooleanEntry("minicraft.settings.quests", false)); + options.put("showquests", new BooleanEntry("minicraft.settings.show_quests", true)); options.get("mode").setChangeAction(value -> options.get("scoretime").setVisible("minicraft.settings.mode.score".equals(value)) @@ -46,21 +47,27 @@ public final class Settings { * @param option The setting to get. * @return The value of the setting */ - public static Object get(String option) { return options.get(option.toLowerCase()).getValue(); } + public static Object get(String option) { + return options.get(option.toLowerCase()).getValue(); + } /** * Returns the index of the value in the list of values for the specified option. * @param option The setting to get. * @return The index of the setting. */ - public static int getIdx(String option) { return options.get(option.toLowerCase()).getSelection(); } + public static int getIdx(String option) { + return options.get(option.toLowerCase()).getSelection(); + } /** * Return the ArrayEntry object associated with the given option name. * @param option The setting to get. * @return The ArrayEntry. */ - public static ArrayEntry getEntry(String option) { return options.get(option.toLowerCase()); } + public static ArrayEntry getEntry(String option) { + return options.get(option.toLowerCase()); + } /** * Sets the value of the given option name, to the given value, provided it is a valid value for that option. diff --git a/src/client/java/minicraft/core/io/Sound.java b/src/client/java/minicraft/core/io/Sound.java index fd547a7a3..6081fa3f3 100644 --- a/src/client/java/minicraft/core/io/Sound.java +++ b/src/client/java/minicraft/core/io/Sound.java @@ -5,26 +5,63 @@ import org.jetbrains.annotations.Nullable; import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioInputStream; import javax.sound.sampled.AudioSystem; import javax.sound.sampled.Clip; import javax.sound.sampled.DataLine; import javax.sound.sampled.Line; -import javax.sound.sampled.LineEvent; import javax.sound.sampled.LineUnavailableException; +import javax.sound.sampled.SourceDataLine; import javax.sound.sampled.UnsupportedAudioFileException; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.Optional; public class Sound { // Creates sounds from their respective files private static final HashMap sounds = new HashMap<>(); + private static final LinkedList pointers = new LinkedList<>(); + private static final AudioFormat STANDARD_FORMAT = + new AudioFormat(44100, 16, 2, true, true); + private static final int MAX_BUFFER_SIZE = 4096; + private static final SourceDataLine dataLine; + private static final int internalBufferSize; + + /* + * Only 2/16/44100 and 1/16/44100 PCM_SIGNED are supported. + */ + + static { + try { + dataLine = AudioSystem.getSourceDataLine(STANDARD_FORMAT); + dataLine.open(); + // Assume DirectAudioDevice is used + internalBufferSize = ((int) (STANDARD_FORMAT.getFrameRate() / 2)) * STANDARD_FORMAT.getFrameSize(); + } catch (LineUnavailableException e) { + throw new RuntimeException(e); + } + } - private Clip clip; // Creates a audio clip to be played + private final short[] raw; + + private class AudioPointer { + private int offset = 0; + + public Optional getData() { + if (offset == raw.length) return Optional.empty(); + return Optional.of(raw[offset++]); + } + } - private Sound(Clip clip) { - this.clip = clip; + private Sound(short[] raw) { + this.raw = raw; } public static void resetSounds() { @@ -33,10 +70,19 @@ public static void resetSounds() { public static void loadSound(String key, InputStream in, String pack) { try { - DataLine.Info info = new DataLine.Info(Clip.class, AudioSystem.getAudioFileFormat(in).getFormat()); + AudioInputStream ain = AudioSystem.getAudioInputStream(in); + AudioFormat format = ain.getFormat(); + DataLine.Info info = new DataLine.Info(Clip.class, format); + + if (format.getEncoding() != AudioFormat.Encoding.PCM_SIGNED || + format.getChannels() > 2 || format.getSampleRate() != 44100 || + format.getSampleSizeInBits() != 16) { + Logging.RESOURCEHANDLER_SOUND.error("Unsupported audio format of file \"{}\" in pack \"{}\": {}", + key, pack, format); + } if (!AudioSystem.isLineSupported(info)) { - Logging.RESOURCEHANDLER_SOUND.error("ERROR: Audio format of file \"{}\" in pack \"\" is not supported: {}", key, pack, AudioSystem.getAudioFileFormat(in)); + Logging.RESOURCEHANDLER_SOUND.error("ERROR: Audio format of file \"{}\" in pack \"{}\" is not supported: {}", key, pack, AudioSystem.getAudioFileFormat(in)); Logging.RESOURCEHANDLER_SOUND.error("Supported audio formats:"); Logging.RESOURCEHANDLER_SOUND.error("-source:"); @@ -51,13 +97,11 @@ public static void loadSound(String key, InputStream in, String pack) { } } Logging.RESOURCEHANDLER_SOUND.error("-target:"); - for (int i = 0; i < tinfo.length; i++) - { - if (tinfo[i] instanceof DataLine.Info) - { + for (int i = 0; i < tinfo.length; i++) { + if (tinfo[i] instanceof DataLine.Info) { DataLine.Info dataLineInfo = (DataLine.Info) tinfo[i]; AudioFormat[] supportedFormats = dataLineInfo.getFormats(); - for (AudioFormat af: supportedFormats) + for (AudioFormat af : supportedFormats) Logging.RESOURCEHANDLER_SOUND.error(af); } } @@ -65,57 +109,140 @@ public static void loadSound(String key, InputStream in, String pack) { return; } - Clip clip = (Clip)AudioSystem.getLine(info); - clip.open(AudioSystem.getAudioInputStream(in)); - - clip.addLineListener(e -> { - if (e.getType() == LineEvent.Type.STOP) { - clip.flush(); - clip.setFramePosition(0); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + byte[] buf = new byte[8192]; + int length; + while ((length = ain.read(buf)) != -1) { + out.write(buf, 0, length); + } + short[] raw0 = new short[out.size()/2]; + ByteBuffer.wrap(out.toByteArray()).order(format.isBigEndian() ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN) + .asShortBuffer().get(raw0); + short[] raw1; + if (format.getChannels() == 1) { + raw1 = new short[raw0.length * 2]; + for (int i = 0; i < raw0.length; ++i) { + raw1[i * 2] = raw0[i]; + raw1[i * 2 + 1] = raw0[i]; } - }); - - sounds.put(key, new Sound(clip)); + } else if (format.getChannels() != 2) { // This should not be executed. + Logging.RESOURCEHANDLER_SOUND.error( + "Audio source \"{}\" in pack \"{}\" is neither mono nor stereo, which is not supported.", + key, pack); + return; + } else { + raw1 = raw0; + } - } catch (LineUnavailableException | UnsupportedAudioFileException | IOException e) { + sounds.put(key, new Sound(raw1)); + } catch (UnsupportedAudioFileException | IOException e) { CrashHandler.errorHandle(e, new CrashHandler.ErrorInfo("Audio Could not Load", CrashHandler.ErrorInfo.ErrorType.REPORT, String.format("Could not load audio: %s in pack: %s", key, pack))); } } - /** Recommend {@link #play(String)} and {@link #loop(String, boolean)}. */ + /** + * Recommend {@link #play(String)} and {@link #loop(String, int)}. + */ @Nullable public static Sound getSound(String key) { return sounds.get(key); } - /** This method does safe check for {@link #play()}. */ + /** + * This method does safe check for {@link #play()}. + */ public static void play(String key) { Sound sound = sounds.get(key); if (sound != null) sound.play(); } - /** This method does safe check for {@link #loop(boolean)}. */ - public static void loop(String key, boolean start) { + /** + * This method does safe check for {@link #loop(int)}. + */ + public static void loop(String key, int count) { Sound sound = sounds.get(key); - if (sound != null) sound.loop(start); + if (sound != null) sound.loop(count); } - public void play() { - if (!(boolean)Settings.get("sound") || clip == null) return; + public static void tick() { + dataLine.start(); + // internalBufferSize - dataLine.available() == used buffer + // Proceed data and then buffer into the data line. + // For 2/16/44100, 2940 bytes would be proceeded per tick. + if (internalBufferSize - dataLine.available() > MAX_BUFFER_SIZE) return; + int available = Math.min(dataLine.available(), MAX_BUFFER_SIZE) / 2; // in 16bit (short) + if (available <= 0) return; // Skips tick if buffer is large causing latency + byte[] buf = new byte[available * 2]; + short[] bufShort = new short[available]; + while (available > 0) { + /* Audio Mixing Algorithm + * Reference Article: https://stackoverflow.com/a/25102339 + * It is pointed out that, non-linear mixing algorithms are not the correct ways to perform mixing, + * but it should be instead handled by (dynamic range) compression. + * For now, C = sum{U_i} / n is not enough, but compression should be applied. + * + * It is noticed that for the quiet sounds, the sounds become quieter when mixed, even overall. + * So, an upward compression is required. We now define a quiet sound to be a signal smaller than + * a one-fourth of the maximum value. + * For each quiet signal, we gain an upward compression factor and finally multiplied altogether to the + * resultant value. And we can get the factor by a non-linear equation: + * F = log2((D-U)/D+1)+1, where F is the factor, D is the one-fourth value, U is the signal value. + * Note that U ∈ [0, D), (D-U)/D ∈ (0, 1], F ∈ (1, 2]. + * But we cannot have this too big, so we make this into F^(1/3), where 2^(1/3) is approximately 1.26. + * This can make sure that the factor would not go great. + * Then, make sure that the factor cannot overflow the value, + * G = sqrt(product{F_i}), + * as a final factor, would then be used. + * + * Finally, if the value really goes close to the maximum value even overflow, like 0.9 of the maximum value, + * we can then apply an ultimate equation: + * H = (J) / (J + 1) * E, + * where H is the value to add with the cut value (0.9 of the maximum), J is the exceeded value and + * E is the certain amount smaller than 0.1 of the maximum, say 0.05 of it here. + * We can get a compressed sound and also limited from the maximum, with 0.95x of the maximum. + */ + + int n = 0; + int sum = 0; + double factor = 1; + for (Iterator iterator = pointers.iterator(); iterator.hasNext(); ) { + AudioPointer pointer = iterator.next(); + Optional d = pointer.getData(); + if (!d.isPresent()) iterator.remove(); + else { + int val = d.get(); // Signed + int net = Math.abs(val); // Bounds are halved for absolute of signed value + if (net < 8192) + factor *= Math.pow(Math.log1p((8192 - net) / 8192D) / Math.log(2) + 1, 1D/3); + sum += val + 32768; // Turning to unsigned + n++; + } + } - if (clip.isRunning() || clip.isActive()) - clip.stop(); + if (n == 0) break; // No more data to be written at the moment + double val = (double) sum / n - 32768; // To signed + val *= Math.sqrt(factor); + double net = Math.abs(val); // Bounds are halved for absolute of signed value + if (net > 32768*.9D) { + val = (32768*.9D + ((net - 32768*.9D) / (net - 32768*.9D + 1) * 32768/10D)) * Math.signum(val); + } - clip.start(); - } + // val should be between -32768 and 32767 exclusively + bufShort[bufShort.length - available] = (short) val; + available--; + } - public void loop(boolean start) { - if (!(boolean)Settings.get("sound") || clip == null) return; + ByteBuffer.wrap(buf).asShortBuffer().put(bufShort); + dataLine.write(buf, 0, buf.length); + } - if (start) - clip.loop(Clip.LOOP_CONTINUOUSLY); - else - clip.stop(); + public void play() { + if (!(boolean) Settings.get("sound")) return; + pointers.add(new AudioPointer()); } + + /** @deprecated no longer supported, but reserved for future implementation. */ + @Deprecated + public void loop(int count) {} } diff --git a/src/client/java/minicraft/entity/Arrow.java b/src/client/java/minicraft/entity/Arrow.java index c5220d4a9..8b565c286 100644 --- a/src/client/java/minicraft/entity/Arrow.java +++ b/src/client/java/minicraft/entity/Arrow.java @@ -23,8 +23,9 @@ public class Arrow extends Entity implements ClientTickable { public Arrow(Mob owner, Direction dir, int dmg) { this(owner, owner.x, owner.y, dir, dmg); } + public Arrow(Mob owner, int x, int y, Direction dir, int dmg) { - super(Math.abs(dir.getX())+1, Math.abs(dir.getY())+1); + super(Math.abs(dir.getX()) + 1, Math.abs(dir.getY()) + 1); this.owner = owner; this.x = x; this.y = y; @@ -34,9 +35,9 @@ public Arrow(Mob owner, int x, int y, Direction dir, int dmg) { col = Color.get(-1, 111, 222, 430); int xt = 0; - if(dir == Direction.LEFT) xt = 1; - if(dir == Direction.UP) xt = 2; - if(dir == Direction.DOWN) xt = 3; + if (dir == Direction.LEFT) xt = 1; + if (dir == Direction.UP) xt = 2; + if (dir == Direction.DOWN) xt = 3; sprite.setSpritePos(xt, 0); if (damage > 3) speed = 8; @@ -49,7 +50,7 @@ public Arrow(Mob owner, int x, int y, Direction dir, int dmg) { * @return string representation of owner, xdir, ydir and damage. */ public String getData() { - return owner.eid + ":" + dir.ordinal() + ":"+damage; + return owner.eid + ":" + dir.ordinal() + ":" + damage; } @Override @@ -74,9 +75,9 @@ public void tick() { mob.hurt(owner, damage, dir); //normal hurting to other mobs } - if (!level.getTile(x / 16, y / 16).mayPass(level, x / 16, y / 16, this) - && !level.getTile(x / 16, y / 16).connectsToFluid - && level.getTile(x / 16, y / 16).id != 16) { + if (!level.getTile(x >> 4, y >> 4).mayPass(level, x >> 4, y >> 4, this) + && !level.getTile(x >> 4, y >> 4).connectsToFluid(level, x >> 4, y >> 4) + && level.getTile(x >> 4, y >> 4).id != 16) { this.remove(); try { sprite.destroy(); diff --git a/src/client/java/minicraft/entity/ClientTickable.java b/src/client/java/minicraft/entity/ClientTickable.java index 81cc73998..55c4325d8 100644 --- a/src/client/java/minicraft/entity/ClientTickable.java +++ b/src/client/java/minicraft/entity/ClientTickable.java @@ -1,9 +1,9 @@ package minicraft.entity; public interface ClientTickable extends Tickable { - + default void clientTick() { tick(); } - + } diff --git a/src/client/java/minicraft/entity/Direction.java b/src/client/java/minicraft/entity/Direction.java index 68c93f079..291be85f9 100644 --- a/src/client/java/minicraft/entity/Direction.java +++ b/src/client/java/minicraft/entity/Direction.java @@ -13,11 +13,17 @@ public enum Direction { public static final Direction[] values = Direction.values(); - public int getX() { return x; } - public int getY() { return y; } + public int getX() { + return x; + } + + public int getY() { + return y; + } public static Direction getDirection(int xd, int yd) { - if (xd == 0 && yd == 0) return Direction.NONE; // The attack was from the same entity, probably; or at least the exact same space. + if (xd == 0 && yd == 0) + return Direction.NONE; // The attack was from the same entity, probably; or at least the exact same space. if (Math.abs(xd) > Math.abs(yd)) { // The x distance is more prominent than the y distance @@ -34,7 +40,10 @@ public static Direction getDirection(int xd, int yd) { } public static Direction getDirection(int dir) { - return values[dir+1]; + return values[dir + 1]; + } + + public int getDir() { + return ordinal() - 1; } - public int getDir() { return ordinal()-1; } } diff --git a/src/client/java/minicraft/entity/Entity.java b/src/client/java/minicraft/entity/Entity.java index 0ff319460..5fb210357 100644 --- a/src/client/java/minicraft/entity/Entity.java +++ b/src/client/java/minicraft/entity/Entity.java @@ -1,5 +1,6 @@ package minicraft.entity; +import minicraft.core.Action; import minicraft.core.Updater; import minicraft.entity.mob.Player; import minicraft.gfx.Rectangle; @@ -14,6 +15,8 @@ import java.util.HashSet; import java.util.List; import java.util.Random; +import java.util.function.BiConsumer; +import java.util.function.BiPredicate; import java.util.function.IntSupplier; public abstract class Entity implements Tickable { @@ -69,41 +72,74 @@ public Entity(int xr, int yr) { // Add color to this later, in color update * Returns true if the entity is removed from the level, otherwise false. * @return removed */ - public boolean isRemoved() { return removed/* || level == null*/; } + public boolean isRemoved() { + return removed/* || level == null*/; + } /** * Returns the level which this entity belongs in. * @return level */ - public Level getLevel() { return level; } + public Level getLevel() { + return level; + } - /** Returns a Rectangle instance using the defined bounds of the entity. */ - protected Rectangle getBounds() { return new Rectangle(x, y, xr * 2, yr * 2, Rectangle.CENTER_DIMS); } + /** + * Returns a Rectangle instance using the defined bounds of the entity. + */ + protected Rectangle getBounds() { + return new Rectangle(x, y, xr * 2, yr * 2, Rectangle.CENTER_DIMS); + } - /** Returns true if this entity is found in the rectangle specified by given two coordinates. */ - public boolean isTouching(Rectangle area) { return area.intersects(getBounds()); } + /** + * Returns true if this entity is found in the rectangle specified by given two coordinates. + */ + public boolean isTouching(Rectangle area) { + return area.intersects(getBounds()); + } - /** Returns if this entity stops other solid entities from moving. */ - public boolean isSolid() { return true; } // Most entities are solid + /** + * Returns if this entity stops other solid entities from moving. + */ + public boolean isSolid() { + return true; + } // Most entities are solid - /** Determines if the given entity should prevent this entity from moving. */ - public boolean blocks(Entity e) { return isSolid() && e.isSolid(); } + /** + * Determines if the given entity should prevent this entity from moving. + */ + public boolean blocks(Entity e) { + return isSolid() && e.isSolid(); + } + + public boolean canSwim() { + return false; + } // Determines if the entity can swim (extended in sub-classes) + + public boolean canWool() { + return false; + } // This, strangely enough, determines if the entity can walk on wool; among some other things..? - public boolean canSwim() { return false; } // Determines if the entity can swim (extended in sub-classes) - public boolean canWool() { return false; } // This, strangely enough, determines if the entity can walk on wool; among some other things..? public boolean canBurn() { return true; } // Determines if the entity can burn. + public boolean canBeAffectedByLava() { return true; } // Determines if the entity can burn in lava. + public int burningDuration = 0; - public int getLightRadius() { return 0; } // Used for lanterns... and player? that might be about it, though, so idk if I want to put it here. + public int getLightRadius() { + return 0; + } // Used for lanterns... and player? that might be about it, though, so idk if I want to put it here. - /** If this entity is touched by another entity (extended by sub-classes) */ - protected void touchedBy(Entity entity) {} + /** + * If this entity is touched by another entity (extended by sub-classes) + */ + protected void touchedBy(Entity entity) { + } /** * Interacts with the entity this method is called on @@ -116,7 +152,9 @@ public boolean interact(Player player, @Nullable Item item, Direction attackDir) return false; } - /** Moves an entity horizontally and vertically. Returns whether entity was unimpeded in it's movement. */ + /** + * Moves an entity horizontally and vertically. Returns whether entity was unimpeded in it's movement. + */ public boolean move(int xd, int yd) { if (Updater.saving || (xd == 0 && yd == 0)) return true; // Pretend that it kept moving @@ -129,7 +167,6 @@ public boolean move(int xd, int yd) { int yt = y >> 4; // The y tile coordinate that the entity is standing on. level.getTile(xt, yt).steppedOn(level, xt, yt, this); // Calls the steppedOn() method in a tile's class. (used for tiles like sand (footprints) or lava (burning)) } - return !stopped; } @@ -153,8 +190,17 @@ protected boolean moveX(int d) { int hitBoxFront = x + xr * sgn; int maxFront = Level.calculateMaxFrontClosestTile(sgn, d, hitBoxLeft, hitBoxRight, hitBoxFront, (front, horTile) -> level.getTile(front, horTile).mayPass(level, front, horTile, this)); // Maximum position can be reached with front hit box - if (maxFront == hitBoxFront) return false; // No movement can be made. - return moveByEntityHitBoxChecks(sgn, hitBoxFront, maxFront, () -> x + sgn, () -> y, () -> x += sgn); + if (maxFront == hitBoxFront) { // Bumping into the facing tile + int hitBoxRightTile = hitBoxRight >> 4; + int frontTile = (hitBoxFront + sgn) >> 4; + for (int horTile = hitBoxLeft >> 4; horTile <= hitBoxRightTile; horTile++) { + level.getTile(frontTile, horTile).bumpedInto(level, frontTile, horTile, this); + } + return false; // No movement can be made. + } + return moveByEntityHitBoxChecks(sgn, hitBoxFront, maxFront, () -> x + sgn, () -> y, () -> x += sgn, hitBoxLeft, hitBoxRight, + (front, horTile) -> level.getTile(front, horTile).bumpedInto(level, front, horTile, this), + (front, horTile) -> level.getTile(front, horTile).steppedOn(level, front, horTile, this)); } /** @@ -177,8 +223,17 @@ protected boolean moveY(int d) { int hitBoxFront = y + yr * sgn; int maxFront = Level.calculateMaxFrontClosestTile(sgn, d, hitBoxLeft, hitBoxRight, hitBoxFront, (front, horTile) -> level.getTile(horTile, front).mayPass(level, horTile, front, this)); // Maximum position can be reached with front hit box - if (maxFront == hitBoxFront) return false; // No movement can be made. - return moveByEntityHitBoxChecks(sgn, hitBoxFront, maxFront, () -> x, () -> y + sgn, () -> y += sgn); + if (maxFront == hitBoxFront) { // Bumping into the facing tile + int hitBoxRightTile = hitBoxRight >> 4; + int frontTile = (hitBoxFront + sgn) >> 4; + for (int horTile = hitBoxLeft >> 4; horTile <= hitBoxRightTile; horTile++) { + level.getTile(horTile, frontTile).bumpedInto(level, horTile, frontTile, this); + } + return false; // No movement can be made. + } + return moveByEntityHitBoxChecks(sgn, hitBoxFront, maxFront, () -> x, () -> y + sgn, () -> y += sgn, hitBoxLeft, hitBoxRight, + (front, horTile) -> level.getTile(horTile, front).bumpedInto(level, horTile, front, this), + (front, horTile) -> level.getTile(horTile, front).steppedOn(level, horTile, front, this)); } /** @@ -189,16 +244,34 @@ protected boolean moveY(int d) { * @param xMove The value of the willing x movement * @param yMove The value of the willing y movement * @param incrementMove The movement call when the movement is possible + * @param hitBoxLeft The left boundary of hit box + * @param hitBoxRight The right boundary of hit box + * @param bumpingHandler The consumer handling bumping into a new tile; + * the first parameter takes the front tile position and second one takes the horizontal position + * @param steppingHandler The consumer handling stepping on a new tile; + * the first parameter takes the front tile position and second one takes the horizontal position * @return {@code true} if the movement is successful, {@code false} otherwise. - * @see #moveByEntityHitBoxChecks(int, int, int, IntSupplier, IntSupplier, Runnable) + * @see Level#calculateMaxFrontClosestTile(int, int, int, int, int, BiPredicate) */ protected boolean moveByEntityHitBoxChecks(int sgn, int hitBoxFront, int maxFront, IntSupplier xMove, - IntSupplier yMove, Runnable incrementMove) { + IntSupplier yMove, Action incrementMove, int hitBoxLeft, int hitBoxRight, + BiConsumer bumpingHandler, BiConsumer steppingHandler) { boolean successful = false; // These lists are named as if the entity has already moved-- it hasn't, though. HashSet wasInside = new HashSet<>(level.getEntitiesInRect(getBounds())); // Gets all the entities that are inside this entity (aka: colliding) before moving. + int frontTile = hitBoxFront << 4; // The original tile the front boundary hit box staying on + boolean handleSteppedOn = false; // Used together with frontTile for (int front = hitBoxFront; sgn < 0 ? front > maxFront : front < maxFront; front += sgn) { + int newFrontTile = (front + sgn) >> 4; + if (newFrontTile != frontTile) { // New tile touched + int hitBoxRightTile = hitBoxRight >> 4; + for (int horTile = hitBoxLeft >> 4; horTile <= hitBoxRightTile; horTile++) { + bumpingHandler.accept(newFrontTile, horTile); + } + frontTile = newFrontTile; + handleSteppedOn = true; + } boolean blocked = false; // If the entity prevents this one from movement, no movement. for (Entity e : level.getEntitiesInRect(new Rectangle(xMove.getAsInt(), yMove.getAsInt(), xr * 2, yr * 2, Rectangle.CENTER_DIMS))) { if (!wasInside.contains(e)) { // Skips entities that were touched. @@ -214,20 +287,35 @@ protected boolean moveByEntityHitBoxChecks(int sgn, int hitBoxFront, int maxFron } } if (blocked) break; - incrementMove.run(); // Movement successful + incrementMove.act(); // Movement successful + if (handleSteppedOn) { // When the movement to a new tile successes + int hitBoxRightTile = hitBoxRight >> 4; + for (int horTile = hitBoxLeft >> 4; horTile <= hitBoxRightTile; horTile++) { + steppingHandler.accept(frontTile, horTile); // Calls the steppedOn() method in a tile's class. (used for tiles like sand (footprints) or lava (burning)) + } + } successful = true; } return successful; } - /** Checks if the entity is able to naturally be despawned in general conditions. Handles (despawns) if true. */ - public void handleDespawn() {} + /** + * Checks if the entity is able to naturally be despawned in general conditions. Handles (despawns) if true. + */ + public void handleDespawn() { + } - /** This exists as a way to signify that the entity has been removed through player action and/or world action; basically, it's actually gone, not just removed from a level because it's out of range or something. Calls to this method are used to, say, drop items. */ - public void die() { remove(); } + /** + * This exists as a way to signify that the entity has been removed through player action and/or world action; basically, it's actually gone, not just removed from a level because it's out of range or something. Calls to this method are used to, say, drop items. + */ + public void die() { + remove(); + } - /** Removes the entity from the level. */ + /** + * Removes the entity from the level. + */ public void remove() { if (removed && !(this instanceof ItemEntity)) // Apparently this happens fairly often with item entities. Logging.ENTITY.debug("Note: remove() called on removed entity: " + this); @@ -240,7 +328,9 @@ public void remove() { level.remove(this); } - /** This should ONLY be called by the Level class. To properly remove an entity from a level, use level.remove(entity) */ + /** + * This should ONLY be called by the Level class. To properly remove an entity from a level, use level.remove(entity) + */ public void remove(Level level) { if (level != this.level) { Logging.ENTITY.debug("Tried to remove entity " + this + " from level it is not in: " + level + "; in level " + this.level); @@ -250,7 +340,9 @@ public void remove(Level level) { } } - /** This should ONLY be called by the Level class. To properly add an entity to a level, use level.add(entity) */ + /** + * This should ONLY be called by the Level class. To properly add an entity to a level, use level.add(entity) + */ public void setLevel(Level level, int x, int y) { if (level == null) { Logging.ENTITY.debug("Tried to set level of entity " + this + " to a null level; Should use remove(level)"); @@ -268,7 +360,8 @@ public void setLevel(Level level, int x, int y) { public boolean isWithin(int tileRadius, Entity other) { if (level == null || other.getLevel() == null) return false; - if (level.depth != other.getLevel().depth) return false; // Obviously, if they are on different levels, they can't be next to each other. + if (level.depth != other.getLevel().depth) + return false; // Obviously, if they are on different levels, they can't be next to each other. double distance = Math.abs(Math.hypot(x - other.x, y - other.y)); // Calculate the distance between the two entities, in entity coordinates. @@ -279,6 +372,7 @@ public boolean isWithin(int tileRadius, Entity other) { * Returns the closest player to this entity. * @return the closest player. */ + @Nullable protected Player getClosestPlayer() { return getClosestPlayer(true); } @@ -289,6 +383,7 @@ protected Player getClosestPlayer() { * @param returnSelf determines if the method can return itself. * @return The closest player to this entity. */ + @Nullable protected Player getClosestPlayer(boolean returnSelf) { if (this instanceof Player && returnSelf) return (Player) this; @@ -298,7 +393,10 @@ protected Player getClosestPlayer(boolean returnSelf) { return level.getClosestPlayer(x, y); } - public String toString() { return getClass().getSimpleName() + getDataPrints(); } + public String toString() { + return getClass().getSimpleName() + getDataPrints(); + } + protected List getDataPrints() { List prints = new ArrayList<>(); prints.add("eid=" + eid); @@ -311,5 +409,7 @@ public final boolean equals(Object other) { } @Override - public final int hashCode() { return eid; } + public final int hashCode() { + return eid; + } } diff --git a/src/client/java/minicraft/entity/ExplosionTileTicker.java b/src/client/java/minicraft/entity/ExplosionTileTicker.java new file mode 100644 index 000000000..5331a82f4 --- /dev/null +++ b/src/client/java/minicraft/entity/ExplosionTileTicker.java @@ -0,0 +1,56 @@ +package minicraft.entity; + +import minicraft.gfx.Screen; +import minicraft.level.Level; +import minicraft.level.tile.ExplodedTile; +import minicraft.level.tile.Tile; +import minicraft.level.tile.Tiles; + +// This is a kind of tile entity. Maybe this should be savable. +public class ExplosionTileTicker extends Entity { + private static final int EXPLOSION_TIME = 18; // 18 ticks == 0.3 second + + private final Level level; + private final int x, y, r; + + private int tick = 0; + + public ExplosionTileTicker(Level level, int x, int y, int r) { + super(0, 0); + this.level = level; + this.x = x; + this.y = y; + this.r = r; + level.setAreaTiles(x, y, r, Tiles.get("explode"), 0, ExplosionTileTicker::explodeBlacklistCheck); + } + + public static void addTicker(Level level, int x, int y, int r) { + level.add(new ExplosionTileTicker(level, x, y, r), x * 16 + 8, y * 16 + 8); + } + + private static boolean explodeBlacklistCheck(Tile tile, int x, int y) { + return !Tiles.explosionBlacklist.contains(tile.id); + } + + private static boolean explodedTileCheck(Tile tile, int x, int y) { + return tile instanceof ExplodedTile; + } + + @Override + public void render(Screen screen) {} + + @Override + public void tick() { + if (tick == EXPLOSION_TIME) { // Does the explosion + if (level.depth != 1) { + level.setAreaTiles(x, y, r, Tiles.get("hole"), 0, ExplosionTileTicker::explodedTileCheck); + } else { + level.setAreaTiles(x, y, r, Tiles.get("Infinite Fall"), 0, ExplosionTileTicker::explodedTileCheck); + } + + remove(); + } + + tick++; + } +} diff --git a/src/client/java/minicraft/entity/FireSpark.java b/src/client/java/minicraft/entity/FireSpark.java index 06dd9daf3..6a67764de 100644 --- a/src/client/java/minicraft/entity/FireSpark.java +++ b/src/client/java/minicraft/entity/FireSpark.java @@ -59,7 +59,8 @@ public void tick() { yy += ya; boolean stopped = true; //noinspection RedundantIfStatement - if (moveX(((int) xx) - x0)) stopped = false; // This kind of difference is handled due to errors by flooring. + if (moveX(((int) xx) - x0)) + stopped = false; // This kind of difference is handled due to errors by flooring. if (moveY(((int) yy) - y0)) stopped = false; if (stopped) { this.stopped = true; @@ -74,7 +75,9 @@ public void tick() { } } - /** Can this entity block you? Nope. */ + /** + * Can this entity block you? Nope. + */ public boolean isSolid() { return false; } diff --git a/src/client/java/minicraft/entity/ItemEntity.java b/src/client/java/minicraft/entity/ItemEntity.java index 6c7e09083..f12622bf1 100644 --- a/src/client/java/minicraft/entity/ItemEntity.java +++ b/src/client/java/minicraft/entity/ItemEntity.java @@ -70,7 +70,7 @@ public ItemEntity(Item item, int x, int y, double zz, int lifetime, int time, do * @return string representation of this entity */ public String getData() { - return String.join(":", (new String[] {item.getData(), zz + "", lifeTime+"", time + "", xa + "", ya + "", za + ""})); + return String.join(":", (new String[] { item.getData(), zz + "", lifeTime + "", time + "", xa + "", ya + "", za + "" })); } @Override @@ -128,18 +128,18 @@ public void render(Screen screen) { if (time / 6 % 2 == 0) return; } - screen.render(x-4, y - 4, item.sprite.getSprite(), 0, false, Color.get(0, 31)); // Item shadow + screen.render(x - 4, y - 4, item.sprite.getSprite(), 0, false, Color.get(0, 31)); // Item shadow screen.render(x - 4, y - 4 - (int) zz, item.sprite); // Item } @Override protected void touchedBy(Entity entity) { - if(!(entity instanceof Player)) return; // For the time being, we only care when a player touches an item. + if (!(entity instanceof Player)) return; // For the time being, we only care when a player touches an item. if (time > 30) { // Conditional prevents this from being collected immediately. if (!pickedUp) {// Don't register if we are online and a player touches it; the client will register that. pickedUp = true; - ((Player)entity).pickupItem(this); + ((Player) entity).pickupItem(this); pickedUp = isRemoved(); } } diff --git a/src/client/java/minicraft/entity/ItemHolder.java b/src/client/java/minicraft/entity/ItemHolder.java index 6e374cfb7..6d6b3191d 100644 --- a/src/client/java/minicraft/entity/ItemHolder.java +++ b/src/client/java/minicraft/entity/ItemHolder.java @@ -3,7 +3,7 @@ import minicraft.item.Inventory; public interface ItemHolder { - + Inventory getInventory(); - + } diff --git a/src/client/java/minicraft/entity/Spark.java b/src/client/java/minicraft/entity/Spark.java index 4ce29a876..049d45d88 100644 --- a/src/client/java/minicraft/entity/Spark.java +++ b/src/client/java/minicraft/entity/Spark.java @@ -50,12 +50,14 @@ public void tick() { y = (int) yy; Player player = getClosestPlayer(); - if (player.isWithin(0,this)) { - player.hurt(owner,1); + if (player != null && player.isWithin(0, this)) { + player.hurt(owner, 1); } } - /** Can this entity block you? Nope. */ + /** + * Can this entity block you? Nope. + */ public boolean isSolid() { return false; } @@ -72,7 +74,6 @@ public void render(Screen screen) { } - randmirror = random.nextInt(4); } diff --git a/src/client/java/minicraft/entity/Tickable.java b/src/client/java/minicraft/entity/Tickable.java index c39c8f4d8..1ab3e4e42 100644 --- a/src/client/java/minicraft/entity/Tickable.java +++ b/src/client/java/minicraft/entity/Tickable.java @@ -2,7 +2,9 @@ public interface Tickable { - /** Called every frame before Render() is called. Most game functionality in the game is based on this method.*/ + /** + * Called every frame before Render() is called. Most game functionality in the game is based on this method. + */ void tick(); } diff --git a/src/client/java/minicraft/entity/furniture/Bed.java b/src/client/java/minicraft/entity/furniture/Bed.java index 41f57fd99..f9515c00a 100644 --- a/src/client/java/minicraft/entity/furniture/Bed.java +++ b/src/client/java/minicraft/entity/furniture/Bed.java @@ -22,7 +22,9 @@ public Bed() { super("Bed", new LinkedSprite(SpriteType.Entity, "bed"), new LinkedSprite(SpriteType.Item, "bed"), 3, 2); } - /** Called when the player attempts to get in bed. */ + /** + * Called when the player attempts to get in bed. + */ public boolean use(Player player) { if (checkCanSleep(player)) { // If it is late enough in the day to sleep... @@ -44,7 +46,7 @@ public static boolean checkCanSleep(Player player) { if (!(Updater.tickCount >= Updater.sleepStartTime || Updater.tickCount < Updater.sleepEndTime && Updater.pastDay1)) { // It is too early to sleep; display how much time is remaining. - int sec = (int)Math.ceil((Updater.sleepStartTime - Updater.tickCount)*1.0 / Updater.normSpeed); // gets the seconds until sleeping is allowed. // normSpeed is in tiks/sec. + int sec = (int) Math.ceil((Updater.sleepStartTime - Updater.tickCount) * 1.0 / Updater.normSpeed); // gets the seconds until sleeping is allowed. // normSpeed is in tiks/sec. String note = Localization.getLocalized("minicraft.notification.cannot_sleep", sec / 60, sec % 60); Game.notifications.add(note); // Add the notification displaying the time remaining in minutes and seconds. @@ -54,9 +56,14 @@ public static boolean checkCanSleep(Player player) { return true; } - public static boolean sleeping() { return playersAwake == 0; } + public static boolean sleeping() { + return playersAwake == 0; + } + + public static boolean inBed(Player player) { + return sleepingPlayers.containsKey(player); + } - public static boolean inBed(Player player) { return sleepingPlayers.containsKey(player); } public static Level getBedLevel(Player player) { Bed bed = sleepingPlayers.get(player); if (bed == null) @@ -69,7 +76,9 @@ public static void removePlayer(Player player) { sleepingPlayers.remove(player); } - public static void removePlayers() { sleepingPlayers.clear(); } + public static void removePlayers() { + sleepingPlayers.clear(); + } // Client should not call this. public static void restorePlayer(Player player) { @@ -83,9 +92,10 @@ public static void restorePlayer(Player player) { playersAwake = 1; } } + // Client should not call this. public static void restorePlayers() { - for (Player p: sleepingPlayers.keySet()) { + for (Player p : sleepingPlayers.keySet()) { Bed bed = sleepingPlayers.get(p); bed.getLevel().add(p); } diff --git a/src/client/java/minicraft/entity/furniture/Chest.java b/src/client/java/minicraft/entity/furniture/Chest.java index b2f186cc6..bba338890 100644 --- a/src/client/java/minicraft/entity/furniture/Chest.java +++ b/src/client/java/minicraft/entity/furniture/Chest.java @@ -16,13 +16,19 @@ import java.io.IOException; import java.util.List; +import java.util.Random; public class Chest extends Furniture implements ItemHolder { private Inventory inventory; // Inventory of the chest - public Chest() { this("Chest"); } + public Chest() { + this("Chest"); + } + + public Chest(String name) { + this(name, new LinkedSprite(SpriteType.Item, "chest")); + } - public Chest(String name) { this(name, new LinkedSprite(SpriteType.Item, "chest")); } /** * Creates a chest with a custom name. * @param name Name of chest. @@ -33,21 +39,23 @@ public Chest(String name, LinkedSprite itemSprite) { inventory = new Inventory(); // Initialize the inventory. } - /** This is what occurs when the player uses the "Menu" command near this */ + /** + * This is what occurs when the player uses the "Menu" command near this + */ public boolean use(Player player) { Game.setDisplay(new ContainerDisplay(player, this)); return true; } - public void populateInvRandom(String lootTable, int depth) { + public void populateInvRandom(Random random, String lootTable, @SuppressWarnings("unused") int depth) { // depth is unused try { - String[] lines = Load.loadFile("/resources/data/chestloot/" + lootTable + ".txt").toArray(new String[]{}); + String[] lines = Load.loadFile("/resources/data/chestloot/" + lootTable + ".txt").toArray(new String[] {}); for (String line : lines) { //System.out.println(line); String[] data = line.split(","); if (!line.startsWith(":")) { - inventory.tryAdd(Integer.parseInt(data[0]), Items.get(data[1]), data.length < 3 ? 1 : Integer.parseInt(data[2])); + inventory.tryAdd(random, Integer.parseInt(data[0]), Items.get(data[1]), data.length < 3 ? 1 : Integer.parseInt(data[2])); } else if (inventory.invSize() == 0) { // Adds the "fallback" items to ensure there's some stuff String[] fallbacks = line.substring(1).split(":"); @@ -77,7 +85,7 @@ public Inventory getInventory() { public void die() { if (level != null) { List items = inventory.getItems(); - level.dropItem(x, y, items.toArray(new Item[items.size()])); + level.dropItem(x, y, items.toArray(new Item[0])); } super.die(); } diff --git a/src/client/java/minicraft/entity/furniture/Composter.java b/src/client/java/minicraft/entity/furniture/Composter.java new file mode 100644 index 000000000..079d90795 --- /dev/null +++ b/src/client/java/minicraft/entity/furniture/Composter.java @@ -0,0 +1,77 @@ +package minicraft.entity.furniture; + +import minicraft.entity.Direction; +import minicraft.entity.mob.Player; +import minicraft.gfx.SpriteLinker; +import minicraft.item.Item; +import minicraft.item.Items; +import minicraft.item.StackableItem; +import org.jetbrains.annotations.Nullable; + +public class Composter extends Furniture { + private static final SpriteLinker.LinkedSprite sprite = new SpriteLinker.LinkedSprite(SpriteLinker.SpriteType.Entity, "composter"); + private static final SpriteLinker.LinkedSprite spriteFilled = new SpriteLinker.LinkedSprite(SpriteLinker.SpriteType.Entity, "composter_filled"); + private static final SpriteLinker.LinkedSprite spriteFull = new SpriteLinker.LinkedSprite(SpriteLinker.SpriteType.Entity, "composter_full"); + private static final SpriteLinker.LinkedSprite itemSprite = new SpriteLinker.LinkedSprite(SpriteLinker.SpriteType.Item, "composter"); + + private static final int MAX_COMPOST = 7; + private int compost = 0; + + public Composter() { + super("Composter", sprite, itemSprite); + } + + @Override + public boolean interact(Player player, @Nullable Item item, Direction attackDir) { + if (compost == MAX_COMPOST) { + compost = 0; + StackableItem i = (StackableItem) Items.get("Fertilizer").copy(); + i.count = 1; + player.getLevel().dropItem(x, y, i); + refreshStatus(); + return true; + } + + if (item instanceof StackableItem) { + // 100% compost as they are heavy food + if (item.getName().equalsIgnoreCase("Baked Potato") || item.getName().equalsIgnoreCase("Bread")) { + compost++; + ((StackableItem) item).count--; + refreshStatus(); + return true; + + // 75% compost as they are crop food + } else if (item.getName().equalsIgnoreCase("Wheat") || item.getName().equalsIgnoreCase("Rose") || + item.getName().equalsIgnoreCase("Flower") || item.getName().equalsIgnoreCase("Apple") || + item.getName().equalsIgnoreCase("Potato") || item.getName().equalsIgnoreCase("Carrot")) { + if (random.nextInt(4) != 0) { // 75% + compost++; + ((StackableItem) item).count--; + refreshStatus(); + return true; + } + + // 66.7& compost as they are seeds + } else if (item.getName().equalsIgnoreCase("Acorn") || item.getName().equalsIgnoreCase("Cactus") || + item.getName().equalsIgnoreCase("Wheat Seeds") || item.getName().equalsIgnoreCase("Grass Seeds")) { + if (random.nextInt(3) != 0) { // 66.7% + compost++; + ((StackableItem) item).count--; + refreshStatus(); + return true; + } + } + } + + return false; + } + + private void refreshStatus() { + if (compost == 0) + super.sprite = sprite; + else if (compost < MAX_COMPOST) + super.sprite = spriteFilled; + else + super.sprite = spriteFull; + } +} diff --git a/src/client/java/minicraft/entity/furniture/Crafter.java b/src/client/java/minicraft/entity/furniture/Crafter.java index 27f40ee23..9326b41b7 100644 --- a/src/client/java/minicraft/entity/furniture/Crafter.java +++ b/src/client/java/minicraft/entity/furniture/Crafter.java @@ -14,12 +14,12 @@ public class Crafter extends Furniture { public enum Type { - Workbench (new LinkedSprite(SpriteType.Entity, "workbench"), new LinkedSprite(SpriteType.Item, "workbench"), 3, 2, Recipes.workbenchRecipes), - Oven (new LinkedSprite(SpriteType.Entity, "oven"), new LinkedSprite(SpriteType.Item, "oven"), 3, 2, Recipes.ovenRecipes), - Furnace (new LinkedSprite(SpriteType.Entity, "furnace"), new LinkedSprite(SpriteType.Item, "furnace"), 3, 2, Recipes.furnaceRecipes), - Anvil (new LinkedSprite(SpriteType.Entity, "anvil"), new LinkedSprite(SpriteType.Item, "anvil"), 3, 2, Recipes.anvilRecipes), - Enchanter (new LinkedSprite(SpriteType.Entity, "enchanter"), new LinkedSprite(SpriteType.Item, "enchanter"), 7, 2, Recipes.enchantRecipes), - Loom (new LinkedSprite(SpriteType.Entity, "loom"), new LinkedSprite(SpriteType.Item, "loom"), 7, 2, Recipes.loomRecipes); + Workbench(new LinkedSprite(SpriteType.Entity, "workbench"), new LinkedSprite(SpriteType.Item, "workbench"), 3, 2, Recipes.workbenchRecipes), + Oven(new LinkedSprite(SpriteType.Entity, "oven"), new LinkedSprite(SpriteType.Item, "oven"), 3, 2, Recipes.ovenRecipes), + Furnace(new LinkedSprite(SpriteType.Entity, "furnace"), new LinkedSprite(SpriteType.Item, "furnace"), 3, 2, Recipes.furnaceRecipes), + Anvil(new LinkedSprite(SpriteType.Entity, "anvil"), new LinkedSprite(SpriteType.Item, "anvil"), 3, 2, Recipes.anvilRecipes), + Enchanter(new LinkedSprite(SpriteType.Entity, "enchanter"), new LinkedSprite(SpriteType.Item, "enchanter"), 7, 2, Recipes.enchantRecipes), + Loom(new LinkedSprite(SpriteType.Entity, "loom"), new LinkedSprite(SpriteType.Item, "loom"), 7, 2, Recipes.loomRecipes); public ArrayList recipes; protected LinkedSprite sprite; @@ -35,6 +35,7 @@ public enum Type { Crafter.names.add(this.name()); } } + public static ArrayList names = new ArrayList<>(); public Crafter.Type type; @@ -59,5 +60,7 @@ public boolean use(Player player) { } @Override - public String toString() { return type.name()+getDataPrints(); } + public String toString() { + return type.name() + getDataPrints(); + } } diff --git a/src/client/java/minicraft/entity/furniture/DeathChest.java b/src/client/java/minicraft/entity/furniture/DeathChest.java index 3e7741dd4..a1fb4d030 100644 --- a/src/client/java/minicraft/entity/furniture/DeathChest.java +++ b/src/client/java/minicraft/entity/furniture/DeathChest.java @@ -22,7 +22,9 @@ public class DeathChest extends Chest { public int time; // Time passed (used for death chest despawn) private int redtick = 0; //This is used to determine the shade of red when the chest is about to expire. private boolean reverse; // What direction the red shade (redtick) is changing. - private Inventory inventory = new Inventory() {{ unlimited = true; }}; // Implement the inventory locally instead. + private Inventory inventory = new Inventory() {{ + unlimited = true; + }}; // Implement the inventory locally instead. /** * Creates a custom chest with the name Death Chest @@ -33,11 +35,11 @@ public DeathChest() { /// Set the expiration time based on the world difficulty. if (Settings.get("diff").equals("minicraft.settings.difficulty.easy")) { - time = 300*Updater.normSpeed; + time = 450 * Updater.normSpeed; } else if (Settings.get("diff").equals("minicraft.settings.difficulty.normal")) { - time = 120*Updater.normSpeed; + time = 300 * Updater.normSpeed; } else if (Settings.get("diff").equals("minicraft.settings.difficulty.hard")) { - time = 30*Updater.normSpeed; + time = 150 * Updater.normSpeed; } } @@ -86,23 +88,22 @@ public void tick() { public void render(Screen screen) { super.render(screen); String timeString = (time / Updater.normSpeed) + "S"; - Font.draw(timeString, screen, x - Font.textWidth(timeString)/2, y - Font.textHeight() - getBounds().getHeight()/2, Color.WHITE); + Font.draw(timeString, screen, x - Font.textWidth(timeString) / 2, y - Font.textHeight() - getBounds().getHeight() / 2, Color.WHITE); } - public boolean use(Player player) { return false; } // can't open it, just walk into it. + public boolean use(Player player) { + return false; + } // can't open it, just walk into it. - public void take(Player player) {} // can't grab a death chest. + public void take(Player player) { + } // can't grab a death chest. @Override public void touchedBy(Entity other) { - if(other instanceof Player) { - Inventory playerInv = ((Player)other).getInventory(); + if (other instanceof Player) { + Inventory playerInv = ((Player) other).getInventory(); for (Item i : inventory.getItems()) { - int total = 1; - if (i instanceof StackableItem) total = ((StackableItem)i).count; - - int returned = playerInv.add(i); - if (returned < total) { + if (playerInv.add(i) != null) { Game.notifications.add("Your inventory is full!"); return; } diff --git a/src/client/java/minicraft/entity/furniture/DungeonChest.java b/src/client/java/minicraft/entity/furniture/DungeonChest.java index a7aaf9ddf..faf63c717 100644 --- a/src/client/java/minicraft/entity/furniture/DungeonChest.java +++ b/src/client/java/minicraft/entity/furniture/DungeonChest.java @@ -9,7 +9,6 @@ import minicraft.gfx.Color; import minicraft.gfx.SpriteLinker.LinkedSprite; import minicraft.gfx.SpriteLinker.SpriteType; -import minicraft.item.Inventory; import minicraft.item.Item; import minicraft.item.Items; import minicraft.item.StackableItem; @@ -22,21 +21,21 @@ public class DungeonChest extends Chest { private static final LinkedSprite openSprite = new LinkedSprite(SpriteType.Entity, "dungeon_chest"); private static final LinkedSprite lockSprite = new LinkedSprite(SpriteType.Entity, "white_chest"); - public Random random = new Random(); private boolean isLocked; /** * Creates a custom chest with the name Dungeon Chest. - * @param populateInv Populate the inventory of the DungeonChest using the loot table system. + * @param random Populate the inventory of the DungeonChest using the loot table system with the given {@link Random} provider. + * {@code null} if populating the inventory is not intended. */ - public DungeonChest(boolean populateInv) { - this(populateInv, false); + public DungeonChest(@Nullable Random random) { + this(random, false); } - public DungeonChest(boolean populateInv, boolean unlocked) { + public DungeonChest(@Nullable Random random, boolean unlocked) { super("Dungeon Chest"); - if (populateInv) { - populateInv(); + if (random != null) { + populateInv(random); } setLocked(!unlocked); @@ -44,7 +43,7 @@ public DungeonChest(boolean populateInv, boolean unlocked) { @Override public @NotNull Furniture copy() { - return new DungeonChest(false, !this.isLocked); + return new DungeonChest(null, !this.isLocked); } public boolean use(Player player) { @@ -52,9 +51,9 @@ public boolean use(Player player) { boolean activeKey = player.activeItem != null && player.activeItem.equals(Items.get("Key")); boolean invKey = player.getInventory().count(Items.get("key")) > 0; - if(activeKey || invKey) { // If the player has a key... + if (activeKey || invKey) { // If the player has a key... if (activeKey) { // Remove activeItem - StackableItem key = (StackableItem)player.activeItem; + StackableItem key = (StackableItem) player.activeItem; key.count--; } else { // Remove from inv player.getInventory().removeItem(Items.get("key")); @@ -63,7 +62,7 @@ public boolean use(Player player) { isLocked = false; this.sprite = openSprite; // Set to the unlocked color - level.add(new SmashParticle(x * 16, y * 16)); + level.add(new SmashParticle(x << 4, y << 4)); level.add(new TextParticle(Localization.getLocalized("minicraft.text_particales.key_consumed"), x, y, Color.RED)); level.chestCount--; @@ -76,20 +75,18 @@ public boolean use(Player player) { } return false; // the chest is locked, and the player has no key. - } - else return super.use(player); // the chest was already unlocked. + } else return super.use(player); // the chest was already unlocked. } /** * Populate the inventory of the DungeonChest using the loot table system. */ - private void populateInv() { + public void populateInv(Random random) { // Clear inventory. - Inventory inv = getInventory(); - inv.clearInv(); + getInventory().clearInv(); // Populate inventory. - populateInvRandom("dungeonchest", 0); + populateInvRandom(random, "dungeonchest", 0); } public boolean isLocked() { @@ -108,13 +105,13 @@ public void setLocked(boolean locked) { */ @Override protected void touchedBy(Entity entity) { - if(!isLocked) // can only be pushed if unlocked. + if (!isLocked) // can only be pushed if unlocked. super.touchedBy(entity); } @Override public boolean interact(Player player, @Nullable Item item, Direction attackDir) { - if(!isLocked) + if (!isLocked) return super.interact(player, item, attackDir); return false; } diff --git a/src/client/java/minicraft/entity/furniture/Furniture.java b/src/client/java/minicraft/entity/furniture/Furniture.java index 148a8098a..2f0cc22a8 100644 --- a/src/client/java/minicraft/entity/furniture/Furniture.java +++ b/src/client/java/minicraft/entity/furniture/Furniture.java @@ -12,7 +12,9 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -/** Many furniture classes are very similar; they might not even need to be there at all... */ +/** + * Many furniture classes are very similar; they might not even need to be there at all... + */ public class Furniture extends Entity { @@ -67,11 +69,19 @@ public void tick() { else multiPushTime = 0; } - /** Draws the furniture on the screen. */ - public void render(Screen screen) { screen.render(x-8, y-8, sprite); } + /** + * Draws the furniture on the screen. + */ + public void render(Screen screen) { + screen.render(x - 8, y - 8, sprite); + } - /** Called when the player presses the MENU key in front of this. */ - public boolean use(Player player) { return false; } + /** + * Called when the player presses the MENU key in front of this. + */ + public boolean use(Player player) { + return false; + } @Override public boolean blocks(Entity e) { @@ -92,11 +102,11 @@ protected void touchedBy(Entity entity) { public boolean interact(Player player, @Nullable Item item, Direction attackDir) { if (item instanceof PowerGloveItem) { Sound.play("monsterhurt"); - remove(); - if (player.activeItem != null && !(player.activeItem instanceof PowerGloveItem)) - player.getLevel().dropItem(player.x, player.y, player.activeItem); // Put whatever item the player is holding into their inventory - player.activeItem = new FurnitureItem(this); // Make this the player's current item. - return true; + remove(); + if (player.activeItem != null && !(player.activeItem instanceof PowerGloveItem)) + player.getLevel().dropItem(player.x, player.y, player.activeItem); // Put whatever item the player is holding into their inventory + player.activeItem = new FurnitureItem(this); // Make this the player's current item. + return true; } return false; } @@ -113,5 +123,7 @@ public void tryPush(Player player) { } @Override - public boolean canWool() { return true; } + public boolean canWool() { + return true; + } } diff --git a/src/client/java/minicraft/entity/furniture/KnightStatue.java b/src/client/java/minicraft/entity/furniture/KnightStatue.java index 566b0ed13..e2a6f5219 100644 --- a/src/client/java/minicraft/entity/furniture/KnightStatue.java +++ b/src/client/java/minicraft/entity/furniture/KnightStatue.java @@ -43,13 +43,16 @@ public boolean interact(Player player, Item heldItem, Direction attackDir) { } @Override - public void tryPush(Player player) {} // Nothing happens. + public void tryPush(Player player) { + } // Nothing happens. @Override - public @NotNull Furniture copy(){ + public @NotNull Furniture copy() { return new KnightStatue(bossHealth); } - public int getBossHealth() { return bossHealth; } + public int getBossHealth() { + return bossHealth; + } } diff --git a/src/client/java/minicraft/entity/furniture/Lantern.java b/src/client/java/minicraft/entity/furniture/Lantern.java index 857108724..664a63e5a 100644 --- a/src/client/java/minicraft/entity/furniture/Lantern.java +++ b/src/client/java/minicraft/entity/furniture/Lantern.java @@ -6,9 +6,9 @@ public class Lantern extends Furniture { public enum Type { - NORM ("Lantern", 9, 0), - IRON ("Iron Lantern", 12, 2), - GOLD ("Gold Lantern", 15, 4); + NORM("Lantern", 9, 0), + IRON("Iron Lantern", 12, 2), + GOLD("Gold Lantern", 15, 4); protected int light, offset; protected String title; diff --git a/src/client/java/minicraft/entity/furniture/Spawner.java b/src/client/java/minicraft/entity/furniture/Spawner.java index 6a9eb9059..3a9f74479 100644 --- a/src/client/java/minicraft/entity/furniture/Spawner.java +++ b/src/client/java/minicraft/entity/furniture/Spawner.java @@ -38,7 +38,7 @@ public class Spawner extends Furniture { private final Random rnd = new Random(); - private static final int ACTIVE_RADIUS = 8*16; + private static final int ACTIVE_RADIUS = 8 << 4; private static final int minSpawnInterval = 200, maxSpawnInterval = 500; private static final int minMobSpawnChance = 10; // 1 in minMobSpawnChance chance of calling trySpawn every interval. @@ -55,7 +55,7 @@ private void initMob(MobAi m) { sprite.setColor(col = mob.col); if (m instanceof EnemyMob) { - lvl = ((EnemyMob)mob).lvl; + lvl = ((EnemyMob) mob).lvl; maxMobLevel = mob.getMaxLevel(); } else { lvl = 1; @@ -72,16 +72,16 @@ private void initMob(MobAi m) { * @param m Mob which will be spawned. */ public Spawner(MobAi m) { - super(getClassName(m.getClass()) + " Spawner", new LinkedSprite(SpriteType.Entity, "spawner"), m instanceof Cow ? new LinkedSprite(SpriteType.Item, "cow_spawner"): - m instanceof Pig ? new LinkedSprite(SpriteType.Item, "pig_spawner"): - m instanceof Sheep ? new LinkedSprite(SpriteType.Item, "sheep_spawner"): - m instanceof Slime ? new LinkedSprite(SpriteType.Item, "slime_spawner"): - m instanceof Zombie ? new LinkedSprite(SpriteType.Item, "zombie_spawner"): - m instanceof Creeper ? new LinkedSprite(SpriteType.Item, "creeper_spawner"): - m instanceof Skeleton ? new LinkedSprite(SpriteType.Item, "skeleton_spawner"): - m instanceof Snake ? new LinkedSprite(SpriteType.Item, "snake_spawner"): - m instanceof Knight ? new LinkedSprite(SpriteType.Item, "knight_spawner"): - new LinkedSprite(SpriteType.Item, "air_wizard_spawner"), 7, 2); + super(getClassName(m.getClass()) + " Spawner", new LinkedSprite(SpriteType.Entity, "spawner"), m instanceof Cow ? new LinkedSprite(SpriteType.Item, "cow_spawner") : + m instanceof Pig ? new LinkedSprite(SpriteType.Item, "pig_spawner") : + m instanceof Sheep ? new LinkedSprite(SpriteType.Item, "sheep_spawner") : + m instanceof Slime ? new LinkedSprite(SpriteType.Item, "slime_spawner") : + m instanceof Zombie ? new LinkedSprite(SpriteType.Item, "zombie_spawner") : + m instanceof Creeper ? new LinkedSprite(SpriteType.Item, "creeper_spawner") : + m instanceof Skeleton ? new LinkedSprite(SpriteType.Item, "skeleton_spawner") : + m instanceof Snake ? new LinkedSprite(SpriteType.Item, "snake_spawner") : + m instanceof Knight ? new LinkedSprite(SpriteType.Item, "knight_spawner") : + new LinkedSprite(SpriteType.Item, "air_wizard_spawner"), 7, 2); health = 100; initMob(m); resetSpawnInterval(); @@ -94,7 +94,7 @@ public Spawner(MobAi m) { */ private static String getClassName(Class c) { String fullName = c.getCanonicalName(); - return fullName.substring(fullName.lastIndexOf(".")+1); + return fullName.substring(fullName.lastIndexOf(".") + 1); } @Override @@ -152,11 +152,11 @@ private void trySpawn() { Point pos = new Point(x >> 4, y >> 4); Point[] areaPositions = level.getAreaTilePositions(pos.x, pos.y, 1); ArrayList validPositions = new ArrayList<>(); - for (Point p: areaPositions) - if (!( !level.getTile(p.x, p.y).mayPass(level, p.x, p.y, newmob) || mob instanceof EnemyMob && level.getTile(p.x, p.y).getLightRadius(level, p.x, p.y) > 0 )) + for (Point p : areaPositions) + if (!(!level.getTile(p.x, p.y).mayPass(level, p.x, p.y, newmob) || mob instanceof EnemyMob && level.getTile(p.x, p.y).getLightRadius(level, p.x, p.y) > 0)) validPositions.add(p); - if(validPositions.size() == 0) return; // Cannot spawn mob. + if (validPositions.size() == 0) return; // Cannot spawn mob. Point spawnPos = validPositions.get(random.nextInt(validPositions.size())); @@ -166,16 +166,16 @@ private void trySpawn() { level.add(newmob); Sound.play("monsterhurt"); for (int i = 0; i < 6; i++) { - int randX = rnd.nextInt(16); - int randY = rnd.nextInt(12); - level.add(new FireParticle(x - 8 + randX, y - 6 + randY)); + int randX = rnd.nextInt(16); + int randY = rnd.nextInt(12); + level.add(new FireParticle(x - 8 + randX, y - 6 + randY)); } } @Override public boolean interact(Player player, Item item, Direction attackDir) { if (item instanceof ToolItem) { - ToolItem tool = (ToolItem)item; + ToolItem tool = (ToolItem) item; Sound.play("monsterhurt"); @@ -222,7 +222,7 @@ public boolean use(Player player) { lvl++; if (lvl > maxMobLevel) lvl = 1; try { - EnemyMob newmob = (EnemyMob)mob.getClass().getConstructor(int.class).newInstance(lvl); + EnemyMob newmob = (EnemyMob) mob.getClass().getConstructor(int.class).newInstance(lvl); initMob(newmob); } catch (Exception ex) { ex.printStackTrace(); @@ -234,5 +234,7 @@ public boolean use(Player player) { } @Override - public @NotNull Furniture copy() { return new Spawner(mob); } + public @NotNull Furniture copy() { + return new Spawner(mob); + } } diff --git a/src/client/java/minicraft/entity/furniture/Tnt.java b/src/client/java/minicraft/entity/furniture/Tnt.java index 9b659d2c0..de02d17c7 100644 --- a/src/client/java/minicraft/entity/furniture/Tnt.java +++ b/src/client/java/minicraft/entity/furniture/Tnt.java @@ -3,6 +3,7 @@ import minicraft.core.io.Sound; import minicraft.entity.Direction; import minicraft.entity.Entity; +import minicraft.entity.ExplosionTileTicker; import minicraft.entity.mob.Mob; import minicraft.entity.mob.Player; import minicraft.gfx.Color; @@ -11,6 +12,7 @@ import minicraft.gfx.SpriteLinker.LinkedSprite; import minicraft.gfx.SpriteLinker.SpriteType; import minicraft.item.Item; +import minicraft.item.PowerGloveItem; import minicraft.level.Level; import minicraft.level.tile.Tile; import minicraft.level.tile.Tiles; @@ -22,17 +24,13 @@ import java.awt.event.ActionListener; import java.util.List; -public class Tnt extends Furniture implements ActionListener { +public class Tnt extends Furniture { private static int FUSE_TIME = 90; private static int BLAST_RADIUS = 32; private static int BLAST_DAMAGE = 75; private int ftik = 0; private boolean fuseLit = false; - private Timer explodeTimer; - private Level levelSave; - - private final String[] explosionBlacklist = new String[]{ "hard rock", "obsidian wall", "stairs up", "stairs down" }; /** * Creates a new tnt furniture. @@ -41,8 +39,6 @@ public Tnt() { super("Tnt", new LinkedSprite(SpriteType.Entity, "tnt"), new LinkedSprite(SpriteType.Item, "tnt"), 3, 2); fuseLit = false; ftik = 0; - - explodeTimer = new Timer(300, this); } @Override @@ -56,21 +52,21 @@ public void tick() { // Blow up List entitiesInRange = level.getEntitiesInRect(new Rectangle(x, y, BLAST_RADIUS * 2, BLAST_RADIUS * 2, Rectangle.CENTER_DIMS)); - for (Entity e: entitiesInRange) { - float dist = (float) Math.hypot(e.x - x, e.y - y); - int dmg = (int) (BLAST_DAMAGE * (1 - (dist / BLAST_RADIUS))) + 1; - if (e instanceof Mob && dmg > 0) - ((Mob)e).onExploded(this, dmg); - - // Ignite other bombs in range. - if (e instanceof Tnt) { - Tnt tnt = (Tnt) e; - if (!tnt.fuseLit) { - tnt.fuseLit = true; - Sound.play("fuse"); - tnt.ftik = FUSE_TIME * 2 / 3; - } - } + for (Entity e : entitiesInRange) { + float dist = (float) Math.hypot(e.x - x, e.y - y); + int dmg = (int) (BLAST_DAMAGE * (1 - (dist / BLAST_RADIUS))) + 1; + if (e instanceof Mob && dmg > 0) + ((Mob) e).onExploded(this, dmg); + + // Ignite other bombs in range. + if (e instanceof Tnt) { + Tnt tnt = (Tnt) e; + if (!tnt.fuseLit) { + tnt.fuseLit = true; + Sound.play("fuse"); + tnt.ftik = FUSE_TIME * 2 / 3; + } + } } int xt = x >> 4; @@ -87,11 +83,7 @@ public void tick() { AchievementsDisplay.setAchievement("minicraft.achievement.demolition", true); Sound.play("explode"); - - level.setAreaTiles(xt, yt, 1, Tiles.get("explode"), 0, explosionBlacklist); - - levelSave = level; - explodeTimer.start(); + ExplosionTileTicker.addTicker(level, xt, yt, 1); super.remove(); } } @@ -100,35 +92,24 @@ public void tick() { @Override public void render(Screen screen) { if (fuseLit) { - int colFctr = 100 * ((ftik%15)/5) + 200; + int colFctr = 100 * ((ftik % 15) / 5) + 200; col = Color.get(-1, colFctr, colFctr + 100, 555); } super.render(screen); } - /** - * Does the explosion. - */ - public void actionPerformed(ActionEvent e) { - explodeTimer.stop(); - int xt = x >> 4; - int yt = (y - 2) >> 4; - - if (levelSave.depth != 1) { - levelSave.setAreaTiles(xt, yt, 1, Tiles.get("hole"), 0, explosionBlacklist); - } else { - levelSave.setAreaTiles(xt, yt, 1, Tiles.get("Infinite Fall"), 0, explosionBlacklist); - } - - levelSave = null; - } - @Override public boolean interact(Player player, Item heldItem, Direction attackDir) { - if (!fuseLit) { - fuseLit = true; - Sound.play("fuse"); - return true; + if (heldItem instanceof PowerGloveItem) { + if (!fuseLit) { + return super.interact(player, heldItem, attackDir); + } + } else { + if (!fuseLit) { + fuseLit = true; + Sound.play("fuse"); + return true; + } } return false; diff --git a/src/client/java/minicraft/entity/mob/AirWizard.java b/src/client/java/minicraft/entity/mob/AirWizard.java index 42920abe7..8f2c2705e 100644 --- a/src/client/java/minicraft/entity/mob/AirWizard.java +++ b/src/client/java/minicraft/entity/mob/AirWizard.java @@ -22,7 +22,7 @@ public class AirWizard extends EnemyMob { }; public static boolean beaten = false; - public static boolean active = true; + public static boolean active = false; public static AirWizard entity = null; private int attackDelay = 0; @@ -32,7 +32,9 @@ public class AirWizard extends EnemyMob { /** * This is used by the spawner to spawn air wizards. {@code lvl} is unused. */ - public AirWizard(int lvl) { this(); } + public AirWizard(int lvl) { + this(); + } /** * Constructor for the AirWizard. @@ -85,7 +87,7 @@ public void tick() { if (player != null && randomWalkTime == 0) { // If there is a player around, and the walking is not random int xd = player.x - x; // The horizontal distance between the player and the air wizard. int yd = player.y - y; // The vertical distance between the player and the air wizard. - if (xd * xd + yd * yd < 16*16 * 2*2) { + if (xd * xd + yd * yd < 16 * 16 * 2 * 2) { /// Move away from the player if less than 2 blocks away this.xmov = 0; // Accelerations @@ -96,12 +98,12 @@ public void tick() { if (xd > 0) this.xmov = -1; if (yd < 0) this.ymov = +1; if (yd > 0) this.ymov = -1; - } else if (xd * xd + yd * yd > 16*16 * 15*15) {// 15 squares away + } else if (xd * xd + yd * yd > 16 * 16 * 15 * 15) {// 15 squares away /// Drags the airwizard to the player, maintaining relative position. double hypot = Math.sqrt(xd * xd + yd * yd); - int newxd = (int)(xd * Math.sqrt(16*16 * 15*15) / hypot); - int newyd = (int)(yd * Math.sqrt(16*16 * 15*15) / hypot); + int newxd = (int) (xd * Math.sqrt(16 * 16 * 15 * 15) / hypot); + int newyd = (int) (yd * Math.sqrt(16 * 16 * 15 * 15) / hypot); x = player.x - newxd; y = player.y - newyd; } @@ -136,30 +138,31 @@ public void render(Screen screen) { if (percent < 16) { textcol = Color.get(1, 204, 0, 0); textcol2 = Color.get(1, 51, 0, 0); - } - else if (percent < 51) { + } else if (percent < 51) { textcol = Color.get(1, 204, 204, 9); textcol2 = Color.get(1, 51, 51, 0); } int textwidth = Font.textWidth(h); - Font.draw(h, screen, (x - textwidth/2) + 1, y - 17, textcol2); - Font.draw(h, screen, (x - textwidth/2), y - 18, textcol); + Font.draw(h, screen, (x - textwidth / 2) + 1, y - 17, textcol2); + Font.draw(h, screen, (x - textwidth / 2), y - 18, textcol); } @Override protected void touchedBy(Entity entity) { if (entity instanceof Player) { // If the entity is the Player, then deal them 1 damage points. - ((Player)entity).hurt(this, 1); + ((Player) entity).hurt(this, 1); } } - /** What happens when the air wizard dies */ + /** + * What happens when the air wizard dies + */ @Override public void die() { Player[] players = level.getPlayers(); if (players.length > 0) { // If the player is still here - for (Player p: players) { + for (Player p : players) { p.addScore(100000); // Give the player 100K points. dropItem(5, 10, Items.get("cloud ore")); // Drop cloud ore to guarantee respawn. } @@ -187,5 +190,7 @@ public void die() { } @Override - public int getMaxLevel() { return 2; } + public int getMaxLevel() { + return 2; + } } diff --git a/src/client/java/minicraft/entity/mob/Cow.java b/src/client/java/minicraft/entity/mob/Cow.java index f7acb4078..4275db4d7 100644 --- a/src/client/java/minicraft/entity/mob/Cow.java +++ b/src/client/java/minicraft/entity/mob/Cow.java @@ -19,9 +19,18 @@ public Cow() { public void die() { int min = 0, max = 0; - if (Settings.get("diff").equals("minicraft.settings.difficulty.easy")) {min = 1; max = 3;} - if (Settings.get("diff").equals("minicraft.settings.difficulty.normal")) {min = 1; max = 2;} - if (Settings.get("diff").equals("minicraft.settings.difficulty.hard")) {min = 0; max = 1;} + if (Settings.get("diff").equals("minicraft.settings.difficulty.easy")) { + min = 1; + max = 3; + } + if (Settings.get("diff").equals("minicraft.settings.difficulty.normal")) { + min = 1; + max = 2; + } + if (Settings.get("diff").equals("minicraft.settings.difficulty.hard")) { + min = 0; + max = 1; + } dropItem(min, max, Items.get("leather"), Items.get("raw beef")); @@ -31,12 +40,9 @@ public void die() { @Override public void tick() { super.tick(); - if (random.nextInt(1000) == 0) { // Grazing without any benefits. - Tile tile = level.getTile(x >> 4, y >> 4); - // If tall grasses are present, these are consumed and then turn into grass tiles. - if (tile instanceof GrassTile) { - level.setTile(x >> 4, y >> 4, Tiles.get("dirt")); - } + Tile tile = level.getTile(x >> 4, y >> 4); + if (tile instanceof GrassTile && random.nextInt(1000) == 0) { // Grazing without any benefits. + level.setTile(x >> 4, y >> 4, Tiles.get("dirt")); } } } diff --git a/src/client/java/minicraft/entity/mob/Creeper.java b/src/client/java/minicraft/entity/mob/Creeper.java index acaa6810d..94860cc37 100644 --- a/src/client/java/minicraft/entity/mob/Creeper.java +++ b/src/client/java/minicraft/entity/mob/Creeper.java @@ -5,6 +5,7 @@ import minicraft.core.io.Sound; import minicraft.entity.Direction; import minicraft.entity.Entity; +import minicraft.entity.ExplosionTileTicker; import minicraft.entity.furniture.Spawner; import minicraft.gfx.Point; import minicraft.gfx.Screen; @@ -17,10 +18,10 @@ public class Creeper extends EnemyMob { private static LinkedSprite[][][] sprites = new LinkedSprite[][][] { - new LinkedSprite[][] {Mob.compileSpriteList(0, 0, 2, 2, 0, 2, "creeper")}, - new LinkedSprite[][] {Mob.compileSpriteList(0, 2, 2, 2, 0, 2, "creeper")}, - new LinkedSprite[][] {Mob.compileSpriteList(0, 4, 2, 2, 0, 2, "creeper")}, - new LinkedSprite[][] {Mob.compileSpriteList(0, 6, 2, 2, 0, 2, "creeper")} + new LinkedSprite[][] { Mob.compileSpriteList(0, 0, 2, 2, 0, 2, "creeper") }, + new LinkedSprite[][] { Mob.compileSpriteList(0, 2, 2, 2, 0, 2, "creeper") }, + new LinkedSprite[][] { Mob.compileSpriteList(0, 4, 2, 2, 0, 2, "creeper") }, + new LinkedSprite[][] { Mob.compileSpriteList(0, 6, 2, 2, 0, 2, "creeper") } }; private static final int MAX_FUSE_TIME = 60; @@ -30,8 +31,6 @@ public class Creeper extends EnemyMob { private int fuseTime = 0; private boolean fuseLit = false; - private final String[] explosionBlacklist = new String[] { "hard rock", "obsidian wall", "raw obsidian"}; - public Creeper(int lvl) { super(lvl, sprites, 10, 50); } @@ -48,7 +47,8 @@ public boolean move(int xd, int yd) { public void tick() { super.tick(); - if (Game.isMode("minicraft.settings.mode.creative")) return; // Creeper should not explode if player is in creative mode + if (Game.isMode("minicraft.settings.mode.creative")) + return; // Creeper should not explode if player is in creative mode if (fuseTime > 0) { fuseTime--; // Fuse getting shorter... @@ -119,12 +119,7 @@ public void tick() { } } if (!hasSpawner) { - if (level.depth != 1) { - level.setAreaTiles(tilePosition.x, tilePosition.y, 0, Tiles.get("hole"), 0, explosionBlacklist); - } else { - level.setAreaTiles(tilePosition.x, tilePosition.y, 0, Tiles.get("Infinite Fall"), 0, explosionBlacklist); - } - + ExplosionTileTicker.addTicker(level, tilePosition.x, tilePosition.y, 0); } } diff --git a/src/client/java/minicraft/entity/mob/EnemyMob.java b/src/client/java/minicraft/entity/mob/EnemyMob.java index 9a950b533..0788005ec 100644 --- a/src/client/java/minicraft/entity/mob/EnemyMob.java +++ b/src/client/java/minicraft/entity/mob/EnemyMob.java @@ -22,8 +22,8 @@ public void handleDespawn() { if (level.depth == 0 && Updater.tickCount >= Updater.dayLength / 4 && Updater.tickCount <= Updater.dayLength / 2) if (isWithinLight()) // If it is now morning and on the surface, the mob despawns when it is within light. super.handleDespawn(); - else if (!isWithinLight()) // Otherwise, it despawns when it is not within light. - super.handleDespawn(); + else if (!isWithinLight()) // Otherwise, it despawns when it is not within light. + super.handleDespawn(); } /** @@ -40,7 +40,7 @@ else if (!isWithinLight()) // Otherwise, it despawns when it is not within light * @param rwChance The chance of this mob will walk in a random direction (random walk chance) */ public EnemyMob(int lvl, LinkedSprite[][][] lvlSprites, int health, boolean isFactor, int detectDist, int lifetime, int rwTime, int rwChance) { - super(lvlSprites[0], isFactor ? (lvl == 0 ? 1 : lvl * lvl) * health * ((Double)(Math.pow(2, Settings.getIdx("diff")))).intValue() : health, lifetime, rwTime, rwChance); + super(lvlSprites[0], isFactor ? (lvl == 0 ? 1 : lvl * lvl) * health * ((Double) (Math.pow(2, Settings.getIdx("diff")))).intValue() : health, lifetime, rwTime, rwChance); this.lvl = lvl == 0 ? 1 : lvl; this.lvlSprites = java.util.Arrays.copyOf(lvlSprites, lvlSprites.length); this.detectDist = detectDist; @@ -66,7 +66,6 @@ public EnemyMob(int lvl, LinkedSprite[][][] lvlSprites, int health, boolean isFa * isFactor=true, * rwTime=60, * rwChance=200. - * * @param lvl The mob's level. * @param lvlSprites The mob's sprites (ordered by level, then direction, then animation frame). * @param health How much health the mob has. @@ -95,7 +94,7 @@ public void tick() { if (yd > sig0) this.ymov = +1; } else { // If the enemy was following the player, but has now lost it, it stops moving. - // *That would be nice, but I'll just make it move randomly instead. + // *That would be nice, but I'll just make it move randomly instead. randomizeWalkDir(false); } } @@ -111,8 +110,8 @@ public void render(Screen screen) { protected void touchedBy(Entity entity) { // If an entity (like the player) touches the enemy mob super.touchedBy(entity); // Hurts the player, damage is based on lvl. - if(entity instanceof Player) { - ((Player)entity).hurt(this, lvl * (Settings.get("diff").equals("minicraft.settings.difficulty.hard") ? 2 : 1)); + if (entity instanceof Player) { + ((Player) entity).hurt(this, lvl * (Settings.get("diff").equals("minicraft.settings.difficulty.hard") ? 2 : 1)); } } @@ -130,7 +129,7 @@ public void die() { public static boolean checkStartPos(Level level, int x, int y) { // Find a place to spawn the mob int r = (level.depth == -4 ? (Game.isMode("minicraft.settings.mode.score") ? 22 : 15) : 13); - if(!MobAi.checkStartPos(level, x, y, 60, r)) + if (!MobAi.checkStartPos(level, x, y, 60, r)) return false; x = x >> 4; diff --git a/src/client/java/minicraft/entity/mob/Knight.java b/src/client/java/minicraft/entity/mob/Knight.java index 91b74df0f..d42a2089e 100644 --- a/src/client/java/minicraft/entity/mob/Knight.java +++ b/src/client/java/minicraft/entity/mob/Knight.java @@ -27,7 +27,7 @@ public void die() { dropItem(0, 2, Items.get("shard") ); - if(random.nextInt(24/lvl/(Settings.getIdx("diff")+1)) == 0) + if (random.nextInt(24 / lvl / (Settings.getIdx("diff") + 1)) == 0) dropItem(1, 1, Items.get("key")); super.die(); diff --git a/src/client/java/minicraft/entity/mob/Mob.java b/src/client/java/minicraft/entity/mob/Mob.java index f0bc64aeb..bd2cd181e 100644 --- a/src/client/java/minicraft/entity/mob/Mob.java +++ b/src/client/java/minicraft/entity/mob/Mob.java @@ -58,7 +58,7 @@ public void tick() { if (canBurn()) { if (this.burningDuration > 0) { - if (level.getTile(x / 16, y / 16) == Tiles.get("water")) this.burningDuration = 0; + if (level.getTile(x >> 4, y >> 4) == Tiles.get("water")) this.burningDuration = 0; if (this.burningDuration % 10 == 0) level.add(new BurnParticle(x - 8 + (random.nextInt(8) - 4), y - 8 + (random.nextInt(8) - 4))); this.burningDuration--; @@ -79,19 +79,22 @@ public void tick() { /// The code below checks the direction of the knockback, moves the Mob accordingly, and brings the knockback closer to 0. int xd = 0, yd = 0; if (xKnockback != 0) { - xd = (int)Math.ceil(xKnockback/2); - xKnockback -= xKnockback/Math.abs(xKnockback); + xd = (int) Math.ceil(xKnockback / 2); + xKnockback -= xKnockback / Math.abs(xKnockback); } if (yKnockback != 0) { - yd = (int)Math.ceil(yKnockback/2); - yKnockback -= yKnockback/Math.abs(yKnockback); + yd = (int) Math.ceil(yKnockback / 2); + yKnockback -= yKnockback / Math.abs(yKnockback); } move(xd, yd, false); } @Override - public boolean move(int xd, int yd) { return move(xd, yd, true); } // Move the mob, overrides from Entity + public boolean move(int xd, int yd) { + return move(xd, yd, true); + } // Move the mob, overrides from Entity + private boolean move(int xd, int yd, boolean changeDir) { // Knockback shouldn't change mob direction if (level == null) return false; // Stopped b/c there's no level to move in! @@ -117,9 +120,9 @@ private boolean move(int xd, int yd, boolean changeDir) { // Knockback shouldn't // This part makes it so you can't move in a direction that you are currently being knocked back from. if (xKnockback != 0) - xd = Math.copySign(xd, xKnockback)*-1 != xd ? xd : 0; // If xKnockback and xd have different signs, do nothing, otherwise, set xd to 0. + xd = Math.copySign(xd, xKnockback) * -1 != xd ? xd : 0; // If xKnockback and xd have different signs, do nothing, otherwise, set xd to 0. if (yKnockback != 0) - yd = Math.copySign(yd, yKnockback)*-1 != yd ? yd : 0; // Same as above. + yd = Math.copySign(yd, yKnockback) * -1 != yd ? yd : 0; // Same as above. moved = super.move(xd, yd); // Call the move method from Entity } @@ -127,22 +130,30 @@ private boolean move(int xd, int yd, boolean changeDir) { // Knockback shouldn't return moved; } - /** The mob immediately despawns if the distance of the closest player is greater than the return value of this. */ + /** + * The mob immediately despawns if the distance of the closest player is greater than the return value of this. + */ protected int getDespawnDistance() { - return 80; + return 1280; } - /** The mob randomly despawns if the distance of the closest player is greater than the return value of this. */ + /** + * The mob randomly despawns if the distance of the closest player is greater than the return value of this. + */ protected int getNoDespawnDistance() { - return 40; + return 640; } - /** @see #handleDespawn() */ + /** + * @see #handleDespawn() + */ protected boolean removeWhenFarAway(@SuppressWarnings("unused") double distance) { return true; } - /** This is an easy way to make a list of sprites that are all part of the same "Sprite", so they have similar parameters, but they're just at different locations on the spreadsheet. */ + /** + * This is an easy way to make a list of sprites that are all part of the same "Sprite", so they have similar parameters, but they're just at different locations on the spreadsheet. + */ public static LinkedSprite[] compileSpriteList(int sheetX, int sheetY, int width, int height, int mirror, int number, String key) { LinkedSprite[] sprites = new LinkedSprite[number]; for (int i = 0; i < sprites.length; i++) @@ -194,7 +205,7 @@ private boolean isWooling() { // supposed to walk at half speed on wool */ public boolean isLight() { if (level == null) return false; - return level.isLight(x>>4, y>>4); + return level.isLight(x >> 4, y >> 4); } /** @@ -216,7 +227,7 @@ public boolean isSwimming() { */ public void hurt(Tile tile, int x, int y, int damage) { // Hurt the mob, when the source of damage is a tile Direction attackDir = Direction.getDirection(dir.getDir() ^ 1); // Set attackDir to our own direction, inverted. XORing it with 1 flips the rightmost bit in the variable, this effectively adds one when even, and subtracts one when odd. - if (!(tile == Tiles.get("lava") && this instanceof Player && ((Player)this).potioneffects.containsKey(PotionType.Lava))) + if (!(tile == Tiles.get("lava") && this instanceof Player && ((Player) this).potioneffects.containsKey(PotionType.Lava))) doHurt(damage, tile.mayPass(level, x, y, this) ? Direction.NONE : attackDir); // Call the method that actually performs damage, and set it to no particular direction } @@ -225,7 +236,9 @@ public void hurt(Tile tile, int x, int y, int damage) { // Hurt the mob, when th * @param mob The mob that hurt this mob * @param damage The amount of damage to hurt the mob with */ - public void hurt(Mob mob, int damage) { hurt(mob, damage, getAttackDir(mob, this)); } + public void hurt(Mob mob, int damage) { + hurt(mob, damage, getAttackDir(mob, this)); + } /** * Do damage to the mob this method is called on. @@ -234,12 +247,12 @@ public void hurt(Tile tile, int x, int y, int damage) { // Hurt the mob, when th * @param attackDir The direction this mob was attacked from */ public void hurt(Mob mob, int damage, Direction attackDir) { // Hurt the mob, when the source is another mob - if (mob instanceof Player && Game.isMode("minicraft.settings.mode.creative") && mob != this) doHurt(health, attackDir); // Kill the mob instantly + if (mob instanceof Player && Game.isMode("minicraft.settings.mode.creative") && mob != this) + doHurt(health, attackDir); // Kill the mob instantly else doHurt(damage, attackDir); // Call the method that actually performs damage, and use our provided attackDir } /** - * * @param sec duration in seconds */ public void burn(int sec) { @@ -251,7 +264,9 @@ public void burn(int sec) { * @param tnt The TNT exploding. * @param dmg The amount of damage the explosion does. */ - public void onExploded(Tnt tnt, int dmg) { doHurt(dmg, getAttackDir(tnt, this)); } + public void onExploded(Tnt tnt, int dmg) { + doHurt(dmg, getAttackDir(tnt, this)); + } /** * Hurt the mob, based on only damage and a direction @@ -260,13 +275,14 @@ public void burn(int sec) { * @param attackDir The direction this mob was attacked from */ protected void doHurt(int damage, Direction attackDir) { - if (isRemoved() || hurtTime > 0) return; // If the mob has been hurt recently and hasn't cooled down, don't continue + if (isRemoved() || hurtTime > 0) + return; // If the mob has been hurt recently and hasn't cooled down, don't continue health -= damage; // Actually change the health // Add the knockback in the correct direction - xKnockback = attackDir.getX()*6; - yKnockback = attackDir.getY()*6; + xKnockback = attackDir.getX() * 6; + yKnockback = attackDir.getY() * 6; hurtTime = 10; // Set a delay before we can be hurt again } @@ -279,7 +295,8 @@ public void heal(int heal) { // Restore health on the mob level.add(new TextParticle("" + heal, x, y, Color.GREEN)); // Add a text particle in our level at our position, that is green and displays the amount healed health += heal; // Actually add the amount to heal to our current health - if (health > (Player.baseHealth + Player.extraHealth)) health = (Player.baseHealth + Player.extraHealth); // If our health has exceeded our maximum, lower it back down to said maximum + if (health > (Player.baseHealth + Player.extraHealth)) + health = (Player.baseHealth + Player.extraHealth); // If our health has exceeded our maximum, lower it back down to said maximum } protected static Direction getAttackDir(Entity attacker, Entity hurt) { diff --git a/src/client/java/minicraft/entity/mob/MobAi.java b/src/client/java/minicraft/entity/mob/MobAi.java index 8195e9171..00c2df1eb 100644 --- a/src/client/java/minicraft/entity/mob/MobAi.java +++ b/src/client/java/minicraft/entity/mob/MobAi.java @@ -6,14 +6,14 @@ import minicraft.entity.furniture.Lantern; import minicraft.entity.particle.TextParticle; import minicraft.gfx.Color; +import minicraft.gfx.Point; import minicraft.gfx.Rectangle; import minicraft.gfx.Screen; import minicraft.gfx.SpriteLinker.LinkedSprite; import minicraft.item.Item; import minicraft.item.PotionType; import minicraft.level.Level; - -import java.util.Arrays; +import minicraft.level.tile.Tile; public abstract class MobAi extends Mob { @@ -65,8 +65,17 @@ public void handleDespawn() { * @return {@code true} if the mob is within any light. */ protected boolean isWithinLight() { - return Arrays.stream(level.getEntityArray()).anyMatch(e -> e instanceof Lantern && isWithin(e.getLightRadius(), e)) - || !level.getMatchingTiles((tile, x, y) -> Math.hypot(Math.abs(this.x - x), Math.abs(this.y - y)) <= tile.getLightRadius(level, x, y)).isEmpty(); + for (Entity e : level.getEntitiesInRect(e -> e instanceof Lantern, new Rectangle(x, y, 8, 8, Rectangle.CENTER_DIMS))) + if (e instanceof Lantern && isWithin(e.getLightRadius(), e)) + return true; + for (Point p : level.getAreaTilePositions(x, y, 5)) { + Tile t = level.getTile(p.x, p.y); + int xx = Math.abs(x - p.x), yy = Math.abs(y - p.y), l = t.getLightRadius(level, p.x, p.y); + if (xx * xx + yy * yy <= l * l) + return true; + } + + return false; } /** @@ -84,7 +93,7 @@ public void tick() { if (lifetime > 0) { age++; if (age > lifetime) { - boolean playerClose = getLevel().entityNearPlayer((Entity) this); + boolean playerClose = getLevel().entityNearPlayer(this); if (!playerClose) { remove(); @@ -95,7 +104,7 @@ public void tick() { if (getLevel() != null) { boolean foundPlayer = false; - for (Player p: level.getPlayers()) { + for (Player p : level.getPlayers()) { if (p.isWithin(8, this) && p.potioneffects.containsKey(PotionType.Time)) { foundPlayer = true; break; @@ -140,7 +149,8 @@ public boolean move(int xd, int yd) { @Override public void doHurt(int damage, Direction attackDir) { - if (isRemoved() || hurtTime > 0) return; // If the mob has been hurt recently and hasn't cooled down, don't continue + if (isRemoved() || hurtTime > 0) + return; // If the mob has been hurt recently and hasn't cooled down, don't continue Player player = getClosestPlayer(); if (player != null) { // If there is a player in the level @@ -165,7 +175,7 @@ public boolean canWool() { /** * Sets the mob to walk in a random direction for a given amount of time. * @param byChance true if the mob should always get a new direction to walk, false if - * there should be a chance that the mob moves. + * there should be a chance that the mob moves. */ public void randomizeWalkDir(boolean byChance) { // Boolean specifies if this method, from where it's called, is called every tick, or after a random chance. if (!byChance && random.nextInt(randomWalkChance) != 0) return; @@ -184,9 +194,9 @@ public void randomizeWalkDir(boolean byChance) { // Boolean specifies if this me * @param items Which items should be added. */ protected void dropItem(int mincount, int maxcount, Item... items) { - int count = random.nextInt(maxcount-mincount+1) + mincount; + int count = random.nextInt(maxcount - mincount + 1) + mincount; for (int i = 0; i < count; i++) - level.dropItem(x, y, items); + level.dropItem(x, y, items); } /** @@ -196,7 +206,7 @@ protected void dropItem(int mincount, int maxcount, Item... items) { * @param y Y map coordinate of spawn. * @param playerDist Max distance from the player the mob can be spawned in. * @param soloRadius How far out can there not already be any entities. - * This is multiplied by the monster density of the level + * This is multiplied by the monster density of the level * @return true if the mob can spawn, false if not. */ protected static boolean checkStartPos(Level level, int x, int y, int playerDist, int soloRadius) { @@ -222,9 +232,12 @@ protected static boolean checkStartPos(Level level, int x, int y, int playerDist */ public abstract int getMaxLevel(); - protected void die(int points) { die(points, 0); } + protected void die(int points) { + die(points, 0); + } + protected void die(int points, int multAdd) { - for (Player p: level.getPlayers()) { + for (Player p : level.getPlayers()) { p.addScore(points); // Add score for mob death if (multAdd != 0) p.addMultiplier(multAdd); diff --git a/src/client/java/minicraft/entity/mob/ObsidianKnight.java b/src/client/java/minicraft/entity/mob/ObsidianKnight.java index 84f833338..5d874e1a5 100644 --- a/src/client/java/minicraft/entity/mob/ObsidianKnight.java +++ b/src/client/java/minicraft/entity/mob/ObsidianKnight.java @@ -16,6 +16,7 @@ import minicraft.gfx.SpriteLinker; import minicraft.item.Items; import minicraft.screen.AchievementsDisplay; +import org.jetbrains.annotations.Range; public class ObsidianKnight extends EnemyMob { private static final SpriteLinker.LinkedSprite[][][] armored = new SpriteLinker.LinkedSprite[][][] { @@ -36,11 +37,14 @@ public class ObsidianKnight extends EnemyMob { public static boolean beaten = false; // If the boss was beaten public static boolean active = false; // If the boss is active - private static int phase = 0; // The phase of the boss. {0, 1} - private static int attackPhaseCooldown = 0; // Cooldown between attacks + @Range(from = 0, to = 1) + private int phase = 0; // The phase of the boss. {0, 1} + private int attackPhaseCooldown = 0; // Cooldown between attacks private AttackPhase attackPhase = AttackPhase.Attacking; - private enum AttackPhase { Attacking, Dashing, Walking; } // Using fire sparks in attacking. + + private enum AttackPhase {Attacking, Dashing, Walking;} // Using fire sparks in attacking. + private static final AttackPhase[] ATTACK_PHASES = AttackPhase.values(); private int dashTime = 0; @@ -70,19 +74,19 @@ public ObsidianKnight(int health) { @Override public void tick() { super.tick(); - if (getClosestPlayer().isRemoved()) { + Player player = getClosestPlayer(); + if (player == null || player.isRemoved()) { active = false; KnightStatue ks = new KnightStatue(health); level.add(ks, x, y, false); this.remove(); + return; } - //Achieve phase2 - if (health <= 2500) { + // Achieve phase 2 + if (health <= 2500 && phase == 0) { // Assume that phase would not turn back to phase 1 phase = 1; - } - if (phase == 1) { - lvlSprites = broken; + lvlSprites = broken; // Refreshing phased sprites } if (Game.isMode("minicraft.settings.mode.creative")) return; // Should not attack if player is in creative @@ -99,7 +103,6 @@ public void tick() { } if (attackPhase == AttackPhase.Attacking) { - Player player = getClosestPlayer(); if (attackDelay > 0) { xmov = ymov = 0; int dir = (attackDelay - 35) / 4 % 4; // The direction of attack. @@ -134,7 +137,7 @@ public void tick() { else if (atan2 < -67.5) attackDir = -90; else if (atan2 < -22.5) attackDir = -45; else attackDir = 0; - double speed = 1 + attackLevel * 0.2 + attackTime / 10 * 0.01; // speed is dependent on the attackType. (higher attackType, faster speeds) + double speed = 1 + attackLevel * 0.2 + attackTime / 10D * 0.01; // speed is dependent on the attackType. (higher attackType, faster speeds) // The range of attack is 90 degrees. With little random factor. int phi = attackDir - 36 + (attackTime % 5) * 18 + random.nextInt(7) - 3; level.add(new FireSpark(this, Math.cos(Math.toRadians(phi)) * speed, Math.sin(Math.toRadians(phi)) * speed)); // Adds a spark entity with the cosine and sine of dir times speed. @@ -217,33 +220,34 @@ public void render(Screen screen) { if (percent < 16) { textcol = Color.get(1, 204, 0, 0); textcol2 = Color.get(1, 51, 0, 0); - } - else if (percent < 51) { + } else if (percent < 51) { textcol = Color.get(1, 204, 204, 9); textcol2 = Color.get(1, 51, 51, 0); } int textwidth = Font.textWidth(h); - Font.draw(h, screen, (x - textwidth/2) + 1, y - 17, textcol2); - Font.draw(h, screen, (x - textwidth/2), y - 18, textcol); + Font.draw(h, screen, (x - textwidth / 2) + 1, y - 17, textcol2); + Font.draw(h, screen, (x - textwidth / 2), y - 18, textcol); } @Override protected void touchedBy(Entity entity) { if (entity instanceof Player) { // If the entity is the Player, then deal them 2 damage points. - ((Player)entity).hurt(this, 2); + ((Player) entity).hurt(this, 2); if (attackPhase == AttackPhase.Dashing) { dashTime = Math.max(dashTime - 10, 0); } } } - /** What happens when the obsidian knight dies */ + /** + * What happens when the obsidian knight dies + */ @Override public void die() { Player[] players = level.getPlayers(); if (players.length > 0) { // If the player is still here - for (Player p: players) { + for (Player p : players) { p.addScore(300000); // Give the player 300K points. dropItem(15, 25, Items.get("shard")); dropItem(1, 1, Items.get("Obsidian Heart")); // Drop it's precious item. diff --git a/src/client/java/minicraft/entity/mob/PassiveMob.java b/src/client/java/minicraft/entity/mob/PassiveMob.java index 0a563787d..e6ec7f6cb 100644 --- a/src/client/java/minicraft/entity/mob/PassiveMob.java +++ b/src/client/java/minicraft/entity/mob/PassiveMob.java @@ -25,10 +25,10 @@ public PassiveMob(LinkedSprite[][] sprites) { * Constructor for a non-hostile (passive) mob. * @param sprites The mob's sprites. * @param healthFactor Determines the mobs health. Will be multiplied by the difficulty - * and then added with 5. + * and then added with 5. */ public PassiveMob(LinkedSprite[][] sprites, int healthFactor) { - super(sprites, 5 + healthFactor * Settings.getIdx("diff"), 5*60*Updater.normSpeed, 45, 40); + super(sprites, 5 + healthFactor * Settings.getIdx("diff"), 5 * 60 * Updater.normSpeed, 45, 40); } @Override diff --git a/src/client/java/minicraft/entity/mob/Pig.java b/src/client/java/minicraft/entity/mob/Pig.java index 1cc2ee567..8881d7391 100644 --- a/src/client/java/minicraft/entity/mob/Pig.java +++ b/src/client/java/minicraft/entity/mob/Pig.java @@ -16,9 +16,18 @@ public Pig() { public void die() { int min = 0, max = 0; - if (Settings.get("diff").equals("minicraft.settings.difficulty.easy")) {min = 1; max = 3;} - if (Settings.get("diff").equals("minicraft.settings.difficulty.normal")) {min = 1; max = 2;} - if (Settings.get("diff").equals("minicraft.settings.difficulty.hard")) {min = 0; max = 2;} + if (Settings.get("diff").equals("minicraft.settings.difficulty.easy")) { + min = 1; + max = 3; + } + if (Settings.get("diff").equals("minicraft.settings.difficulty.normal")) { + min = 1; + max = 2; + } + if (Settings.get("diff").equals("minicraft.settings.difficulty.hard")) { + min = 0; + max = 2; + } dropItem(min, max, Items.get("raw pork")); diff --git a/src/client/java/minicraft/entity/mob/Player.java b/src/client/java/minicraft/entity/mob/Player.java index a669d05ce..385e78052 100644 --- a/src/client/java/minicraft/entity/mob/Player.java +++ b/src/client/java/minicraft/entity/mob/Player.java @@ -103,7 +103,8 @@ public class Player extends Mob implements ItemHolder, ClientTickable { public int hunger, stamina, armor; // The current stats public int armorDamageBuffer; - @Nullable public ArmorItem curArmor; // The color/type of armor to be displayed. + @Nullable + public ArmorItem curArmor; // The color/type of armor to be displayed. private int staminaRecharge; // The ticks before charging a bolt of the player's stamina private static final int maxStaminaRecharge = 10; // Cutoff value for staminaRecharge @@ -111,10 +112,10 @@ public class Player extends Mob implements ItemHolder, ClientTickable { private int hungerStamCnt, stamHungerTicks; // Tiers of hunger penalties before losing a burger. private static final int maxHungerTicks = 400; // The cutoff value for stamHungerTicks - private static final int[] maxHungerStams = {10, 7, 5}; // TungerStamCnt required to lose a burger. - private static final int[] hungerTickCount = {120, 30, 10}; // Ticks before decrementing stamHungerTicks. - private static final int[] hungerStepCount = {8, 3, 1}; // Steps before decrementing stamHungerTicks. - private static final int[] minStarveHealth = {5, 3, 0}; // Min hearts required for hunger to hurt you. + private static final int[] maxHungerStams = { 10, 7, 5 }; // TungerStamCnt required to lose a burger. + private static final int[] hungerTickCount = { 120, 30, 10 }; // Ticks before decrementing stamHungerTicks. + private static final int[] hungerStepCount = { 8, 3, 1 }; // Steps before decrementing stamHungerTicks. + private static final int[] minStarveHealth = { 5, 3, 0 }; // Min hearts required for hunger to hurt you. private int stepCount; // Used to penalize hunger for movement. private int hungerChargeDelay; // The delay between each time the hunger bar increases your health private int hungerStarveDelay; // The delay between each time the hunger bar decreases your health @@ -166,8 +167,8 @@ public Item remove(int idx) { } @Override - public int add(int slot, Item item) { - int res = super.add(slot, item); + public @Nullable Item add(Item item) { + Item res = super.add(item); triggerTrigger(); return res; } @@ -214,7 +215,9 @@ public void updateInv(String items) { updateSprites(); } - public int getMultiplier() { return Game.isMode("minicraft.settings.mode.score") ? multiplier : 1; } + public int getMultiplier() { + return Game.isMode("minicraft.settings.mode.score") ? multiplier : 1; + } void resetMultiplier() { multiplier = 1; @@ -223,7 +226,7 @@ void resetMultiplier() { public void addMultiplier(int value) { if (!Game.isMode("minicraft.settings.mode.score")) return; - multiplier = Math.min(MAX_MULTIPLIER, multiplier+value); + multiplier = Math.min(MAX_MULTIPLIER, multiplier + value); multipliertime = Math.max(multipliertime, mtm - 5); } @@ -234,8 +237,14 @@ public void tickMultiplier() { } } - public int getScore() { return score; } - public void setScore(int score) { this.score = score; } + public int getScore() { + return score; + } + + public void setScore(int score) { + this.score = score; + } + public void addScore(int points) { score += points * getMultiplier(); } @@ -261,16 +270,18 @@ public void addPotionEffect(PotionType type) { * Returns all the potion effects currently affecting the player. * @return all potion effects on the player. */ - public HashMap getPotionEffects() { return potioneffects; } + public HashMap getPotionEffects() { + return potioneffects; + } @Override public void tick() { if (level == null || isRemoved()) return; if (Game.getDisplay() != null) return; // Don't tick player when menu is open - if (input.getKey("F3-Y").clicked) { + if (input.getMappedKey("F3-Y").isClicked()) { World.scheduleLevelChange(1); return; - } else if (input.getKey("F3-H").clicked) { + } else if (input.getMappedKey("F3-H").isClicked()) { World.scheduleLevelChange(-1); return; } @@ -285,10 +296,11 @@ public void tick() { } if (potioneffects.size() > 0 && !Bed.inBed(this)) { - for (PotionType potionType: potioneffects.keySet().toArray(new PotionType[0])) { + for (PotionType potionType : potioneffects.keySet().toArray(new PotionType[0])) { if (potioneffects.get(potionType) <= 1) // If time is zero (going to be set to 0 in a moment)... PotionItem.applyPotion(this, potionType, false); // Automatically removes this potion effect. - else potioneffects.put(potionType, potioneffects.get(potionType) - 1); // Otherwise, replace it with one less. + else + potioneffects.put(potionType, potioneffects.get(potionType) - 1); // Otherwise, replace it with one less. } } @@ -333,7 +345,8 @@ public void tick() { } onStairDelay = 10; // Resets the delay, if on a stairs tile, but the delay is greater than 0. In other words, this prevents you from ever activating a level change on a stair tile, UNTIL you get off the tile for 10+ ticks. - } else if (onStairDelay > 0) onStairDelay--; // Decrements stairDelay if it's > 0, but not on stair tile... does the player get removed from the tile beforehand, or something? + } else if (onStairDelay > 0) + onStairDelay--; // Decrements stairDelay if it's > 0, but not on stair tile... does the player get removed from the tile beforehand, or something? if (onTile == Tiles.get("Infinite Fall") && !Game.isMode("minicraft.settings.mode.creative")) { if (onFallDelay <= 0) { @@ -360,7 +373,8 @@ public void tick() { if (staminaRechargeDelay == 0) { staminaRecharge++; // Ticks since last recharge, accounting for the time potion effect. - if (isSwimming() && !potioneffects.containsKey(PotionType.Swim)) staminaRecharge = 0; // Don't recharge stamina while swimming. + if (isSwimming() && !potioneffects.containsKey(PotionType.Swim)) + staminaRecharge = 0; // Don't recharge stamina while swimming. // Recharge a bolt for each multiple of maxStaminaRecharge. while (staminaRecharge > maxStaminaRecharge) { @@ -374,14 +388,14 @@ public void tick() { if (hunger < 0) hunger = 0; // Error correction if (stamina < maxStamina) { - stamHungerTicks-=diffIdx; // Affect hunger if not at full stamina; this is 2 levels away from a hunger "burger". - if( stamina == 0) stamHungerTicks-=diffIdx; // Double effect if no stamina at all. + stamHungerTicks -= diffIdx; // Affect hunger if not at full stamina; this is 2 levels away from a hunger "burger". + if (stamina == 0) stamHungerTicks -= diffIdx; // Double effect if no stamina at all. } // This if statement encapsulates the hunger system - if(!Bed.inBed(this)) { + if (!Bed.inBed(this)) { if (hungerChargeDelay > 0) { // If the hunger is recharging health... - stamHungerTicks -= 2+diffIdx; // Penalize the hunger + stamHungerTicks -= 2 + diffIdx; // Penalize the hunger if (hunger == 0) stamHungerTicks -= diffIdx; // Further penalty if at full hunger } @@ -404,14 +418,13 @@ public void tick() { } /// System that heals you depending on your hunger - if (health < (baseHealth + extraHealth) && hunger > maxHunger/2) { + if (health < (baseHealth + extraHealth) && hunger > maxHunger / 2) { hungerChargeDelay++; - if (hungerChargeDelay > 20*Math.pow(maxHunger-hunger+2, 2)) { + if (hungerChargeDelay > 20 * Math.pow(maxHunger - hunger + 2, 2)) { health++; hungerChargeDelay = 0; } - } - else hungerChargeDelay = 0; + } else hungerChargeDelay = 0; if (hungerStarveDelay == 0) { hungerStarveDelay = 120; @@ -479,16 +492,16 @@ public void tick() { if (activeItem != null && (input.inputPressed("drop-one") || input.inputPressed("drop-stack"))) { Item drop = activeItem.copy(); - if (input.inputPressed("drop-one") && drop instanceof StackableItem && ((StackableItem)drop).count > 1) { - // Drop one from stack - ((StackableItem)activeItem).count--; - ((StackableItem)drop).count = 1; - } else { + if (!input.inputPressed("drop-stack") || !(drop instanceof StackableItem) || ((StackableItem) drop).count <= 1) { activeItem = null; // Remove it from the "inventory" if (isFishing) { isFishing = false; fishingTicks = maxFishingTicks; } + } else { + // Drop one from stack + ((StackableItem) activeItem).count--; + ((StackableItem) drop).count = 1; } level.dropItem(x, y, drop); @@ -501,16 +514,8 @@ public void tick() { attack(); } - if (input.inputPressed("menu") && activeItem != null) { - int returned = inventory.add(0, activeItem); - if (activeItem instanceof StackableItem) { - StackableItem stackable = (StackableItem)activeItem; - if (stackable.count > 0) { - getLevel().dropItem(x, y, stackable.copy()); - } - } else if (returned <= 0) { - getLevel().dropItem(x, y, activeItem); - } + if ((input.inputPressed("menu") || input.inputPressed("craft")) && activeItem != null) { + tryAddToInvOrDrop(activeItem); activeItem = null; if (isFishing) { @@ -520,14 +525,19 @@ public void tick() { } if (Game.getDisplay() == null) { - if (input.inputPressed("menu") && !use()) // !use() = no furniture in front of the player; this prevents player inventory from opening (will open furniture inventory instead) + if (input.inputPressed("craft") && !use()) { + Game.setDisplay(new CraftingDisplay(Recipes.craftRecipes, "minicraft.displays.crafting", this, true)); + return; + } else if (input.inputPressed("menu") && !use()) { // !use() = no furniture in front of the player; this prevents player inventory from opening (will open furniture inventory instead) Game.setDisplay(new PlayerInvDisplay(this)); - if (input.inputPressed("pause")) + return; + } else if (input.inputPressed("pause")) { Game.setDisplay(new PauseDisplay()); - if (input.inputPressed("craft") && !use()) - Game.setDisplay(new CraftingDisplay(Recipes.craftRecipes, "minicraft.displays.crafting", this, true)); - - if (input.inputDown("info")) Game.setDisplay(new InfoDisplay()); + return; + } else if (input.inputDown("info")) { + Game.setDisplay(new InfoDisplay()); + return; + } if (input.inputDown("quicksave") && !Updater.saving) { Updater.saving = true; @@ -557,7 +567,7 @@ public void tick() { if (attackTime > 0) { attackTime--; - if(attackTime == 0) attackItem = null; // null the attackItem once we are done attacking. + if (attackTime == 0) attackItem = null; // null the attackItem once we are done attacking. } } } @@ -569,14 +579,7 @@ public void tick() { public void resolveHeldItem() { if (!(activeItem instanceof PowerGloveItem)) { // If you are now holding something other than a power glove... if (prevItem != null) { // and you had a previous item that we should care about... - int returned = inventory.add(0, prevItem); // Then add that previous item to your inventory so it isn't lost. - if (prevItem instanceof StackableItem) { - if (((StackableItem)prevItem).count > 0) { - getLevel().dropItem(x, y, prevItem.copy()); - } - } else if (returned == 0) { - getLevel().dropItem(x, y, prevItem); - } + tryAddToInvOrDrop(prevItem); // Then add that previous item to your inventory so it isn't lost. } // If something other than a power glove is being held, but the previous item is null, then nothing happens; nothing added to inventory, and current item remains as the new one. } else activeItem = prevItem; // Otherwise, if you're holding a power glove, then the held item didn't change, so we can remove the power glove and make it what it was before. @@ -605,6 +608,10 @@ protected void attack() { activeItem.interactOn(Tiles.get("rock"), level, 0, 0, this, attackDir); if (activeItem.isDepleted()) { activeItem = null; + if (isFishing) { + isFishing = false; + fishingTicks = maxFishingTicks; + } } return; } @@ -628,14 +635,18 @@ protected void attack() { if (!Game.isMode("minicraft.settings.mode.creative")) tool.dur--; - AchievementsDisplay.setAchievement("minicraft.achievement.bow",true); + AchievementsDisplay.setAchievement("minicraft.achievement.bow", true); return; } } // If the interaction between you and an entity is successful, then return. - if (interact(getInteractionBox(INTERACT_DIST))) return; + if (interact(getInteractionBox(INTERACT_DIST))) { + if (activeItem.isDepleted()) + activeItem = null; + return; + } // Attempt to interact with the tile. Point t = getInteractionTile(); @@ -655,7 +666,7 @@ protected void attack() { done = true; // Returns true if the target tile successfully interacts with the item. - } else if (tile.interact(level, t.x, t.y, this, activeItem, attackDir)){ + } else if (tile.interact(level, t.x, t.y, this, activeItem, attackDir)) { done = true; } } @@ -663,6 +674,10 @@ protected void attack() { if (activeItem.isDepleted()) { // If the activeItem has 0 items left, then "destroy" it. activeItem = null; + if (isFishing) { + isFishing = false; + fishingTicks = maxFishingTicks; + } } } if (done) return; // Skip the rest if interaction was handled @@ -683,7 +698,7 @@ protected void attack() { } if (used && activeItem instanceof ToolItem) - ((ToolItem)activeItem).payDurability(); + ((ToolItem) activeItem).payDurability(); } } @@ -694,10 +709,10 @@ private Rectangle getInteractionBox(int range) { int paraClose = 4, paraFar = range; int perpClose = 0, perpFar = 8; - int xClose = x + dir.getX()*paraClose + dir.getY()*perpClose; - int yClose = y + dir.getY()*paraClose + dir.getX()*perpClose; - int xFar = x + dir.getX()*paraFar + dir.getY()*perpFar; - int yFar = y + dir.getY()*paraFar + dir.getX()*perpFar; + int xClose = x + dir.getX() * paraClose + dir.getY() * perpClose; + int yClose = y + dir.getY() * paraClose + dir.getX() * perpClose; + int xFar = x + dir.getX() * paraFar + dir.getY() * perpFar; + int yFar = y + dir.getY() * paraFar + dir.getX() * perpFar; return new Rectangle(Math.min(xClose, xFar), Math.min(yClose, yFar), Math.max(xClose, xFar), Math.max(yClose, yFar), Rectangle.CORNERS); } @@ -705,8 +720,8 @@ private Rectangle getInteractionBox(int range) { private Point getInteractionTile() { int x = this.x, y = this.y - 2; - x += dir.getX()*INTERACT_DIST; - y += dir.getY()*INTERACT_DIST; + x += dir.getX() * INTERACT_DIST; + y += dir.getY() * INTERACT_DIST; return new Point(x >> 4, y >> 4); } @@ -729,7 +744,7 @@ private void goFishing() { } if (data != null) { // If you've caught something - for (String line: data) { + for (String line : data) { // Check all the entries in the data // The number is a percent, if one fails, it moves down the list @@ -748,7 +763,7 @@ private void goFishing() { Game.notifications.add(itemData.substring(1)); } else { if (Items.get(itemData).equals(Items.get("Raw Fish"))) { - AchievementsDisplay.setAchievement("minicraft.achievement.fish",true); + AchievementsDisplay.setAchievement("minicraft.achievement.fish", true); } level.dropItem(x, y, Items.get(itemData)); caught = true; @@ -766,27 +781,37 @@ private void goFishing() { fishingTicks = maxFishingTicks; // If you didn't catch anything, try again in 120 ticks } - private boolean use() { return use(getInteractionBox(INTERACT_DIST)); } + private boolean use() { + return use(getInteractionBox(INTERACT_DIST)); + } - /** called by other use method; this serves as a buffer in case there is no entity in front of the player. */ + /** + * called by other use method; this serves as a buffer in case there is no entity in front of the player. + */ private boolean use(Rectangle area) { List entities = level.getEntitiesInRect(area); // Gets the entities within the 4 points for (Entity e : entities) { - if (e instanceof Furniture && ((Furniture) e).use(this)) return true; // If the entity is not the player, then call it's use method, and return the result. Only some furniture classes use this. + if (e instanceof Furniture && ((Furniture) e).use(this)) + return true; // If the entity is not the player, then call it's use method, and return the result. Only some furniture classes use this. } return false; } - /** same, but for interaction. */ + /** + * same, but for interaction. + */ private boolean interact(Rectangle area) { List entities = level.getEntitiesInRect(area); for (Entity e : entities) { - if (e != this && e.interact(this, activeItem, attackDir)) return true; // This is the ONLY place that the Entity.interact method is actually called. + if (e != this && e.interact(this, activeItem, attackDir)) + return true; // This is the ONLY place that the Entity.interact method is actually called. } return false; } - /** same, but for attacking. */ + /** + * same, but for attacking. + */ private boolean hurt(Rectangle area) { List entities = level.getEntitiesInRect(area); int maxDmg = 0; @@ -810,7 +835,7 @@ private boolean hurt(Rectangle area) { private int getAttackDamage(Entity e) { int dmg = random.nextInt(2) + 1; if (activeItem != null && activeItem instanceof ToolItem) { - dmg += ((ToolItem)activeItem).getAttackDamageBonus(e); // Sword/Axe are more effective at dealing damage. + dmg += ((ToolItem) activeItem).getAttackDamageBonus(e); // Sword/Axe are more effective at dealing damage. } return dmg; } @@ -836,26 +861,26 @@ public void render(Screen screen) { // Renders swimming if (isSwimming() && onFallDelay <= 0) { yo += 4; // y offset is moved up by 4 - if (level.getTile(x / 16, y / 16) == Tiles.get("water")) { + if (level.getTile(x >> 4, y >> 4) == Tiles.get("water")) { // animation effect - if (tickTime / 8 % 2 == 0) { - screen.render(xo + 0, yo + 3, 5, 0, 0, hudSheet.getSheet()); // Render the water graphic - screen.render(xo + 8, yo + 3, 5, 0, 1, hudSheet.getSheet()); // Render the mirrored water graphic to the right. - } else { + if (tickTime / 8 % 2 == 0) { + screen.render(xo + 0, yo + 3, 5, 0, 0, hudSheet.getSheet()); // Render the water graphic + screen.render(xo + 8, yo + 3, 5, 0, 1, hudSheet.getSheet()); // Render the mirrored water graphic to the right. + } else { screen.render(xo + 0, yo + 3, 5, 1, 0, hudSheet.getSheet()); screen.render(xo + 8, yo + 3, 5, 1, 1, hudSheet.getSheet()); - } + } - } else if (level.getTile(x / 16, y / 16) == Tiles.get("lava")) { + } else if (level.getTile(x >> 4, y >> 4) == Tiles.get("lava")) { - if (tickTime / 8 % 2 == 0) { + if (tickTime / 8 % 2 == 0) { screen.render(xo + 0, yo + 3, 6, 0, 1, hudSheet.getSheet()); // Render the lava graphic screen.render(xo + 8, yo + 3, 6, 0, 0, hudSheet.getSheet()); // Render the mirrored lava graphic to the right. - } else { + } else { screen.render(xo + 0, yo + 3, 6, 1, 1, hudSheet.getSheet()); screen.render(xo + 8, yo + 3, 6, 1, 0, hudSheet.getSheet()); - } + } } } @@ -954,36 +979,59 @@ public void render(Screen screen) { if (activeItem instanceof FurnitureItem) { Furniture furniture = ((FurnitureItem) activeItem).furniture; furniture.x = x; - furniture.y = yo-4; + furniture.y = yo - 4; furniture.render(screen); } } /** What happens when the player interacts with a itemEntity */ public void pickupItem(ItemEntity itemEntity) { - int picked = 0; - int total = 1; - if (itemEntity.item instanceof StackableItem && ((StackableItem)itemEntity.item).stacksWith(activeItem)) { // Picked up item equals the one in your hand - ((StackableItem)activeItem).count += ((StackableItem)itemEntity.item).count; - picked = ((StackableItem)itemEntity.item).count; - } else { - if (itemEntity.item instanceof StackableItem) total = ((StackableItem)itemEntity.item).count; - picked = inventory.add(itemEntity.item); // Add item to inventory + boolean successful = false; // If there is any item successfully added to the player + boolean remove = false; // Whether to remove the item entity (when empty) + if (itemEntity.item instanceof StackableItem && ((StackableItem) itemEntity.item).stacksWith(activeItem)) { // Picked up item equals the one in your hand + int toAdd = Math.min(((StackableItem) activeItem).count + ((StackableItem) itemEntity.item).count, ((StackableItem) activeItem).maxCount) + - ((StackableItem) activeItem).count; + if (toAdd > 0) { + ((StackableItem) activeItem).count += toAdd; + ((StackableItem) itemEntity.item).count -= toAdd; + successful = true; + } + if (((StackableItem) itemEntity.item).count == 0) { // Empty + remove = true; // Remove the item entity + } } - if (picked == total) { - Sound.play("pickup"); + if (!(itemEntity.item instanceof StackableItem && ((StackableItem) itemEntity.item).count == 0)) { + // Add item to inventory + Item remaining; + if (itemEntity.item instanceof StackableItem) { + int orig = ((StackableItem) itemEntity.item).count; + remaining = inventory.add(itemEntity.item); + if (remaining != null && ((StackableItem) remaining).count != orig) { + successful = true; + } + } else remaining = inventory.add(itemEntity.item); + if (remaining == null) { + successful = remove = true; + } + } - itemEntity.remove(); + if (remove) itemEntity.remove(); + if (successful) { + Sound.play("pickup"); addScore(1); } } // The player can swim. - public boolean canSwim() { return true; } + public boolean canSwim() { + return true; + } // Can walk on wool tiles..? quickly..? - public boolean canWool() { return true; } + public boolean canWool() { + return true; + } /** * Finds a starting position for the player. @@ -999,7 +1047,10 @@ public void findStartPos(Level level, long spawnSeed) { * Finds the starting position for the player in a level. * @param level The level. */ - public void findStartPos(Level level) { findStartPos(level, true); } + public void findStartPos(Level level) { + findStartPos(level, true); + } + public void findStartPos(Level level, boolean setSpawn) { Point spawnPos; @@ -1013,13 +1064,13 @@ public void findStartPos(Level level, boolean setSpawn) { // There are no tiles in the entire map which the player is allowed to stand on. Not likely. if (spawnTilePositions.size() == 0) { - spawnPos = new Point(random.nextInt(level.w/4)+level.w*3/8, random.nextInt(level.h/4)+level.h*3/8); + spawnPos = new Point(random.nextInt(level.w / 4) + level.w * 3 / 8, random.nextInt(level.h / 4) + level.h * 3 / 8); level.setTile(spawnPos.x, spawnPos.y, Tiles.get("grass")); } else { // Gets random valid spawn tile position. spawnPos = spawnTilePositions.get(random.nextInt(spawnTilePositions.size())); } - if(setSpawn) { + if (setSpawn) { // Used to save (tile) coordinates of spawn point outside this method. spawnx = spawnPos.x; spawny = spawnPos.y; @@ -1050,7 +1101,8 @@ public void respawn(Level level) { * @return true if the player had enough stamina, false if not. */ public boolean payStamina(int cost) { - if (potioneffects.containsKey(PotionType.Energy)) return true; // If the player has the potion effect for infinite stamina, return true (without subtracting cost). + if (potioneffects.containsKey(PotionType.Energy)) + return true; // If the player has the potion effect for infinite stamina, return true (without subtracting cost). else if (stamina <= 0) return false; // If the player doesn't have enough stamina, then return false; failure. if (cost < 0) cost = 0; // Error correction @@ -1067,13 +1119,16 @@ public int getLightRadius() { if (activeItem != null && activeItem instanceof FurnitureItem) { // If player is holding furniture int rr = ((FurnitureItem) activeItem).furniture.getLightRadius(); // Gets furniture light radius - if (rr > r) r = rr; // Brings player light up to furniture light, if less, since the furnture is not yet part of the level and so doesn't emit light even if it should. + if (rr > r) + r = rr; // Brings player light up to furniture light, if less, since the furnture is not yet part of the level and so doesn't emit light even if it should. } return r; // Return light radius } - /** What happens when the player dies */ + /** + * What happens when the player dies + */ @Override public void die() { Analytics.SinglePlayerDeath.ping(); @@ -1101,15 +1156,19 @@ public void onExploded(Tnt tnt, int dmg) { payStamina(dmg * 2); } - /** Hurt the player. + /** + * Hurt the player. * @param damage How much damage to do to player. * @param attackDir What direction to attack. */ - public void hurt(int damage, Direction attackDir) { doHurt(damage, attackDir); } + public void hurt(int damage, Direction attackDir) { + doHurt(damage, attackDir); + } @Override protected void doHurt(int damage, Direction attackDir) { - if (Game.isMode("minicraft.settings.mode.creative") || hurtTime > 0 || Bed.inBed(this)) return; // Can't get hurt in creative, hurt cooldown, or while someone is in bed + if (Game.isMode("minicraft.settings.mode.creative") || hurtTime > 0 || Bed.inBed(this)) + return; // Can't get hurt in creative, hurt cooldown, or while someone is in bed int healthDam = 0, armorDam = 0; if (this == Game.player) { @@ -1119,8 +1178,8 @@ protected void doHurt(int damage, Direction attackDir) { armorDamageBuffer += damage; armorDam += damage; - while (armorDamageBuffer >= curArmor.level+1) { - armorDamageBuffer -= curArmor.level+1; + while (armorDamageBuffer >= curArmor.level + 1) { + armorDamageBuffer -= curArmor.level + 1; healthDam++; } } @@ -1153,7 +1212,8 @@ protected void doHurt(int damage, Direction attackDir) { * @param attackDir The direction of attack. */ private void directHurt(int damage, Direction attackDir) { - if (Game.isMode("minicraft.settings.mode.creative") || hurtTime > 0 || Bed.inBed(this)) return; // Can't get hurt in creative, hurt cooldown, or while someone is in bed + if (Game.isMode("minicraft.settings.mode.creative") || hurtTime > 0 || Bed.inBed(this)) + return; // Can't get hurt in creative, hurt cooldown, or while someone is in bed int healthDam = 0; if (this == Game.player) { @@ -1180,20 +1240,17 @@ public Inventory getInventory() { return inventory; } - public String getDebugHunger() { return hungerStamCnt + "_" + stamHungerTicks; } + public String getDebugHunger() { + return hungerStamCnt + "_" + stamHungerTicks; + } /** - * Trying to add item(s) to the player inventory. - * If no more item(s) can be added to the inventory, drop the item(s) near the player. + * Trying to add a stack of item(s) to the top of player inventory. + * If there is/are no more item(s) can be added to the inventory, drop the item(s) near the player. */ public void tryAddToInvOrDrop(@Nullable Item item) { if (item != null) { - int returned = inventory.add(0, item); - if (item instanceof StackableItem) { - if (((StackableItem)item).count > 0) { - getLevel().dropItem(x, y, item); - } - } else if (returned == 0) { + if (inventory.add(item) != null) { getLevel().dropItem(x, y, item); } } diff --git a/src/client/java/minicraft/entity/mob/Sheep.java b/src/client/java/minicraft/entity/mob/Sheep.java index 90a594d49..f8c1dc583 100644 --- a/src/client/java/minicraft/entity/mob/Sheep.java +++ b/src/client/java/minicraft/entity/mob/Sheep.java @@ -45,12 +45,9 @@ public void render(Screen screen) { public void tick() { super.tick(); Tile tile = level.getTile(x >> 4, y >> 4); - // If tall grasses are present, these are consumed and then turn into grass tiles. - if (tile instanceof GrassTile) { - if (random.nextInt(1000) == 0) { // Grazing - level.setTile(x >> 4, y >> 4, Tiles.get("dirt")); - cut = false; - } + if (tile instanceof GrassTile && random.nextInt(1000) == 0) { // Grazing + level.setTile(x >> 4, y >> 4, Tiles.get("dirt")); + cut = false; } } @@ -70,9 +67,18 @@ public boolean interact(Player player, @Nullable Item item, Direction attackDir) public void die() { int min = 0, max = 0; - if (Settings.get("diff").equals("minicraft.settings.difficulty.easy")) {min = 1; max = 3;} - if (Settings.get("diff").equals("minicraft.settings.difficulty.normal")) {min = 1; max = 2;} - if (Settings.get("diff").equals("minicraft.settings.difficulty.hard")) {min = 0; max = 2;} + if (Settings.get("diff").equals("minicraft.settings.difficulty.easy")) { + min = 1; + max = 3; + } + if (Settings.get("diff").equals("minicraft.settings.difficulty.normal")) { + min = 1; + max = 2; + } + if (Settings.get("diff").equals("minicraft.settings.difficulty.hard")) { + min = 0; + max = 2; + } if (!cut) dropItem(min, max, Items.get("wool")); dropItem(min, max, Items.get("Raw Beef")); diff --git a/src/client/java/minicraft/entity/mob/Skeleton.java b/src/client/java/minicraft/entity/mob/Skeleton.java index 09fc27c56..fdf78ac5c 100644 --- a/src/client/java/minicraft/entity/mob/Skeleton.java +++ b/src/client/java/minicraft/entity/mob/Skeleton.java @@ -50,8 +50,8 @@ public void tick() { } public void die() { - int[] diffrands = {20, 20, 30}; - int[] diffvals = {13, 18, 28}; + int[] diffrands = { 20, 20, 30 }; + int[] diffvals = { 13, 18, 28 }; int diff = Settings.getIdx("diff"); int count = random.nextInt(3 - diff) + 1; diff --git a/src/client/java/minicraft/entity/mob/Slime.java b/src/client/java/minicraft/entity/mob/Slime.java index e6a416ba2..e8294c2c6 100644 --- a/src/client/java/minicraft/entity/mob/Slime.java +++ b/src/client/java/minicraft/entity/mob/Slime.java @@ -9,10 +9,10 @@ public class Slime extends EnemyMob { private static LinkedSprite[][][] sprites = new LinkedSprite[][][] { - new LinkedSprite[][] {Mob.compileSpriteList(0, 0, 2, 2, 0, 2, "slime")}, - new LinkedSprite[][] {Mob.compileSpriteList(0, 2, 2, 2, 0, 2, "slime")}, - new LinkedSprite[][] {Mob.compileSpriteList(0, 4, 2, 2, 0, 2, "slime")}, - new LinkedSprite[][] {Mob.compileSpriteList(0, 6, 2, 2, 0, 2, "slime")} + new LinkedSprite[][] { Mob.compileSpriteList(0, 0, 2, 2, 0, 2, "slime") }, + new LinkedSprite[][] { Mob.compileSpriteList(0, 2, 2, 2, 0, 2, "slime") }, + new LinkedSprite[][] { Mob.compileSpriteList(0, 4, 2, 2, 0, 2, "slime") }, + new LinkedSprite[][] { Mob.compileSpriteList(0, 6, 2, 2, 0, 2, "slime") } }; private int jumpTime = 0; // jumpTimer, also acts as a rest timer before the next jump @@ -60,8 +60,7 @@ public void render(Screen screen) { if (jumpTime > 0) { walkDist = 8; // Set to jumping sprite. y -= 4; // Raise up a bit. - } - else walkDist = 0; // Set to ground sprite. + } else walkDist = 0; // Set to ground sprite. dir = Direction.DOWN; diff --git a/src/client/java/minicraft/entity/mob/Snake.java b/src/client/java/minicraft/entity/mob/Snake.java index fdcc43eaa..81c66b340 100644 --- a/src/client/java/minicraft/entity/mob/Snake.java +++ b/src/client/java/minicraft/entity/mob/Snake.java @@ -21,7 +21,7 @@ public Snake(int lvl) { protected void touchedBy(Entity entity) { if (entity instanceof Player) { int damage = lvl + Settings.getIdx("diff"); - ((Player)entity).hurt(this, damage); + ((Player) entity).hurt(this, damage); } } diff --git a/src/client/java/minicraft/entity/mob/Zombie.java b/src/client/java/minicraft/entity/mob/Zombie.java index 987b26072..5885203a0 100644 --- a/src/client/java/minicraft/entity/mob/Zombie.java +++ b/src/client/java/minicraft/entity/mob/Zombie.java @@ -33,9 +33,9 @@ public void die() { int rand = random.nextInt(3); if (rand == 0) { level.dropItem(x, y, Items.get("green clothes")); - } else if(rand == 1) { + } else if (rand == 1) { level.dropItem(x, y, Items.get("red clothes")); - } else if(rand == 2) { + } else if (rand == 2) { level.dropItem(x, y, Items.get("blue clothes")); } } diff --git a/src/client/java/minicraft/entity/particle/BurnParticle.java b/src/client/java/minicraft/entity/particle/BurnParticle.java index 53f0db4b1..0ef444d80 100644 --- a/src/client/java/minicraft/entity/particle/BurnParticle.java +++ b/src/client/java/minicraft/entity/particle/BurnParticle.java @@ -11,7 +11,6 @@ public class BurnParticle extends Particle { /** * Creates a new particle at the given position. It has a lifetime of 30 ticks * and a fire looking sprite. - * * @param x X map position * @param y Y map position */ diff --git a/src/client/java/minicraft/entity/particle/FireParticle.java b/src/client/java/minicraft/entity/particle/FireParticle.java index cfb3aadb2..900019d8f 100644 --- a/src/client/java/minicraft/entity/particle/FireParticle.java +++ b/src/client/java/minicraft/entity/particle/FireParticle.java @@ -9,7 +9,6 @@ public class FireParticle extends Particle { /** * Creates a new particle at the given position. It has a lifetime of 30 ticks * and a fire looking sprite. - * * @param x X map position * @param y Y map position */ diff --git a/src/client/java/minicraft/entity/particle/Particle.java b/src/client/java/minicraft/entity/particle/Particle.java index 5480f4876..04e0382ec 100644 --- a/src/client/java/minicraft/entity/particle/Particle.java +++ b/src/client/java/minicraft/entity/particle/Particle.java @@ -31,6 +31,7 @@ public Particle(int x, int y, int xr, int lifetime, LinkedSprite sprite) { this.sprite = sprite; time = 0; } + public Particle(int x, int y, int lifetime, LinkedSprite sprite) { this(x, y, 1, lifetime, sprite); } @@ -49,8 +50,12 @@ public void tick() { } @Override - public void render(Screen screen) { screen.render(x, y, sprite); } + public void render(Screen screen) { + screen.render(x, y, sprite); + } @Override - public boolean isSolid() { return false; } + public boolean isSolid() { + return false; + } } diff --git a/src/client/java/minicraft/entity/particle/SandParticle.java b/src/client/java/minicraft/entity/particle/SandParticle.java index ea268e113..b5048f565 100644 --- a/src/client/java/minicraft/entity/particle/SandParticle.java +++ b/src/client/java/minicraft/entity/particle/SandParticle.java @@ -6,13 +6,14 @@ import java.util.Random; public class SandParticle extends Particle { + public static final LinkedSprite sprite = new LinkedSprite(SpriteType.Entity, "sand_footsteps"); + /** * Creating a sand particle. * @param x X map position * @param y Y map position */ public SandParticle(int x, int y) { - super(x, y, 180 + new Random().nextInt(71) - 35, new LinkedSprite(SpriteType.Entity, "sand_dust")); - this.sprite.setMirror(random.nextInt(4)); + super(x, y, 180 + new Random().nextInt(81) - 40, sprite); } } diff --git a/src/client/java/minicraft/entity/particle/SmashParticle.java b/src/client/java/minicraft/entity/particle/SmashParticle.java index 3873604c2..c5063c1ec 100644 --- a/src/client/java/minicraft/entity/particle/SmashParticle.java +++ b/src/client/java/minicraft/entity/particle/SmashParticle.java @@ -7,7 +7,6 @@ public class SmashParticle extends Particle { /** * Creates a smash particle at the given position. Has a lifetime of 10 ticks. * Will also play a monsterhurt sound when created. - * * @param x X map position * @param y Y map position */ diff --git a/src/client/java/minicraft/entity/particle/TextParticle.java b/src/client/java/minicraft/entity/particle/TextParticle.java index d4d9a8892..504317e40 100644 --- a/src/client/java/minicraft/entity/particle/TextParticle.java +++ b/src/client/java/minicraft/entity/particle/TextParticle.java @@ -8,12 +8,11 @@ public class TextParticle extends Particle { private String msg; // Message of the text particle private double xa, ya, za; // x, y, z acceleration private double xx, yy, zz; // x, y, z coordinates - + private FontStyle style; - + /** * Creates a text particle which shows a message on the screen. - * * @param msg Message to display * @param x X map position * @param y Y map position @@ -21,13 +20,13 @@ public class TextParticle extends Particle { */ public TextParticle(String msg, int x, int y, int col) { super(x, y, msg.length(), 60, null); - + style = new FontStyle(col).setShadowType(Color.BLACK, false); this.msg = msg; xx = x; // Assigns x pos yy = y; // Assigns y pos zz = 2; // Assigns z pos to be 2 - + // Assigns x,y,z acceleration: xa = random.nextGaussian() * 0.3; ya = random.nextGaussian() * 0.2; @@ -37,13 +36,13 @@ public TextParticle(String msg, int x, int y, int col) { @Override public void tick() { super.tick(); - + // Move the particle according to the acceleration xx += xa; yy += ya; zz += za; if (zz < 0) { - + // If z pos if less than 0, alter accelerations... zz = 0; za *= -0.5; @@ -55,12 +54,12 @@ public void tick() { x = (int) xx; y = (int) yy; } - + @Override public void render(Screen screen) { - style.setXPos(x - msg.length() * 4).setYPos(y - (int)zz).draw(msg, screen); + style.setXPos(x - msg.length() * 4).setYPos(y - (int) zz).draw(msg, screen); } - + /** * Returns the message and color divied by the character :. * @return string representation of the particle diff --git a/src/client/java/minicraft/entity/particle/WaterParticle.java b/src/client/java/minicraft/entity/particle/WaterParticle.java new file mode 100644 index 000000000..b91491dc2 --- /dev/null +++ b/src/client/java/minicraft/entity/particle/WaterParticle.java @@ -0,0 +1,58 @@ +package minicraft.entity.particle; + +import minicraft.gfx.SpriteLinker; + +public class WaterParticle extends Particle { + private final int destX; + private final int destY; + private int count; + private boolean stopped; + + public WaterParticle(int x, int y, int lifetime, SpriteLinker.LinkedSprite sprite, int destX, int destY) { + super(x, y, lifetime, sprite); + this.destX = destX; + this.destY = destY; + count = 0; + stopped = false; + } + + @Override + public void tick() { + move: + if (!stopped) { + count++; + if (x == destX && y == destY) { + stopped = true; + break move; + } + if (count == 2) { + int diffX = destX - x; + int diffY = destY - y; + if (Math.abs(diffX) < 3 && Math.abs(diffY) < 3) { + move(destX, destY); + stopped = true; + break move; + } + + double phi = Math.atan2(diffY, diffX); + double moveX = Math.cos(phi); + double moveY = Math.sin(phi); + int moveXI = 0; + int moveYI = 0; + if (Math.abs(moveX / moveY) > 1.4) moveXI = (int) Math.signum(moveX); // Difference in X is greater. + else if (Math.abs(moveY / moveX) > 1.4) + moveYI = (int) Math.signum(moveY); // Difference in Y is greater. + else { // The difference is small. + moveXI = (int) Math.signum(moveX); + moveYI = (int) Math.signum(moveY); + } + + if (!move(moveXI, moveYI)) + stopped = true; + count = 0; + } + } + + super.tick(); + } +} diff --git a/src/client/java/minicraft/gfx/Color.java b/src/client/java/minicraft/gfx/Color.java index cdc1e757d..c5f0b6fb4 100644 --- a/src/client/java/minicraft/gfx/Color.java +++ b/src/client/java/minicraft/gfx/Color.java @@ -51,22 +51,25 @@ public class Color { public static final String MAGENTA_CODE = Color.toStringCode(Color.MAGENTA); public static final String CYAN_CODE = Color.toStringCode(Color.CYAN); - /** This returns a minicraftrgb. - * a should be between 0-1, r,g,and b should be 0-255 */ + /** + * This returns a minicraftrgb. + * a should be between 0-1, r,g,and b should be 0-255 + */ public static int get(int a, int r, int g, int b) { return (a << 24) + (r << 16) + (g << 8) + (b); } + public static int get(int a, int copy) { return get(a, copy, copy, copy); } public static String toStringCode(int color) { return new String(new char[] { - Color.COLOR_CHAR, - (char) ((color >> 24) & 0xFF), // Alpha - (char) ((color >> 16) & 0xFF), // Red - (char) ((color >> 8) & 0xFF), // Blue - (char) (color & 0xFF) // Green + Color.COLOR_CHAR, + (char) ((color >> 24) & 0xFF), // Alpha + (char) ((color >> 16) & 0xFF), // Red + (char) ((color >> 8) & 0xFF), // Blue + (char) (color & 0xFF) // Green }); } @@ -91,7 +94,9 @@ public static int rgb(int red, int green, int blue) { // rgbInt array -> rgbRead return red / 50 * 100 + green / 50 * 10 + blue / 50; // This is: rgbReadable } - /** This method darkens or lightens a color by the specified amount. */ + /** + * This method darkens or lightens a color by the specified amount. + */ public static int tint(int color, int amount, boolean isSpriteCol) { if (isSpriteCol) { int[] rgbBytes = separateEncodedSprite(color); // This just separates the four 8-bit sprite colors; they are still in base-6 added form. @@ -103,19 +108,25 @@ public static int tint(int color, int amount, boolean isSpriteCol) { return tint(color, amount); // This is: rgbByte } } + private static int tint(int rgbByte, int amount) { if (rgbByte == 255) return 255; // See description of bit shifting above; it will hold the 255 value, not -1 int[] rgb = decodeRGB(rgbByte); // This returns the rgb values as 0-5 numbers. for (int i = 0; i < rgb.length; i++) - rgb[i] = limit(rgb[i]+amount, 0, 5); + rgb[i] = limit(rgb[i] + amount, 0, 5); return rgb[0] * 36 + rgb[1] * 6 + rgb[2]; // This is: rgbByte } - /** seperates a 4-part sprite color (rgb4Sprite) into it's original 4 component colors (which are each rgbBytes) */ + /** + * seperates a 4-part sprite color (rgb4Sprite) into it's original 4 component colors (which are each rgbBytes) + */ /// Reverse of Color.get(a, b, c, d). - public static int[] separateEncodedSprite(int rgb4Sprite) { return separateEncodedSprite(rgb4Sprite, false); } + public static int[] separateEncodedSprite(int rgb4Sprite) { + return separateEncodedSprite(rgb4Sprite, false); + } + public static int[] separateEncodedSprite(int rgb4Sprite, boolean convertToReadable) { // The numbers are stored, most to least shifted, as d, c, b, a. @@ -124,7 +135,7 @@ public static int[] separateEncodedSprite(int rgb4Sprite, boolean convertToReada int c = (rgb4Sprite & 0x00_00_FF_00) >> 8; int d = (rgb4Sprite & 0x00_00_00_FF); - if(convertToReadable) { + if (convertToReadable) { // They become rgbReadable a = unGet(a); b = unGet(b); @@ -132,20 +143,22 @@ public static int[] separateEncodedSprite(int rgb4Sprite, boolean convertToReada d = unGet(d); } // Else, they are rgbByte - return new int[] {a, b, c, d}; + return new int[] { a, b, c, d }; } - /** This turns a 216 scale rgb int into a 0-5 scale "concatenated" rgb int. (aka rgbByte -> r/g/b Readables) */ + /** + * This turns a 216 scale rgb int into a 0-5 scale "concatenated" rgb int. (aka rgbByte -> r/g/b Readables) + */ public static int[] decodeRGB(int rgbByte) { int r = (rgbByte / 36) % 6; int g = (rgbByte / 6) % 6; int b = rgbByte % 6; - return new int[] {r, g, b}; + return new int[] { r, g, b }; } public static int unGet(int rgbByte) { // rgbByte -> rgbReadable int[] cols = decodeRGB(rgbByte); - return cols[0]*100 + cols[1]*10 + cols[2]; + return cols[0] * 100 + cols[1] * 10 + cols[2]; } /// This turns a 25-bit minicraft color into a 24-bit rgb color. @@ -160,7 +173,7 @@ protected static int tintColor(int rgbInt, int amount) { int[] comps = decodeRGBColor(rgbInt); for (int i = 0; i < comps.length; i++) - comps[i] = limit(comps[i]+amount, 0, 255); + comps[i] = limit(comps[i] + amount, 0, 255); return comps[0] << 16 | comps[1] << 8 | comps[2]; } @@ -170,7 +183,20 @@ protected static int[] decodeRGBColor(int rgbInt) { int g = (rgbInt & 0x00_FF_00) >> 8; int b = (rgbInt & 0x00_00_FF); - return new int[] {r, g, b}; + return new int[] { r, g, b }; + } + + /** + * Gets the lightness of the given 24-bit RGB color value. + * This is strictly calculated by L from RGB to HSL conversion. + * For other formula and method reference: https://stackoverflow.com/a/56678483. + * @return lightness, from 0 to 1 floating point number + */ + public static float getLightnessFromRGB(int color) { + int r = (color >> 16) & 0xFF; + int g = (color >> 8) & 0xFF; + int b = color & 0xFF; + return (Math.max(Math.max(r, g), b) + Math.min(Math.min(r, g), b)) / 510f; } /// This is for color testing. diff --git a/src/client/java/minicraft/gfx/Dimension.java b/src/client/java/minicraft/gfx/Dimension.java index 8b13c9f1b..374876ebc 100644 --- a/src/client/java/minicraft/gfx/Dimension.java +++ b/src/client/java/minicraft/gfx/Dimension.java @@ -1,21 +1,24 @@ package minicraft.gfx; public class Dimension { - + public int width, height; - - public Dimension() { this(0, 0); } + + public Dimension() { + this(0, 0); + } + public Dimension(int width, int height) { this.width = width; this.height = height; } - + public Dimension(Dimension model) { width = model.width; height = model.height; } - + public String toString() { - return width+"x"+height; + return width + "x" + height; } } diff --git a/src/client/java/minicraft/gfx/Ellipsis.java b/src/client/java/minicraft/gfx/Ellipsis.java index a26fbe971..5d6d9d456 100644 --- a/src/client/java/minicraft/gfx/Ellipsis.java +++ b/src/client/java/minicraft/gfx/Ellipsis.java @@ -5,30 +5,41 @@ import minicraft.gfx.Ellipsis.DotUpdater.TimeUpdater; public abstract class Ellipsis { - + private final DotUpdater updateMethod; - + protected Ellipsis(DotUpdater updateMethod, int intervalCount) { this.updateMethod = updateMethod; updateMethod.setIntervalCount(intervalCount); } - + public String updateAndGet() { updateMethod.update(); return get(); } + protected abstract String get(); - protected void nextInterval(int interval) {} - - protected int getInterval() { return updateMethod.getInterval(); } - protected int getIntervalCount() { return updateMethod.getIntervalCount(); } - + + protected void nextInterval(int interval) { + } + + protected int getInterval() { + return updateMethod.getInterval(); + } + + protected int getIntervalCount() { + return updateMethod.getIntervalCount(); + } + public static class SequentialEllipsis extends Ellipsis { - public SequentialEllipsis() { this(new CallUpdater(Updater.normSpeed*2/3)); } + public SequentialEllipsis() { + this(new CallUpdater(Updater.normSpeed * 2 / 3)); + } + public SequentialEllipsis(DotUpdater updater) { super(updater, 3); } - + @Override public String get() { StringBuilder dots = new StringBuilder(); @@ -39,70 +50,82 @@ public String get() { else dots.append(" "); } - + return dots.toString(); } } - + public static class SmoothEllipsis extends Ellipsis { - + private static final String dotString = " "; - + private final char[] dots = dotString.toCharArray(); - - public SmoothEllipsis() { this(new TimeUpdater()); } + + public SmoothEllipsis() { + this(new TimeUpdater()); + } + public SmoothEllipsis(DotUpdater updater) { - super(updater, dotString.length()*2); + super(updater, dotString.length() * 2); updater.setEllipsis(this); } - + @Override - public String get() { return new String(dots); } - + public String get() { + return new String(dots); + } + @Override protected void nextInterval(int interval) { int epos = interval % dots.length; - char set = interval < getIntervalCount()/2 ? '.' : ' '; + char set = interval < getIntervalCount() / 2 ? '.' : ' '; dots[epos] = set; } } - - + + public static abstract class DotUpdater { private final int countPerCycle; private int intervalCount; private int curInterval; private int countPerInterval; private int counter; - + private Ellipsis ellipsis = null; - + private boolean started = false; - + protected DotUpdater(int countPerCycle) { this.countPerCycle = countPerCycle; } - - void setEllipsis(Ellipsis ellipsis) { this.ellipsis = ellipsis; } - + + void setEllipsis(Ellipsis ellipsis) { + this.ellipsis = ellipsis; + } + // Called by Ellipsis classes, passing their value. void setIntervalCount(int numIntervals) { intervalCount = numIntervals; - countPerInterval = Math.max(1, Math.round(countPerCycle / (float)intervalCount)); + countPerInterval = Math.max(1, Math.round(countPerCycle / (float) intervalCount)); + } + + public int getInterval() { + return curInterval; + } + + public int getIntervalCount() { + return intervalCount; } - - public int getInterval() { return curInterval; } - public int getIntervalCount() { return intervalCount; } - + private void incInterval(int amt) { if (ellipsis != null) - for (int i = curInterval+1; i <= curInterval+amt; i++) - ellipsis.nextInterval(i%intervalCount); - + for (int i = curInterval + 1; i <= curInterval + amt; i++) + ellipsis.nextInterval(i % intervalCount); + curInterval += amt; curInterval %= intervalCount; } - + protected void incCounter(int amt) { counter += amt; int intervals = counter / countPerInterval; @@ -111,24 +134,33 @@ protected void incCounter(int amt) { counter -= intervals * countPerInterval; } } - - void start() { started = true; } + + void start() { + started = true; + } + void update() { if (!started) start(); } - + public static class TickUpdater extends DotUpdater { private int lastTick; - - public TickUpdater() { this(Updater.normSpeed); } + + public TickUpdater() { + this(Updater.normSpeed); + } + public TickUpdater(int ticksPerCycle) { super(ticksPerCycle); } - + @Override - void start() { super.start(); lastTick = Updater.tickCount; } - + void start() { + super.start(); + lastTick = Updater.tickCount; + } + @Override void update() { super.update(); @@ -138,18 +170,24 @@ void update() { incCounter(ticksPassed); } } - + public static class TimeUpdater extends DotUpdater { private long lastTime; - - public TimeUpdater() { this(750); } + + public TimeUpdater() { + this(750); + } + public TimeUpdater(int millisPerCycle) { super(millisPerCycle); } - + @Override - void start() { super.start(); lastTime = System.nanoTime(); } - + void start() { + super.start(); + lastTime = System.nanoTime(); + } + @Override void update() { super.update(); @@ -159,15 +197,18 @@ void update() { incCounter(diffMillis); } } - + public static class CallUpdater extends DotUpdater { - + public CallUpdater(int callsPerCycle) { super(callsPerCycle); } - + @Override - void update() { super.update(); incCounter(1); } + void update() { + super.update(); + incCounter(1); + } } } } diff --git a/src/client/java/minicraft/gfx/Font.java b/src/client/java/minicraft/gfx/Font.java index ff141eea8..dc8eb1766 100644 --- a/src/client/java/minicraft/gfx/Font.java +++ b/src/client/java/minicraft/gfx/Font.java @@ -1,7 +1,6 @@ package minicraft.gfx; import minicraft.core.Renderer; -import minicraft.core.io.Localization; import minicraft.gfx.SpriteLinker.SpriteType; import java.util.ArrayList; @@ -11,25 +10,31 @@ public class Font { // These are all the characters that will be translated to the screen. (The spaces are important) private static final String chars = - "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345"+ - "6789.,!?'\"-+=/\\%()<>:;^@ÁÉÍÓÚÑ¿¡"+ - "ÃÊÇÔÕĞÇÜİÖŞÆØÅŰŐ[]#|{}_АБВГДЕЁЖЗ"+ - "ИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯÀÂÄÈÎÌÏÒ"+ - "ÙÛÝ*«»£$&€§ªº"; + "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345" + + "6789.,!?'\"-+=/\\%()<>:;^@ÁÉÍÓÚÑ¿¡" + + "ÃÊÇÔÕĞÇÜİÖŞÆØÅŰŐ[]#|{}_АБВГДЕЁЖЗ" + + "ИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯÀÂÄÈÎÌÏÒ" + + "ÙÛÝ*«»£$&€§ªºabcdefghijklmnopqrs" + + "tuvwxyzáàãâäéèêëíìîïóòõôöúùûüçñý" + + "ÿабвгдеёжзийклмнопрстуфхцчшщъыьэ" + + "юяışő"; /* The order of the letters in the chars string is represented in the order that they appear in the sprite-sheet. */ - public static void draw(String msg, Screen screen, int x, int y) { draw(msg, screen, x, y, -1); } + public static void draw(String msg, Screen screen, int x, int y) { + draw(msg, screen, x, y, -1); + } - /** Draws the message to the x & y coordinates on the screen. */ + /** + * Draws the message to the x & y coordinates on the screen. + */ public static void draw(String msg, Screen screen, int x, int y, int whiteTint) { - msg = msg.toUpperCase(Localization.getSelectedLocale()); //makes all letters uppercase. for (int i = 0; i < msg.length(); i++) { // Loops through all the characters that you typed int ix = chars.indexOf(msg.charAt(i)); // The current letter in the message loop if (ix >= 0) { // If that character's position is larger than or equal to 0, then render the character on the screen. - screen.render(x + i * textWidth(msg.substring(i, i+1)), y, ix % 32, ix / 32, 0, Renderer.spriteLinker.getSheet(SpriteType.Gui, "font"), whiteTint); + screen.render(x + i * textWidth(msg.substring(i, i + 1)), y, ix % 32, ix / 32, 0, Renderer.spriteLinker.getSheet(SpriteType.Gui, "font"), whiteTint); } } } @@ -63,12 +68,13 @@ public static void drawColor(String message, Screen screen, int x, int y) { } } - public static void drawBackground(String msg, Screen screen, int x, int y) { drawBackground(msg, screen, x, y, -1); } + public static void drawBackground(String msg, Screen screen, int x, int y) { + drawBackground(msg, screen, x, y, -1); + } public static void drawBackground(String msg, Screen screen, int x, int y, int whiteTint) { - String newMsg = msg.toUpperCase(Localization.getSelectedLocale()); - for (int i = 0; i < newMsg.length(); i++) { // Renders the black boxes under the text - screen.render(x + i * textWidth(newMsg.substring(i, i+1)), y, 5, 2, 0, Renderer.spriteLinker.getSheet(SpriteType.Gui, "hud")); + for (int i = 0; i < msg.length(); i++) { // Renders the black boxes under the text + screen.render(x + i * textWidth(msg.substring(i, i + 1)), y, 5, 2, 0, Renderer.spriteLinker.getSheet(SpriteType.Gui, "hud")); } // Renders the text @@ -78,6 +84,7 @@ public static void drawBackground(String msg, Screen screen, int x, int y, int w public static int textWidth(String text) { // Filtering out coloring codes. return (int) (Math.max(text.length() - text.chars().filter(ch -> ch == Color.COLOR_CHAR).count() * 5, 0) * 8); } + public static int textWidth(String[] para) { // This returns the maximum length of all the lines. if (para == null || para.length == 0) return 0; @@ -100,7 +107,10 @@ public static void drawCentered(String msg, Screen screen, int y, int color) { /// note: the y centering values in the FontStyle object will be used as a paragraph y centering value instead. - public static void drawParagraph(String para, Screen screen, FontStyle style, int lineSpacing) { drawParagraph(para, screen, Screen.w, Screen.h, style, lineSpacing); } + public static void drawParagraph(String para, Screen screen, FontStyle style, int lineSpacing) { + drawParagraph(para, screen, Screen.w, Screen.h, style, lineSpacing); + } + public static void drawParagraph(String para, Screen screen, int w, int h, FontStyle style, int lineSpacing) { drawParagraph(screen, style, lineSpacing, getLines(para, w, h, lineSpacing)); } @@ -109,12 +119,16 @@ public static void drawParagraph(String para, Screen screen, int w, int h, FontS public static void drawParagraph(List lines, Screen screen, FontStyle style, int lineSpacing) { drawParagraph(screen, style, lineSpacing, lines.toArray(new String[0])); } + public static void drawParagraph(Screen screen, FontStyle style, int lineSpacing, String... lines) { - for(int i = 0; i < lines.length; i++) + for (int i = 0; i < lines.length; i++) style.drawParagraphLine(lines, i, lineSpacing, screen); } - public static String[] getLines(String para, int w, int h, int lineSpacing) { return getLines(para, w, h, lineSpacing, false); } + public static String[] getLines(String para, int w, int h, int lineSpacing) { + return getLines(para, w, h, lineSpacing, false); + } + public static String[] getLines(String para, int w, int h, int lineSpacing, boolean keepEmptyRemainder) { ArrayList lines = new ArrayList<>(); @@ -123,21 +137,21 @@ public static String[] getLines(String para, int w, int h, int lineSpacing, bool // then I reset the para String at the index, and do it again until para is an empty string. int height = textHeight(); - while(para.length() > 0) { // continues to loop as long as there are more characters to parse. + while (para.length() > 0) { // continues to loop as long as there are more characters to parse. int splitIndex = getLine(para, w); // determine how many letters can be fit on to this line. lines.add(para.substring(0, splitIndex)); // add the specified number of characters. - if(splitIndex < para.length() && para.substring(splitIndex, splitIndex+1).matches("[ \n]")) + if (splitIndex < para.length() && para.substring(splitIndex, splitIndex + 1).matches("[ \n]")) splitIndex++; // if there are more characters to do, and the next character is a space or newline, skip it (because the getLine() method will always break before newlines, and will usually otherwise break before spaces. para = para.substring(splitIndex); // remove the characters that have now been added on to the line height += lineSpacing + textHeight(); // move y pos down a line - if(height > h) + if (height > h) break; // If we've run out of space to draw lines, then there's no point in parsing more characters, so we should break out of the loop. } - if(para.length() > 0 || keepEmptyRemainder) + if (para.length() > 0 || keepEmptyRemainder) lines.add(para); // add remainder, but don't add empty lines unintentionally. return lines.toArray(new String[0]); @@ -146,7 +160,7 @@ public static String[] getLines(String para, int w, int h, int lineSpacing, bool // this returns the position index at which the given string should be split so that the first part is the longest line possible. // note, the index returned is exclusive; it should not be included in the line. private static int getLine(String text, int maxWidth) { - if(maxWidth <= 0) return 0; // just to pass the monkey test. :P + if (maxWidth <= 0) return 0; // just to pass the monkey test. :P text = text.replaceAll(" ?\n ?", " \n "); @@ -154,22 +168,22 @@ private static int getLine(String text, int maxWidth) { int curWidth = textWidth(words[0]); - if(curWidth > maxWidth) { + if (curWidth > maxWidth) { // we can't even fit the first word on to the line, even by itself. So we'll have to fit what we can. int i; - for(i = 1; i < words[0].length(); i++) // find how many characters do fit - if(textWidth(words[0].substring(0, i+1)) > maxWidth) + for (i = 1; i < words[0].length(); i++) // find how many characters do fit + if (textWidth(words[0].substring(0, i + 1)) > maxWidth) break; return i; // stop here and return, because we know we can't fit more so we can ignore all that's below } int i; - for(i = 1; i < words.length; i++) { - if(words[i].equals("\n")) break; + for (i = 1; i < words.length; i++) { + if (words[i].equals("\n")) break; - curWidth += textWidth(" "+words[i]); - if(curWidth > maxWidth) + curWidth += textWidth(" " + words[i]); + if (curWidth > maxWidth) break; } // i now contains the number of words that fit on the line. diff --git a/src/client/java/minicraft/gfx/FontStyle.java b/src/client/java/minicraft/gfx/FontStyle.java index 5b70e4c1d..81d2c6e75 100644 --- a/src/client/java/minicraft/gfx/FontStyle.java +++ b/src/client/java/minicraft/gfx/FontStyle.java @@ -8,13 +8,13 @@ public class FontStyle { /// this specifies the x and y offsets for each binary value in the "shadow location byte", and is what causes each value to progress in a circle. - private static int[] shadowPosMap = { 0, 1, 1, 1, 0, -1, -1, -1, - -1, -1, 0, 1, 1, 1, 0, -1}; + private static int[] shadowPosMap = { 0, 1, 1, 1, 0, -1, -1, -1, + -1, -1, 0, 1, 1, 1, 0, -1 }; /** - The shadowing technique uses binary strings to specify where to outline a string of text. It was going to be a straight byte, since there are 8 positions, but since it's going to be a string anyway, I decided to make it accept a string. - Each position is specified fairly simply: it goes clockwise, starting from the top. Then it goes top right, right, bottom right, bottom, etc. up to top left. It's kind of like a compass, with a position for N, NE, E, etc. - For an example, for the default shadow, the string is "00010000". though, becuase of the way it's designed, the trailing zeros may be dropped, so it could just be "0001". This doesn't quite read like binary, but it doesn't have to, so whatever. :P - */ + * The shadowing technique uses binary strings to specify where to outline a string of text. It was going to be a straight byte, since there are 8 positions, but since it's going to be a string anyway, I decided to make it accept a string. + * Each position is specified fairly simply: it goes clockwise, starting from the top. Then it goes top right, right, bottom right, bottom, etc. up to top left. It's kind of like a compass, with a position for N, NE, E, etc. + * For an example, for the default shadow, the string is "00010000". though, becuase of the way it's designed, the trailing zeros may be dropped, so it could just be "0001". This doesn't quite read like binary, but it doesn't have to, so whatever. :P + */ private int mainColor; @@ -29,12 +29,15 @@ public class FontStyle { private Rectangle paraBounds; private int padX = 0, padY = 0; - public FontStyle() { this(Color.WHITE); } + public FontStyle() { + this(Color.WHITE); + } + public FontStyle(int mainColor) { this.mainColor = mainColor; shadowColor = Color.get(-1, -1); shadowType = ""; - anchor = new Point(Screen.w/2, Screen.h/2); + anchor = new Point(Screen.w / 2, Screen.h / 2); /// By default, the styling is set so as to center the text in the middle of the screen, with no shadow. } @@ -81,14 +84,14 @@ public void configureForParagraph(String[] para, int spacing) { // In a paragraph, it could be the left side, or right, or top... it depends. // Either way, the draw method needs to use a different position. - Dimension size = new Dimension(Font.textWidth(para), para.length*(Font.textHeight()+spacing)); + Dimension size = new Dimension(Font.textWidth(para), para.length * (Font.textHeight() + spacing)); paraBounds = relTextPos.positionRect(size, anchor, new Rectangle()); } public void setupParagraphLine(String[] para, int line, int spacing) { if (para == null || line < 0 || line >= para.length) { Logger.tag("FontStyle").error("FontStyle.java: " + - (para == null ? "paragraph is null" : "index "+line+" is invalid") + "; can't draw line."); + (para == null ? "paragraph is null" : "index " + line + " is invalid") + "; can't draw line."); return; } @@ -96,8 +99,8 @@ public void setupParagraphLine(String[] para, int line, int spacing) { configureForParagraph(para, spacing); Rectangle textArea = new Rectangle(paraBounds); - textArea.setSize(textArea.getWidth(), Font.textHeight()+spacing, RelPos.TOP_LEFT); - textArea.translate(0, line*textArea.getHeight()); + textArea.setSize(textArea.getWidth(), Font.textHeight() + spacing, RelPos.TOP_LEFT); + textArea.translate(0, line * textArea.getHeight()); anchor = textArea.getPosition(relTextPos.getOpposite()); // For the relpos to put the rect in the correct pos, the anchor should be fetched using to opposite relpos. @@ -114,14 +117,21 @@ public void drawParagraphLine(String[] para, int line, int spacing, Screen scree /* -- All the font modifier methods are below. They all return the current FontStyle instance for chaining. -- */ - /** Sets the color of the text itself. */ + /** + * Sets the color of the text itself. + */ public FontStyle setColor(int col) { mainColor = col; return this; } - /** sets the x position of the text anchor. This causes the text to be left-justified, if alignment is reset. */ - public FontStyle setXPos(int pos) { return setXPos(pos, true); } + /** + * sets the x position of the text anchor. This causes the text to be left-justified, if alignment is reset. + */ + public FontStyle setXPos(int pos) { + return setXPos(pos, true); + } + public FontStyle setXPos(int pos, boolean resetAlignment) { anchor.x = pos; if (resetAlignment) { @@ -130,8 +140,14 @@ public FontStyle setXPos(int pos, boolean resetAlignment) { } return this; } - /** sets the y position of the text anchor. This sets the y pos to be the top of the block, if alignment is reset. */ - public FontStyle setYPos(int pos) { return setYPos(pos, true); } + + /** + * sets the y position of the text anchor. This sets the y pos to be the top of the block, if alignment is reset. + */ + public FontStyle setYPos(int pos) { + return setYPos(pos, true); + } + public FontStyle setYPos(int pos, boolean resetAlignment) { anchor.y = pos; if (resetAlignment) { @@ -146,33 +162,46 @@ public FontStyle setAnchor(int x, int y) { return this; } - /** Sets the position of the text box relative to the anchor. */ - public FontStyle setRelTextPos(RelPos relPos) { return setRelTextPos(relPos, true); } + /** + * Sets the position of the text box relative to the anchor. + */ + public FontStyle setRelTextPos(RelPos relPos) { + return setRelTextPos(relPos, true); + } + public FontStyle setRelTextPos(RelPos relPos, boolean setBoth) { this.relTextPos = relPos; if (setBoth) relLinePos = relTextPos.getOpposite(); return this; } - /** Sets the position of a paragraph of text relative to the anchor. */ + /** + * Sets the position of a paragraph of text relative to the anchor. + */ public FontStyle setRelLinePos(RelPos relPos) { relLinePos = relPos; return this; } - /** This enables text shadowing, and sets the shadow color and type. It is a convenience method that offers a preset for text outlines, and a single shadow in a standard direction. */ + /** + * This enables text shadowing, and sets the shadow color and type. It is a convenience method that offers a preset for text outlines, and a single shadow in a standard direction. + */ public FontStyle setShadowType(int color, boolean full) { String type = full ? "10101010" : "00010000"; setShadowType(color, type); return this; } - /** This is what acutally sets the values described above. It also allows custom shadows. */ + /** + * This is what acutally sets the values described above. It also allows custom shadows. + */ public FontStyle setShadowType(int color, String type) { shadowColor = color; shadowType = type; return this; } - public int getColor() { return mainColor; } + public int getColor() { + return mainColor; + } } diff --git a/src/client/java/minicraft/gfx/Insets.java b/src/client/java/minicraft/gfx/Insets.java index 3728f22ec..1e156e691 100644 --- a/src/client/java/minicraft/gfx/Insets.java +++ b/src/client/java/minicraft/gfx/Insets.java @@ -1,40 +1,49 @@ package minicraft.gfx; public class Insets { - + public int left, top, right, bottom; - - public Insets() { this(0); } - public Insets(int dist) { this(dist, dist, dist, dist); } + + public Insets() { + this(0); + } + + public Insets(int dist) { + this(dist, dist, dist, dist); + } + public Insets(int left, int top, int right, int bottom) { this.left = left; this.top = top; this.right = right; this.bottom = bottom; } - + public Rectangle addTo(Rectangle r) { - return new Rectangle(r.getLeft()-left, r.getTop()-top, r.getRight()+right, r.getBottom()+bottom, Rectangle.CORNERS); + return new Rectangle(r.getLeft() - left, r.getTop() - top, r.getRight() + right, r.getBottom() + bottom, Rectangle.CORNERS); } + public Rectangle subtractFrom(Rectangle r) { - return new Rectangle(r.getLeft()+left, r.getTop()+top, r.getRight()-right, r.getBottom()-bottom, Rectangle.CORNERS); + return new Rectangle(r.getLeft() + left, r.getTop() + top, r.getRight() - right, r.getBottom() - bottom, Rectangle.CORNERS); } - + public Dimension addTo(Dimension d) { return new Dimension(d.width + left + right, d.height + top + bottom); } + public Dimension subtractFrom(Dimension d) { return new Dimension(d.width - left - right, d.height - top - bottom); } - + public Insets addInsets(Insets s) { - return new Insets(left+s.left, top+s.top, right+s.right, bottom+s.bottom); + return new Insets(left + s.left, top + s.top, right + s.right, bottom + s.bottom); } + public Insets subtractInsets(Insets s) { - return new Insets(left-s.left, top-s.top, right-s.right, bottom-s.bottom); + return new Insets(left - s.left, top - s.top, right - s.right, bottom - s.bottom); } - + public String toString() { - return super.toString()+"[left=" + left + ",top=" + top + ",right=" + right + ",bottom=" + bottom + "]"; + return super.toString() + "[left=" + left + ",top=" + top + ",right=" + right + ",bottom=" + bottom + "]"; } } diff --git a/src/client/java/minicraft/gfx/MinicraftImage.java b/src/client/java/minicraft/gfx/MinicraftImage.java index 9ef850960..42183125a 100644 --- a/src/client/java/minicraft/gfx/MinicraftImage.java +++ b/src/client/java/minicraft/gfx/MinicraftImage.java @@ -1,59 +1,67 @@ package minicraft.gfx; -import minicraft.core.CrashHandler; import minicraft.gfx.SpriteLinker.LinkedSprite; +import minicraft.util.Logging; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Range; import java.awt.image.BufferedImage; -import java.io.IOException; +import java.util.Objects; /** * Although we have SpriteLinker, we still need SpriteSheet for buffering. * As BufferedImage is heavy. Our current rendering system still depends on this array. */ public class MinicraftImage { - /** Each sprite tile size. */ + /** + * Each sprite tile size. + */ public static final int boxWidth = 8; public final int width, height; // Width and height of the sprite sheet public final int[] pixels; // Integer array of the image's pixels /** - * Default with maximum size of image. - * @param image The image to be added. - * @throws IOException if I/O exception occurs. + * Initializes a {@code MinicraftImage} instance from the provided size. + * All values are filled with zero after construction. + * @param width the final width of this image + * @param height the final height of this image + * @throws IllegalArgumentException if either {@code width} or {@code height} is zero or negative */ - public MinicraftImage(BufferedImage image) throws IOException { - this(image, image.getWidth(), image.getHeight()); + public MinicraftImage(int width, int height) { + if (width < 1) throw new IllegalArgumentException("width cannot be zero or negative"); + if (height < 1) throw new IllegalArgumentException("height cannot be zero or negative"); + + this.width = width; + this.height = height; + pixels = new int[width * height]; } + /** - * Custom size. - * @param image The image to be added. - * @param width The width of the {@link MinicraftImage} to be applied to the {@link LinkedSprite}. - * @param height The height of the {@link MinicraftImage} to be applied to the {@link LinkedSprite}. - * @throws IOException - */ - public MinicraftImage(BufferedImage image, int width, int height) throws IOException { - if (width % 8 != 0) - CrashHandler.errorHandle(new IllegalArgumentException("Invalid width of SpriteSheet."), new CrashHandler.ErrorInfo( - "Invalid SpriteSheet argument.", CrashHandler.ErrorInfo.ErrorType.HANDLED, - String.format("Invalid width: {}, SpriteSheet width should be a multiple of 8.") - )); - if (height % 8 != 0) - CrashHandler.errorHandle(new IllegalArgumentException("Invalid height of SpriteSheet."), new CrashHandler.ErrorInfo( - "Invalid SpriteSheet argument.", CrashHandler.ErrorInfo.ErrorType.HANDLED, - String.format("Invalid height: {}, SpriteSheet height should be a multiple of 8.") - )); - - // Sets width and height to that of the image - this.width = width - width % 8; - this.height = height - height % 8; - - // If size is bigger than image source, throw error. - if (this.width > image.getWidth() || this.height > image.getHeight()) { - throw new IOException(new IndexOutOfBoundsException(String.format("Requested size %s*%s out of source size %s*%s", - this.width, this.height, image.getWidth(), image.getHeight()))); - } + * Constructs a {@code MinicraftImage} with the maximum size of dimension supplied from the source {@code BufferedImage}. + * @param image the {@code BufferedImage} to be constructed from + * @see LinkedSprite + */ + public MinicraftImage(@NotNull BufferedImage image) { + this(image, image.getWidth(), image.getHeight()); + } + + /** + * Constructs a {@code MinicraftImage} with the given size from the source {@code BufferedImage}. + * If the requested size is out of the source's dimension, the remaining values will be left {@code 0}. + * @param image the {@code BufferedImage} to be constructed from + * @param width the requested width for this image, must be a non-zero natural number + * @param height the requested height for this image, must be a non-zero natural number + * @throws IllegalArgumentException if either {@code width} or {@code height} is zero or negative + * @see LinkedSprite + */ + public MinicraftImage(@NotNull BufferedImage image, int width, int height) { + Objects.requireNonNull(image, "image"); + if (width < 1) throw new IllegalArgumentException("width cannot be zero or negative"); + if (height < 1) throw new IllegalArgumentException("height cannot be zero or negative"); + this.width = width; + this.height = height; pixels = image.getRGB(0, 0, width, height, null, 0, width); // Gets the color array of the image pixels // Applying the RGB array into Minicraft rendering system 25 bits RBG array. @@ -84,4 +92,65 @@ public MinicraftImage(BufferedImage image, int width, int height) throws IOExcep pixels[i] = (transparent << 24) + red + green + blue; } } + + /** + * Creates a {@link MinicraftImage} from the provided image with default dimension validation. + * @param image the {@code BufferedImage} to be constructed from + * @return the constructed {@code Minicraft} + * @throws MinicraftImageDimensionIncompatibleException if the image's dimension is not a multiple of 8 + */ + public static MinicraftImage createDefaultCompatible(BufferedImage image) throws MinicraftImageDimensionIncompatibleException { + validateImageDimension(image); + return new MinicraftImage(image); + } + + /** + * Validates if the provided image is compatible with the game's general sprite rendering system. + * @param image The image to be validated + * @throws MinicraftImageDimensionIncompatibleException if the image's dimension is not a multiple of 8 + */ + public static void validateImageDimension(BufferedImage image) throws MinicraftImageDimensionIncompatibleException { + if (image.getHeight() % 8 != 0 || image.getWidth() % 8 != 0) + throw new MinicraftImageDimensionIncompatibleException(image.getWidth(), image.getHeight()); + } + + /** + * Validates if the provided image is respective to the required size. + * @param image The image to be validated + * @param width The requested width + * @param height The requested height + * @throws MinicraftImageRequestOutOfBoundsException if the requested size is out of the image's dimension + */ + public static void validateImageDimension(BufferedImage image, int width, int height) + throws MinicraftImageRequestOutOfBoundsException { + if (image.getWidth() < width || image.getHeight() < height) + throw new MinicraftImageRequestOutOfBoundsException(image.getWidth(), image.getHeight(), width, height); + } + + public static class MinicraftImageDimensionIncompatibleException extends Exception { + private final int width, height; + + public MinicraftImageDimensionIncompatibleException(int width, int height) { + this.width = width; + this.height = height; + } + + public final int getWidth() { return width; } + public final int getHeight() { return height; } + } + + public static class MinicraftImageRequestOutOfBoundsException extends Exception { + private final int srcW, srcH, rqtW, rqtH; + public MinicraftImageRequestOutOfBoundsException(int srcW, int srcH, int rqtW, int rqtH) { + this.srcW = srcW; + this.srcH = srcH; + this.rqtW = rqtW; + this.rqtH = rqtH; + } + + public final int getSourceWidth() { return srcW; } + public final int getSourceHeight() { return srcH; } + public final int getRequestedWidth() { return rqtW; } + public final int getRequestedHeight() { return rqtH; } + } } diff --git a/src/client/java/minicraft/gfx/Point.java b/src/client/java/minicraft/gfx/Point.java index b1c756bec..feea0c624 100644 --- a/src/client/java/minicraft/gfx/Point.java +++ b/src/client/java/minicraft/gfx/Point.java @@ -1,36 +1,41 @@ package minicraft.gfx; public class Point { - + public int x, y; - - public Point() { this(0, 0); } + + public Point() { + this(0, 0); + } + public Point(int x, int y) { this.x = x; this.y = y; } - + public Point(Point model) { x = model.x; y = model.y; } - + public void translate(int xoff, int yoff) { x += xoff; y += yoff; } - + public String toString() { - return "("+x+","+y+")"; + return "(" + x + "," + y + ")"; } - + @Override public boolean equals(Object other) { if (!(other instanceof Point)) return false; Point o = (Point) other; return x == o.x && y == o.y; } - + @Override - public int hashCode() { return x * 71 + y; } + public int hashCode() { + return x * 71 + y; + } } diff --git a/src/client/java/minicraft/gfx/Rectangle.java b/src/client/java/minicraft/gfx/Rectangle.java index 348d5cc83..46cb10779 100644 --- a/src/client/java/minicraft/gfx/Rectangle.java +++ b/src/client/java/minicraft/gfx/Rectangle.java @@ -10,16 +10,16 @@ public class Rectangle { private int x, y, w, h; - public Rectangle() {} // 0 all. + public Rectangle() { + } // 0 all. public Rectangle(int x, int y, int x1, int y1, int type) { - if(type < 0 || type > 2) type = 0; - + if (type < 0 || type > 2) type = 0; if (type != CENTER_DIMS) { // x and y are the coords of the top left corner. this.x = x; this.y = y; } else { // x and y are the coords of the center. - this.x = x - x1/2; - this.y = y - y1/2; + this.x = x - x1 / 2; + this.y = y - y1 / 2; } if (type != CORNERS) { // x1 and y1 are the width and height. @@ -31,7 +31,9 @@ public Rectangle(int x, int y, int x1, int y1, int type) { } } - public Rectangle(Point p, Dimension d) { this(false, p, d); } + public Rectangle(Point p, Dimension d) { + this(false, p, d); + } public Rectangle(boolean isCenter, Point p, Dimension d) { this(p.x, p.y, d.width, d.height, isCenter ? CENTER_DIMS : CORNER_DIMS); } @@ -44,28 +46,39 @@ public Rectangle(Rectangle model) { } public int getLeft() { return x; } - public int getRight() { return x + w; } - public int getTop() { return y; } - public int getBottom() { return y + h; } + public int getRight() { return x + w; + } - public int getWidth() { return w; } - public int getHeight() { return h; } + public int getTop() { + return y; + } + + public int getBottom() { + return y + h; +} - public Point getCenter() { return new Point(x + w/2, y + h/2); } - public Dimension getSize() { return new Dimension(w, h); } + public int getWidth() { + return w; + }public int getHeight() { return h; } + public Point getCenter() { return new Point(x + w/2, y + h/2); + } + + public Dimension getSize() { + return new Dimension(w, h); +} public Point getPosition(RelPos relPos) { Point p = new Point(x, y); - p.x += relPos.xIndex * w/2; - p.y += relPos.yIndex * h/2; + p.x += relPos.xIndex * w / 2; + p.y += relPos.yIndex * h / 2; return p; } public boolean intersects(Rectangle other) { - return !( getLeft() > other.getRight() // Left side is past the other right side - || other.getLeft() > getRight() // Other left side is past the right side - || getBottom() < other.getTop() // Other top is below the bottom - || other.getBottom() < getTop() // Top is below the other bottom + return !(getLeft() > other.getRight() // Left side is past the other right side + || other.getLeft() > getRight() // Other left side is past the right side + || getBottom() < other.getTop() // Other top is below the bottom + || other.getBottom() < getTop() // Top is below the other bottom ); } @@ -78,8 +91,8 @@ && getLeft() >= other.getLeft() // Left is on the right of the other left public void setPosition(Point p, RelPos relPos) { setPosition(p.x, p.y, relPos); } public void setPosition(int x, int y, RelPos relPos) { - this.x = x - relPos.xIndex*w/2; - this.y = y - relPos.yIndex*h/2; + this.x = x - relPos.xIndex * w / 2; + this.y = y - relPos.yIndex * h / 2; } public void translate(int xoff, int yoff) { @@ -87,7 +100,9 @@ public void translate(int xoff, int yoff) { y += yoff; } - public void setSize(Dimension d, RelPos anchor) { setSize(d.width, d.height, anchor); } + public void setSize(Dimension d, RelPos anchor) { + setSize(d.width, d.height, anchor); + } public void setSize(int width, int height, RelPos anchor) { Point p = getPosition(anchor); this.w = width; @@ -95,5 +110,7 @@ public void setSize(int width, int height, RelPos anchor) { setPosition(p, anchor); } - public String toString() { return super.toString()+"[center=" + getCenter() + "; size=" + getSize() + "]"; } + public String toString() { + return super.toString() + "[center=" + getCenter() + "; size=" + getSize() + "]"; + } } diff --git a/src/client/java/minicraft/gfx/Screen.java b/src/client/java/minicraft/gfx/Screen.java index 8491cd62b..dbc05cb22 100644 --- a/src/client/java/minicraft/gfx/Screen.java +++ b/src/client/java/minicraft/gfx/Screen.java @@ -4,14 +4,28 @@ import minicraft.core.Updater; import minicraft.gfx.SpriteLinker.LinkedSprite; import minicraft.gfx.SpriteLinker.SpriteType; - -import java.util.Arrays; +import org.intellij.lang.annotations.MagicConstant; +import org.jetbrains.annotations.NotNull; + +import java.awt.AlphaComposite; +import java.awt.Graphics2D; +import java.awt.RadialGradientPaint; +import java.awt.image.BufferedImage; +import java.awt.image.DataBufferByte; +import java.awt.image.DataBufferInt; +import java.math.BigDecimal; +import java.math.MathContext; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.stream.IntStream; public class Screen { public static final int w = Renderer.WIDTH; // Width of the screen public static final int h = Renderer.HEIGHT; // Height of the screen - public static final Point center = new Point(w/2, h/2); + public static final Point center = new Point(w / 2, h / 2); private static final int MAXDARK = 128; @@ -23,115 +37,384 @@ public class Screen { private static final int BIT_MIRROR_X = 0x01; // Written in hexadecimal; binary: 01 private static final int BIT_MIRROR_Y = 0x02; // Binary: 10 - public int[] pixels; // Pixels on the screen + private final BufferedImage image; + private final int[] pixels; + + private final ArrayDeque renderings = new ArrayDeque<>(); + private final LightOverlay lightOverlay; + private ClearRendering lastClearRendering = null; // Outdated Information: // Since each sheet is 256x256 pixels, each one has 1024 8x8 "tiles" // So 0 is the start of the item sheet 1024 the start of the tile sheet, 2048 the start of the entity sheet, // And 3072 the start of the gui sheet - public Screen() { - /// Screen width and height are determined by the actual game window size, meaning the screen is only as big as the window. - pixels = new int[Screen.w * Screen.h]; // Makes new integer array for all the pixels on the screen. + public Screen(BufferedImage image) { + /// Screen width and height are determined by the actual game window size, meaning the screen is only as big as the window.buffer = new BufferedImage(Screen.w, Screen.h); + this.image = image; + pixels = ((DataBufferInt) image.getRaster().getDataBuffer()).getData(); + lightOverlay = new LightOverlay(); + } + + private interface Rendering { + /** Invoked by {@link Renderer#render()}. */ + void render(Graphics2D graphics); + } + + private void queue(Rendering rendering) { + renderings.add(rendering); + } + + private static abstract class ClearRendering implements Rendering {} + + private static class SolidClearRendering extends ClearRendering { + private final int color; + + public SolidClearRendering(int color) { + this.color = color; + } + + @Override + public void render(Graphics2D graphics) { + + graphics.setColor(new java.awt.Color(color)); + graphics.fillRect(0, 0, Screen.w, Screen.h); + } + } + + private static class PlainClearRendering extends ClearRendering { + @Override + public void render(Graphics2D graphics) { + graphics.clearRect(0, 0, Screen.w, Screen.h); + } + } + + private class SpriteRendering implements Rendering { + private final int xp, yp, xt, yt, tw, th, mirrors, whiteTint, color; + private final boolean fullBright; + private final MinicraftImage sheet; + + public SpriteRendering(int xp, int yp, int xt, int yt, int tw, int th, + int mirrors, int whiteTint, boolean fullBright, int color, MinicraftImage sheet) { + this.xp = xp; + this.yp = yp; + this.xt = xt; + this.yt = yt; + this.tw = tw; + this.th = th; + this.mirrors = mirrors; + this.whiteTint = whiteTint; + this.fullBright = fullBright; + this.color = color; + this.sheet = sheet; + } + + @Override + public void render(Graphics2D graphics) { + int toffs = xt + yt * sheet.width; + // Determines if the image should be mirrored... + boolean mirrorX = (mirrors & BIT_MIRROR_X) > 0; // Horizontally. + boolean mirrorY = (mirrors & BIT_MIRROR_Y) > 0; // Vertically. + for (int y = 0; y < th; ++y) { // Relative + if (y + yp < 0) continue; // If the pixel is out of bounds, then skip the rest of the loop. + if (y + yp >= h) break; + int sy = mirrorY ? th - 1 - y : y; // Source relative; reverse if necessary + for (int x = 0; x < tw; ++x) { // Relative + if (x + xp < 0) continue; // Skip rest if out of bounds. + if (x + xp >= w) break; + int sx = mirrorX ? tw - 1 - x : x; // Source relative; reverse if necessary + int col = sheet.pixels[toffs + sx + sy * sheet.width]; // Gets the color of the current pixel from the value stored in the sheet. + if (col >> 24 != 0) { // if not transparent + int index = (xp + x) + (yp + y) * w; + if (whiteTint != -1 && col == 0x1FFFFFF) { + // If this is white, write the whiteTint over it + pixels[index] = Color.upgrade(whiteTint); + } else { + // Inserts the colors into the image + if (fullBright) { + pixels[index] = Color.WHITE; + } else { + if (color != 0) { + pixels[index] = color; + } else { + pixels[index] = Color.upgrade(col); + } + } + } + } + } + } + } } - /** Clears all the colors on the screen */ + private static class FillRectRendering implements Rendering { + private final int xp, yp, w, h, color; + + public FillRectRendering(int xp, int yp, int w, int h, int color) { + this.xp = xp; + this.yp = yp; + this.w = w; + this.h = h; + this.color = color; + } + + @Override + public void render(Graphics2D graphics) { + graphics.setColor(new java.awt.Color(color)); + graphics.fillRect(xp, yp, w, h); + } + } + + private static class DrawRectRendering implements Rendering { + private final int xp, yp, w, h, color; + + public DrawRectRendering(int xp, int yp, int w, int h, int color) { + this.xp = xp; + this.yp = yp; + this.w = w; + this.h = h; + this.color = color; + } + + @Override + public void render(Graphics2D graphics) { + graphics.setColor(new java.awt.Color(color)); + graphics.drawRect(xp, yp, w, h); + } + } + + private static class DrawLineRendering implements Rendering { + private final int x0, y0, x1, y1, color; + + public DrawLineRendering(int x0, int y0, int x1, int y1, int color) { + this.x0 = x0; + this.y0 = y0; + this.x1 = x1; + this.y1 = y1; + this.color = color; + } + + @Override + public void render(Graphics2D graphics) { + graphics.setColor(new java.awt.Color(color)); + graphics.drawLine(x0, y0, x1, y1); + } + } + + /** Placeholder way, for Sign cursor rendering */ + private class DrawLineSpecialRendering implements Rendering { + private final int x0, y0, l; + private final @MagicConstant(intValues = {0, 1}) int axis; // 0: x-axis; 1: Y-axis + + public DrawLineSpecialRendering(int x0, int y0, int l, int axis) { + this.x0 = x0; + this.y0 = y0; + this.l = l; + this.axis = axis; + } + + @Override + public void render(Graphics2D graphics) { + switch (axis) { + case 0: + for (int i = 0; i < l; i++) { // 1 pixel high and 8 pixel wide + int idx = x0 + i + y0 * Screen.w; + pixels[idx] = Color.getLightnessFromRGB(pixels[idx]) >= .5 ? Color.BLACK : Color.WHITE; + } + break; + case 1: + for (int i = 0; i < l; i++) { // 8 pixel high and 1 pixel wide + int idx = x0 + (y0 + i) * Screen.w; + pixels[idx] = Color.getLightnessFromRGB(pixels[idx]) >= .5 ? Color.BLACK : Color.WHITE; + } + break; + } + } + } + + private class OverlayRendering implements Rendering { + private final int currentLevel, xa, ya; + private final double darkFactor; + + private OverlayRendering(int currentLevel, int xa, int ya, double darkFactor) { + this.currentLevel = currentLevel; + this.xa = xa; + this.ya = ya; + this.darkFactor = darkFactor; + } + + @Override + public void render(Graphics2D graphics) { + double alpha = lightOverlay.getOverlayOpacity(currentLevel, darkFactor); + BufferedImage overlay = lightOverlay.render(xa, ya); + graphics.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, .02f)); // Lightening + graphics.setColor(java.awt.Color.WHITE); + graphics.fillRect(0, 0, w, h); + graphics.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, (float) alpha)); // Shaders + graphics.drawImage(overlay, null, 0, 0); + } + } + + /** + * Clears all the colors on the screen + */ public void clear(int color) { // Turns each pixel into a single color (clearing the screen!) - Arrays.fill(pixels, color); + if (color == 0) { + queueClearRendering(new PlainClearRendering()); + } else { + queueClearRendering(new SolidClearRendering(color)); + } + } + + private void queueClearRendering(ClearRendering clearRendering) { + lastClearRendering = clearRendering; + queue(clearRendering); + } + + public void flush() { + Graphics2D g2d = image.createGraphics(); + Rendering rendering; + do { // Skips until the latest clear rendering is obtained. + rendering = renderings.poll(); // This can prevent redundant renderings operated. + if (rendering == null) return; + } while (rendering != lastClearRendering); + do { // Renders all renderings until all are operated. + rendering.render(g2d); + } while ((rendering = renderings.poll()) != null); } - public void render(int xp, int yp, int xt, int yt, int bits, MinicraftImage sheet) { render(xp, yp, xt, yt, bits, sheet, -1); } - public void render(int xp, int yp, int xt, int yt, int bits, MinicraftImage sheet, int whiteTint) { render(xp, yp, xt, yt, bits, sheet, whiteTint, false); } - /** This method takes care of assigning the correct spritesheet to assign to the sheet variable **/ - public void render(int xp, int yp, int xt, int yt, int bits, MinicraftImage sheet, int whiteTint, boolean fullbright) { + public void render(int xp, int yp, int xt, int yt, int bits, MinicraftImage sheet) { + render(xp, yp, xt, yt, bits, sheet, -1); + } + + public void render(int xp, int yp, int xt, int yt, int bits, MinicraftImage sheet, int whiteTint) { + render(xp, yp, xt, yt, bits, sheet, whiteTint, false); + } + + /** + * This method takes care of assigning the correct spritesheet to assign to the sheet variable + **/ + public void render(int xp, int yp, int xt, int yt, int bits, MinicraftImage sheet, int whiteTint, boolean fullbright) { render(xp, yp, xt, yt, bits, sheet, whiteTint, fullbright, 0); - } + } + + public void render(int xp, int yp, LinkedSprite sprite) { + render(xp, yp, sprite.getSprite()); + } + + public void render(int xp, int yp, Sprite sprite) { + render(xp, yp, sprite, false); + } + + public void render(int xp, int yp, Sprite sprite, boolean fullbright) { + render(xp, yp, sprite, 0, fullbright, 0); + } + + public void render(int xp, int yp, Sprite sprite, int mirror, boolean fullbright) { + render(xp, yp, sprite, mirror, fullbright, 0); + } - public void render(int xp, int yp, LinkedSprite sprite) { render(xp, yp, sprite.getSprite()); } - public void render(int xp, int yp, Sprite sprite) { render(xp, yp, sprite, false); } - public void render(int xp, int yp, Sprite sprite, boolean fullbright) { render(xp, yp, sprite, 0, fullbright, 0); } - public void render(int xp, int yp, Sprite sprite, int mirror, boolean fullbright) { render(xp, yp, sprite, mirror, fullbright, 0); } public void render(int xp, int yp, Sprite sprite, int mirror, boolean fullbright, int color) { + boolean mirrorX = (mirror & BIT_MIRROR_X) > 0; // Horizontally. + boolean mirrorY = (mirror & BIT_MIRROR_Y) > 0; // Vertically. for (int r = 0; r < sprite.spritePixels.length; r++) { - for (int c = 0; c < sprite.spritePixels[r].length; c++) { - Sprite.Px px = sprite.spritePixels[r][c]; + int lr = mirrorY ? sprite.spritePixels.length - 1 - r : r; + for (int c = 0; c < sprite.spritePixels[lr].length; c++) { + Sprite.Px px = sprite.spritePixels[lr][mirrorX ? sprite.spritePixels[lr].length - 1 - c : c]; render(xp + c * 8, yp + r * 8, px, mirror, sprite.color, fullbright, color); } } } - public void render(int xp, int yp, Sprite.Px pixel) { render(xp, yp, pixel, -1); } - public void render(int xp, int yp, Sprite.Px pixel, int whiteTint) { render(xp, yp, pixel, 0, whiteTint); } - public void render(int xp, int yp, Sprite.Px pixel, int mirror, int whiteTint) { render(xp, yp, pixel, mirror, whiteTint, false); } - public void render(int xp, int yp, Sprite.Px pixel, int mirror, int whiteTint, boolean fullbright) { render(xp, yp, pixel, mirror, whiteTint, fullbright, 0); } + public void render(int xp, int yp, Sprite.Px pixel) { + render(xp, yp, pixel, -1); + } + + public void render(int xp, int yp, Sprite.Px pixel, int whiteTint) { + render(xp, yp, pixel, 0, whiteTint); + } + + public void render(int xp, int yp, Sprite.Px pixel, int mirror, int whiteTint) { + render(xp, yp, pixel, mirror, whiteTint, false); + } + + public void render(int xp, int yp, Sprite.Px pixel, int mirror, int whiteTint, boolean fullbright) { + render(xp, yp, pixel, mirror, whiteTint, fullbright, 0); + } + public void render(int xp, int yp, Sprite.Px pixel, int mirror, int whiteTint, boolean fullbright, int color) { render(xp, yp, pixel.x, pixel.y, pixel.mirror ^ mirror, pixel.sheet, whiteTint, fullbright, color); } - /** Renders an object from the sprite sheet based on screen coordinates, tile (SpriteSheet location), colors, and bits (for mirroring). I believe that xp and yp refer to the desired position of the upper-left-most pixel. */ - public void render(int xp, int yp, int xt, int yt, int bits, MinicraftImage sheet, int whiteTint, boolean fullbright, int color) { + /** + * Renders an object from the sprite sheet based on screen coordinates, tile (SpriteSheet location), colors, and bits (for mirroring). I believe that xp and yp refer to the desired position of the upper-left-most pixel. + */ + public void render(int xp, int yp, int xt, int yt, int bits, MinicraftImage sheet, int whiteTint, boolean fullbright, int color) { if (sheet == null) return; // Verifying that sheet is not null. // xp and yp are originally in level coordinates, but offset turns them to screen coordinates. - xp -= xOffset; //account for screen offset - yp -= yOffset; + // xOffset and yOffset account for screen offset + render(xp - xOffset, yp - yOffset, xt * 8, yt * 8, 8, 8, sheet, bits, whiteTint, fullbright, color); + } - // Determines if the image should be mirrored... - boolean mirrorX = (bits & BIT_MIRROR_X) > 0; // Horizontally. - boolean mirrorY = (bits & BIT_MIRROR_Y) > 0; // Vertically. + public void render(int xp, int yp, int xt, int yt, int tw, int th, MinicraftImage sheet) { + render(xp, yp, xt, yt ,tw, th, sheet, 0); + } + public void render(int xp, int yp, int xt, int yt, int tw, int th, MinicraftImage sheet, int mirrors) { + render(xp, yp, xt, yt ,tw, th, sheet, mirrors, -1); + } + public void render(int xp, int yp, int xt, int yt, int tw, int th, MinicraftImage sheet, int mirrors, int whiteTint) { + render(xp, yp, xt, yt, tw, th, sheet, mirrors, whiteTint, false); + } + public void render(int xp, int yp, int xt, int yt, int tw, int th, MinicraftImage sheet, int mirrors, int whiteTint, boolean fullbright) { + render(xp, yp, xt, yt, tw, th, sheet, mirrors, whiteTint, fullbright, 0); + } + // Any single pixel from the image can be rendered using this method. + public void render(int xp, int yp, int xt, int yt, int tw, int th, MinicraftImage sheet, int mirrors, int whiteTint, boolean fullBright, int color) { + if (sheet == null) return; // Verifying that sheet is not null. // Validation check - if (sheet == null || xt * 8 + yt * 8 * sheet.width + 7 + 7 * sheet.width >= sheet.pixels.length) { - sheet = Renderer.spriteLinker.missingSheet(SpriteType.Item); - xt = 0; - yt = 0; + if (xt + tw > sheet.width && yt + th > sheet.height) { + render(xp, yp, 0, 0, mirrors, Renderer.spriteLinker.missingSheet(SpriteType.Item)); + return; } - int xTile = xt; // Gets x position of the spritesheet "tile" - int yTile = yt; // Gets y position - int toffs = xTile * 8 + yTile * 8 * sheet.width; // Gets the offset of the sprite into the spritesheet pixel array, the 8's represent the size of the box. (8 by 8 pixel sprite boxes) - - // THIS LOOPS FOR EVERY PIXEL - for (int y = 0; y < 8; y++) { // Loops 8 times (because of the height of the tile) - int ys = y; // Current y pixel - if (mirrorY) ys = 7 - y; // Reverses the pixel for a mirroring effect - if (y + yp < 0 || y + yp >= h) continue; // If the pixel is out of bounds, then skip the rest of the loop. - for (int x = 0; x < 8; x++) { // Loops 8 times (because of the width of the tile) - if (x + xp < 0 || x + xp >= w) continue; // Skip rest if out of bounds. - - int xs = x; // Current x pixel - if (mirrorX) xs = 7 - x; // Reverses the pixel for a mirroring effect + queue(new SpriteRendering(xp, yp, xt, yt, tw, th, mirrors, whiteTint, fullBright, color, sheet)); + } - int col = sheet.pixels[toffs + xs + ys * sheet.width]; // Gets the color of the current pixel from the value stored in the sheet. + public void fillRect(int xp, int yp, int w, int h, int color) { + queue(new FillRectRendering(xp, yp, w, h, color)); + } - boolean isTransparent = (col >> 24 == 0); + public void drawRect(int xp, int yp, int w, int h, int color) { + queue(new DrawRectRendering(xp, yp, w, h, color)); + } - if (!isTransparent) { - int index = (x + xp) + (y + yp) * w; + /** + * Draw a straight line along an axis. + * @param axis The axis to draw along: {@code 0} for x-axis; {@code 1} for y-axis + * @param l The length of the line + */ + public void drawAxisLine(int xp, int yp, @MagicConstant(intValues = {0, 1}) int axis, int l, int color) { + switch (axis) { + case 0: queue(new DrawLineRendering(xp, yp, xp + l, yp, color)); break; + case 1: queue(new DrawLineRendering(xp, yp, xp, yp + l, color)); break; + } + } - if (whiteTint != -1 && col == 0x1FFFFFF) { - // If this is white, write the whiteTint over it - pixels[index] = Color.upgrade(whiteTint); - } else { - // Inserts the colors into the image - if (fullbright) { - pixels[index] = Color.WHITE; - } else { - if (color != 0) { + public void drawLine(int x0, int y0, int x1, int y1, int color) { + queue(new DrawLineRendering(x0, y0, x1, y1, color)); + } - pixels[index] = color; - } else { - pixels[index] = Color.upgrade(col); - } - } - } - } - } - } + /** Placeholder line drawing method specialized for sign cursor drawing */ + public void drawLineSpecial(int x0, int y0, @MagicConstant(intValues = {0, 1}) int axis, int l) { + queue(new DrawLineSpecialRendering(x0, y0, l, axis)); } - /** Sets the offset of the screen */ + /** + * Sets the offset of the screen + */ public void setOffset(int xOffset, int yOffset) { // This is called in few places, one of which is level.renderBackground, right before all the tiles are rendered. The offset is determined by the Game class (this only place renderBackground is called), by using the screen's width and the player's position in the level. // In other words, the offset is a conversion factor from level coordinates to screen coordinates. It makes a certain coord in the level the upper left corner of the screen, when subtracted from the tile coord. @@ -147,86 +430,143 @@ public void setOffset(int xOffset, int yOffset) { In the end, "every other every row", will need, for example in column 1, 15 light to be lit, then 0 light to be lit, then 12 light to be lit, then 3 light to be lit. So, the pixels of lower light levels will generally be lit every other pixel, while the brighter ones appear more often. The reason for the variance in values is to provide EVERY number between 0 and 15, so that all possible light levels (below 16) are represented fittingly with their own pattern of lit and not lit. 16 is the minimum pixel lighness required to ensure that the pixel will always remain lit. */ - private static final int[] dither = new int[] { - 0, 8, 2, 10, - 12, 4, 14, 6, - 3, 11, 1, 9, - 15, 7, 13, 5 - }; - - /** Overlays the screen with pixels */ - public void overlay(Screen screen2, int currentLevel, int xa, int ya) { - double tintFactor = 0; + + /** + * Overlays the screen with pixels + */ + public void overlay(int currentLevel, int xa, int ya) { + double darkFactor = 0; if (currentLevel >= 3 && currentLevel < 5) { int transTime = Updater.dayLength / 4; double relTime = (Updater.tickCount % transTime) * 1.0 / transTime; switch (Updater.getTime()) { - case Morning: tintFactor = Updater.pastDay1 ? (1-relTime) * MAXDARK : 0; break; - case Day: tintFactor = 0; break; - case Evening: tintFactor = relTime * MAXDARK; break; - case Night: tintFactor = MAXDARK; break; + case Morning: + darkFactor = Updater.pastDay1 ? (1 - relTime) * MAXDARK : 0; + break; + case Day: + darkFactor = 0; + break; + case Evening: + darkFactor = relTime * MAXDARK; + break; + case Night: + darkFactor = MAXDARK; + break; } - if (currentLevel > 3) tintFactor -= (tintFactor < 10 ? tintFactor : 10); - tintFactor *= -1; // All previous operations were assuming this was a darkening factor. - } - else if(currentLevel >= 5) - tintFactor = -MAXDARK; - - int[] oPixels = screen2.pixels; // The Integer array of pixels to overlay the screen with. - int i = 0; // Current pixel on the screen - for (int y = 0; y < h; y++) { // loop through height of screen - for (int x = 0; x < w; x++) { // loop through width of screen - if (oPixels[i] / 10 <= dither[((x + xa) & 3) + ((y + ya) & 3) * 4]) { - - /// The above if statement is simply comparing the light level stored in oPixels with the minimum light level stored in dither. if it is determined that the oPixels[i] is less than the minimum requirements, the pixel is considered "dark", and the below is executed... - if (currentLevel < 3) { // if in caves... - /// in the caves, not being lit means being pitch black. - pixels[i] = 0; - } else { - /// Outside the caves, not being lit simply means being darker. - pixels[i] = Color.tintColor(pixels[i], (int)tintFactor); // darkens the color one shade. - } - } - - // Increase the tinting of all colors by 20. - pixels[i] = Color.tintColor(pixels[i], 20); - i++; // Moves to the next pixel. - } - } - } + if (currentLevel > 3) darkFactor -= (darkFactor < 10 ? darkFactor : 10); + } else if (currentLevel >= 5) + darkFactor = MAXDARK; + + // The Integer array of pixels to overlay the screen with. + queue(new OverlayRendering(currentLevel, xa, ya, darkFactor)); + } public void renderLight(int x, int y, int r) { // Applies offsets: - x -= xOffset; - y -= yOffset; - // Starting, ending, x, y, positions of the circle (of light) - int x0 = x - r; - int x1 = x + r; - int y0 = y - r; - int y1 = y + r; - - // Prevent light from rendering off the screen: - if (x0 < 0) x0 = 0; - if (y0 < 0) y0 = 0; - if (x1 > w) x1 = w; - if (y1 > h) y1 = h; - - for (int yy = y0; yy < y1; yy++) { // Loop through each y position - int yd = yy - y; // Get distance to the previous y position. - yd = yd * yd; // Square that distance - for (int xx = x0; xx < x1; xx++) { // Loop though each x pos - int xd = xx - x; // Get x delta - int dist = xd * xd + yd; // Square x delta, then add the y delta, to get total distance. - - if (dist <= r * r) { - // If the distance from the center (x,y) is less or equal to the radius... - int br = 255 - dist * 255 / (r * r); // area where light will be rendered. // r*r is becuase dist is still x*x+y*y, of pythag theorem. - // br = brightness... literally. from 0 to 255. - if (pixels[xx + yy * w] < br) pixels[xx + yy * w] = br; // Pixel cannot be smaller than br; in other words, the pixel color (brightness) cannot be less than br. + lightOverlay.renderLight(x - xOffset, y - yOffset, r); + } + + private static class LightOverlay { + private static final int[] dither = new int[] { + 0, 8, 2, 10, + 12, 4, 14, 6, + 3, 11, 1, 9, + 15, 7, 13, 5 + }; + + public final float[] graFractions; + public final java.awt.Color[] graColors; + public final BufferedImage buffer = new BufferedImage(w, h, BufferedImage.TYPE_BYTE_GRAY); + public final byte[] bufPixels; + public final BufferedImage overlay = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); + public final int[] olPixels; + public final HashMap<@NotNull Point, @NotNull Integer> lights = new HashMap<>(); + + public LightOverlay() { + bufPixels = ((DataBufferByte) buffer.getRaster().getDataBuffer()).getData(); + olPixels = ((DataBufferInt) overlay.getRaster().getDataBuffer()).getData(); + ArrayList graFractions = new ArrayList<>(); + ArrayList graColors = new ArrayList<>(); + BigDecimal oneFiftieth = BigDecimal.ONE.divide(BigDecimal.valueOf(50), MathContext.UNLIMITED); + BigDecimal twoFiveFive = BigDecimal.valueOf(255); + for (BigDecimal i = BigDecimal.ZERO; i.compareTo(BigDecimal.ONE) <= 0; i = i.add(oneFiftieth)) { + graFractions.add(i.floatValue()); + graColors.add(new java.awt.Color(255, 255, 255, 255 - i.pow(4).multiply(twoFiveFive).intValue())); + } + this.graFractions = new float[graFractions.size()]; + for (int i = 0; i < graFractions.size(); ++i) this.graFractions[i] = graFractions.get(i); + this.graColors = graColors.toArray(new java.awt.Color[0]); + } + + /** + * Gets the overlay light darkness opacity instantly. + * @param currentLevel the current level index of the target + * @param darkFactor the tint factor to darken, from {@code 1} to {@code 128} + * @return opacity of darkness from {@code 0} to {@code 1} + */ + public double getOverlayOpacity(int currentLevel, double darkFactor) { + // The above if statement is simply comparing the light level stored in oPixels with the minimum light level stored in dither. if it is determined that the oPixels[i] is less than the minimum requirements, the pixel is considered "dark", and the below is executed... + if (currentLevel < 3) { // if in caves... + // in the caves, not being lit means being pitch black. + return 1; + } else { + // Outside the caves, not being lit simply means being darker. + return darkFactor / 128; // darkens the color one shade. + } + } + + public void renderLight(int x, int y, int r) { + lights.put(new Point(x, y), r); + } + + public BufferedImage render(int xa, int ya) { + Graphics2D g2d = buffer.createGraphics(); + g2d.setBackground(java.awt.Color.BLACK); + g2d.clearRect(0, 0, w, h); + for (Map.Entry e : lights.entrySet()) { + int x = e.getKey().x, y = e.getKey().y, r = e.getValue(); + boolean[] surrounds = new boolean[8]; + for (int xx = -16; xx < 17; ++xx) { + for (int yy = -16; yy < 17; ++yy) { + if (xx != 0 || yy != 0) { + Point pp = new Point(x + xx, y + yy); + if (lights.containsKey(pp) && r <= lights.get(pp)) { + double theta = Math.atan2(yy, xx); + if (theta < 0) theta += 2 * Math.PI; // Ensures it is positive. + surrounds[(int) (theta * 4 / Math.PI)] = true; + } + } + } + } + + // Reduce lighting circles on screen + if (IntStream.range(0, surrounds.length).allMatch(i -> surrounds[i])) { + g2d.setColor(java.awt.Color.WHITE); + g2d.fillRect(x - 8, y - 8, 16, 16); + } else { + g2d.setPaint(new RadialGradientPaint(x, y, r, graFractions, graColors)); + g2d.fillOval(x - r, y - r, r * 2, r * 2); + } + } + g2d.dispose(); + lights.clear(); + + for (int x = 0; x < w; ++x) { + for (int y = 0; y < h; ++y) { + int i = x + y * w; + // Grade of lightness + int grade = bufPixels[i] & 0xFF; + // (a + b) & 3 acts like (a + b) % 4 + if (grade / 10 <= dither[((x + xa) & 3) + ((y + ya) & 3) * 4]) { + olPixels[i] = (255 - grade) << 24; + } else { + olPixels[i] = 0; + } } } + return overlay; } } } diff --git a/src/client/java/minicraft/gfx/Sprite.java b/src/client/java/minicraft/gfx/Sprite.java index c913a82f3..e5484cf88 100644 --- a/src/client/java/minicraft/gfx/Sprite.java +++ b/src/client/java/minicraft/gfx/Sprite.java @@ -1,15 +1,17 @@ package minicraft.gfx; -/** This class represents a group of pixels on their sprite sheet(s). */ +/** + * This class represents a group of pixels on their sprite sheet(s). + */ public class Sprite { /** - This class needs to store a list of similar segments that make up a sprite, just once for everything. There's usually four groups, but the components are: - -spritesheet location (x, y) - -mirror type - - That's it! - The screen's render method only draws one 8x8 pixel of the spritesheet at a time, so the "sprite size" will be determined by how many repetitions of the above group there are. - */ + * This class needs to store a list of similar segments that make up a sprite, just once for everything. There's usually four groups, but the components are: + * -spritesheet location (x, y) + * -mirror type + *

+ * That's it! + * The screen's render method only draws one 8x8 pixel of the spritesheet at a time, so the "sprite size" will be determined by how many repetitions of the above group there are. + */ public Px[][] spritePixels; public int color = -1; @@ -21,15 +23,17 @@ public Sprite(Px[][] pixels) { public String toString() { StringBuilder out = new StringBuilder(getClass().getName().replace("minicraft.gfx.", "") + "; pixels:"); - for (Px[] row: spritePixels) - for (Px pixel: row) + for (Px[] row : spritePixels) + for (Px pixel : row) out.append("\n").append(pixel.toString()); out.append("\n"); return out.toString(); } - /** This class represents a pixel on the sprite sheet. */ + /** + * This class represents a pixel on the sprite sheet. + */ public static class Px { protected int x, y, mirror; protected MinicraftImage sheet; diff --git a/src/client/java/minicraft/gfx/SpriteAnimation.java b/src/client/java/minicraft/gfx/SpriteAnimation.java index 3b5782676..7df098a68 100644 --- a/src/client/java/minicraft/gfx/SpriteAnimation.java +++ b/src/client/java/minicraft/gfx/SpriteAnimation.java @@ -15,9 +15,10 @@ import java.util.ArrayList; import java.util.HashMap; -import java.util.function.BiFunction; -/** This is not applicable for mob sprite animations. Only for generic sprite animations. */ +/** + * This is not applicable for mob sprite animations. Only for generic sprite animations. + */ public class SpriteAnimation implements Destroyable { private static final ArrayList spriteAnimations = new ArrayList<>(); private static final HashMap metas = new HashMap<>(); @@ -34,7 +35,9 @@ public static SpriteMeta getMetadata(String key) { return metas.get(key); } - /** Refreshing all currently registered animations. */ + /** + * Refreshing all currently registered animations. + */ public static void refreshAnimations() { spriteAnimations.forEach(a -> a.refreshAnimation(metas.get(a.key))); } @@ -50,7 +53,7 @@ public static void refreshAnimations() { // Border settings. private LinkedSprite border = null; private LinkedSprite corner = null; - private BiFunction connectChecker; + private TileConnectionChecker connectionChecker; private boolean singletonWithConnective = false; // Refreshing only data. @@ -62,7 +65,10 @@ public static void refreshAnimations() { * @param type The sprite category. * @param key The sprite resource key. */ - public SpriteAnimation(SpriteType type, String key) { this(metas.get(key), type, key); } + public SpriteAnimation(SpriteType type, String key) { + this(metas.get(key), type, key); + } + /** * Constructing animations with the provided metadata and key. It should already be validated. * @param meta The metadata of the sprite sheet. @@ -77,13 +83,18 @@ public SpriteAnimation(SpriteMeta meta, SpriteType type, String key) { spriteAnimations.add(this); } + @FunctionalInterface + public interface TileConnectionChecker { + boolean check(Level level, int x, int y, Tile tile, boolean side); + } + /** * Setting the tile class of this animation used for tile connector rendering. - * @param connectChecker The tile connection checker. + * @param connectionChecker The tile connection checker. * @return The instance itself. */ - public SpriteAnimation setConnectChecker(BiFunction connectChecker) { - this.connectChecker = connectChecker; + public SpriteAnimation setConnectionChecker(TileConnectionChecker connectionChecker) { + this.connectionChecker = connectionChecker; return this; } @@ -187,16 +198,16 @@ public LinkedSprite getFrame(int frame) { */ public void render(Screen screen, Level level, int x, int y) { // If border and the tile class is set. - if (connectChecker != null && (border != null || corner != null)) { - boolean u = connectChecker.apply(level.getTile(x, y - 1), true); - boolean d = connectChecker.apply(level.getTile(x, y + 1), true); - boolean l = connectChecker.apply(level.getTile(x - 1, y), true); - boolean r = connectChecker.apply(level.getTile(x + 1, y), true); + if (connectionChecker != null && (border != null || corner != null)) { + boolean u = connectionChecker.check(level, x, y - 1, level.getTile(x, y - 1), true); + boolean d = connectionChecker.check(level, x, y + 1, level.getTile(x, y + 1), true); + boolean l = connectionChecker.check(level, x - 1, y, level.getTile(x - 1, y), true); + boolean r = connectionChecker.check(level, x + 1, y, level.getTile(x + 1, y), true); - boolean ul = connectChecker.apply(level.getTile(x - 1, y - 1), false); - boolean dl = connectChecker.apply(level.getTile(x - 1, y + 1), false); - boolean ur = connectChecker.apply(level.getTile(x + 1, y - 1), false); - boolean dr = connectChecker.apply(level.getTile(x + 1, y + 1), false); + boolean ul = connectionChecker.check(level, x - 1, y - 1, level.getTile(x - 1, y - 1), false); + boolean dl = connectionChecker.check(level, x - 1, y + 1, level.getTile(x - 1, y + 1), false); + boolean ur = connectionChecker.check(level, x + 1, y - 1, level.getTile(x + 1, y - 1), false); + boolean dr = connectionChecker.check(level, x + 1, y + 1, level.getTile(x + 1, y + 1), false); x = x << 4; y = y << 4; @@ -266,14 +277,16 @@ public void render(Screen screen, Level level, int x, int y) { } } - /** Refreshing the animation data for this instance. */ + /** + * Refreshing the animation data for this instance. + */ public void refreshAnimation(SpriteMeta metadata) { frame = 0; frametick = 0; this.metadata = metadata; MinicraftImage sheet = Renderer.spriteLinker.getSheet(type, key); if (sheet == null) { - animations = new LinkedSprite[] {SpriteLinker.missingTexture(type)}; + animations = new LinkedSprite[] { SpriteLinker.missingTexture(type) }; border = null; corner = null; return; @@ -301,7 +314,7 @@ public void refreshAnimation(SpriteMeta metadata) { if (metadata.border != null) border = new LinkedSprite(type, metadata.border); if (metadata.corner != null) corner = new LinkedSprite(type, metadata.corner); } else { - animations = new LinkedSprite[] {new LinkedSprite(type, key).setSpriteSize(width, width)}; + animations = new LinkedSprite[] { new LinkedSprite(type, key).setSpriteSize(width, width) }; border = null; corner = null; } diff --git a/src/client/java/minicraft/gfx/SpriteLinker.java b/src/client/java/minicraft/gfx/SpriteLinker.java index cd987ac6f..fd3badbbd 100644 --- a/src/client/java/minicraft/gfx/SpriteLinker.java +++ b/src/client/java/minicraft/gfx/SpriteLinker.java @@ -10,14 +10,20 @@ import java.util.HashMap; public class SpriteLinker { - /** Buffering SpriteSheet for caching. */ + /** + * Buffering SpriteSheet for caching. + */ private final HashMap entitySheets = new HashMap<>(), - guiSheets = new HashMap<>(), itemSheets = new HashMap<>(), tileSheets = new HashMap<>(); + guiSheets = new HashMap<>(), itemSheets = new HashMap<>(), tileSheets = new HashMap<>(); - /** Storing all exist in-used LinkedSprite. */ + /** + * Storing all exist in-used LinkedSprite. + */ private final ArrayList linkedSheets = new ArrayList<>(); - /** Clearing all Sprite buffers for the upcoming resource pack application. */ + /** + * Clearing all Sprite buffers for the upcoming resource pack application. + */ public void resetSprites() { entitySheets.clear(); guiSheets.clear(); @@ -34,10 +40,18 @@ public void resetSprites() { */ public void setSprite(SpriteType t, String key, MinicraftImage spriteSheet) { switch (t) { - case Entity: entitySheets.put(key, spriteSheet); break; - case Gui: guiSheets.put(key, spriteSheet); break; - case Item: itemSheets.put(key, spriteSheet); break; - case Tile: tileSheets.put(key, spriteSheet); break; + case Entity: + entitySheets.put(key, spriteSheet); + break; + case Gui: + guiSheets.put(key, spriteSheet); + break; + case Item: + itemSheets.put(key, spriteSheet); + break; + case Tile: + tileSheets.put(key, spriteSheet); + break; } } @@ -49,16 +63,22 @@ public void setSprite(SpriteType t, String key, MinicraftImage spriteSheet) { */ public MinicraftImage getSheet(SpriteType t, String key) { switch (t) { - case Entity: return entitySheets.get(key); - case Gui: return guiSheets.get(key); - case Item: return itemSheets.get(key); - case Tile: return tileSheets.get(key); + case Entity: + return entitySheets.get(key); + case Gui: + return guiSheets.get(key); + case Item: + return itemSheets.get(key); + case Tile: + return tileSheets.get(key); } return null; } - /** Cleaing all skin sheets in entity sheets. */ + /** + * Cleaing all skin sheets in entity sheets. + */ public void clearSkins() { for (String k : new ArrayList<>(entitySheets.keySet())) { if (k.startsWith("skin.")) entitySheets.remove(k); @@ -81,10 +101,14 @@ public void setSkin(String key, MinicraftImage spriteSheet) { */ public static LinkedSprite missingTexture(SpriteType type) { switch (type) { - case Entity: return new LinkedSprite(SpriteType.Entity, "missing_entity"); - case Item: return new LinkedSprite(SpriteType.Item, "missing_item"); - case Tile: return new LinkedSprite(SpriteType.Tile, "missing_tile"); - default: return null; + case Entity: + return new LinkedSprite(SpriteType.Entity, "missing_entity"); + case Item: + return new LinkedSprite(SpriteType.Item, "missing_item"); + case Tile: + return new LinkedSprite(SpriteType.Tile, "missing_tile"); + default: + return null; } } @@ -95,29 +119,43 @@ public static LinkedSprite missingTexture(SpriteType type) { */ public MinicraftImage missingSheet(SpriteType type) { switch (type) { // The sheets should be found. - case Entity: return entitySheets.get("missing_entity"); - case Item: return itemSheets.get("missing_item"); - case Tile: return tileSheets.get("missing_tile"); - default: return null; + case Entity: + return entitySheets.get("missing_entity"); + case Item: + return itemSheets.get("missing_item"); + case Tile: + return tileSheets.get("missing_tile"); + default: + return null; } } - /** Updating all existing LinkedSheet for resource pack application. */ + /** + * Updating all existing LinkedSheet for resource pack application. + */ public void updateLinkedSheets() { Logging.SPRITE.debug("Updating all LinkedSprite."); linkedSheets.forEach(s -> s.reload()); } - /** The metadata of the sprite sheet. */ + /** + * The metadata of the sprite sheet. + */ public static class SpriteMeta { - /** The sprite animation configuration. */ + /** + * The sprite animation configuration. + */ public int frames = 1, // Minimum with 1. - frametime = 0; // 0 if no animation. - /** The sprite connector configuration. */ + frametime = 0; // 0 if no animation. + /** + * The sprite connector configuration. + */ public String border = null, corner = null; } - /** The sprite categories in the image resources. TODO Removed for the new save system */ + /** + * The sprite categories in the image resources. TODO Removed for the new save system + */ public static enum SpriteType { Item, Gui, Tile, Entity; // Only for resource packs; Skin is not applied. } @@ -130,18 +168,30 @@ public static enum SpriteType { public void linkSpriteSheet(LinkedSprite sheet, SpriteType type) { // Because of the private access. switch (type) { - case Entity: sheet.linkedMap = Renderer.spriteLinker.entitySheets; break; - case Gui: sheet.linkedMap = Renderer.spriteLinker.guiSheets; break; - case Item: sheet.linkedMap = Renderer.spriteLinker.itemSheets; break; - case Tile: sheet.linkedMap = Renderer.spriteLinker.tileSheets; break; + case Entity: + sheet.linkedMap = Renderer.spriteLinker.entitySheets; + break; + case Gui: + sheet.linkedMap = Renderer.spriteLinker.guiSheets; + break; + case Item: + sheet.linkedMap = Renderer.spriteLinker.itemSheets; + break; + case Tile: + sheet.linkedMap = Renderer.spriteLinker.tileSheets; + break; } } - /** A sprite collector with resource collector. */ + /** + * A sprite collector with resource collector. + */ public static class LinkedSprite implements Destroyable { private final String key; // The resource key. - /** The sprite configuration. */ + /** + * The sprite configuration. + */ private int x, y, w, h, color = -1, mirror = 0, flip = 0; // Sprite data. @@ -183,6 +233,7 @@ public LinkedSprite setSpriteSize(int w, int h) { reloaded = false; // Reload this. return this; } + /** * Setting the sprite position. * @param x The x position of the sprite. @@ -195,6 +246,7 @@ public LinkedSprite setSpritePos(int x, int y) { reloaded = false; // Reload this. return this; } + /** * Setting the sprite position and size. * @param x The x position of the sprite. @@ -209,6 +261,7 @@ public LinkedSprite setSpriteDim(int x, int y, int w, int h) { reloaded = false; // Reload this. return this; } + /** * Setting the white tint. * @param color The color of the white tint. @@ -219,6 +272,7 @@ public LinkedSprite setColor(int color) { reloaded = false; // Reload this. return this; } + /** * Setting the mirror of the sprite. * @param mirror The mirror of the sprite. @@ -229,6 +283,7 @@ public LinkedSprite setMirror(int mirror) { reloaded = false; // Reload this. return this; } + /** * Setting the flip of the sprite sheet. * @param flip The mirror of the sprite sheet. @@ -252,9 +307,16 @@ public Sprite getSprite() { return sprite; } - /** Requiring the sprite to be reloaded when the next time generated. */ - public void reload() { reloaded = false; } - /** Reloading the sprite with the configuration. */ + /** + * Requiring the sprite to be reloaded when the next time generated. + */ + public void reload() { + reloaded = false; + } + + /** + * Reloading the sprite with the configuration. + */ private void reloadSprite() { MinicraftImage sheet = linkedMap.get(key); if (sheet != null) { @@ -267,8 +329,8 @@ private void reloadSprite() { for (int r = 0; r < h; r++) { for (int c = 0; c < w; c++) { // The offsets are there to determine the pixel that will be there: the one in order, or on the opposite side. - int xOffset = flipX ? w-1 - c : c; - int yOffset = flipY ? h-1 - r : r; + int xOffset = flipX ? w - 1 - c : c; + int yOffset = flipY ? h - 1 - r : r; pixels[r][c] = new Sprite.Px(x + xOffset, y + yOffset, mirror, sheet); } } @@ -283,13 +345,18 @@ private void reloadSprite() { reloaded = true; } - /** Unlink this LinkedSprite from SpriteLinker. */ + /** + * Unlink this LinkedSprite from SpriteLinker. + */ @Override public void destroy() throws DestroyFailedException { Renderer.spriteLinker.linkedSheets.remove(this); // Unlink this instance. destoryed = true; } - /** If this LinkedSprite is unlinked from SpriteLinker. */ + + /** + * If this LinkedSprite is unlinked from SpriteLinker. + */ @Override public boolean isDestroyed() { return destoryed; diff --git a/src/client/java/minicraft/item/ArmorItem.java b/src/client/java/minicraft/item/ArmorItem.java index 430fc3b85..80304ef3f 100644 --- a/src/client/java/minicraft/item/ArmorItem.java +++ b/src/client/java/minicraft/item/ArmorItem.java @@ -28,7 +28,10 @@ protected static ArrayList getAllInstances() { private final int staminaCost; public final int level; - private ArmorItem(String name, LinkedSprite sprite, float health, int level) { this(name, sprite, 1, health, level); } + private ArmorItem(String name, LinkedSprite sprite, float health, int level) { + this(name, sprite, 1, health, level); + } + private ArmorItem(String name, LinkedSprite sprite, int count, float health, int level) { super(name, sprite, count); this.armor = health; @@ -48,7 +51,9 @@ public boolean interactOn(Tile tile, Level level, int xt, int yt, Player player, } @Override - public boolean interactsWithWorld() { return false; } + public boolean interactsWithWorld() { + return false; + } public @NotNull ArmorItem copy() { return new ArmorItem(getName(), sprite, count, armor, level); diff --git a/src/client/java/minicraft/item/BookItem.java b/src/client/java/minicraft/item/BookItem.java index f5f1c911c..2a3b8bf4d 100644 --- a/src/client/java/minicraft/item/BookItem.java +++ b/src/client/java/minicraft/item/BookItem.java @@ -1,6 +1,7 @@ package minicraft.item; import minicraft.core.Game; +import minicraft.core.io.Localization; import minicraft.entity.Direction; import minicraft.entity.mob.Player; import minicraft.gfx.SpriteLinker.LinkedSprite; @@ -17,7 +18,7 @@ public class BookItem extends Item { protected static ArrayList getAllInstances() { ArrayList items = new ArrayList(); - items.add(new BookItem("Book", new LinkedSprite(SpriteType.Item, "book"), null)); + items.add(new BookItem("Book", new LinkedSprite(SpriteType.Item, "book"), () -> Localization.getLocalized("minicraft.displays.book.default_book"))); items.add(new BookItem("Antidious", new LinkedSprite(SpriteType.Item, "antidious_book"), () -> BookData.antVenomBook.collect(), true)); return items; } @@ -30,7 +31,10 @@ public static interface BookContent { protected BookContent book; // TODO this is not saved yet; it could be, for editable books. private final boolean hasTitlePage; - private BookItem(String title, LinkedSprite sprite, BookContent book) { this(title, sprite, book, false); } + private BookItem(String title, LinkedSprite sprite, BookContent book) { + this(title, sprite, book, false); + } + private BookItem(String title, LinkedSprite sprite, BookContent book, boolean hasTitlePage) { super(title, sprite); this.book = book; @@ -43,7 +47,9 @@ public boolean interactOn(Tile tile, Level level, int xt, int yt, Player player, } @Override - public boolean interactsWithWorld() { return false; } + public boolean interactsWithWorld() { + return false; + } public @NotNull BookItem copy() { return new BookItem(getName(), sprite, book, hasTitlePage); diff --git a/src/client/java/minicraft/item/BucketItem.java b/src/client/java/minicraft/item/BucketItem.java index 81e8ad6f1..608c6e8c2 100644 --- a/src/client/java/minicraft/item/BucketItem.java +++ b/src/client/java/minicraft/item/BucketItem.java @@ -15,9 +15,9 @@ public class BucketItem extends StackableItem { public enum Fill { - Empty (Tiles.get("hole"), 2), - Water (Tiles.get("water"), 0), - Lava (Tiles.get("lava"), 1); + Empty(Tiles.get("hole"), 2), + Water(Tiles.get("water"), 0), + Lava(Tiles.get("lava"), 1); public Tile contained; public int offset; @@ -31,14 +31,14 @@ public enum Fill { protected static ArrayList getAllInstances() { ArrayList items = new ArrayList<>(); - for (Fill fill: Fill.values()) + for (Fill fill : Fill.values()) items.add(new BucketItem(fill)); return items; } private static Fill getFilling(Tile tile) { - for (Fill fill: Fill.values()) + for (Fill fill : Fill.values()) if (fill.contained.id == tile.id) return fill; @@ -47,7 +47,10 @@ private static Fill getFilling(Tile tile) { private Fill filling; - private BucketItem(Fill fill) { this(fill, 1); } + private BucketItem(Fill fill) { + this(fill, 1); + } + private BucketItem(Fill fill, int count) { super(fill.toString() + " Bucket", new LinkedSprite(SpriteType.Item, fill == Fill.Empty ? "bucket" : fill == Fill.Lava ? "lava_bucket" : "water_bucket"), count); @@ -61,11 +64,13 @@ public boolean interactOn(Tile tile, Level level, int xt, int yt, Player player, if (filling != Fill.Empty) { if (fill == Fill.Empty) { level.setTile(xt, yt, filling.contained); - if (!Game.isMode("minicraft.settings.mode.creative")) player.activeItem = editBucket(player, Fill.Empty); + if (!Game.isMode("minicraft.settings.mode.creative")) + player.activeItem = editBucket(player, Fill.Empty); return true; } else if (fill == Fill.Lava && filling == Fill.Water) { level.setTile(xt, yt, Tiles.get("Obsidian")); - if (!Game.isMode("minicraft.settings.mode.creative")) player.activeItem = editBucket(player, Fill.Empty); + if (!Game.isMode("minicraft.settings.mode.creative")) + player.activeItem = editBucket(player, Fill.Empty); return true; } } else { // This is an empty bucket @@ -77,25 +82,27 @@ public boolean interactOn(Tile tile, Level level, int xt, int yt, Player player, return false; } - /** This method exists due to the fact that buckets are stackable, but only one should be changed at one time. */ + /** + * This method exists due to the fact that buckets are stackable, but only one should be changed at one time. + */ private BucketItem editBucket(Player player, Fill newFill) { if (count == 0) return null; // This honestly should never happen... if (count == 1) return new BucketItem(newFill); // This item object is a stack of buckets. count--; - if (player.getInventory().add(new BucketItem(newFill)) == 0) { - player.getLevel().dropItem(player.x, player.y, new BucketItem(newFill)); - } + player.tryAddToInvOrDrop(new BucketItem(newFill)); return this; } public boolean equals(Item other) { - return super.equals(other) && filling == ((BucketItem)other).filling; + return super.equals(other) && filling == ((BucketItem) other).filling; } @Override - public int hashCode() { return super.hashCode() + filling.offset * 31; } + public int hashCode() { + return super.hashCode() + filling.offset * 31; + } public @NotNull BucketItem copy() { return new BucketItem(filling, count); diff --git a/src/client/java/minicraft/item/ClothingItem.java b/src/client/java/minicraft/item/ClothingItem.java index b453ffacf..49711a92a 100644 --- a/src/client/java/minicraft/item/ClothingItem.java +++ b/src/client/java/minicraft/item/ClothingItem.java @@ -1,5 +1,6 @@ package minicraft.item; +import minicraft.core.Game; import minicraft.entity.Direction; import minicraft.entity.mob.Player; import minicraft.gfx.Color; @@ -18,20 +19,23 @@ protected static ArrayList getAllInstances() { items.add(new ClothingItem("Red Clothes", new LinkedSprite(SpriteType.Item, "red_clothes"), Color.get(1, 204, 0, 0))); items.add(new ClothingItem("Blue Clothes", new LinkedSprite(SpriteType.Item, "blue_clothes"), Color.get(1, 0, 0, 204))); - items.add(new ClothingItem("Green Clothes", new LinkedSprite(SpriteType.Item, "green_clothes"), Color.get(1, 0, 204, 0))); - items.add(new ClothingItem("Yellow Clothes", new LinkedSprite(SpriteType.Item, "yellow_clothes"), Color.get(1, 204, 204, 0))); - items.add(new ClothingItem("Black Clothes", new LinkedSprite(SpriteType.Item, "black_clothes"), Color.get(1, 51))); - items.add(new ClothingItem("Orange Clothes", new LinkedSprite(SpriteType.Item, "orange_clothes"), Color.get(1, 255, 102, 0))); - items.add(new ClothingItem("Purple Clothes", new LinkedSprite(SpriteType.Item, "purple_clothes"), Color.get(1, 102, 0, 153))); - items.add(new ClothingItem("Cyan Clothes", new LinkedSprite(SpriteType.Item, "cyan_clothes"), Color.get(1, 0, 102, 153))); - items.add(new ClothingItem("Reg Clothes", new LinkedSprite(SpriteType.Item, "reg_clothes"), Color.get(1, 51, 51, 0))); + items.add(new ClothingItem("Green Clothes", new LinkedSprite(SpriteType.Item, "green_clothes"), Color.get(1, 0, 204, 0))); + items.add(new ClothingItem("Yellow Clothes", new LinkedSprite(SpriteType.Item, "yellow_clothes"), Color.get(1, 204, 204, 0))); + items.add(new ClothingItem("Black Clothes", new LinkedSprite(SpriteType.Item, "black_clothes"), Color.get(1, 51))); + items.add(new ClothingItem("Orange Clothes", new LinkedSprite(SpriteType.Item, "orange_clothes"), Color.get(1, 255, 102, 0))); + items.add(new ClothingItem("Purple Clothes", new LinkedSprite(SpriteType.Item, "purple_clothes"), Color.get(1, 102, 0, 153))); + items.add(new ClothingItem("Cyan Clothes", new LinkedSprite(SpriteType.Item, "cyan_clothes"), Color.get(1, 0, 102, 153))); + items.add(new ClothingItem("Reg Clothes", new LinkedSprite(SpriteType.Item, "reg_clothes"), Color.get(1, 51, 51, 0))); return items; } private int playerCol; - private ClothingItem(String name, LinkedSprite sprite, int pcol) { this(name, 1, sprite, pcol); } + private ClothingItem(String name, LinkedSprite sprite, int pcol) { + this(name, 1, sprite, pcol); + } + private ClothingItem(String name, int count, LinkedSprite sprite, int pcol) { super(name, sprite, count); playerCol = pcol; @@ -42,20 +46,24 @@ public boolean interactOn(Tile tile, Level level, int xt, int yt, Player player, if (player.shirtColor == playerCol) { return false; } else { - ClothingItem lastClothing = (ClothingItem) getAllInstances().stream().filter(i -> i instanceof ClothingItem && ((ClothingItem) i).playerCol == player.shirtColor) - .findAny().orElse(null); - if (lastClothing == null) - lastClothing = (ClothingItem) Items.get("Reg Clothes"); - lastClothing = lastClothing.copy(); - lastClothing.count = 1; - player.tryAddToInvOrDrop(lastClothing); + if (!Game.isMode("minicraft.settings.mode.creative")) { + ClothingItem lastClothing = (ClothingItem) getAllInstances().stream().filter(i -> i instanceof ClothingItem && ((ClothingItem) i).playerCol == player.shirtColor) + .findAny().orElse(null); + if (lastClothing == null) + lastClothing = (ClothingItem) Items.get("Reg Clothes"); + lastClothing = lastClothing.copy(); + lastClothing.count = 1; + player.tryAddToInvOrDrop(lastClothing); + } player.shirtColor = playerCol; return super.interactOn(true); } } @Override - public boolean interactsWithWorld() { return false; } + public boolean interactsWithWorld() { + return false; + } public @NotNull ClothingItem copy() { return new ClothingItem(getName(), count, sprite, playerCol); diff --git a/src/client/java/minicraft/item/FishingData.java b/src/client/java/minicraft/item/FishingData.java index 4f74224c7..2d0928c33 100644 --- a/src/client/java/minicraft/item/FishingData.java +++ b/src/client/java/minicraft/item/FishingData.java @@ -8,22 +8,22 @@ public class FishingData { - public static final List fishData = getData("fish"); + public static final List fishData = getData("fish"); - public static final List toolData = getData("tool"); + public static final List toolData = getData("tool"); - public static final List junkData = getData("junk"); + public static final List junkData = getData("junk"); - public static final List rareData = getData("rare"); + public static final List rareData = getData("rare"); - public static List getData(String name) { - List data; - try { - data = Load.loadFile("/resources/data/fishing/" + name + "_loot.txt"); - } catch (IOException e) { - e.printStackTrace(); - data = new ArrayList<>(); - } - return data; - } + public static List getData(String name) { + List data; + try { + data = Load.loadFile("/resources/data/fishing/" + name + "_loot.txt"); + } catch (IOException e) { + e.printStackTrace(); + data = new ArrayList<>(); + } + return data; + } } diff --git a/src/client/java/minicraft/item/FishingRodItem.java b/src/client/java/minicraft/item/FishingRodItem.java index 5a8fade64..957ed1017 100644 --- a/src/client/java/minicraft/item/FishingRodItem.java +++ b/src/client/java/minicraft/item/FishingRodItem.java @@ -15,75 +15,78 @@ public class FishingRodItem extends Item { - protected static ArrayList getAllInstances() { - ArrayList items = new ArrayList<>(); - - for (int i = 0; i < 4; i++) { - items.add(new FishingRodItem(i)); - } - - return items; - } - private int uses = 0; // The more uses, the higher the chance of breaking - public int level; // The higher the level the lower the chance of breaking - - private Random random = new Random(); - - /* These numbers are a bit confusing, so here's an explanation - * If you want to know the percent chance of a category (let's say tool, which is third) - * You have to subtract 1 + the "tool" number from the number before it (for the first number subtract from 100)*/ - private static final int[][] LEVEL_CHANCES = { - {44, 14, 9, 4}, // They're in the order "fish", "junk", "tools", "rare" - {24, 14, 9, 4}, // Iron has very high chance of fish - {59, 49, 9, 4}, // Gold has very high chance of tools - {79, 69, 59, 4} // Gem has very high chance of rare items - }; - - private static final String[] LEVEL_NAMES = { - "Wood", - "Iron", - "Gold", - "Gem" - }; - - public FishingRodItem(int level) { - super(LEVEL_NAMES[level] + " Fishing Rod", new LinkedSprite(SpriteType.Item, + protected static ArrayList getAllInstances() { + ArrayList items = new ArrayList<>(); + + for (int i = 0; i < 4; i++) { + items.add(new FishingRodItem(i)); + } + + return items; + } + + private int uses = 0; // The more uses, the higher the chance of breaking + public int level; // The higher the level the lower the chance of breaking + + private Random random = new Random(); + + /* These numbers are a bit confusing, so here's an explanation + * If you want to know the percent chance of a category (let's say tool, which is third) + * You have to subtract 1 + the "tool" number from the number before it (for the first number subtract from 100)*/ + private static final int[][] LEVEL_CHANCES = { + { 44, 14, 9, 4 }, // They're in the order "fish", "junk", "tools", "rare" + { 24, 14, 9, 4 }, // Iron has very high chance of fish + { 59, 49, 9, 4 }, // Gold has very high chance of tools + { 79, 69, 59, 4 } // Gem has very high chance of rare items + }; + + private static final String[] LEVEL_NAMES = { + "Wood", + "Iron", + "Gold", + "Gem" + }; + + public FishingRodItem(int level) { + super(LEVEL_NAMES[level] + " Fishing Rod", new LinkedSprite(SpriteType.Item, LEVEL_NAMES[level].toLowerCase().replace("wood", "wooden") + "_fishing_rod")); - this.level = level; - } - - public static int getChance(int idx, int level) { - return LEVEL_CHANCES[level][idx]; - } - - @Override - public boolean interactOn(Tile tile, Level level, int xt, int yt, Player player, Direction attackDir) { - if (tile == Tiles.get("water") && !player.isSwimming()) { // Make sure not to use it if swimming - uses++; - player.isFishing = true; - player.fishingLevel = this.level; - return true; - } - - return false; - } - - @Override - public boolean canAttack() { return false; } - - @Override - public boolean isDepleted() { - if (random.nextInt(100) > 120 - uses + level * 6) { // Breaking is random, the lower the level, and the more times you use it, the higher the chance - Game.notifications.add("Your Fishing rod broke."); - return true; - } - return false; - } - - @Override - public @NotNull Item copy() { - FishingRodItem item = new FishingRodItem(this.level); - item.uses = this.uses; - return item; - } + this.level = level; + } + + public static int getChance(int idx, int level) { + return LEVEL_CHANCES[level][idx]; + } + + @Override + public boolean interactOn(Tile tile, Level level, int xt, int yt, Player player, Direction attackDir) { + if (tile == Tiles.get("water") && !player.isSwimming()) { // Make sure not to use it if swimming + uses++; + player.isFishing = true; + player.fishingLevel = this.level; + return true; + } + + return false; + } + + @Override + public boolean canAttack() { + return false; + } + + @Override + public boolean isDepleted() { + if (random.nextInt(100) > 120 - uses + level * 6) { // Breaking is random, the lower the level, and the more times you use it, the higher the chance + Game.notifications.add("Your Fishing rod broke."); + return true; + } + return false; + } + + @Override + public @NotNull Item copy() { + FishingRodItem item = new FishingRodItem(this.level); + item.uses = this.uses; + return item; + } } diff --git a/src/client/java/minicraft/item/FoodItem.java b/src/client/java/minicraft/item/FoodItem.java index d3d02d7aa..1be9c9e81 100644 --- a/src/client/java/minicraft/item/FoodItem.java +++ b/src/client/java/minicraft/item/FoodItem.java @@ -32,13 +32,18 @@ protected static ArrayList getAllInstances() { private final int feed; // The amount of hunger the food "satisfies" you by. private static final int staminaCost = 2; // The amount of stamina it costs to consume the food. - private FoodItem(String name, LinkedSprite sprite, int feed) { this(name, sprite, 1, feed); } + private FoodItem(String name, LinkedSprite sprite, int feed) { + this(name, sprite, 1, feed); + } + private FoodItem(String name, LinkedSprite sprite, int count, int feed) { super(name, sprite, count); this.feed = feed; } - /** What happens when the player uses the item on a tile */ + /** + * What happens when the player uses the item on a tile + */ public boolean interactOn(Tile tile, Level level, int xt, int yt, Player player, Direction attackDir) { boolean success = false; if (count > 0 && player.hunger < Player.maxHunger && player.payStamina(staminaCost)) { // If the player has hunger to fill, and stamina to pay... @@ -50,7 +55,9 @@ public boolean interactOn(Tile tile, Level level, int xt, int yt, Player player, } @Override - public boolean interactsWithWorld() { return false; } + public boolean interactsWithWorld() { + return false; + } public @NotNull FoodItem copy() { return new FoodItem(getName(), sprite, count, feed); diff --git a/src/client/java/minicraft/item/FurnitureItem.java b/src/client/java/minicraft/item/FurnitureItem.java index 0bf800a8d..780edc594 100644 --- a/src/client/java/minicraft/item/FurnitureItem.java +++ b/src/client/java/minicraft/item/FurnitureItem.java @@ -5,6 +5,7 @@ import minicraft.entity.Direction; import minicraft.entity.furniture.Bed; import minicraft.entity.furniture.Chest; +import minicraft.entity.furniture.Composter; import minicraft.entity.furniture.Crafter; import minicraft.entity.furniture.DungeonChest; import minicraft.entity.furniture.Furniture; @@ -44,19 +45,20 @@ protected static ArrayList getAllInstances() { items.add(new FurnitureItem(new Spawner(new Knight(1)))); items.add(new FurnitureItem(new Chest())); - items.add(new FurnitureItem(new DungeonChest(false, true))); + items.add(new FurnitureItem(new DungeonChest(null, true))); // Add the various types of crafting furniture - for (Crafter.Type type: Crafter.Type.values()) { + for (Crafter.Type type : Crafter.Type.values()) { items.add(new FurnitureItem(new Crafter(type))); } // Add the various lanterns - for (Lantern.Type type: Lantern.Type.values()) { - items.add(new FurnitureItem(new Lantern(type))); + for (Lantern.Type type : Lantern.Type.values()) { + items.add(new FurnitureItem(new Lantern(type))); } items.add(new FurnitureItem(new Tnt())); items.add(new FurnitureItem(new Bed())); + items.add(new FurnitureItem(new Composter())); return items; } @@ -70,19 +72,23 @@ public FurnitureItem(Furniture furniture) { placed = false; } - /** Determines if you can attack enemies with furniture (you can't) */ + /** + * Determines if you can attack enemies with furniture (you can't) + */ public boolean canAttack() { return false; } - /** What happens when you press the "Attack" key with the furniture in your hands */ + /** + * What happens when you press the "Attack" key with the furniture in your hands + */ public boolean interactOn(Tile tile, Level level, int xt, int yt, Player player, Direction attackDir) { if (tile.mayPass(level, xt, yt, furniture)) { // If the furniture can go on the tile Sound.play("craft"); // Placed furniture's X and Y positions - furniture.x = xt * 16 + 8; - furniture.y = yt * 16 + 8; + furniture.x = (xt << 4) + 8; + furniture.y = (yt << 4) + 8; level.add(furniture); // Adds the furniture to the world if (Game.isMode("minicraft.settings.mode.creative")) diff --git a/src/client/java/minicraft/item/HeartItem.java b/src/client/java/minicraft/item/HeartItem.java index 320fec1ed..632d5d2b3 100644 --- a/src/client/java/minicraft/item/HeartItem.java +++ b/src/client/java/minicraft/item/HeartItem.java @@ -6,6 +6,7 @@ import minicraft.gfx.SpriteLinker; import minicraft.level.Level; import minicraft.level.tile.Tile; +import org.jetbrains.annotations.NotNull; import java.util.ArrayList; @@ -22,14 +23,19 @@ protected static ArrayList getAllInstances() { private int health; // The amount of health to increase by. private int staminaCost; // The amount of stamina it costs to consume. - private HeartItem(String name, SpriteLinker.LinkedSprite sprite, int health) { this(name, sprite, 1, health); } + private HeartItem(String name, SpriteLinker.LinkedSprite sprite, int health) { + this(name, sprite, 1, health); + } + private HeartItem(String name, SpriteLinker.LinkedSprite sprite, int count, int health) { super(name, sprite, count); this.health = health; staminaCost = 7; } - /** What happens when the player uses the item on a tile */ + /** + * What happens when the player uses the item on a tile + */ public boolean interactOn(Tile tile, Level level, int xt, int yt, Player player, Direction attackDir) { boolean success = false; @@ -37,8 +43,7 @@ public boolean interactOn(Tile tile, Level level, int xt, int yt, Player player, Player.extraHealth += health; // Permanent increase of health by health variable (Basically 5) player.health += health; // Adds health to the player when used. (Almost like absorbing the item's power first time) success = true; - } - else { + } else { Updater.notifyAll("Health increase is at max!"); // When at max, health cannot be increased more and doesn't consume item return false; } @@ -47,9 +52,11 @@ public boolean interactOn(Tile tile, Level level, int xt, int yt, Player player, } @Override - public boolean interactsWithWorld() { return false; } + public boolean interactsWithWorld() { + return false; + } - public HeartItem clone() { + public @NotNull HeartItem copy() { return new HeartItem(getName(), sprite, count, health); } } diff --git a/src/client/java/minicraft/item/Inventory.java b/src/client/java/minicraft/item/Inventory.java index 106d6b26c..ee6ed0b97 100644 --- a/src/client/java/minicraft/item/Inventory.java +++ b/src/client/java/minicraft/item/Inventory.java @@ -1,7 +1,7 @@ package minicraft.item; -import minicraft.entity.furniture.Furniture; import minicraft.util.Logging; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; @@ -9,7 +9,6 @@ import java.util.Random; public class Inventory { - private final Random random = new Random(); private final List items = new ArrayList<>(); // The list of items that is in the inventory. protected int maxItem = 27; @@ -23,72 +22,76 @@ public int getMaxSlots() { * Returns all the items which are in this inventory. * @return ArrayList containing all the items in the inventory. */ - public List getItems() { return new ArrayList<>(items); } - public void clearInv() { items.clear(); } - public int invSize() { return items.size(); } + public List getItems() { + return new ArrayList<>(items); + } + + public void clearInv() { + items.clear(); + } + + public int invSize() { + return items.size(); + } /** * Get one item in this inventory. * @param idx The index of the item in the inventory's item array. * @return The specified item. */ - public Item get(int idx) { return items.get(idx); } + public Item get(int idx) { + return items.get(idx); + } /** * Remove an item in this inventory. * @param idx The index of the item in the inventory's item array. * @return The removed item. */ - public Item remove(int idx) { return items.remove(idx); } - - /** Adds an item to the inventory */ - public int add(@Nullable Item item) { - if (item != null) - return add(items.size(), item); // Adds the item to the end of the inventory list - return 0; + public Item remove(int idx) { + return items.remove(idx); } /** * Adds several copies of the same item to the end of the inventory. * @param item Item to be added. * @param num Amount of items to add. + * @return the remaining item not being added; empty if whole stack of items has been added successfully */ - public int add(Item item, int num) { - int total = 0; - for (int i = 0; i < num; i++) - total += add(item.copy()); - return total; + public List add(@NotNull Item item, int num) { + ArrayList remaining = new ArrayList<>(); + for (int i = 0; i < num; i++) { + Item remain = add(item.copy()); + if (remain != null) remaining.add(remain); + } + return remaining; } /** - * Adds an item to a specific spot in the inventory. - * @param slot Index to place item at. + * Adds an item at the end of the inventory. * @param item Item to be added. - * @return The number of items added. + * @return the remaining item not being added; {@code null} if whole stack of items has been added successfully */ - public int add(int slot, Item item) { - + public @Nullable Item add(@Nullable Item item) { + if (item == null) return null; // Do not add to inventory if it is a PowerGlove if (item instanceof PowerGloveItem) { Logging.INVENTORY.warn("Tried to add power glove to inventory. stack trace:", new Exception()); - return 0; + return null; } if (item instanceof StackableItem) { // If the item is a item... StackableItem toTake = (StackableItem) item; // ...convert it into a StackableItem object. - int total = toTake.count; - for (Item value : items) { if (toTake.stacksWith(value)) { StackableItem stack = (StackableItem) value; - if (!unlimited) { if (stack.count < stack.maxCount) { int r = stack.maxCount - stack.count; if (r >= toTake.count) { // Matching implies that the other item is stackable, too. stack.count += toTake.count; - return total; + return null; } else { toTake.count -= r; stack.count += r; @@ -96,46 +99,46 @@ public int add(int slot, Item item) { } } else { stack.count += toTake.count; - return total; + return null; } } } if (!unlimited) { if (items.size() < maxItem) { - int c = (int) Math.ceil(toTake.count/100.0); - for (int i = 0; i < c; i++) { + while (toTake.count > 0) { + if (items.size() == maxItem) return toTake; StackableItem adding = toTake.copy(); - adding.count = i + 1 == c && toTake.count % 100 > 0 ? toTake.count % 100 : 100; - if (adding.count == 0) break; - if (items.size() == maxItem) return total - toTake.count; + adding.count = Math.min(toTake.count, toTake.maxCount); items.add(adding); // Add the item to the items list toTake.count -= adding.count; } - return total; + return null; } else { - return total - toTake.count; + return toTake; } } else { - items.add(slot, toTake); - return total; + items.add(toTake); + return null; } } if (!unlimited) { if (items.size() < maxItem) { - items.add(slot, item); // Add the item to the items list - return 1; + items.add(item); // Add the item to the items list + return null; } else { - return 0; + return item; } } else { - items.add(slot, item); - return 1; + items.add(item); + return null; } } - /** Removes items from your inventory; looks for stacks, and removes from each until reached count. returns amount removed. */ + /** + * Removes items from your inventory; looks for stacks, and removes from each until reached count. returns amount removed. + */ private int removeFromStack(StackableItem given, int count) { int removed = 0; // To keep track of amount removed. for (int i = 0; i < items.size(); i++) { @@ -143,7 +146,7 @@ private int removeFromStack(StackableItem given, int count) { StackableItem curItem = (StackableItem) items.get(i); if (!curItem.stacksWith(given)) continue; // Can't do equals, becuase that includes the stack size. // equals; and current item is stackable. - int amountRemoving = Math.min(count-removed, curItem.count); // This is the number of items that are being removed from the stack this run-through. + int amountRemoving = Math.min(count - removed, curItem.count); // This is the number of items that are being removed from the stack this run-through. curItem.count -= amountRemoving; if (curItem.count == 0) { // Remove the item from the inventory if its stack is empty. remove(i); @@ -152,13 +155,14 @@ private int removeFromStack(StackableItem given, int count) { removed += amountRemoving; if (removed == count) break; if (removed > count) { // Just in case... - Logging.INVENTORY.info("SCREW UP while removing items from stack: " + (removed-count) + " too many."); + Logging.INVENTORY.info("SCREW UP while removing items from stack: " + (removed - count) + " too many."); break; } // If not all have been removed, look for another stack. } - if (removed < count) Logging.INVENTORY.info("Inventory: could not remove all items; " + (count-removed) + " left."); + if (removed < count) + Logging.INVENTORY.info("Inventory: could not remove all items; " + (count - removed) + " left."); return removed; } @@ -168,7 +172,7 @@ private int removeFromStack(StackableItem given, int count) { public void removeItem(Item i) { //if (Game.debug) System.out.println("original item: " + i); if (i instanceof StackableItem) - removeItems(i.copy(), ((StackableItem)i).count); + removeItems(i.copy(), ((StackableItem) i).count); else removeItems(i.copy(), 1); } @@ -180,7 +184,7 @@ public void removeItem(Item i) { */ public void removeItems(Item given, int count) { if (given instanceof StackableItem) - count -= removeFromStack((StackableItem)given, count); + count -= removeFromStack((StackableItem) given, count); else { for (int i = 0; i < items.size(); i++) { Item curItem = items.get(i); @@ -193,10 +197,12 @@ public void removeItems(Item given, int count) { } if (count > 0) - Logging.INVENTORY.warn("Could not remove " + count + " " + given + (count>1?"s":"") + " from inventory"); + Logging.INVENTORY.warn("Could not remove " + count + " " + given + (count > 1 ? "s" : "") + " from inventory"); } - /** Returns the how many of an item you have in the inventory. */ + /** + * Returns the how many of an item you have in the inventory. + */ public int count(Item given) { if (given == null) return 0; // null requests get no items. :) @@ -220,7 +226,7 @@ else if (curItem.equals(given)) */ public String getItemData() { StringBuilder itemdata = new StringBuilder(); - for (Item i: items) + for (Item i : items) itemdata.append(i.getData()).append(":"); if (itemdata.length() > 0) @@ -238,43 +244,32 @@ public void updateInv(String items) { if (items.length() == 0) return; // There are no items to add. - for (String item: items.split(":")) // This still generates a 1-item array when "items" is blank... [""]. + for (String item : items.split(":")) // This still generates a 1-item array when "items" is blank... [""]. add(Items.get(item)); } /** * Tries to add an item to the inventory. + * @param random The {@code Random} number generator. * @param chance Chance for the item to be added. * @param item Item to be added. * @param num How many of the item. * @param allOrNothing if true, either all items will be added or none, if false its possible to add - * between 0-num items. + * between 0-num items. */ - public void tryAdd(int chance, Item item, int num, boolean allOrNothing) { + public void tryAdd(Random random, int chance, Item item, int num, boolean allOrNothing) { if (!allOrNothing || random.nextInt(chance) == 0) for (int i = 0; i < num; i++) if (allOrNothing || random.nextInt(chance) == 0) add(item.copy()); } - public void tryAdd(int chance, @Nullable Item item, int num) { + + public void tryAdd(Random random, int chance, @Nullable Item item, int num) { if (item == null) return; if (item instanceof StackableItem) { - ((StackableItem)item).count *= num; - tryAdd(chance, item, 1, true); + ((StackableItem) item).count *= num; + tryAdd(random, chance, item, 1, true); } else - tryAdd(chance, item, num, false); - } - public void tryAdd(int chance, @Nullable Item item) { tryAdd(chance, item, 1); } - public void tryAdd(int chance, ToolType type, int lvl) { - tryAdd(chance, new ToolItem(type, lvl)); - } - - /** - * Tries to add an Furniture to the inventory. - * @param chance Chance for the item to be added. - * @param type Type of furniture to add. - */ - public void tryAdd(int chance, Furniture type) { - tryAdd(chance, new FurnitureItem(type)); + tryAdd(random, chance, item, num, false); } } diff --git a/src/client/java/minicraft/item/Item.java b/src/client/java/minicraft/item/Item.java index a7fed6f38..2761d3b2c 100644 --- a/src/client/java/minicraft/item/Item.java +++ b/src/client/java/minicraft/item/Item.java @@ -25,42 +25,57 @@ protected Item(String name) { sprite = SpriteLinker.missingTexture(SpriteType.Item); this.name = name; } + protected Item(String name, LinkedSprite sprite) { this.name = name; this.sprite = sprite; } - /** Renders an item on the HUD */ + /** + * Renders an item on the HUD + */ public void renderHUD(Screen screen, int x, int y, int fontColor) { String dispName = getDisplayName(); screen.render(x, y, sprite); Font.drawBackground(dispName, screen, x + 8, y, fontColor); } - /** Determines what happens when the player interacts with a tile */ + /** + * Determines what happens when the player interacts with a tile + */ public boolean interactOn(Tile tile, Level level, int xt, int yt, Player player, Direction attackDir) { return false; } - /** Returning true causes this item to be removed from the player's active item slot */ + /** + * Returning true causes this item to be removed from the player's active item slot + */ public boolean isDepleted() { return false; } - /** Returns if the item can attack mobs or not */ + /** + * Returns if the item can attack mobs or not + */ public boolean canAttack() { return false; } - /** Sees if an item equals another item */ + /** + * Sees if an item equals another item + */ public boolean equals(Item item) { return item != null && item.getClass().equals(getClass()) && item.name.equals(name); } @Override - public int hashCode() { return name.hashCode(); } + public int hashCode() { + return name.hashCode(); + } - /** This returns a copy of this item, in all necessary detail. */ + /** + * This returns a copy of this item, in all necessary detail. + */ @NotNull public abstract Item copy(); @@ -69,22 +84,30 @@ public String toString() { return name + "-Item"; } - /** Gets the necessary data to send over a connection. This data should always be directly input-able into Items.get() to create a valid item with the given properties. */ + /** + * Gets the necessary data to send over a connection. This data should always be directly input-able into Items.get() to create a valid item with the given properties. + */ public String getData() { return name; } - /** Gets the description used for display item information. */ + /** + * Gets the description used for display item information. + */ public String getDescription() { return getName(); } - public final String getName() { return name; } + public final String getName() { + return name; + } // Returns the String that should be used to display this item in a menu or list. public String getDisplayName() { return " " + Localization.getLocalized(getName()); } - public boolean interactsWithWorld() { return true; } + public boolean interactsWithWorld() { + return true; + } } diff --git a/src/client/java/minicraft/item/Items.java b/src/client/java/minicraft/item/Items.java index 9430bd63c..1cd9a1860 100644 --- a/src/client/java/minicraft/item/Items.java +++ b/src/client/java/minicraft/item/Items.java @@ -12,25 +12,25 @@ public class Items { // ...well, that used to be true... /** - Ok, so here's the actual big idea: - - This class is meant to define all the different kinds of items in minicraft. Item(Type).java might be what maps the different item sprites in the spritesheet to a name, but it doesn't really define anything final. This class has all the items you could possibly have, and every form of them, more or less. - - If you want to access one of those items, you do it through this class, by calling get("item name"); casing does not matter. + * Ok, so here's the actual big idea: + *

+ * This class is meant to define all the different kinds of items in minicraft. Item(Type).java might be what maps the different item sprites in the spritesheet to a name, but it doesn't really define anything final. This class has all the items you could possibly have, and every form of them, more or less. + *

+ * If you want to access one of those items, you do it through this class, by calling get("item name"); casing does not matter. */ - private static ArrayList items = new ArrayList<>(); + private static final ArrayList items = new ArrayList<>(); private static void add(Item i) { items.add(i); } + private static void addAll(ArrayList items) { - for (Item i: items) add(i); + for (Item i : items) add(i); } static { add(new PowerGloveItem()); addAll(FurnitureItem.getAllInstances()); - addAll(TorchItem.getAllInstances()); addAll(BucketItem.getAllInstances()); addAll(BookItem.getAllInstances()); addAll(TileItem.getAllInstances()); @@ -43,19 +43,23 @@ private static void addAll(ArrayList items) { addAll(FishingRodItem.getAllInstances()); addAll(SummonItem.getAllInstances()); addAll(HeartItem.getAllInstances()); + addAll(WateringCanItem.getAllInstances()); } public static ArrayList getAll() { return new ArrayList<>(items); } - /** fetches an item from the list given its name. */ + /** + * fetches an item from the list given its name. + */ @NotNull public static Item get(String name) { Item i = get(name, false); if (i == null) return new UnknownItem("NULL"); // Technically shouldn't ever happen return i; } + @Nullable public static Item get(String name, boolean allowNull) { name = name.toUpperCase(); @@ -65,16 +69,15 @@ public static Item get(String name, boolean allowNull) { if (name.contains("_")) { hadUnderscore = true; try { - data = Integer.parseInt(name.substring(name.indexOf("_")+1)); + data = Integer.parseInt(name.substring(name.indexOf("_") + 1)); } catch (Exception ex) { ex.printStackTrace(); } name = name.substring(0, name.indexOf("_")); - } - else if (name.contains(";")) { + } else if (name.contains(";")) { hadUnderscore = true; try { - data = Integer.parseInt(name.substring(name.indexOf(";")+1)); + data = Integer.parseInt(name.substring(name.indexOf(";") + 1)); } catch (Exception ex) { ex.printStackTrace(); } @@ -93,7 +96,7 @@ public static Item get(String name, boolean allowNull) { return new UnknownItem("BLANK"); Item i = null; - for (Item cur: items) { + for (Item cur : items) { if (cur.getName().equalsIgnoreCase(name)) { i = cur; break; @@ -103,9 +106,11 @@ public static Item get(String name, boolean allowNull) { if (i != null) { i = i.copy(); if (i instanceof StackableItem) - ((StackableItem)i).count = data; + ((StackableItem) i).count = data; if (i instanceof ToolItem && hadUnderscore) - ((ToolItem)i).dur = data; + ((ToolItem) i).dur = data; + if (i instanceof WateringCanItem) + ((WateringCanItem) i).content = data; return i; } else { Logging.ITEMS.error("Requested invalid item with name: '{}'", name); diff --git a/src/client/java/minicraft/item/PotionItem.java b/src/client/java/minicraft/item/PotionItem.java index 7146ec279..55ca3775e 100644 --- a/src/client/java/minicraft/item/PotionItem.java +++ b/src/client/java/minicraft/item/PotionItem.java @@ -1,5 +1,6 @@ package minicraft.item; +import minicraft.core.Game; import minicraft.entity.Direction; import minicraft.entity.mob.Player; import minicraft.gfx.SpriteLinker.LinkedSprite; @@ -16,7 +17,7 @@ public class PotionItem extends StackableItem { protected static ArrayList getAllInstances() { ArrayList items = new ArrayList<>(); - for(PotionType type: PotionType.values()) + for (PotionType type : PotionType.values()) items.add(new PotionItem(type)); return items; @@ -24,7 +25,10 @@ protected static ArrayList getAllInstances() { public PotionType type; - private PotionItem(PotionType type) { this(type, 1); } + private PotionItem(PotionType type) { + this(type, 1); + } + private PotionItem(PotionType type, int count) { super(type.name, new LinkedSprite(SpriteType.Item, "potion").setColor(type.dispColor), count); this.type = type; @@ -33,13 +37,13 @@ private PotionItem(PotionType type, int count) { // The return value is used to determine if the potion was used, which means being discarded. public boolean interactOn(Tile tile, Level level, int xt, int yt, Player player, Direction attackDir) { if (type.equals(PotionType.Lava)) { - AchievementsDisplay.setAchievement("minicraft.achievement.lava",true); + AchievementsDisplay.setAchievement("minicraft.achievement.lava", true); } return interactOn(applyPotion(player, type, true), player); } protected boolean interactOn(boolean subClassSuccess, Player player) { - if (subClassSuccess) + if (subClassSuccess && !Game.isMode("minicraft.settings.mode.creative")) player.tryAddToInvOrDrop(Items.get("glass bottle")); return super.interactOn(subClassSuccess); } @@ -50,6 +54,7 @@ public static boolean applyPotion(Player player, PotionType type, int time) { if (result && time > 0) player.addPotionEffect(type, time); // Overrides time return result; } + /// Main apply potion method public static boolean applyPotion(Player player, PotionType type, boolean addEffect) { if (player.getPotionEffects().containsKey(type) != addEffect) { // If hasEffect, and is disabling, or doesn't have effect, and is enabling... @@ -65,14 +70,18 @@ public static boolean applyPotion(Player player, PotionType type, boolean addEff @Override public boolean equals(Item other) { - return super.equals(other) && ((PotionItem)other).type == type; + return super.equals(other) && ((PotionItem) other).type == type; } @Override - public int hashCode() { return super.hashCode() + type.name.hashCode(); } + public int hashCode() { + return super.hashCode() + type.name.hashCode(); + } @Override - public boolean interactsWithWorld() { return false; } + public boolean interactsWithWorld() { + return false; + } public @NotNull PotionItem copy() { return new PotionItem(type, count); diff --git a/src/client/java/minicraft/item/PotionType.java b/src/client/java/minicraft/item/PotionType.java index 51bad8ba3..67714a2be 100644 --- a/src/client/java/minicraft/item/PotionType.java +++ b/src/client/java/minicraft/item/PotionType.java @@ -7,33 +7,33 @@ import minicraft.level.Level; public enum PotionType { - Awkward (Color.get(1, 41, 51, 255), 0), + Awkward(Color.get(1, 41, 51, 255), 0), - Speed (Color.get(1, 105, 209, 105), 4200) { + Speed(Color.get(1, 105, 209, 105), 4200) { public boolean toggleEffect(Player player, boolean addEffect) { - player.moveSpeed += (double)( addEffect ? 1 : (player.moveSpeed > 1 ? -1 : 0) ); + player.moveSpeed += (double) (addEffect ? 1 : (player.moveSpeed > 1 ? -1 : 0)); return true; } }, - Light (Color.get(1, 183, 183, 91), 6000), - Swim (Color.get(1, 51, 51, 255), 4800), - Energy (Color.get(1, 237, 110, 78), 8400), - Regen (Color.get(1, 219, 70, 189), 1800), + Light(Color.get(1, 183, 183, 91), 6000), + Swim(Color.get(1, 51, 51, 255), 4800), + Energy(Color.get(1, 237, 110, 78), 8400), + Regen(Color.get(1, 219, 70, 189), 1800), - Health (Color.get(1, 194, 56, 84), 0) { + Health(Color.get(1, 194, 56, 84), 0) { public boolean toggleEffect(Player player, boolean addEffect) { if (addEffect) player.heal(5); return true; } }, - Time (Color.get(1, 163), 1800), - Lava (Color.get(1, 199, 58, 58), 7200), - Shield (Color.get(1, 84, 84, 204), 5400), - Haste (Color.get(1, 201, 71, 201), 4800), + Time(Color.get(1, 163), 1800), + Lava(Color.get(1, 199, 58, 58), 7200), + Shield(Color.get(1, 84, 84, 204), 5400), + Haste(Color.get(1, 201, 71, 201), 4800), - Escape (Color.get(1, 222, 162, 162), 0) { + Escape(Color.get(1, 222, 162, 162), 0) { public boolean toggleEffect(Player player, boolean addEffect) { if (addEffect) { int playerDepth = player.getLevel().depth; diff --git a/src/client/java/minicraft/item/Recipe.java b/src/client/java/minicraft/item/Recipe.java index 9ab4f1dd5..d50cdfe3e 100644 --- a/src/client/java/minicraft/item/Recipe.java +++ b/src/client/java/minicraft/item/Recipe.java @@ -41,19 +41,31 @@ public Recipe(String createdItem, String... reqItems) { public Item getProduct() { return Items.get(product); } - public Map getCosts() { return new HashMap<>(costs); } - public int getAmount() { return amount; } - public boolean getCanCraft() { return canCraft; } + public Map getCosts() { + return new HashMap<>(costs); + } + + public int getAmount() { + return amount; + } + + public boolean getCanCraft() { + return canCraft; + } + public boolean checkCanCraft(Player player) { canCraft = getCanCraft(player); return canCraft; } - /** Checks if the player can craft the recipe */ + + /** + * Checks if the player can craft the recipe + */ private boolean getCanCraft(Player player) { if (Game.isMode("minicraft.settings.mode.creative")) return true; - for (String cost: costs.keySet().toArray(new String[0])) { // Cycles through the costs list + for (String cost : costs.keySet().toArray(new String[0])) { // Cycles through the costs list /// This method ONLY WORKS if costs does not contain two elements such that inventory.count will count an item it contains as matching more than once. if (player.getInventory().count(Items.get(cost)) < costs.get(cost)) { return false; @@ -69,7 +81,7 @@ public boolean craft(Player player) { if (!Game.isMode("minicraft.settings.mode.creative")) { // Remove the cost items from the inventory. - for (String cost: costs.keySet().toArray(new String[0])) { + for (String cost : costs.keySet().toArray(new String[0])) { player.getInventory().removeItems(Items.get(cost), costs.get(cost)); } } @@ -77,7 +89,7 @@ public boolean craft(Player player) { // Rdd the crafted items. for (int i = 0; i < amount; i++) { Item product = getProduct(); - if (player.getInventory().add(product) == 0) + if (player.getInventory().add(product) != null) player.getLevel().dropItem(player.x, player.y, product); } diff --git a/src/client/java/minicraft/item/Recipes.java b/src/client/java/minicraft/item/Recipes.java index 725406d9a..64015de86 100644 --- a/src/client/java/minicraft/item/Recipes.java +++ b/src/client/java/minicraft/item/Recipes.java @@ -1,6 +1,40 @@ package minicraft.item; +import minicraft.entity.furniture.Bed; +import minicraft.saveload.Save; +import org.json.JSONArray; +import org.json.JSONObject; + +import javax.swing.BorderFactory; +import javax.swing.Box; +import javax.swing.BoxLayout; +import javax.swing.JButton; +import javax.swing.JDialog; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JTextArea; +import javax.swing.JTextField; +import javax.swing.Spring; +import javax.swing.SpringLayout; +import javax.swing.UIManager; +import javax.swing.border.EmptyBorder; + +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.Container; +import java.awt.Dialog; +import java.awt.Frame; +import java.awt.event.WindowEvent; +import java.awt.event.WindowListener; +import java.io.File; +import java.io.IOException; import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.function.Function; public class Recipes { @@ -18,21 +52,25 @@ public class Recipes { craftRecipes.add(new Recipe("plank_2", "Wood_1")); craftRecipes.add(new Recipe("Plank Wall_1", "plank_3")); craftRecipes.add(new Recipe("Wood Door_1", "plank_5")); + craftRecipes.add(new Recipe("Wood Fence_1", "plank_3")); workbenchRecipes.add(new Recipe("Workbench_1", "Wood_10")); workbenchRecipes.add(new Recipe("Torch_2", "Wood_1", "coal_1")); workbenchRecipes.add(new Recipe("plank_2", "Wood_1")); workbenchRecipes.add(new Recipe("Plank Wall_1", "plank_3")); workbenchRecipes.add(new Recipe("Wood Door_1", "plank_5")); + workbenchRecipes.add(new Recipe("Wood Fence_1", "plank_3")); workbenchRecipes.add(new Recipe("Lantern_1", "Wood_8", "slime_4", "glass_3")); workbenchRecipes.add(new Recipe("Stone Brick_1", "Stone_2")); workbenchRecipes.add(new Recipe("Ornate Stone_1", "Stone_2")); workbenchRecipes.add(new Recipe("Stone Wall_1", "Stone Brick_3")); workbenchRecipes.add(new Recipe("Stone Door_1", "Stone Brick_5")); + workbenchRecipes.add(new Recipe("Stone Fence_1", "Stone Brick_3")); workbenchRecipes.add(new Recipe("Obsidian Brick_1", "Raw Obsidian_2")); workbenchRecipes.add(new Recipe("Ornate Obsidian_1", "Raw Obsidian_2")); workbenchRecipes.add(new Recipe("Obsidian Wall_1", "Obsidian Brick_3")); workbenchRecipes.add(new Recipe("Obsidian Door_1", "Obsidian Brick_5")); + workbenchRecipes.add(new Recipe("Obsidian Fence_1", "Obsidian Brick_3")); workbenchRecipes.add(new Recipe("Oven_1", "Stone_15")); workbenchRecipes.add(new Recipe("Furnace_1", "Stone_20")); workbenchRecipes.add(new Recipe("Enchanter_1", "Wood_5", "String_2", "Lapis_10")); @@ -109,9 +147,10 @@ public class Recipes { anvilRecipes.add(new Recipe("Gem Shovel_1", "Wood_5", "gem_50")); anvilRecipes.add(new Recipe("Gem Bow_1", "Wood_5", "gem_50", "string_2")); anvilRecipes.add(new Recipe("Shears_1", "Iron_4")); + anvilRecipes.add(new Recipe("Watering Can_1", "Iron_3")); - furnaceRecipes.add(new Recipe("iron_1", "iron Ore_4", "coal_1")); - furnaceRecipes.add(new Recipe("gold_1", "gold Ore_4", "coal_1")); + furnaceRecipes.add(new Recipe("iron_1", "iron Ore_3", "coal_1")); + furnaceRecipes.add(new Recipe("gold_1", "gold Ore_3", "coal_1")); furnaceRecipes.add(new Recipe("glass_1", "sand_4", "coal_1")); furnaceRecipes.add(new Recipe("glass bottle_1", "glass_3")); @@ -130,9 +169,315 @@ public class Recipes { enchantRecipes.add(new Recipe("lava potion_1", "awkward potion_1", "Lava Bucket_1")); enchantRecipes.add(new Recipe("energy potion_1", "awkward potion_1", "gem_25")); enchantRecipes.add(new Recipe("regen potion_1", "awkward potion_1", "Gold Apple_1")); - enchantRecipes.add(new Recipe("Health Potion_1", "awkward potion_1", "GunPowder_2", "Leather Armor_1")); - enchantRecipes.add(new Recipe("Escape Potion_1", "awkward potion_1", "GunPowder_3", "Lapis_7")); - enchantRecipes.add(new Recipe("Totem of Air_1", "gold_10", "gem_10", "Lapis_5","Cloud Ore_5")); - enchantRecipes.add(new Recipe("Obsidian Poppet_1", "gold_10", "gem_10", "Lapis_5","Shard_15")); + enchantRecipes.add(new Recipe("Health Potion_1", "awkward potion_1", "Gunpowder_2", "Leather Armor_1")); + enchantRecipes.add(new Recipe("Escape Potion_1", "awkward potion_1", "Gunpowder_3", "Lapis_7")); + enchantRecipes.add(new Recipe("Totem of Air_1", "gold_10", "gem_10", "Lapis_5", "Cloud Ore_5")); + enchantRecipes.add(new Recipe("Obsidian Poppet_1", "gold_10", "gem_10", "Lapis_5", "Shard_15")); + enchantRecipes.add(new Recipe("Arcane Fertilizer_3", "Lapis_6", "Bone_2")); + } + + /** + * This regenerates the recipes.json at once by the recipes above. + * Remind that it is recommended to use String Manipulation plugin to resort (JSON Sort) the file if using IntelliJ IDEA. + */ + public static void main(String[] args) { + HashSet recipes = new HashSet<>(); + recipes.addAll(anvilRecipes); + recipes.addAll(ovenRecipes); + recipes.addAll(furnaceRecipes); + recipes.addAll(workbenchRecipes); + recipes.addAll(enchantRecipes); + recipes.addAll(craftRecipes); + recipes.addAll(loomRecipes); + HashMap recipeMap = new HashMap<>(); + HashMap> duplicatedRecipes = new HashMap<>(); + Function itemNameFixer = item -> { + String name = item.getName(); + return (name.equalsIgnoreCase("gold apple") ? name.replaceAll("(?i)gold", "golden") : + item instanceof ToolItem ? name.replaceAll("(?i)wood", "wooden").replaceAll("(?i)rock", "stone") : name) + .toLowerCase().replace(' ', '_'); + }; + Function recipeNameFixer = recipe -> { // This is applied when duplication occurs. + Item item = recipe.getProduct(); + String name = itemNameFixer.apply(item); + /*if (item instanceof DyeItem) { TODO + Map costs = recipe.getCosts(); + if (costs.size() == 2 && costs.containsKey("WHITE DYE")) + return name + "_from_white_dye"; + return name; + } else*/ if (item instanceof FurnitureItem && ((FurnitureItem) item).furniture instanceof Bed) { + if (recipe.getCosts().containsKey("WHITE BED")) + return name + "_from_white_bed"; + return name; + } + return name; + }; + for (Recipe recipe : recipes) { + if (recipes.stream().anyMatch(r -> r != recipe && r.getProduct().equals(recipe.getProduct()))) { + if (recipes.stream().anyMatch(r -> r != recipe && recipeNameFixer.apply(r).equals(recipeNameFixer.apply(recipe)))) { + duplicatedRecipes.compute(recipeNameFixer.apply(recipe), (k, v) -> { + if (v == null) return new HashSet<>(Collections.singletonList(recipe)); + else { + v.add(recipe); + return v; + } + }); + } else { + recipeMap.put(recipeNameFixer.apply(recipe), recipe); + } + } else { + recipeMap.put(itemNameFixer.apply(recipe.getProduct()), recipe); + } + } + for (String key : duplicatedRecipes.keySet()) { + HashSet duplications = duplicatedRecipes.get(key); + HashMap inputs = new HashMap<>(); + JDialog dialog = new JDialog((Frame) null, "Recipe Duplication: " + key); + dialog.setLayout(new BorderLayout()); + dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE); + dialog.addWindowListener(new WindowListener() { + @Override + public void windowOpened(WindowEvent e) {} + @Override + public void windowClosing(WindowEvent e) { + dialog.setVisible(false); + JOptionPane.showMessageDialog(null, "Exit Program"); + dialog.dispose(); + System.exit(0); + } + @Override + public void windowClosed(WindowEvent e) {} + @Override + public void windowIconified(WindowEvent e) {} + @Override + public void windowDeiconified(WindowEvent e) {} + @Override + public void windowActivated(WindowEvent e) {} + @Override + public void windowDeactivated(WindowEvent e) {} + }); + + JPanel inputPanel = new JPanel(new SpringLayout()); + inputPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); + for (Recipe recipe : duplications) { + JLabel l = new JLabel(recipe.toString(), JLabel.TRAILING); + inputPanel.add(l); + JTextField textField = new JTextField(key, 20); + l.setLabelFor(textField); + inputPanel.add(textField); + inputs.put(recipe, textField); + } + + makeCompactGrid(inputPanel, + duplications.size(), 2, //rows, cols + 6, 6, //initX, initY + 6, 6); //xPad, yPad + + JPanel buttonPane = new JPanel(); + buttonPane.setLayout(new BoxLayout(buttonPane, BoxLayout.X_AXIS)); + buttonPane.setBorder(BorderFactory.createEmptyBorder(0, 10, 10, 10)); + buttonPane.add(Box.createHorizontalGlue()); + JButton doneButton = new JButton("Done"); + doneButton.addActionListener(e -> { + inputs.forEach((recipe, text) -> recipeMap.put(text.getText(), recipe)); + dialog.setVisible(false); + dialog.dispose(); + }); + doneButton.setDefaultCapable(true); + buttonPane.add(doneButton); + buttonPane.add(Box.createHorizontalGlue()); + + class JMultilineLabel extends JTextArea { // Reference: https://stackoverflow.com/a/11034405 + private static final long serialVersionUID = 1L; + public JMultilineLabel(String text){ + super(text); // According to Mr. Polywhirl, this might improve it -> text + System.lineSeparator() + setEditable(false); + setCursor(null); + setOpaque(false); + setFocusable(false); + setFont(UIManager.getFont("Label.font")); + setWrapStyleWord(true); + setLineWrap(true); + //According to Mariana this might improve it + setBorder(new EmptyBorder(5, 5, 5, 5)); + setAlignmentY(JLabel.CENTER_ALIGNMENT); + } + } + + Container dialogPane = dialog.getContentPane(); + dialogPane.add(new JMultilineLabel("Recipes:\n" + + String.join("\n", duplicatedRecipes.get(key).stream().map(Recipe::toString)::iterator)), + BorderLayout.NORTH); + dialogPane.add(inputPanel, BorderLayout.CENTER); + dialogPane.add(buttonPane, BorderLayout.SOUTH); + dialog.pack(); + dialog.setLocationRelativeTo(null); + dialog.setModalityType(Dialog.ModalityType.APPLICATION_MODAL); + dialog.setVisible(true); + } + + JSONObject json = new JSONObject(); + for (String key : recipeMap.keySet()) { + Recipe recipe = recipeMap.get(key); + JSONObject recipeUnlockingJson = new JSONObject(); + + ArrayList costs = new ArrayList<>(); + JSONObject criteriaJson = new JSONObject(); + Map costMap = recipe.getCosts(); + for (String itemKey : costMap.keySet()) { + Item item = Items.get(itemKey); + JSONObject criterionJson = new JSONObject(); + + criterionJson.put("trigger", "inventory_changed"); + + JSONObject conditionsJson = new JSONObject(); + JSONArray itemConditionsJsonArray = new JSONArray(); + JSONObject itemConditionsJson = new JSONObject(); + JSONArray itemsJson = new JSONArray(); + itemsJson.put(item.getName()); + itemConditionsJson.put("items", itemsJson); + itemConditionsJsonArray.put(itemConditionsJson); + conditionsJson.put("items", itemConditionsJsonArray); + criterionJson.put("conditions", conditionsJson); + criteriaJson.put("has_" + itemNameFixer.apply(item), criterionJson); + + costs.add(item.getName() + "_" + costMap.get(itemKey)); + } + recipeUnlockingJson.put("criteria", criteriaJson); + + JSONArray requirementsJson = new JSONArray(); + JSONArray criterionNamesJson = new JSONArray(); + criterionNamesJson.putAll(criteriaJson.keySet()); + requirementsJson.put(criterionNamesJson); + recipeUnlockingJson.put("requirements", requirementsJson); + + JSONObject rewardsJson = new JSONObject(); + JSONObject recipesJson = new JSONObject(); + JSONArray costsJson = new JSONArray(); + costsJson.putAll(costs); + recipesJson.put(recipe.getProduct().getName() + "_" + recipe.getAmount(), costsJson); + rewardsJson.put("recipes", recipesJson); + recipeUnlockingJson.put("rewards", rewardsJson); + + json.put("minicraft.advancements.recipes." + key, recipeUnlockingJson); + } + + try { + Save.writeJSONToFile(new File(System.getProperty("user.dir"), "src/client/resources/resources/recipes.json").toString(), + json.toString(2)); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + /* Used by makeCompactGrid. */ + private static SpringLayout.Constraints getConstraintsForCell( + int row, int col, + Container parent, + int cols) { + SpringLayout layout = (SpringLayout) parent.getLayout(); + Component c = parent.getComponent(row * cols + col); + return layout.getConstraints(c); + } + + /* + * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * - Neither the name of Oracle or the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + /** + * Aligns the first rows * cols + * components of parent in + * a grid. Each component in a column is as wide as the maximum + * preferred width of the components in that column; + * height is similarly determined for each row. + * The parent is made just big enough to fit them all. + * + * @param rows number of rows + * @param cols number of columns + * @param initialX x location to start the grid at + * @param initialY y location to start the grid at + * @param xPad x padding between cells + * @param yPad y padding between cells + */ + @SuppressWarnings("SameParameterValue") + private static void makeCompactGrid(Container parent, + int rows, int cols, + int initialX, int initialY, + int xPad, int yPad) { + SpringLayout layout; + try { + layout = (SpringLayout)parent.getLayout(); + } catch (ClassCastException exc) { + System.err.println("The first argument to makeCompactGrid must use SpringLayout."); + return; + } + + //Align all cells in each column and make them the same width. + Spring x = Spring.constant(initialX); + for (int c = 0; c < cols; c++) { + Spring width = Spring.constant(0); + for (int r = 0; r < rows; r++) { + width = Spring.max(width, + getConstraintsForCell(r, c, parent, cols). + getWidth()); + } + for (int r = 0; r < rows; r++) { + SpringLayout.Constraints constraints = + getConstraintsForCell(r, c, parent, cols); + constraints.setX(x); + constraints.setWidth(width); + } + x = Spring.sum(x, Spring.sum(width, Spring.constant(xPad))); + } + + //Align all cells in each row and make them the same height. + Spring y = Spring.constant(initialY); + for (int r = 0; r < rows; r++) { + Spring height = Spring.constant(0); + for (int c = 0; c < cols; c++) { + height = Spring.max(height, + getConstraintsForCell(r, c, parent, cols). + getHeight()); + } + for (int c = 0; c < cols; c++) { + SpringLayout.Constraints constraints = + getConstraintsForCell(r, c, parent, cols); + constraints.setY(y); + constraints.setHeight(height); + } + y = Spring.sum(y, Spring.sum(height, Spring.constant(yPad))); + } + + //Set the parent's size. + SpringLayout.Constraints pCons = layout.getConstraints(parent); + pCons.setConstraint(SpringLayout.SOUTH, y); + pCons.setConstraint(SpringLayout.EAST, x); } } diff --git a/src/client/java/minicraft/item/StackableItem.java b/src/client/java/minicraft/item/StackableItem.java index 66479a80d..b66dfac8b 100644 --- a/src/client/java/minicraft/item/StackableItem.java +++ b/src/client/java/minicraft/item/StackableItem.java @@ -2,6 +2,7 @@ import minicraft.core.Game; import minicraft.core.io.Localization; +import minicraft.gfx.SpriteLinker; import minicraft.gfx.SpriteLinker.LinkedSprite; import minicraft.gfx.SpriteLinker.SpriteType; import org.jetbrains.annotations.NotNull; @@ -19,8 +20,8 @@ protected static ArrayList getAllInstances() { items.add(new StackableItem("Leather", new LinkedSprite(SpriteType.Item, "leather"))); items.add(new StackableItem("Wheat", new LinkedSprite(SpriteType.Item, "wheat"))); items.add(new StackableItem("Key", new LinkedSprite(SpriteType.Item, "key"))); - items.add(new StackableItem("arrow", new LinkedSprite(SpriteType.Item, "arrow"))); - items.add(new StackableItem("string", new LinkedSprite(SpriteType.Item, "string"))); + items.add(new StackableItem("Arrow", new LinkedSprite(SpriteType.Item, "arrow"))); + items.add(new StackableItem("String", new LinkedSprite(SpriteType.Item, "string"))); items.add(new StackableItem("Coal", new LinkedSprite(SpriteType.Item, "coal"))); items.add(new StackableItem("Iron Ore", new LinkedSprite(SpriteType.Item, "iron_ore"))); items.add(new StackableItem("Lapis", new LinkedSprite(SpriteType.Item, "lapis"))); @@ -30,13 +31,16 @@ protected static ArrayList getAllInstances() { items.add(new StackableItem("Rose", new LinkedSprite(SpriteType.Item, "red_flower"))); items.add(new StackableItem("Gunpowder", new LinkedSprite(SpriteType.Item, "gunpowder"))); items.add(new StackableItem("Slime", new LinkedSprite(SpriteType.Item, "slime"))); - items.add(new StackableItem("glass", new LinkedSprite(SpriteType.Item, "glass"))); - items.add(new StackableItem("cloth", new LinkedSprite(SpriteType.Item, "cloth"))); - items.add(new StackableItem("gem", new LinkedSprite(SpriteType.Item, "gem"))); + items.add(new StackableItem("Glass", new LinkedSprite(SpriteType.Item, "glass"))); + items.add(new StackableItem("Cloth", new LinkedSprite(SpriteType.Item, "cloth"))); + items.add(new StackableItem("Gem", new LinkedSprite(SpriteType.Item, "gem"))); items.add(new StackableItem("Scale", new LinkedSprite(SpriteType.Item, "scale"))); items.add(new StackableItem("Shard", new LinkedSprite(SpriteType.Item, "shard"))); items.add(new StackableItem("Cloud Ore", new LinkedSprite(SpriteType.Item, "cloud_ore"))); items.add(new StackableItem("Glass Bottle", new LinkedSprite(SpriteType.Item, "glass_bottle"))); + items.add(new StackableItem("Tomato", new LinkedSprite(SpriteType.Item, "tomato"))); + items.add(new StackableItem("Bone", new LinkedSprite(SpriteType.Item, "bone"))); + items.add(new StackableItem("Fertilizer", new SpriteLinker.LinkedSprite(SpriteLinker.SpriteType.Item, "fertilizer"))); return items; } @@ -48,12 +52,15 @@ protected StackableItem(String name, LinkedSprite sprite) { super(name, sprite); count = 1; } + protected StackableItem(String name, LinkedSprite sprite, int count) { this(name, sprite); this.count = count; } - public boolean stacksWith(Item other) { return other instanceof StackableItem && other.getName().equals(getName()); } + public boolean stacksWith(Item other) { + return other instanceof StackableItem && other.getName().equals(getName()); + } // This is used by (most) subclasses, to standardize the count decrement behavior. This is not the normal interactOn method. protected boolean interactOn(boolean subClassSuccess) { @@ -62,7 +69,9 @@ protected boolean interactOn(boolean subClassSuccess) { return subClassSuccess; } - /** Called to determine if this item should be removed from an inventory. */ + /** + * Called to determine if this item should be removed from an inventory. + */ @Override public boolean isDepleted() { return count <= 0; @@ -75,7 +84,7 @@ public boolean isDepleted() { @Override public String toString() { - return super.toString() + "-Stack_Size:"+count; + return super.toString() + "-Stack_Size:" + count; } public String getData() { diff --git a/src/client/java/minicraft/item/SummonItem.java b/src/client/java/minicraft/item/SummonItem.java index de4508c5d..bf0d73df0 100644 --- a/src/client/java/minicraft/item/SummonItem.java +++ b/src/client/java/minicraft/item/SummonItem.java @@ -3,6 +3,7 @@ import minicraft.core.Game; import minicraft.core.io.Localization; import minicraft.entity.Direction; +import minicraft.entity.Entity; import minicraft.entity.furniture.KnightStatue; import minicraft.entity.mob.AirWizard; import minicraft.entity.mob.ObsidianKnight; @@ -30,13 +31,18 @@ protected static ArrayList getAllInstances() { private final String mob; - private SummonItem(String name, LinkedSprite sprite, String mob) { this(name, sprite, 1, mob); } + private SummonItem(String name, LinkedSprite sprite, String mob) { + this(name, sprite, 1, mob); + } + private SummonItem(String name, LinkedSprite sprite, int count, String mob) { super(name, sprite, count); this.mob = mob; } - /** What happens when the player uses the item on a tile */ + /** + * What happens when the player uses the item on a tile + */ public boolean interactOn(Tile tile, Level level, int xt, int yt, Player player, Direction attackDir) { boolean success = false; @@ -53,8 +59,7 @@ public boolean interactOn(Tile tile, Level level, int xt, int yt, Player player, Logger.tag("SummonItem").debug("Summoned new Air Wizard"); success = true; } - } - else { + } else { Game.notifications.add(Localization.getLocalized("minicraft.notification.boss_limit")); } } else { @@ -66,14 +71,25 @@ public boolean interactOn(Tile tile, Level level, int xt, int yt, Player player, // Check if we are on the right level and tile if (level.depth == -4) { // If the player nears the center. - if (new Rectangle(level.w/2-3, level.h/2-3, 7, 7).contains(player.x >> 4, player.y >> 4)) { + if (new Rectangle(level.w / 2 - 3, level.h / 2 - 3, 7, 7).contains(player.x >> 4, player.y >> 4)) { if (!ObsidianKnight.active) { + boolean exists = false; + for (Entity e : level.getEntityArray()) { + if (e instanceof KnightStatue) { + exists = true; + break; + } + } - // Pay stamina - if (player.payStamina(2)) { - level.add(new KnightStatue(5000), level.w/2, level.h/2, true); - Logger.tag("SummonItem").debug("Summoned new Knight Statue"); - success = true; + if (!exists) { // Prevent unintended behaviors + // Pay stamina + if (player.payStamina(2)) { + level.add(new KnightStatue(5000), level.w / 2, level.h / 2, true); + Logger.tag("SummonItem").debug("Summoned new Knight Statue"); + success = true; + } + } else { + Game.notifications.add(Localization.getLocalized("minicraft.notification.knight_statue_exists")); } } else { Game.notifications.add(Localization.getLocalized("minicraft.notification.boss_limit")); @@ -94,7 +110,9 @@ public boolean interactOn(Tile tile, Level level, int xt, int yt, Player player, } @Override - public boolean interactsWithWorld() { return false; } + public boolean interactsWithWorld() { + return false; + } public @NotNull SummonItem copy() { return new SummonItem(getName(), sprite, count, mob); diff --git a/src/client/java/minicraft/item/TileItem.java b/src/client/java/minicraft/item/TileItem.java index 0212fbdcd..4c4ea0d3e 100644 --- a/src/client/java/minicraft/item/TileItem.java +++ b/src/client/java/minicraft/item/TileItem.java @@ -11,8 +11,11 @@ import minicraft.level.Level; import minicraft.level.tile.Tile; import minicraft.level.tile.Tiles; +import minicraft.screen.AchievementsDisplay; +import minicraft.screen.SignDisplay; import minicraft.util.AdvancementElement; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.tinylog.Logger; import java.util.ArrayList; @@ -25,99 +28,152 @@ protected static ArrayList getAllInstances() { ArrayList items = new ArrayList<>(); /// TileItem sprites all have 1x1 sprites. - items.add(new TileItem("Flower", new LinkedSprite(SpriteType.Item, "white_flower"), "flower", "grass")); - items.add(new TileItem("Acorn", new LinkedSprite(SpriteType.Item, "acorn"), "tree Sapling", "grass")); - items.add(new TileItem("Dirt", new LinkedSprite(SpriteType.Item, "dirt"), "dirt", "hole", "water", "lava")); - items.add(new TileItem("Natural Rock", new LinkedSprite(SpriteType.Item, "stone"), "rock", "hole", "dirt", "sand", "grass", "path", "water", "lava")); - - items.add(new TileItem("Plank", new LinkedSprite(SpriteType.Item, "plank"), "Wood Planks", "hole", "water", "cloud")); - items.add(new TileItem("Plank Wall", new LinkedSprite(SpriteType.Item, "plank_wall"), "Wood Wall", "Wood Planks")); - items.add(new TileItem("Wood Door", new LinkedSprite(SpriteType.Item, "wood_door"), "Wood Door", "Wood Planks")); - items.add(new TileItem("Stone", new LinkedSprite(SpriteType.Item, "stone"), "Stone", "hole", "water", "cloud", "lava")); - items.add(new TileItem("Stone Brick", new LinkedSprite(SpriteType.Item, "stone_brick"), "Stone Bricks", "hole", "water", "cloud", "lava")); - items.add(new TileItem("Ornate Stone", new LinkedSprite(SpriteType.Item, "stone_brick"), "Ornate Stone", "hole", "water", "cloud", "lava")); - items.add(new TileItem("Stone Wall", new LinkedSprite(SpriteType.Item, "stone_wall"), "Stone Wall", "Stone Bricks")); - items.add(new TileItem("Stone Door", new LinkedSprite(SpriteType.Item, "stone_wall"), "Stone Door", "Stone Bricks")); - items.add(new TileItem("Raw Obsidian", new LinkedSprite(SpriteType.Item, "obsidian"), "Raw Obsidian", "hole", "water", "cloud", "lava")); - items.add(new TileItem("Obsidian Brick", new LinkedSprite(SpriteType.Item, "obsidian_brick"), "Obsidian", "hole", "water", "cloud", "lava")); - items.add(new TileItem("Ornate Obsidian", new LinkedSprite(SpriteType.Item, "obsidian_brick"), "Ornate Obsidian","hole", "water", "cloud", "lava")); - items.add(new TileItem("Obsidian Wall", new LinkedSprite(SpriteType.Item, "obsidian_wall"), "Obsidian Wall", "Obsidian")); - items.add(new TileItem("Obsidian Door", new LinkedSprite(SpriteType.Item, "obsidian_door"), "Obsidian Door", "Obsidian")); - - items.add(new TileItem("Wool", new LinkedSprite(SpriteType.Item, "wool"), "Wool", "hole", "water")); - items.add(new TileItem("Red Wool", new LinkedSprite(SpriteType.Item, "red_wool"), "Red Wool", "hole", "water")); - items.add(new TileItem("Blue Wool", new LinkedSprite(SpriteType.Item, "blue_wool"), "Blue Wool", "hole", "water")); - items.add(new TileItem("Green Wool", new LinkedSprite(SpriteType.Item, "green_wool"), "Green Wool", "hole", "water")); - items.add(new TileItem("Yellow Wool", new LinkedSprite(SpriteType.Item, "yellow_wool"), "Yellow Wool", "hole", "water")); - items.add(new TileItem("Black Wool", new LinkedSprite(SpriteType.Item, "black_wool"), "Black Wool", "hole", "water")); - - items.add(new TileItem("Sand", new LinkedSprite(SpriteType.Item, "sand"), "sand", "hole", "water", "lava")); - items.add(new TileItem("Cactus", new LinkedSprite(SpriteType.Item, "cactus"), "cactus Sapling", "sand")); - items.add(new TileItem("Bone", new LinkedSprite(SpriteType.Item, "bone"), "tree", "tree Sapling")); - items.add(new TileItem("Cloud", new LinkedSprite(SpriteType.Item, "cloud"), "cloud", "Infinite Fall")); - - items.add(new TileItem("Wheat Seeds", new LinkedSprite(SpriteType.Item, "seed"), "wheat", "farmland")); - items.add(new TileItem("Potato", new LinkedSprite(SpriteType.Item, "potato"), "potato", "farmland")); - items.add(new TileItem("Grass Seeds", new LinkedSprite(SpriteType.Item, "seed"), "grass", "dirt")); + items.add(new TileItem("Flower", new LinkedSprite(SpriteType.Item, "white_flower"), new TileModel("flower"), "grass")); + items.add(new TileItem("Acorn", new LinkedSprite(SpriteType.Item, "acorn"), new TileModel("tree Sapling"), "grass")); + items.add(new TileItem("Dirt", new LinkedSprite(SpriteType.Item, "dirt"), new TileModel("dirt"), "hole", "water", "lava")); + items.add(new TileItem("Natural Rock", new LinkedSprite(SpriteType.Item, "stone"), new TileModel("rock"), "hole", "dirt", "sand", "grass", "path", "water", "lava")); + + String[] solidTiles = { "dirt", "Wood Planks", "Stone Bricks", "Obsidian", "Wool", "Red Wool", "Blue Wool", + "Green Wool", "Yellow Wool", "Black Wool", "grass", "sand", "path", "ornate stone", "ornate obsidian", "Raw Obsidian", "Stone" }; + TileModel.TileDataGetter placeOverWithID = (model1, target, level, xt, yt, player, attackDir) -> target.id; + + items.add(new TileItem("Plank", new LinkedSprite(SpriteType.Item, "plank"), new TileModel("Wood Planks"), "hole", "water", "cloud")); + items.add(new TileItem("Ornate Wood", new LinkedSprite(SpriteType.Item, "plank"), new TileModel("Ornate Wood"), "hole", "water", "cloud")); + items.add(new TileItem("Plank Wall", new LinkedSprite(SpriteType.Item, "plank_wall"), new TileModel("Wood Wall"), "Wood Planks")); + items.add(new TileItem("Wood Door", new LinkedSprite(SpriteType.Item, "wood_door"), new TileModel("Wood Door"), "Wood Planks")); + items.add(new TileItem("Wood Fence", new LinkedSprite(SpriteType.Item, "wood_fence"), new TileModel("Wood Fence", placeOverWithID), solidTiles)); + items.add(new TileItem("Stone", new LinkedSprite(SpriteType.Item, "stone"), new TileModel("Stone"), "hole", "water", "cloud", "lava")); + items.add(new TileItem("Stone Brick", new LinkedSprite(SpriteType.Item, "stone_brick"), new TileModel("Stone Bricks"), "hole", "water", "cloud", "lava")); + items.add(new TileItem("Ornate Stone", new LinkedSprite(SpriteType.Item, "stone_brick"), new TileModel("Ornate Stone"), "hole", "water", "cloud", "lava")); + items.add(new TileItem("Stone Wall", new LinkedSprite(SpriteType.Item, "stone_wall"), new TileModel("Stone Wall"), "Stone Bricks")); + items.add(new TileItem("Stone Door", new LinkedSprite(SpriteType.Item, "stone_door"), new TileModel("Stone Door"), "Stone Bricks")); + items.add(new TileItem("Stone Fence", new LinkedSprite(SpriteType.Item, "stone_fence"), new TileModel("Stone Fence", placeOverWithID), solidTiles)); + items.add(new TileItem("Raw Obsidian", new LinkedSprite(SpriteType.Item, "obsidian"), new TileModel("Raw Obsidian"), "hole", "water", "cloud", "lava")); + items.add(new TileItem("Obsidian Brick", new LinkedSprite(SpriteType.Item, "obsidian_brick"), new TileModel("Obsidian"), "hole", "water", "cloud", "lava")); + items.add(new TileItem("Ornate Obsidian", new LinkedSprite(SpriteType.Item, "obsidian_brick"), new TileModel("Ornate Obsidian"), "hole", "water", "cloud", "lava")); + items.add(new TileItem("Obsidian Wall", new LinkedSprite(SpriteType.Item, "obsidian_wall"), new TileModel("Obsidian Wall"), "Obsidian")); + items.add(new TileItem("Obsidian Door", new LinkedSprite(SpriteType.Item, "obsidian_door"), new TileModel("Obsidian Door"), "Obsidian")); + items.add(new TileItem("Obsidian Fence", new LinkedSprite(SpriteType.Item, "obsidian_fence"), new TileModel("Obsidian Fence", placeOverWithID), solidTiles)); + + items.add(new TileItem("Wool", new LinkedSprite(SpriteType.Item, "wool"), new TileModel("Wool"), "hole", "water")); + items.add(new TileItem("Red Wool", new LinkedSprite(SpriteType.Item, "red_wool"), new TileModel("Red Wool"), "hole", "water")); + items.add(new TileItem("Blue Wool", new LinkedSprite(SpriteType.Item, "blue_wool"), new TileModel("Blue Wool"), "hole", "water")); + items.add(new TileItem("Green Wool", new LinkedSprite(SpriteType.Item, "green_wool"), new TileModel("Green Wool"), "hole", "water")); + items.add(new TileItem("Yellow Wool", new LinkedSprite(SpriteType.Item, "yellow_wool"), new TileModel("Yellow Wool"), "hole", "water")); + items.add(new TileItem("Black Wool", new LinkedSprite(SpriteType.Item, "black_wool"), new TileModel("Black Wool"), "hole", "water")); + + items.add(new TileItem("Sand", new LinkedSprite(SpriteType.Item, "sand"), new TileModel("sand"), "hole", "water", "lava")); + items.add(new TileItem("Cactus", new LinkedSprite(SpriteType.Item, "cactus"), new TileModel("cactus Sapling"), "sand")); + items.add(new TileItem("Cloud", new LinkedSprite(SpriteType.Item, "cloud"), new TileModel("cloud"), "Infinite Fall")); + + TileModel.TileDataGetter seedPlanting = (model1, target, level, xt, yt, player, attackDir) -> { + AchievementsDisplay.setAchievement("minicraft.achievement.plant_seed", true); + return TileModel.KEEP_DATA.getTileData(model1, target, level, xt, yt, player, attackDir); + }; + items.add(new TileItem("Wheat Seeds", new LinkedSprite(SpriteType.Item, "seed"), new TileModel("wheat", seedPlanting), "farmland")); + items.add(new TileItem("Potato", new LinkedSprite(SpriteType.Item, "potato"), new TileModel("potato", TileModel.KEEP_DATA), "farmland")); + items.add(new TileItem("Carrot", new LinkedSprite(SpriteType.Item, "carrot"), new TileModel("carrot", TileModel.KEEP_DATA), "farmland")); + items.add(new TileItem("Tomato Seeds", new LinkedSprite(SpriteType.Item, "seed"), new TileModel("tomato", seedPlanting), "farmland")); + items.add(new TileItem("Heavenly Berries", new LinkedSprite(SpriteType.Item, "heavenly_berries"), new TileModel("heavenly berries", TileModel.KEEP_DATA), "farmland")); + items.add(new TileItem("Hellish Berries", new LinkedSprite(SpriteType.Item, "hellish_berries"), new TileModel("hellish berries", TileModel.KEEP_DATA), "farmland")); + items.add(new TileItem("Grass Seeds", new LinkedSprite(SpriteType.Item, "seed"), new TileModel("grass"), "dirt")); + + items.add(new TileItem("Torch", new LinkedSprite(SpriteType.Item, "torch"), new TileModel("Torch", placeOverWithID), solidTiles)); + items.add(new TileItem("Sign", new LinkedSprite(SpriteType.Item, "sign"), new TileModel("Sign", (model1, target, level, xt, yt, player, attackDir) -> { + Game.setDisplay(new SignDisplay(level, xt, yt)); + return placeOverWithID.getTileData(model1, target, level, xt, yt, player, attackDir); + }), solidTiles)); // Creative mode available tiles: - items.add(new TileItem("Farmland", SpriteLinker.missingTexture(SpriteType.Item), "farmland", "dirt", "grass", "hole")); - items.add(new TileItem("Exploded", SpriteLinker.missingTexture(SpriteType.Item), "explode", "dirt", "grass")); - items.add(new TileItem("hole", SpriteLinker.missingTexture(SpriteType.Item), "hole", "dirt", "grass")); - items.add(new TileItem("lava", SpriteLinker.missingTexture(SpriteType.Item), "lava", "dirt", "grass", "hole")); - items.add(new TileItem("path", SpriteLinker.missingTexture(SpriteType.Item), "path", "dirt", "grass", "hole")); - items.add(new TileItem("water", SpriteLinker.missingTexture(SpriteType.Item), "water", "dirt", "grass", "hole")); + items.add(new TileItem("Farmland", SpriteLinker.missingTexture(SpriteType.Item), new TileModel("farmland"), "dirt", "grass", "hole")); + items.add(new TileItem("Hole", SpriteLinker.missingTexture(SpriteType.Item), new TileModel("hole"), "dirt", "grass")); + items.add(new TileItem("Lava", SpriteLinker.missingTexture(SpriteType.Item), new TileModel("lava"), "dirt", "grass", "hole")); + items.add(new TileItem("Path", SpriteLinker.missingTexture(SpriteType.Item), new TileModel("path"), "dirt", "grass", "hole")); + items.add(new TileItem("Water", SpriteLinker.missingTexture(SpriteType.Item), new TileModel("water"), "dirt", "grass", "hole")); return items; } - public final String model; + public final @Nullable TileModel model; public final List validTiles; - protected TileItem(String name, LinkedSprite sprite, String model, String... validTiles) { + protected TileItem(String name, LinkedSprite sprite, TileModel model, String... validTiles) { this(name, sprite, 1, model, Arrays.asList(validTiles)); } - protected TileItem(String name, LinkedSprite sprite, int count, String model, String... validTiles) { + + protected TileItem(String name, LinkedSprite sprite, int count, TileModel model, String... validTiles) { this(name, sprite, count, model, Arrays.asList(validTiles)); } - protected TileItem(String name, LinkedSprite sprite, int count, String model, List validTiles) { + + protected TileItem(String name, LinkedSprite sprite, int count, @Nullable TileModel model, List validTiles) { super(name, sprite, count); - this.model = model.toUpperCase(); + this.model = model; this.validTiles = new ArrayList<>(); - for (String tile: validTiles) - this.validTiles.add(tile.toUpperCase()); + for (String tile : validTiles) + this.validTiles.add(tile.toUpperCase()); + } + + public static class TileModel { + public static final TileDataGetter DEFAULT_DATA = ((model, target, level, xt, yt, player, attackDir) -> model.getDefaultData()); + public static final TileDataGetter KEEP_DATA = ((model, target, level, xt, yt, player, attackDir) -> level.getData(xt, yt)); + + public final @NotNull String tile; + public final TileDataGetter data; + + @FunctionalInterface + public interface TileDataGetter { + int getTileData(Tile model, Tile target, Level level, int xt, int yt, Player player, Direction attackDir); + } + + public TileModel(String tile) { + this(tile, DEFAULT_DATA); + } + + public TileModel(String tile, TileDataGetter data) { + this.tile = tile.toUpperCase(); + this.data = data; + } + + public static Tile getTile(@Nullable TileModel model) { + return model == null ? Tiles.get((short) 0) : Tiles.get(model.tile); + } + + public static int getTileData(@Nullable TileModel model, Tile tile, Tile target, Level level, int xt, int yt, Player player, Direction attackDir) { + if (model == null) return DEFAULT_DATA.getTileData(tile, target, level, xt, yt, player, attackDir); + return model.data.getTileData(tile, target, level, xt, yt, player, attackDir); + } } public boolean interactOn(Tile tile, Level level, int xt, int yt, Player player, Direction attackDir) { for (String tilename : validTiles) { if (tile.matches(level.getData(xt, yt), tilename)) { - level.setTile(xt, yt, model); // TODO maybe data should be part of the saved tile..? + Tile t = TileModel.getTile(model); + level.setTile(xt, yt, t, TileModel.getTileData(model, t, tile, level, xt, yt, player, attackDir)); AdvancementElement.AdvancementTrigger.PlacedTileTrigger.INSTANCE.trigger( new AdvancementElement.AdvancementTrigger.PlacedTileTrigger.PlacedTileTriggerConditionHandler.PlacedTileTriggerConditions( this, level.getTile(xt, yt), level.getData(xt, yt), xt, yt, level.depth )); Sound.play("craft"); - return super.interactOn(true); } } Logger.tag("TileItem").debug("{} cannot be placed on {}.", model, tile.name); - String note = ""; - if (model.contains("WALL")) { - note = Localization.getLocalized("minicraft.notification.invalid_placement", Tiles.getName(validTiles.get(0))); - } - else if (model.contains("DOOR")) { - note = Localization.getLocalized("minicraft.notification.invalid_placement", Tiles.getName(validTiles.get(0))); - } - else if ((model.contains("BRICK") || model.contains("PLANK") || model.equals("STONE") || model.contains("ORNATE"))) { - note = Localization.getLocalized("minicraft.notification.dig_hole"); - } + if (model != null) { + String note = ""; + if (model.tile.contains("WALL")) { + note = Localization.getLocalized("minicraft.notification.invalid_placement", Tiles.getName(validTiles.get(0))); + } else if (model.tile.contains("DOOR")) { + note = Localization.getLocalized("minicraft.notification.invalid_placement", Tiles.getName(validTiles.get(0))); + } else if ((model.tile.contains("BRICK") || model.tile.contains("PLANK") || model.tile.equals("STONE") || model.tile.contains("ORNATE"))) { + note = Localization.getLocalized("minicraft.notification.dig_hole"); + } - if (note.length() > 0) { - Game.notifications.add(note); + if (note.length() > 0) { + Game.notifications.add(note); + } } return super.interactOn(false); @@ -125,11 +181,13 @@ else if ((model.contains("BRICK") || model.contains("PLANK") || model.equals("ST @Override public boolean equals(Item other) { - return super.equals(other) && model.equals(((TileItem)other).model); + return super.equals(other) && (model == null || model.equals(((TileItem) other).model)); } @Override - public int hashCode() { return super.hashCode() + model.hashCode(); } + public int hashCode() { + return super.hashCode() + (model == null ? 0xFF123 : model.hashCode()); + } public @NotNull TileItem copy() { return new TileItem(getName(), sprite, count, model, validTiles); diff --git a/src/client/java/minicraft/item/ToolItem.java b/src/client/java/minicraft/item/ToolItem.java index 297760fd1..6a8c945db 100644 --- a/src/client/java/minicraft/item/ToolItem.java +++ b/src/client/java/minicraft/item/ToolItem.java @@ -30,7 +30,7 @@ protected static ArrayList getAllInstances() { private Random random = new Random(); - public static final String[] LEVEL_NAMES = {"Wood", "Rock", "Iron", "Gold", "Gem"}; // The names of the different levels. A later level means a stronger tool. + public static final String[] LEVEL_NAMES = { "Wood", "Rock", "Iron", "Gold", "Gem" }; // The names of the different levels. A later level means a stronger tool. public ToolType type; // Type of tool (Sword, hoe, axe, pickaxe, shovel) public int level; // Level of said tool @@ -42,7 +42,9 @@ private static String getSpriteName(String typeName, String level) { return level + typeName.toLowerCase(); } - /** Tool Item, requires a tool type (ToolType.Sword, ToolType.Axe, ToolType.Hoe, etc) and a level (0 = wood, 2 = iron, 4 = gem, etc) */ + /** + * Tool Item, requires a tool type (ToolType.Sword, ToolType.Axe, ToolType.Hoe, etc) and a level (0 = wood, 2 = iron, 4 = gem, etc) + */ public ToolItem(ToolType type, int level) { super(LEVEL_NAMES[level] + " " + type.name(), new LinkedSprite(SpriteType.Item, getSpriteName(type.toString(), LEVEL_NAMES[level] + "_"))); @@ -60,10 +62,13 @@ public ToolItem(ToolType type) { dur = type.durability; } - /** Gets the name of this tool (and it's type) as a display string. */ + /** + * Gets the name of this tool (and it's type) as a display string. + */ @Override public String getDisplayName() { - if (!type.noLevel) return " " + Localization.getLocalized(LEVEL_NAMES[level]) + " " + Localization.getLocalized(type.toString()); + if (!type.noLevel) + return " " + Localization.getLocalized(LEVEL_NAMES[level]) + " " + Localization.getLocalized(type.toString()); else return " " + Localization.getLocalized(type.toString()); } @@ -71,7 +76,9 @@ public boolean isDepleted() { return dur <= 0 && type.durability > 0; } - /** You can attack mobs with tools. */ + /** + * You can attack mobs with tools. + */ public boolean canAttack() { return type != ToolType.Shears; } @@ -86,7 +93,9 @@ public int getDamage() { return random.nextInt(5) + damage; } - /** Gets the attack damage bonus from an item/tool (sword/axe) */ + /** + * Gets the attack damage bonus from an item/tool (sword/axe) + */ public int getAttackDamageBonus(Entity e) { if (!payDurability()) return 0; @@ -111,7 +120,9 @@ public String getData() { return super.getData() + "_" + dur; } - /** Sees if this item equals another. */ + /** + * Sees if this item equals another. + */ @Override public boolean equals(Item item) { if (item instanceof ToolItem) { @@ -122,7 +133,9 @@ public boolean equals(Item item) { } @Override - public int hashCode() { return type.name().hashCode() + level; } + public int hashCode() { + return type.name().hashCode() + level; + } public @NotNull ToolItem copy() { ToolItem ti; diff --git a/src/client/java/minicraft/item/ToolType.java b/src/client/java/minicraft/item/ToolType.java index 242a82e31..b6e8e1883 100644 --- a/src/client/java/minicraft/item/ToolType.java +++ b/src/client/java/minicraft/item/ToolType.java @@ -1,14 +1,14 @@ package minicraft.item; public enum ToolType { - Shovel (0, 34), // If there's a second number, it specifies durability. - Hoe (1, 30), - Sword (2, 52), - Pickaxe (3, 38), - Axe (4, 34), - Bow (5, 30), - Claymore (6, 44), - Shears (0, 42, true); + Shovel(0, 34), // If there's a second number, it specifies durability. + Hoe(1, 30), + Sword(2, 52), + Pickaxe(3, 38), + Axe(4, 34), + Bow(5, 30), + Claymore(6, 44), + Shears(0, 42, true); public final int xPos; // X Position of origin public final int yPos; // Y position of origin diff --git a/src/client/java/minicraft/item/TorchItem.java b/src/client/java/minicraft/item/TorchItem.java deleted file mode 100644 index 6df20168b..000000000 --- a/src/client/java/minicraft/item/TorchItem.java +++ /dev/null @@ -1,46 +0,0 @@ -package minicraft.item; - -import minicraft.entity.Direction; -import minicraft.entity.mob.Player; -import minicraft.gfx.SpriteLinker.LinkedSprite; -import minicraft.gfx.SpriteLinker.SpriteType; -import minicraft.level.Level; -import minicraft.level.tile.Tile; -import minicraft.level.tile.TorchTile; -import org.jetbrains.annotations.NotNull; - -import java.util.ArrayList; - -public class TorchItem extends TileItem { - - public static ArrayList getAllInstances() { - ArrayList items = new ArrayList<>(); - items.add(new TorchItem()); - return items; - } - - private TorchItem() { this(1); } - private TorchItem(int count) { - super("Torch", new LinkedSprite(SpriteType.Item, "torch"), count, "", "dirt", "Wood Planks", "Stone Bricks", "Obsidian", "Wool", "Red Wool", "Blue Wool", "Green Wool", "Yellow Wool", "Black Wool", "grass", "sand","path","ornate stone","ornate obsidian"); - } - - public boolean interactOn(Tile tile, Level level, int xt, int yt, Player player, Direction attackDir) { - if (validTiles.contains(tile.name)) { - level.setTile(xt, yt, TorchTile.getTorchTile(tile)); - return super.interactOn(true); - } - return super.interactOn(false); - } - - @Override - public boolean equals(Item other) { - return other instanceof TorchItem; - } - - @Override - public int hashCode() { return 8931; } - - public @NotNull TorchItem copy() { - return new TorchItem(count); - } -} diff --git a/src/client/java/minicraft/item/WateringCanItem.java b/src/client/java/minicraft/item/WateringCanItem.java new file mode 100644 index 000000000..486d1c218 --- /dev/null +++ b/src/client/java/minicraft/item/WateringCanItem.java @@ -0,0 +1,139 @@ +package minicraft.item; + +import minicraft.entity.Direction; +import minicraft.entity.mob.Player; +import minicraft.entity.particle.Particle; +import minicraft.entity.particle.WaterParticle; +import minicraft.gfx.Point; +import minicraft.gfx.SpriteLinker; +import minicraft.level.Level; +import minicraft.level.tile.DirtTile; +import minicraft.level.tile.GrassTile; +import minicraft.level.tile.Tile; +import minicraft.level.tile.Tiles; +import minicraft.level.tile.WaterTile; +import minicraft.level.tile.farming.CropTile; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.Random; + +public class WateringCanItem extends Item { + protected static ArrayList getAllInstances() { + ArrayList items = new ArrayList<>(); + items.add(new WateringCanItem("Watering Can")); + return items; + } + + private static final SpriteLinker.LinkedSprite sprite = new SpriteLinker.LinkedSprite(SpriteLinker.SpriteType.Item, "watering_can"); + private static final SpriteLinker.LinkedSprite spriteFilled = new SpriteLinker.LinkedSprite(SpriteLinker.SpriteType.Item, "watering_can_filled"); + private static final SpriteLinker.LinkedSprite particleSprite = new SpriteLinker.LinkedSprite(SpriteLinker.SpriteType.Entity, "glint"); + + private static final SpriteLinker.LinkedSprite[] spriteSplash = new SpriteLinker.LinkedSprite[] { + new SpriteLinker.LinkedSprite(SpriteLinker.SpriteType.Entity, "splash_0"), + new SpriteLinker.LinkedSprite(SpriteLinker.SpriteType.Entity, "splash_1"), + new SpriteLinker.LinkedSprite(SpriteLinker.SpriteType.Entity, "splash_2"), + new SpriteLinker.LinkedSprite(SpriteLinker.SpriteType.Entity, "splash_3") + }; + + public final int CAPACITY = 1800; + public int content = 0; + private int renderingTick = 0; + + protected WateringCanItem(String name) { + super(name, sprite); + } + + @Override + public boolean interactOn(Tile tile, Level level, int xt, int yt, Player player, Direction attackDir) { + if (tile instanceof WaterTile) { + content = CAPACITY; + updateSprite(); + return true; + } else if (content > 0) { + content--; + updateSprite(); + renderingTick++; + Random random = new Random(); + if (renderingTick >= 8) { + for (int i = 0; i < 4; i++) { + SpriteLinker.LinkedSprite splash = spriteSplash[random.nextInt(spriteSplash.length)]; + // 2-pixel deviation for centering particle sprites. + int destX = player.x - 2 + 12 * attackDir.getX() + random.nextInt(9) - 4; + int destY = player.y - 2 + 12 * attackDir.getY() + random.nextInt(9) - 4; + int x = player.x - 2 + 4 * attackDir.getX() + random.nextInt(5) - 2; + int y = player.y - 2 + 4 * attackDir.getY() + random.nextInt(5) - 2; + level.add(new WaterParticle(x, y, 80 + random.nextInt(61) - 30, splash, destX, destY)); + renderingTick = 0; + } + } + if (tile instanceof CropTile) { + int fertilization = ((CropTile) tile).getFertilization(level.getData(xt, yt)); + if (fertilization < 150) { // Maximum of 5 levels watering can can fertilize. + ((CropTile) tile).fertilize(level, xt, yt, 1); + } + if (random.nextInt(5) == 0) { + double x = (double) xt * 16 + 8 + (random.nextGaussian() * 0.5) * 8; + double y = (double) yt * 16 + 8 + (random.nextGaussian() * 0.5) * 8; + level.add(new Particle((int) x, (int) y, 120 + random.nextInt(21) - 40, particleSprite)); + } + } else if (tile instanceof DirtTile || tile instanceof GrassTile) { + if (tile instanceof GrassTile) { + if (random.nextInt(15) == 0) { + double x = (double) xt * 16 + 8 + (random.nextGaussian() * 0.5) * 8; + double y = (double) yt * 16 + 8 + (random.nextGaussian() * 0.5) * 8; + level.add(new Particle((int) x, (int) y, 120 + random.nextInt(21) - 40, particleSprite)); + } + if (random.nextInt(60) == 0) { // Small chance for growing flowers + level.setTile(xt, yt, Tiles.get((short) 2), random.nextInt(2)); + } + } + + for (Point p : level.getAreaTilePositions(xt, yt, 1)) { + Tile t = level.getTile(p.x, p.y); + if (tile instanceof DirtTile) { + if (t instanceof GrassTile) { // Grass tile exists. + if (random.nextInt(5) == 0) { + double x = (double) xt * 16 + 8 + (random.nextGaussian() * 0.5) * 8; + double y = (double) yt * 16 + 8 + (random.nextGaussian() * 0.5) * 8; + level.add(new Particle((int) x, (int) y, 120 + random.nextInt(21) - 40, particleSprite)); + } + if (random.nextInt(10) == 0) + level.setTile(xt, yt, Tiles.get("grass")); // Grass extends. + break; // Operation finished. + } + } else { // tile instanceof GrassTile + if (t instanceof DirtTile) { // Dirt tile exists. + if (random.nextInt(5) == 0) { + double x = (double) xt * 16 + 8 + (random.nextGaussian() * 0.5) * 8; + double y = (double) yt * 16 + 8 + (random.nextGaussian() * 0.5) * 8; + level.add(new Particle((int) x, (int) y, 120 + random.nextInt(21) - 40, particleSprite)); + } + if (random.nextInt(15) == 0) + level.setTile(p.x, p.y, Tiles.get("grass")); // Grass extends. + break; // Operation finished. + } + } + } + } + + return true; + } + + return false; + } + + private void updateSprite() { + super.sprite = content > 0 ? spriteFilled : sprite; + } + + @Override + public String getData() { + return super.getData() + "_" + content; + } + + @Override + public @NotNull Item copy() { + return new WateringCanItem(getName()); + } +} diff --git a/src/client/java/minicraft/level/Level.java b/src/client/java/minicraft/level/Level.java index 18ab8f210..791ccdaa1 100644 --- a/src/client/java/minicraft/level/Level.java +++ b/src/client/java/minicraft/level/Level.java @@ -2,7 +2,6 @@ import minicraft.core.Game; import minicraft.core.Updater; -import minicraft.core.World; import minicraft.core.io.Localization; import minicraft.core.io.Settings; import minicraft.entity.Entity; @@ -33,7 +32,9 @@ import minicraft.level.tile.Tile; import minicraft.level.tile.Tiles; import minicraft.level.tile.TorchTile; +import minicraft.level.tile.TreeTile; import minicraft.util.Logging; +import minicraft.util.MyUtils; import java.util.ArrayList; import java.util.Arrays; @@ -50,9 +51,15 @@ public class Level { private final Random random; - private static final String[] levelNames = {"Sky", "Surface", "Iron", "Gold", "Lava", "Dungeon"}; - public static String getLevelName(int depth) { return levelNames[-1 * depth + 1]; } - public static String getDepthString(int depth) { return Localization.getLocalized("minicraft.displays.loading.message.level", depth < 0 ? "B" + (-depth) : depth); } + private static final String[] levelNames = { "Sky", "Surface", "Iron", "Gold", "Lava", "Dungeon" }; + + public static String getLevelName(int depth) { + return levelNames[-1 * depth + 1]; + } + + public static String getDepthString(int depth) { + return Localization.getLocalized("minicraft.displays.loading.message.level", depth < 0 ? "B" + (-depth) : depth); + } private static final int MOB_SPAWN_FACTOR = 100; // The chance of a mob actually trying to spawn when trySpawn is called equals: mobCount / maxMobCount * MOB_SPAWN_FACTOR. so, it basically equals the chance, 1/number, of a mob spawning when the mob cap is reached. I hope that makes sense... @@ -62,6 +69,8 @@ public class Level { public short[] tiles; // An array of all the tiles in the world. public short[] data; // An array of the data of the tiles in the world. + public final TreeTile.TreeType[] treeTypes; // An array of tree types + public final int depth; // Depth level of the level public int monsterDensity = 16; // Affects the number of monsters that are on the level, bigger the number the less monsters spawn. public int maxMobCount; @@ -79,7 +88,9 @@ public class Level { @SuppressWarnings("Convert2Lambda") private static Comparator spriteSorter = Comparator.comparingInt(new ToIntFunction() { @Override - public int applyAsInt(Entity e) { return e.y; } + public int applyAsInt(Entity e) { + return e.y; + } }); public Entity[] getEntitiesToSave() { @@ -94,7 +105,10 @@ public Entity[] getEntitiesToSave() { // This is a solely a debug method I made, to make printing repetitive stuff easier. // Should be changed to accept prepend and entity, or a tile (as an Object). It will get the coordinates and class name from the object, and will divide coords by 16 if passed an entity. - public void printLevelLoc(String prefix, int x, int y) { printLevelLoc(prefix, x, y, ""); } + public void printLevelLoc(String prefix, int x, int y) { + printLevelLoc(prefix, x, y, ""); + } + public void printLevelLoc(String prefix, int x, int y, String suffix) { String levelName = getLevelName(depth); @@ -107,9 +121,10 @@ public void printTileLocs(Tile t) { if (getTile(x, y).id == t.id) printLevelLoc(t.name, x, y); } + public void printEntityLocs(Class c) { int numfound = 0; - for (Entity entity: getEntityArray()) { + for (Entity entity : getEntityArray()) { if (c.isAssignableFrom(entity.getClass())) { printLevelLoc(entity.toString(), entity.x >> 4, entity.y >> 4); numfound++; @@ -133,12 +148,43 @@ public Level(int w, int h, long seed, int level, Level parentLevel, boolean make random = new Random(seed); short[][] maps; // Multidimensional array (an array within a array), used for the map + treeTypes = new TreeTile.TreeType[w * h]; + { + LevelGen noise1 = new LevelGen(w, h, 32); + LevelGen noise2 = new LevelGen(w, h, 32); + TreeTile.TreeType[] types = TreeTile.TreeType.values(); + for (int y = 0; y < h; y++) { // Loop through height + for (int x = 0; x < w; x++) { // Loop through width + // Randomly selecting a tree type. + int i = x + y * w; + double val = Math.abs(noise1.values[i] - noise2.values[i]) * 3 - 2; + // This calculates a sort of distance based on the current coordinate. + double xd = x / (w - 1.0) * 2 - 1; + double yd = y / (h - 1.0) * 2 - 1; + if (xd < 0) xd = -xd; + if (yd < 0) yd = -yd; + double dist = Math.max(xd, yd); + dist = dist * dist * dist * dist; + dist = dist * dist * dist * dist; + val += 1 - dist * 20; + val += 1.5; // Assuming the range of value is from 0 to 2. + val *= types.length / 2.0; + val += 1; // Incrementing index. + // The original val mainly falls in small interval instead of averagely. + val = 1.0 / (3 * types.length) * Math.pow(val - 5, 2); // Quadratically bloating the value. + int idx = (int) Math.round(val - 1); // Decrementing index. + treeTypes[x + y * w] = (idx >= types.length || idx < 0) ? TreeTile.TreeType.OAK // Oak by default. + : types[idx]; + } + } + } + if (level != -4 && level != 0) monsterDensity = 8; updateMobCap(); - if(!makeWorld) { + if (!makeWorld) { int arrsize = w * h; tiles = new short[arrsize]; data = new short[arrsize]; @@ -156,6 +202,7 @@ public Level(int w, int h, long seed, int level, Level parentLevel, boolean make tiles = maps[0]; // Assigns the tiles in the map data = maps[1]; // Assigns the data of the tiles + if (level < 0) generateSpawnerStructures(); @@ -171,13 +218,11 @@ public Level(int w, int h, long seed, int level, Level parentLevel, boolean make if (parentLevel.getTile(x, y) == Tiles.get("Stairs Down")) { // If the tile in the level above the current one is a stairs down then... if (level == -4) { /// Make the obsidian wall formation around the stair in the dungeon level Structure.dungeonGate.draw(this, x, y); // Te gate should not intersect with the boss room. - Structure.dungeonBossRoom.draw(this, w/2, h/2); // Generating the boss room at the center. - } - else if (level == 0) { // Surface + Structure.dungeonBossRoom.draw(this, w / 2, h / 2); // Generating the boss room at the center. + } else if (level == 0) { // Surface Logging.WORLD.trace("Setting tiles around " + x + "," + y + " to hard rock"); setAreaTiles(x, y, 1, Tiles.get("Hard Rock"), 0); // surround the sky stairs with hard rock - } - else // Any other level, the up-stairs should have dirt on all sides. + } else // Any other level, the up-stairs should have dirt on all sides. setAreaTiles(x, y, 1, Tiles.get("dirt"), 0); setTile(x, y, Tiles.get("Stairs Up")); // Set a stairs up tile in the same position on the current level @@ -212,7 +257,9 @@ public Level(int w, int h, int level, Level parentLevel, boolean makeWorld) { this(w, h, 0, level, parentLevel, makeWorld); } - /** Level which the world is contained in */ + /** + * Level which the world is contained in + */ public Level(int w, int h, int level, Level parentLevel) { this(w, h, level, parentLevel, true); } @@ -224,17 +271,18 @@ public long getSeed() { public void checkAirWizard() { checkAirWizard(true); } + private void checkAirWizard(boolean check) { if (depth == 1 && !AirWizard.beaten) { // Add the airwizard to the surface boolean found = false; if (check) { - for (Entity e: entitiesToAdd) + for (Entity e : entitiesToAdd) if (e instanceof AirWizard) { found = true; break; } - for (Entity e: entities) + for (Entity e : entities) if (e instanceof AirWizard) { found = true; break; @@ -243,7 +291,7 @@ private void checkAirWizard(boolean check) { if (!found) { AirWizard aw = new AirWizard(); - add(aw, w/2, h/2, true); + add(aw, w / 2, h / 2, true); } } } @@ -251,6 +299,7 @@ private void checkAirWizard(boolean check) { public void checkChestCount() { checkChestCount(true); } + private void checkChestCount(boolean check) { // If the level is the dungeon, and we're not just loading the world... if (depth != -4) return; @@ -258,10 +307,10 @@ private void checkChestCount(boolean check) { int numChests = 0; if (check) { - for (Entity e: entitiesToAdd) + for (Entity e : entitiesToAdd) if (e instanceof DungeonChest) numChests++; - for (Entity e: entities) + for (Entity e : entities) if (e instanceof DungeonChest) numChests++; Logging.WORLDNAMED.debug("Found " + numChests + " chests."); @@ -269,7 +318,7 @@ private void checkChestCount(boolean check) { /// Make DungeonChests! for (int i = numChests; i < 10 * (w / 128); i++) { - DungeonChest d = new DungeonChest(true); + DungeonChest d = new DungeonChest(random); boolean addedchest = false; while (!addedchest) { // Keep running until we successfully add a DungeonChest @@ -294,8 +343,8 @@ private void checkChestCount(boolean check) { } } if (d.x == 0 && d.y == 0) { - d.x = x2 * 16 - 8; - d.y = y2 * 16 - 8; + d.x = (x2 << 4) - 8; + d.y = (y2 << 4) - 8; } add(d); @@ -332,7 +381,8 @@ public void tick(boolean fullTick) { boolean inLevel = entities.contains(entity); if (!inLevel) { - if (Logging.logLevel) printEntityStatus("Adding ", entity, "furniture.DungeonChest", "mob.AirWizard", "mob.Player"); + if (Logging.logLevel) + printEntityStatus("Adding ", entity, "furniture.DungeonChest", "mob.AirWizard", "mob.Player"); synchronized (entityLock) { entities.add(entity); @@ -404,8 +454,8 @@ public double distanceOfClosestPlayer(Entity entity) { public void printEntityStatus(String entityMessage, Entity entity, String... searching) { // "searching" can contain any number of class names I want to print when found. String clazz = entity.getClass().getCanonicalName(); - clazz = clazz.substring(clazz.lastIndexOf(".")+1); - for (String search: searching) { + clazz = clazz.substring(clazz.lastIndexOf(".") + 1); + for (String search : searching) { try { if (Class.forName("minicraft.entity." + search).isAssignableFrom(entity.getClass())) { printLevelLoc(entityMessage + clazz, entity.x >> 4, entity.y >> 4, ": " + entity); @@ -418,16 +468,19 @@ public void printEntityStatus(String entityMessage, Entity entity, String... sea } public void dropItem(int x, int y, int mincount, int maxcount, Item... items) { - dropItem(x, y, mincount+random.nextInt(maxcount - mincount + 1), items); + dropItem(x, y, mincount + random.nextInt(maxcount - mincount + 1), items); } + public void dropItem(int x, int y, int count, Item... items) { for (int i = 0; i < count; i++) dropItem(x, y, items); } + public void dropItem(int x, int y, Item... items) { - for (Item i: items) + for (Item i : items) dropItem(x, y, i); } + public ItemEntity dropItem(int x, int y, Item i) { int ranx, rany; @@ -478,7 +531,7 @@ public void renderLight(Screen screen, int xScroll, int yScroll, int brightness) int r = 8; List entities = getEntitiesInTiles(xo - r, yo - r, w + xo + r, h + yo + r); - for (Entity e: entities) { + for (Entity e : entities) { int lr = e.getLightRadius(); if (lr > 0) screen.renderLight(e.x - 1, e.y - 4, lr * brightness); } @@ -488,7 +541,7 @@ public void renderLight(Screen screen, int xScroll, int yScroll, int brightness) if (x < 0 || y < 0 || x >= this.w || y >= this.h) continue; int lr = getTile(x, y).getLightRadius(this, x, y); - if (lr > 0) screen.renderLight(x * 16 + 8, y * 16 + 8, lr * brightness); + if (lr > 0) screen.renderLight((x << 4) + 8, (y << 4) + 8, lr * brightness); } } screen.setOffset(0, 0); @@ -505,19 +558,21 @@ private void sortAndRender(Screen screen, List list) { } public Tile getTile(int x, int y) { - if (x < 0 || y < 0 || x >= w || y >= h /* || (x + y * w) >= tiles.length*/ ) return Tiles.get("connector tile"); - int id = tiles[x + y * w]; - if(id < 0) id += 256; - return Tiles.get(id); + if (x < 0 || y < 0 || x >= w || y >= h /* || (x + y * w) >= tiles.length*/) return Tiles.get("connector tile"); + return Tiles.get(tiles[x + y * w]); } + /** + * @deprecated Currently unused, but this should be prevented being used. + */ + @Deprecated public void setTile(int x, int y, String tilewithdata) { if (!tilewithdata.contains("_")) { setTile(x, y, Tiles.get(tilewithdata)); return; } String name = tilewithdata.substring(0, tilewithdata.indexOf("_")); - int data = Tiles.get(name).getData(tilewithdata.substring(name.length()+1)); + int data = Tiles.get(name).getData(tilewithdata.substring(name.length() + 1)); setTile(x, y, Tiles.get(name), data); } @@ -530,11 +585,12 @@ public void setTile(int x, int y, Tile t, int dataVal) { tiles[x + y * w] = t.id; data[x + y * w] = (short) dataVal; + t.onTileSet(this, x, y); } public int getData(int x, int y) { if (x < 0 || y < 0 || x >= w || y >= h) return 0; - return data[x + y * w] & 0xff; + return data[x + y * w] & 0xFFFF; } public void setData(int x, int y, int val) { @@ -542,13 +598,20 @@ public void setData(int x, int y, int val) { data[x + y * w] = (short) val; } - public void add(Entity e) { if(e==null) return; add(e, e.x, e.y); } - public void add(Entity entity, int x, int y) { add(entity, x, y, false); } + public void add(Entity e) { + if (e == null) return; + add(e, e.x, e.y); + } + + public void add(Entity entity, int x, int y) { + add(entity, x, y, false); + } + public void add(Entity entity, int x, int y, boolean tileCoords) { - if(entity == null) return; - if(tileCoords) { - x = x * 16 + 8; - y = y * 16 + 8; + if (entity == null) return; + if (tileCoords) { + x = (x << 4) + 8; + y = (y << 4) + 8; } entity.setLevel(this, x, y); @@ -563,7 +626,9 @@ public void remove(Entity e) { entitiesToRemove.add(e); } - /** Natural spawn. */ + /** + * Natural spawn. + */ private void trySpawn() { int spawnSkipChance = (int) (MOB_SPAWN_FACTOR * Math.pow(mobCount, 2) / Math.pow(maxMobCount, 2)); if (spawnSkipChance > 0 && random.nextInt(spawnSkipChance) != 0) @@ -571,12 +636,13 @@ private void trySpawn() { boolean spawned = false; for (Player player : players) { - int lvl = World.lvlIdx(player.getLevel().depth); + assert player.getLevel().depth == depth; + int lvl = -MyUtils.clamp(player.getLevel().depth, -4, 0); for (int i = 0; i < 30 && !spawned; i++) { int rnd = random.nextInt(100); int nx = random.nextInt(w) * 16 + 8, ny = random.nextInt(h) * 16 + 8; double distance = Math.hypot(Math.abs(nx - player.x), Math.abs(ny - player.y)); - if (distance < 10 || distance > 40) continue; // Spawns only between 10 and 40 tiles far from players. + if (distance < 160) continue; // Spawns only far from 10 tiles away. //System.out.println("trySpawn on level " + depth + " of lvl " + lvl + " mob w/ rand " + rnd + " at tile " + nx + "," + ny); @@ -615,7 +681,7 @@ private void trySpawn() { } public void removeAllEnemies() { - for (Entity e: getEntityArray()) { + for (Entity e : getEntityArray()) { if (e instanceof EnemyMob) if (!(e instanceof AirWizard) || Game.isMode("minicraft.settings.mode.creative")) // Don't remove the airwizard bosses! Unless in creative, since you can spawn more. e.remove(); @@ -640,10 +706,14 @@ public Entity[] getEntityArray() { return entityArray; } - public List getEntitiesInTiles(int xt, int yt, int radius) { return getEntitiesInTiles(xt, yt, radius, false); } + public List getEntitiesInTiles(int xt, int yt, int radius) { + return getEntitiesInTiles(xt, yt, radius, false); + } @SafeVarargs - public final List getEntitiesInTiles(int xt, int yt, int radius, boolean includeGiven, Class... entityClasses) { return getEntitiesInTiles(xt-radius, yt-radius, xt+radius, yt+radius, includeGiven, entityClasses); } + public final List getEntitiesInTiles(int xt, int yt, int radius, boolean includeGiven, Class... entityClasses) { + return getEntitiesInTiles(xt - radius, yt - radius, xt + radius, yt + radius, includeGiven, entityClasses); + } /** * Get entities in a certain area on the level. @@ -652,7 +722,9 @@ public Entity[] getEntityArray() { * @param xt1 Right * @param yt1 Bottom */ - public List getEntitiesInTiles(int xt0, int yt0, int xt1, int yt1) { return getEntitiesInTiles(xt0, yt0, xt1, yt1, false); } + public List getEntitiesInTiles(int xt0, int yt0, int xt1, int yt1) { + return getEntitiesInTiles(xt0, yt0, xt1, yt1, false); + } /** * Get entities in a certain area on the level, and filter them by class. @@ -667,7 +739,7 @@ public Entity[] getEntityArray() { @SafeVarargs public final List getEntitiesInTiles(int xt0, int yt0, int xt1, int yt1, boolean includeGiven, Class... entityClasses) { List contained = new ArrayList<>(); - for (Entity e: getEntityArray()) { + for (Entity e : getEntityArray()) { int xt = e.x >> 4; int yt = e.y >> 4; @@ -697,7 +769,7 @@ public final List getEntitiesInTiles(int xt0, int yt0, int xt1, int yt1, * @return True if there is an entity on the tile. */ public final boolean isEntityOnTile(int x, int y) { - for (Entity e: getEntityArray()) { + for (Entity e : getEntityArray()) { int xt = e.x >> 4; int yt = e.y >> 4; @@ -710,7 +782,7 @@ public final boolean isEntityOnTile(int x, int y) { public List getEntitiesInRect(Rectangle area) { List result = new ArrayList<>(); - for (Entity e: getEntityArray()) { + for (Entity e : getEntityArray()) { if (e.isTouching(area)) result.add(e); } @@ -730,7 +802,7 @@ public List getEntitiesInRect(Predicate filter, Rectangle area) /// Finds all entities that are an instance of the given entity. public Entity[] getEntitiesOfClass(Class targetClass) { ArrayList matches = new ArrayList<>(); - for (Entity e: getEntityArray()) { + for (Entity e : getEntityArray()) { if (targetClass.isAssignableFrom(e.getClass())) matches.add(e); } @@ -753,7 +825,7 @@ public Player getClosestPlayer(int x, int y) { for (int i = 1; i < players.length; i++) { int curxd = players[i].x - x; int curyd = players[i].y - y; - if(xd*xd + yd*yd > curxd*curxd + curyd*curyd) { + if (xd * xd + yd * yd > curxd * curxd + curyd * curyd) { closest = players[i]; xd = curxd; yd = curyd; @@ -771,11 +843,11 @@ public Player getClosestPlayer(int x, int y) { * @param hitBoxRight The right boundary of hit box * @param hitBoxFront The front boundary of hit box * @param frontTilePassableCheck The check of whether the front boundary of hit box hits the tile hit box; - * the first parameter takes the front tile position and second one takes the horizontal position + * the first parameter takes the front tile position and second one takes the horizontal position * @return The maximum front position can be reached by tile hit box check */ public static int calculateMaxFrontClosestTile(int sgn, int d, int hitBoxLeft, int hitBoxRight, int hitBoxFront, - BiPredicate frontTilePassableCheck) { + BiPredicate frontTilePassableCheck) { int hitBoxFront1 = hitBoxFront + d; // After maximum movement int hitBoxLeftTile = hitBoxLeft >> 4; int hitBoxRightTile = hitBoxRight >> 4; @@ -783,11 +855,12 @@ public static int calculateMaxFrontClosestTile(int sgn, int d, int hitBoxLeft, i int hitBoxFrontTile1 = hitBoxFront1 >> 4; int maxFrontTile = hitBoxFrontTile1; // Value for full tile movement // Skips the current tile by adding 1. + mainLoop: for (int front = hitBoxFrontTile + sgn; sgn < 0 ? front >= hitBoxFrontTile1 : front <= hitBoxFrontTile1; front += sgn) { for (int horTile = hitBoxLeftTile; horTile <= hitBoxRightTile; horTile++) { if (!frontTilePassableCheck.test(front, horTile)) { maxFrontTile = front - sgn; // Rolls back a tile by subtracting 1. - break; // Tile hit box check stops. + break mainLoop; // Tile hit box check stops. } } } @@ -796,40 +869,49 @@ public static int calculateMaxFrontClosestTile(int sgn, int d, int hitBoxLeft, i (sgn > 0 ? Math.min(d, (maxFrontTile << 4) - hitBoxFront + (1 << 4) - 1) : Math.max(d, (maxFrontTile << 4) - hitBoxFront)); } - public Point[] getAreaTilePositions(int x, int y, int r) { return getAreaTilePositions(x, y, r, r); } + public Point[] getAreaTilePositions(int x, int y, int r) { + return getAreaTilePositions(x, y, r, r); + } + public Point[] getAreaTilePositions(int x, int y, int rx, int ry) { ArrayList local = new ArrayList<>(); - for (int yp = y-ry; yp <= y+ry; yp++) - for (int xp = x-rx; xp <= x+rx; xp++) + for (int yp = y - ry; yp <= y + ry; yp++) + for (int xp = x - rx; xp <= x + rx; xp++) if (xp >= 0 && xp < w && yp >= 0 && yp < h) local.add(new Point(xp, yp)); return local.toArray(new Point[0]); } - public Tile[] getAreaTiles(int x, int y, int r) { return getAreaTiles(x, y, r, r); } + public Tile[] getAreaTiles(int x, int y, int r) { + return getAreaTiles(x, y, r, r); + } + public Tile[] getAreaTiles(int x, int y, int rx, int ry) { ArrayList local = new ArrayList<>(); - for (Point p: getAreaTilePositions(x, y, rx, ry)) + for (Point p : getAreaTilePositions(x, y, rx, ry)) local.add(getTile(p.x, p.y)); return local.toArray(new Tile[0]); } - public void setAreaTiles(int xt, int yt, int r, Tile tile, int data) { setAreaTiles(xt, yt, r, tile, data, false); } + public void setAreaTiles(int xt, int yt, int r, Tile tile, int data) { + setAreaTiles(xt, yt, r, tile, data, false); + } + public void setAreaTiles(int xt, int yt, int r, Tile tile, int data, boolean overwriteStairs) { - for(int y = yt - r; y <= yt + r; y++) { + for (int y = yt - r; y <= yt + r; y++) { for (int x = xt - r; x <= xt + r; x++) { - if(overwriteStairs || (!getTile(x, y).name.toLowerCase().contains("stairs"))) + if (overwriteStairs || (!getTile(x, y).name.toLowerCase().contains("stairs"))) setTile(x, y, tile, data); } } } - public void setAreaTiles(int xt, int yt, int r, Tile tile, int data, String[] blacklist) { + public void setAreaTiles(int xt, int yt, int r, Tile tile, int data, TileCheck condition) { for (int y = yt - r; y <= yt + r; y++) { for (int x = xt - r; x <= xt + r; x++) { - if (!Arrays.asList(blacklist).contains(getTile(x, y).name.toLowerCase())) + if (condition.check(getTile(x, y), x, y)) setTile(x, y, tile, data); } } @@ -840,15 +922,19 @@ public interface TileCheck { boolean check(Tile t, int x, int y); } - public List getMatchingTiles(Tile search) { return getMatchingTiles((t, x, y) -> t.equals(search)); } + public List getMatchingTiles(Tile search) { + return getMatchingTiles((t, x, y) -> t.equals(search)); + } + public List getMatchingTiles(Tile... search) { return getMatchingTiles((t, x, y) -> { - for (Tile poss: search) + for (Tile poss : search) if (t.equals(poss)) return true; return false; }); } + public List getMatchingTiles(TileCheck condition) { List matches = new ArrayList<>(); for (int y = 0; y < h; y++) @@ -860,11 +946,12 @@ public List getMatchingTiles(TileCheck condition) { } public boolean isLight(int x, int y) { - for (Tile t: getAreaTiles(x, y, 3)) + for (Tile t : getAreaTiles(x, y, 3)) if (t instanceof TorchTile) return true; for (Entity e : getEntitiesInRect(e -> e instanceof Lantern, new Rectangle(x, y, 8, 8, Rectangle.CENTER_DIMS))) { - if (Math.hypot((e.x >> 4) - x, (e.y >> 4) - y) < e.getLightRadius() - 1) + int xx = (e.x >> 4) - x, yy = (e.y >> 4) - y, rr = e.getLightRadius() - 1; + if (xx * xx + yy * yy < rr * rr) return true; } @@ -896,8 +983,8 @@ private void generateSpawnerStructures() { if (xaxis2) { for (int s2 = x3; s2 < w - s2; s2++) { if (getTile(s2, y3) == Tiles.get("rock")) { - sp.x = s2 * 16 - 24; - sp.y = y3 * 16 - 24; + sp.x = (s2 << 4) - 24; + sp.y = (y3 << 4) - 24; } } } else { @@ -914,23 +1001,23 @@ private void generateSpawnerStructures() { sp.y = y3 * 16 - 8; } - if (getTile(sp.x / 16, sp.y / 16) == Tiles.get("rock")) { - setTile(sp.x / 16, sp.y / 16, Tiles.get("dirt")); + if (getTile(sp.x >> 4, sp.y >> 4) == Tiles.get("rock")) { + setTile(sp.x >> 4, sp.y >> 4, Tiles.get("dirt")); } - Structure.mobDungeonCenter.draw(this, sp.x / 16, sp.y / 16, random.nextInt(3) * 5 + 90, random); + Structure.mobDungeonCenter.draw(this, sp.x >> 4, sp.y >> 4, random.nextInt(3) * 5 + 90, random); - if (getTile(sp.x / 16, sp.y / 16 - 4) == Tiles.get("dirt")) { - Structure.mobDungeonNorth.draw(this, sp.x / 16, sp.y / 16 - 5, random.nextInt(3) * 5 + 90, random); + if (getTile(sp.x >> 4, (sp.y >> 4) - 4) == Tiles.get("dirt")) { + Structure.mobDungeonNorth.draw(this, sp.x >> 4, (sp.y >> 4) - 5, random.nextInt(3) * 5 + 90, random); } - if (getTile(sp.x / 16, sp.y / 16 + 4) == Tiles.get("dirt")) { - Structure.mobDungeonSouth.draw(this, sp.x / 16, sp.y / 16 + 5, random.nextInt(3) * 5 + 90, random); + if (getTile(sp.x >> 4, (sp.y >> 4) + 4) == Tiles.get("dirt")) { + Structure.mobDungeonSouth.draw(this, sp.x >> 4, (sp.y >> 4) + 5, random.nextInt(3) * 5 + 90, random); } - if (getTile(sp.x / 16 + 4, sp.y / 16) == Tiles.get("dirt")) { - Structure.mobDungeonEast.draw(this, sp.x / 16 + 5, sp.y / 16, random.nextInt(3) * 5 + 90, random); + if (getTile((sp.x >> 4) + 4, sp.y >> 4) == Tiles.get("dirt")) { + Structure.mobDungeonEast.draw(this, (sp.x >> 4) + 5, sp.y >> 4, random.nextInt(3) * 5 + 90, random); } - if (getTile(sp.x / 16 - 4, sp.y / 16) == Tiles.get("dirt")) { - Structure.mobDungeonWest.draw(this, sp.x / 16 - 5, sp.y / 16, random.nextInt(3) * 5 + 90, random); + if (getTile((sp.x >> 4) - 4, sp.y >> 4) == Tiles.get("dirt")) { + Structure.mobDungeonWest.draw(this, (sp.x >> 4) - 5, sp.y >> 4, random.nextInt(3) * 5 + 90, random); } add(sp); @@ -939,14 +1026,13 @@ private void generateSpawnerStructures() { Chest c = new Chest(); int chance = -depth; - c.populateInvRandom("minidungeon", chance); + c.populateInvRandom(random, "minidungeon", chance); add(c, sp.x - 16 + rpt * 32, sp.y - 16); } } } - } - else { + } else { for (int i = 0; i < 18 * (w / 128); i++) { /// For generating spawner dungeons @@ -986,16 +1072,16 @@ private void generateSpawnerStructures() { sp.y = y3 * 16 - 8; } - if (getTile(sp.x / 16, sp.y / 16) == Tiles.get("Obsidian Wall")) { - setTile(sp.x / 16, sp.y / 16, Tiles.get("dirt")); + if (getTile(sp.x >> 4, sp.y >> 4) == Tiles.get("Obsidian Wall")) { + setTile(sp.x >> 4, sp.y >> 4, Tiles.get("dirt")); } - Structure.dungeonSpawner.draw(this, sp.x / 16, sp.y / 16); + Structure.dungeonSpawner.draw(this, sp.x >> 4, sp.y >> 4); add(sp); for (int rpt = 0; rpt < 2; rpt++) { if (random.nextInt(2) != 0) continue; - DungeonChest c = new DungeonChest(true); + DungeonChest c = new DungeonChest(random); chestCount++; add(c, sp.x - 16 + rpt * 32, sp.y - 16); @@ -1052,7 +1138,7 @@ private void generateVillages() { // Add a chest to some houses if (hasChest) { Chest c = new Chest(); - c.populateInvRandom("villagehouse", 1); + c.populateInvRandom(random, "villagehouse", 1); add(c, (x + random.nextInt(2) + xo) << 4, (y + random.nextInt(2) + yo) << 4); } } @@ -1072,7 +1158,10 @@ private void generateDungeonStructures() { if (random.nextBoolean()) { Structure.dungeonGarden.draw(this, x, y); } else { - Structure.dungeonChest.draw(this, x, y); + Structure.dungeonChest.draw(this, x, y, furniture -> { + if (furniture instanceof DungeonChest) + ((DungeonChest) furniture).populateInv(random); + }); } } } @@ -1083,9 +1172,9 @@ private void generateDungeonStructures() { */ public void regenerateBossRoom() { if (depth == -4) { - Structure.dungeonBossRoom.draw(tiles, w/2, h/2, w); // Generating the boss room at the center. - for (int x = w/2-4; x < w/2+5; x++) { // Resetting tile data. - for (int y = h/2-4; y < h/2+5; y++) { + Structure.dungeonBossRoom.draw(tiles, w / 2, h / 2, w); // Generating the boss room at the center. + for (int x = w / 2 - 4; x < w / 2 + 5; x++) { // Resetting tile data. + for (int y = h / 2 - 4; y < h / 2 + 5; y++) { setData(x, y, 0); } } diff --git a/src/client/java/minicraft/level/LevelGen.java b/src/client/java/minicraft/level/LevelGen.java index 8342f8d4f..613073d5e 100644 --- a/src/client/java/minicraft/level/LevelGen.java +++ b/src/client/java/minicraft/level/LevelGen.java @@ -37,7 +37,9 @@ public class LevelGen { private final int w, h; // Width and height of the map private static final int stairRadius = 15; - /** This creates noise to create random values for level generation */ + /** + * This creates noise to create random values for level generation + */ public LevelGen(int w, int h, int featureSize) { this.w = w; this.h = h; @@ -169,7 +171,7 @@ private static short[][] createAndValidateTopMap(int w, int h) { } while (true); } - private static short[][] createAndValidateUndergroundMap(int w, int h, int depth) { + private static short[] @Nullable [] createAndValidateUndergroundMap(int w, int h, int depth) { random.setSeed(worldSeed); do { short[][] result = createUndergroundMap(w, h, depth); @@ -210,7 +212,7 @@ private static short[][] createAndValidateDungeon(int w, int h) { } while (true); } - private static short[][] createAndValidateSkyMap(int w, int h) { + private static short[] @Nullable [] createAndValidateSkyMap(int w, int h) { random.setSeed(worldSeed); do { @@ -517,7 +519,7 @@ private static short[][] createTopMap(int w, int h) { // Create surface map if (count >= w / 21) break; } - return new short[][]{map, data}; + return new short[][] { map, data }; } private static short[][] createDungeon(int w, int h) { @@ -581,7 +583,7 @@ private static short[][] createDungeon(int w, int h) { } } - return new short[][]{map, data}; + return new short[][] { map, data }; } @@ -670,10 +672,10 @@ private static short[][] createUndergroundMap(int w, int h, int depth) { } if (depth > 2) { // The level above dungeon. - int xm = w/2; - int ym = h/2; + int xm = w / 2; + int ym = h / 2; int side = 6; // The side of the lock is 5, and pluses margin with 1. - int edgeMargin = w/20; // The distance between the world enge and the lock sides. + int edgeMargin = w / 20; // The distance between the world enge and the lock sides. Rectangle edgeRect = new Rectangle(edgeMargin, edgeMargin, w - edgeMargin, h - edgeMargin, Rectangle.CORNERS); Rectangle lockRect = new Rectangle(0, 0, side, side, 0); Rectangle bossRoomRect = new Rectangle(xm, ym, 20, 20, Rectangle.CENTER_DIMS); @@ -712,7 +714,7 @@ private static short[][] createUndergroundMap(int w, int h, int depth) { } } - return new short[][]{map, data}; + return new short[][] { map, data }; } private static short[][] createSkyMap(int w, int h) { @@ -780,7 +782,7 @@ private static short[][] createSkyMap(int w, int h) { if (count >= w / 64) break; } - return new short[][]{map, data}; + return new short[][] { map, data }; } public static void main(String[] args) { diff --git a/src/client/java/minicraft/level/Structure.java b/src/client/java/minicraft/level/Structure.java index e7d65ac1a..40c1390b1 100644 --- a/src/client/java/minicraft/level/Structure.java +++ b/src/client/java/minicraft/level/Structure.java @@ -12,6 +12,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Random; +import java.util.function.Consumer; // this stores structures that can be drawn at any location. public class Structure { @@ -23,6 +24,7 @@ public Structure() { tiles = new HashSet<>(); furniture = new HashMap<>(); } + public Structure(Structure struct) { this.tiles = struct.tiles; this.furniture = struct.furniture; @@ -31,16 +33,22 @@ public Structure(Structure struct) { public void setTile(int x, int y, Tile tile) { tiles.add(new TilePoint(x, y, tile)); } + public void addFurniture(int x, int y, Furniture furniture) { this.furniture.put(new Point(x, y), furniture); } - public void draw(Level level, int xt, int yt) { - for (TilePoint p: tiles) - level.setTile(xt+p.x, yt+p.y, p.t); + public void draw(Level level, int xt, int yt) { draw(level, xt, yt, f -> { }); } - for (Point p: furniture.keySet()) - level.add(furniture.get(p).copy(), xt+p.x, yt+p.y, true); + public void draw(Level level, int xt, int yt, Consumer furnitureHandler) { + for (TilePoint p : tiles) + level.setTile(xt + p.x, yt + p.y, p.t); + + for (Point p : furniture.keySet()) { + Furniture fur = furniture.get(p).copy(); + furnitureHandler.accept(fur); + level.add(fur, xt + p.x, yt + p.y, true); + } } public void draw(Level level, int xt, int yt, float integrity, Random random) { @@ -52,7 +60,7 @@ public void draw(Level level, int xt, int yt, float integrity, Random random) { } public void draw(short[] map, int xt, int yt, int mapWidth) { - for (TilePoint p: tiles) + for (TilePoint p : tiles) map[(xt + p.x) + (yt + p.y) * mapWidth] = p.t.id; } @@ -75,7 +83,7 @@ public void setData(String keys, String data) { for (int c = 0; c < dataLines[i].length(); c++) { if (dataLines[i].charAt(c) != '*') { Tile tile = Tiles.get(keyPairs.get(String.valueOf(dataLines[i].charAt(c)))); - this.setTile(-width / 2 + i, - height / 2 + c, tile); + this.setTile(-width / 2 + i, -height / 2 + c, tile); } } } @@ -134,21 +142,21 @@ public int hashCode() { static { dungeonGate = new Structure(); dungeonGate.setData("O:Obsidian,D:Obsidian Door,W:Obsidian Wall", - "WWDWW\n" + - "WOOOW\n" + - "DOOOD\n" + - "WOOOW\n" + - "WWDWW" + "WWDWW\n" + + "WOOOW\n" + + "DOOOD\n" + + "WOOOW\n" + + "WWDWW" ); dungeonGate.addFurniture(-1, -1, new Lantern(Lantern.Type.IRON)); dungeonLock = new Structure(); dungeonLock.setData("O:Obsidian,W:Obsidian Wall", - "WWWWW\n" + - "WOOOW\n" + - "WOOOW\n" + - "WOOOW\n" + - "WWWWW" + "WWWWW\n" + + "WOOOW\n" + + "WOOOW\n" + + "WOOOW\n" + + "WWWWW" ); dungeonBossRoom = new Structure(); dungeonBossRoom.setData("O:Obsidian Boss Floor,D:Obsidian Boss Door,W:Obsidian Boss Wall", @@ -162,7 +170,7 @@ public int hashCode() { "WOOOOOOOW\n" + "WWWWDWWWW" ); - dungeonBossRoom.addFurniture(0,0,new KnightStatue(5000)); + dungeonBossRoom.addFurniture(0, 0, new KnightStatue(5000)); dungeonSpawner = new Structure(); dungeonSpawner.setData("F:Grass,W:Obsidian Wall,O:Ornate Obsidian,D:Obsidian Door", @@ -177,8 +185,8 @@ public int hashCode() { lavaPool = new Structure(); lavaPool.setData("L:Lava", - "LL\n" + - "LL" + "LL\n" + + "LL" ); ornateLavaPool = new Structure(); @@ -213,94 +221,94 @@ public int hashCode() { "WOOOOOW\n" + "WWWDWWW" ); - dungeonChest.addFurniture(0,0, new DungeonChest(true)); + dungeonChest.addFurniture(0, 0, new DungeonChest(null)); mobDungeonCenter = new Structure(); mobDungeonCenter.setData("B:Stone Bricks,W:Stone Wall", - "WWBWW\n" + - "WBBBW\n" + - "BBBBB\n" + - "WBBBW\n" + - "WWBWW" + "WWBWW\n" + + "WBBBW\n" + + "BBBBB\n" + + "WBBBW\n" + + "WWBWW" ); mobDungeonNorth = new Structure(); mobDungeonNorth.setData("B:Stone Bricks,W:Stone Wall", - "WWWWW\n" + - "WBBBB\n" + - "BBBBB\n" + - "WBBBB\n" + - "WWWWW" + "WWWWW\n" + + "WBBBB\n" + + "BBBBB\n" + + "WBBBB\n" + + "WWWWW" ); mobDungeonSouth = new Structure(); mobDungeonSouth.setData("B:Stone Bricks,W:Stone Wall", - "WWWWW\n" + - "BBBBW\n" + - "BBBBB\n" + - "BBBBW\n" + - "WWWWW" + "WWWWW\n" + + "BBBBW\n" + + "BBBBB\n" + + "BBBBW\n" + + "WWWWW" ); mobDungeonEast = new Structure(); mobDungeonEast.setData("B:Stone Bricks,W:Stone Wall", - "WBBBW\n" + - "WBBBW\n" + - "WBBBW\n" + - "WBBBW\n" + - "WWBWW" + "WBBBW\n" + + "WBBBW\n" + + "WBBBW\n" + + "WBBBW\n" + + "WWBWW" ); mobDungeonWest = new Structure(); mobDungeonWest.setData("B:Stone Bricks,W:Stone Wall", - "WWBWW\n" + - "WBBBW\n" + - "WBBBW\n" + - "WBBBW\n" + - "WBBBW" + "WWBWW\n" + + "WBBBW\n" + + "WBBBW\n" + + "WBBBW\n" + + "WBBBW" ); airWizardHouse = new Structure(); airWizardHouse.setData("F:Wood Planks,W:Wood Wall,D:Wood Door", - "WWWWWWW\n" + - "WFFFFFW\n" + - "DFFFFFW\n" + - "WFFFFFW\n" + - "WWWWWWW" + "WWWWWWW\n" + + "WFFFFFW\n" + + "DFFFFFW\n" + + "WFFFFFW\n" + + "WWWWWWW" ); airWizardHouse.addFurniture(-2, 0, new Lantern(Lantern.Type.GOLD)); airWizardHouse.addFurniture(0, 0, new Crafter(Crafter.Type.Enchanter)); villageHouseNormal = new Structure(); villageHouseNormal.setData("F:Wood Planks,W:Wood Wall,D:Wood Door,G:Grass", - "WWWWW\n" + - "WFFFW\n" + - "WFFFD\n" + - "WFFFG\n" + - "WWWWW" + "WWWWW\n" + + "WFFFW\n" + + "WFFFD\n" + + "WFFFG\n" + + "WWWWW" ); villageHouseTwoDoor = new Structure(); villageHouseTwoDoor.setData("F:Wood Planks,W:Wood Wall,D:Wood Door,G:Grass", - "WWWWW\n" + - "WFFFW\n" + - "DFFFW\n" + - "WFFFW\n" + - "WWDWW" + "WWWWW\n" + + "WFFFW\n" + + "DFFFW\n" + + "WFFFW\n" + + "WWDWW" ); villageRuinedOverlay1 = new Structure(); villageRuinedOverlay1.setData("G:Grass,F:Wood Planks", - "**FG*\n" + - "F*GG*\n" + - "*G**F\n" + - "G*G**\n" + - "***G*" + "**FG*\n" + + "F*GG*\n" + + "*G**F\n" + + "G*G**\n" + + "***G*" ); villageRuinedOverlay2 = new Structure(); villageRuinedOverlay2.setData("G:Grass,F:Wood Planks", - "F**G*\n" + - "*****\n" + - "*GG**\n" + - "F**G*\n" + - "*F**G" + "F**G*\n" + + "*****\n" + + "*GG**\n" + + "F**G*\n" + + "*F**G" ); } } diff --git a/src/client/java/minicraft/level/tile/BossWallTile.java b/src/client/java/minicraft/level/tile/BossWallTile.java index 12d1ea05f..54c2d7f82 100644 --- a/src/client/java/minicraft/level/tile/BossWallTile.java +++ b/src/client/java/minicraft/level/tile/BossWallTile.java @@ -14,7 +14,7 @@ public class BossWallTile extends WallTile { private static SpriteAnimation obsidian = new SpriteAnimation(SpriteLinker.SpriteType.Tile, "obsidian_wall") - .setConnectChecker((tile, side) -> tile.getClass() == BossWallTile.class); + .setConnectionChecker((level, x, y, tile, side) -> tile instanceof WallTile); private static final String wallMsg = "minicraft.notification.defeat_obsidian_knight_first"; diff --git a/src/client/java/minicraft/level/tile/CactusTile.java b/src/client/java/minicraft/level/tile/CactusTile.java index 3fa2c59f7..8f076592a 100644 --- a/src/client/java/minicraft/level/tile/CactusTile.java +++ b/src/client/java/minicraft/level/tile/CactusTile.java @@ -20,7 +20,11 @@ public class CactusTile extends Tile { protected CactusTile(String name) { super(name, sprite); - connectsToSand = true; + } + + @Override + public boolean connectsToSand(Level level, int x, int y) { + return true; } public boolean mayPass(Level level, int x, int y, Entity e) { @@ -31,14 +35,14 @@ public boolean hurt(Level level, int x, int y, Mob source, int dmg, Direction at int damage = level.getData(x, y) + dmg; int cHealth = 10; if (Game.isMode("minicraft.settings.mode.creative")) dmg = damage = cHealth; - level.add(new SmashParticle(x * 16, y * 16)); - level.add(new TextParticle("" + dmg, x * 16 + 8, y * 16 + 8, Color.RED)); + level.add(new SmashParticle(x << 4, y << 4)); + level.add(new TextParticle("" + dmg, (x << 4) + 8, (y << 4) + 8, Color.RED)); if (damage >= cHealth) { //int count = random.nextInt(2) + 2; level.setTile(x, y, Tiles.get("sand")); Sound.play("monsterhurt"); - level.dropItem(x * 16 + 8, y * 16 + 8, 2, 4, Items.get("Cactus")); + level.dropItem((x << 4) + 8, (y << 4) + 8, 2, 4, Items.get("Cactus")); } else { level.setData(x, y, damage); } @@ -52,7 +56,7 @@ public void render(Screen screen, Level level, int x, int y) { } public void bumpedInto(Level level, int x, int y, Entity entity) { - if(!(entity instanceof Mob)) return; + if (!(entity instanceof Mob)) return; Mob m = (Mob) entity; if (Settings.get("diff").equals("minicraft.settings.difficulty.easy")) { m.hurt(this, x, y, 1); diff --git a/src/client/java/minicraft/level/tile/CloudTile.java b/src/client/java/minicraft/level/tile/CloudTile.java index 6503df7c1..869ffb0f1 100644 --- a/src/client/java/minicraft/level/tile/CloudTile.java +++ b/src/client/java/minicraft/level/tile/CloudTile.java @@ -15,7 +15,7 @@ public class CloudTile extends Tile { private static SpriteAnimation sprite = new SpriteAnimation(SpriteType.Tile, "cloud") - .setConnectChecker((tile, side) -> tile.getClass() != InfiniteFallTile.class) + .setConnectionChecker((level, x, y, tile, side) -> !(tile instanceof InfiniteFallTile)) .setSingletonWithConnective(true); protected CloudTile(String name) { @@ -34,7 +34,7 @@ public boolean interact(Level level, int xt, int yt, Player player, Item item, D int data = level.getData(xt, yt); level.setTile(xt, yt, Tiles.get("Infinite Fall")); // Would allow you to shovel cloud, I think. Sound.play("monsterhurt"); - level.dropItem(xt * 16 + 8, yt * 16 + 8, 1, 3, Items.get("Cloud")); + level.dropItem((xt << 4) + 8, (yt << 4) + 8, 1, 3, Items.get("Cloud")); AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.INSTANCE.trigger( new AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.ItemUsedOnTileTriggerConditionHandler.ItemUsedOnTileTriggerConditions( item, this, data, xt, yt, level.depth)); diff --git a/src/client/java/minicraft/level/tile/ConnectTile.java b/src/client/java/minicraft/level/tile/ConnectTile.java index c6db32812..f46f1a197 100644 --- a/src/client/java/minicraft/level/tile/ConnectTile.java +++ b/src/client/java/minicraft/level/tile/ConnectTile.java @@ -9,17 +9,17 @@ // TODO Remove this. // IMPORTANT: This tile should never be used for anything, it only exists to allow tiles right next to the edge of the world to connect to it public class ConnectTile extends Tile { - public ConnectTile() { - super("connector tile", new SpriteAnimation(SpriteType.Tile, "missing_tile")); - } + public ConnectTile() { + super("connector tile", new SpriteAnimation(SpriteType.Tile, "missing_tile")); + } - @Override - public boolean mayPass(Level level, int x, int y, Entity e) { - return false; - } + @Override + public boolean mayPass(Level level, int x, int y, Entity e) { + return false; + } - @Override - public boolean maySpawn() { - return false; - } + @Override + public boolean maySpawn() { + return false; + } } diff --git a/src/client/java/minicraft/level/tile/DecorTile.java b/src/client/java/minicraft/level/tile/DecorTile.java index a40f13f2a..a3ee6968c 100644 --- a/src/client/java/minicraft/level/tile/DecorTile.java +++ b/src/client/java/minicraft/level/tile/DecorTile.java @@ -4,6 +4,7 @@ import minicraft.entity.Direction; import minicraft.entity.Entity; import minicraft.entity.mob.Player; +import minicraft.gfx.Screen; import minicraft.gfx.SpriteAnimation; import minicraft.gfx.SpriteLinker.SpriteType; import minicraft.item.Item; @@ -13,22 +14,51 @@ import minicraft.util.AdvancementElement; public class DecorTile extends Tile { - private static SpriteAnimation stoneSprite = new SpriteAnimation(SpriteType.Tile, "ornate_stone"); - private static SpriteAnimation obsidianSprite = new SpriteAnimation(SpriteType.Tile, "ornate_obsidian"); + private static final SpriteAnimation stoneSprite = new SpriteAnimation(SpriteType.Tile, "ornate_stone"); + private static final SpriteAnimation obsidianSprite = new SpriteAnimation(SpriteType.Tile, "ornate_obsidian"); + private static final SpriteAnimation woodSprite = new SpriteAnimation(SpriteType.Tile, "ornate_wood"); + private static final SpriteAnimation sandStoneSprite = new SpriteAnimation(SpriteType.Tile, "sandstone"); + private static final SpriteAnimation rawEtherealSprite = new SpriteAnimation(SpriteType.Tile, "cloud");//"raw_ethereal"); - protected Material type; + public enum decorType { + ORNATE_OBSIDIAN(obsidianSprite, "Ornate Obsidian", Material.Obsidian), + ORNATE_STONE(stoneSprite, "Ornate Stone", Material.Stone), + ORNATE_WOOD(woodSprite, "Ornate Wood", Material.Wood), + SANDSTONE(sandStoneSprite, "Sandstone", Material.Stone), + RAW_ETHEREAL(rawEtherealSprite, "Raw Ethereal", Material.Obsidian),; - protected DecorTile(Material type) { - super((type == Material.Obsidian ? "Ornate Obsidian" : type == Material.Stone ? "Ornate Stone" : "Decorated " + type.name()), - type == Material.Stone ? stoneSprite : obsidianSprite); - this.type = type; + private final SpriteAnimation decorSprite; + private final String name; + private final Material mType; + + decorType (SpriteAnimation sprite, String name, Material mType) { + this.decorSprite = sprite; + this.name = name; + this.mType = mType; + } + } + + private final decorType thisType; + private final Material mType; + + protected DecorTile(decorType type) { + super(type.name, null); maySpawn = true; + thisType = type; + sprite = thisType.decorSprite; + mType = thisType.mType; + } + + @Override + public void render(Screen screen, Level level, int x, int y) { + super.render(screen, level, x, y); + screen.render(x * 16 + 0, y * 16, sprite.getCurrentFrame().getSprite().spritePixels[0][0]); } public boolean interact(Level level, int xt, int yt, Player player, Item item, Direction attackDir) { if (item instanceof ToolItem) { ToolItem tool = (ToolItem) item; - if (tool.type == type.getRequiredTool()) { + if (tool.type == mType.getRequiredTool()) { if (player.payStamina(4 - tool.level) && tool.payDurability()) { int data = level.getData(xt, yt); if (level.depth == 1) { @@ -37,13 +67,21 @@ public boolean interact(Level level, int xt, int yt, Player player, Item item, D level.setTile(xt, yt, Tiles.get("Hole")); } Item drop; - switch (type) { - case Stone: drop = Items.get("Ornate Stone"); break; - case Obsidian: drop = Items.get("Ornate Obsidian"); break; - default: throw new IllegalStateException("Unexpected value: " + type); + switch (thisType) { + case ORNATE_STONE: + drop = Items.get("Ornate Stone"); + break; + case ORNATE_OBSIDIAN: + drop = Items.get("Ornate Obsidian"); + break; + case ORNATE_WOOD: + drop = Items.get("Ornate Wood"); + break; + default: + throw new IllegalStateException("Unexpected value: " + thisType); } Sound.play("monsterhurt"); - level.dropItem(xt * 16 + 8, yt * 16 + 8, drop); + level.dropItem((xt << 4) + 8, (yt << 4) + 8, drop); AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.INSTANCE.trigger( new AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.ItemUsedOnTileTriggerConditionHandler.ItemUsedOnTileTriggerConditions( item, this, data, xt, yt, level.depth)); diff --git a/src/client/java/minicraft/level/tile/DirtTile.java b/src/client/java/minicraft/level/tile/DirtTile.java index 090f19ff4..32bdf3112 100644 --- a/src/client/java/minicraft/level/tile/DirtTile.java +++ b/src/client/java/minicraft/level/tile/DirtTile.java @@ -28,18 +28,25 @@ protected DirtTile(String name) { protected static int dCol(int depth) { switch (depth) { - case 1: return Color.get(1, 194, 194, 194); // Sky. - case 0: return Color.get(1, 129, 105, 83); // Surface. - case -4: return Color.get(1, 76, 30, 100); // Dungeons. - default: return Color.get(1, 102); // Caves. + case 1: + return Color.get(1, 194, 194, 194); // Sky. + case 0: + return Color.get(1, 129, 105, 83); // Surface. + case -4: + return Color.get(1, 76, 30, 100); // Dungeons. + default: + return Color.get(1, 102); // Caves. } } protected static int dIdx(int depth) { switch (depth) { - case 0: return 0; // Surface - case -4: return 2; // Dungeons - default: return 1; // Caves + case 0: + return 0; // Surface + case -4: + return 2; // Dungeons + default: + return 1; // Caves } } @@ -55,7 +62,7 @@ public boolean interact(Level level, int xt, int yt, Player player, Item item, D int data = level.getData(xt, yt); level.setTile(xt, yt, Tiles.get("Hole")); Sound.play("monsterhurt"); - level.dropItem(xt * 16 + 8, yt * 16 + 8, Items.get("Dirt")); + level.dropItem((xt << 4) + 8, (yt << 4) + 8, Items.get("Dirt")); AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.INSTANCE.trigger( new AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.ItemUsedOnTileTriggerConditionHandler.ItemUsedOnTileTriggerConditions( item, this, data, xt, yt, level.depth)); diff --git a/src/client/java/minicraft/level/tile/DoorTile.java b/src/client/java/minicraft/level/tile/DoorTile.java index e01b023cc..495595c7a 100644 --- a/src/client/java/minicraft/level/tile/DoorTile.java +++ b/src/client/java/minicraft/level/tile/DoorTile.java @@ -19,7 +19,10 @@ public class DoorTile extends Tile { private SpriteAnimation closedSprite; private SpriteAnimation openSprite; - protected DoorTile(Material type) { this(type, null); } + protected DoorTile(Material type) { + this(type, null); + } + protected DoorTile(Material type, String name) { super(type.name() + " " + (name == null ? "Door" : name), null); this.type = type; @@ -52,9 +55,9 @@ public boolean interact(Level level, int xt, int yt, Player player, Item item, D if (tool.type == type.getRequiredTool()) { if (player.payStamina(4 - tool.level) && tool.payDurability()) { int data = level.getData(xt, yt); - level.setTile(xt, yt, Tiles.get(id + 3)); // Will get the corresponding floor tile. + level.setTile(xt, yt, Tiles.get((short) (id + 3))); // Will get the corresponding floor tile. Sound.play("monsterhurt"); - level.dropItem(xt * 16 + 8, yt * 16 + 8, Items.get(type.name() + " Door")); + level.dropItem((xt << 4) + 8, (yt << 4) + 8, Items.get(type.name() + " Door")); AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.INSTANCE.trigger( new AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.ItemUsedOnTileTriggerConditionHandler.ItemUsedOnTileTriggerConditions( item, this, data, xt, yt, level.depth)); diff --git a/src/client/java/minicraft/level/tile/ExplodedTile.java b/src/client/java/minicraft/level/tile/ExplodedTile.java index af333f481..b79123d94 100644 --- a/src/client/java/minicraft/level/tile/ExplodedTile.java +++ b/src/client/java/minicraft/level/tile/ExplodedTile.java @@ -8,12 +8,20 @@ /// This class is for tiles WHILE THEY ARE EXPLODING public class ExplodedTile extends Tile { private static SpriteAnimation sprite = new SpriteAnimation(SpriteType.Tile, "exploded") - .setConnectChecker((tile, side) -> tile.getClass() == ExplodedTile.class); + .setConnectionChecker((level, x, y, tile, side) -> tile instanceof ExplodedTile); protected ExplodedTile(String name) { super(name, sprite); - connectsToSand = true; - connectsToFluid = true; + } + + @Override + public boolean connectsToFluid(Level level, int x, int y) { + return true; + } + + @Override + public boolean connectsToSand(Level level, int x, int y) { + return true; } public boolean mayPass(Level level, int x, int y, Entity e) { diff --git a/src/client/java/minicraft/level/tile/FenceTile.java b/src/client/java/minicraft/level/tile/FenceTile.java new file mode 100644 index 000000000..c62f84ab6 --- /dev/null +++ b/src/client/java/minicraft/level/tile/FenceTile.java @@ -0,0 +1,139 @@ +package minicraft.level.tile; + +import minicraft.core.Game; +import minicraft.core.io.Sound; +import minicraft.entity.Direction; +import minicraft.entity.Entity; +import minicraft.entity.mob.Mob; +import minicraft.entity.mob.Player; +import minicraft.entity.particle.SmashParticle; +import minicraft.gfx.Screen; +import minicraft.gfx.SpriteAnimation; +import minicraft.gfx.SpriteLinker.SpriteType; +import minicraft.item.Item; +import minicraft.item.Items; +import minicraft.item.ToolItem; +import minicraft.level.Level; +import minicraft.util.AdvancementElement; + +public class FenceTile extends Tile { + + private static final SpriteAnimation wood = new SpriteAnimation(SpriteType.Tile, "wood_fence"); + private static final SpriteAnimation stone = new SpriteAnimation(SpriteType.Tile, "stone_fence"); + private static final SpriteAnimation obsidian = new SpriteAnimation(SpriteType.Tile, "obsidian_fence"); + + protected final Material type; + + protected final SpriteAnimation top, bottom, left, right; + + public boolean connectUp = false, connectDown = false, connectLeft = false, connectRight = false; + + protected FenceTile(Material type) { this(type, null); } + + protected FenceTile(Material type, String name) { + super(type + " " + (name == null ? "Fence" : name), null); + this.type = type; + switch (type) { + case Wood: + sprite = wood; + break; + case Stone: + sprite = stone; + break; + case Obsidian: + sprite = obsidian; + break; + } + top = new SpriteAnimation(SpriteType.Tile, type.toString().toLowerCase() + "_fence_top"); + bottom = new SpriteAnimation(SpriteType.Tile, type.toString().toLowerCase() + "_fence_bottom"); + left = new SpriteAnimation(SpriteType.Tile, type.toString().toLowerCase() + "_fence_left"); + right = new SpriteAnimation(SpriteType.Tile, type.toString().toLowerCase() + "_fence_right"); + } + + @Override + public boolean connectsToSand(Level level, int x, int y) { + return Tiles.get((short) level.getData(x, y)).connectsToSand(level, x, y); + } + + @Override + public boolean connectsToFluid(Level level, int x, int y) { + return Tiles.get((short) level.getData(x, y)).connectsToFluid(level, x, y); + } + + @Override + public boolean connectsToGrass(Level level, int x, int y) { + return Tiles.get((short) level.getData(x, y)).connectsToGrass(level, x, y); + } + + public void updateConnections(Level level, int x, int y) { + // TODO Tile#updateNeighbourhood + connectUp = level.getTile(x, y - 1) instanceof FenceTile; + connectDown = level.getTile(x, y + 1) instanceof FenceTile; + connectLeft = level.getTile(x - 1, y) instanceof FenceTile; + connectRight = level.getTile(x + 1, y) instanceof FenceTile; + } + + public boolean mayPass(Level level, int x, int y, Entity e) { + return false; + } + + public void render(Screen screen, Level level, int x, int y) { + Tiles.get((short) level.getData(x, y)).render(screen, level, x, y); + sprite.render(screen, level, x, y); + updateConnections(level, x, y); + + // up + if (connectUp) { + top.render(screen, level, x, y); + } + // bottom + if (connectDown) { + bottom.render(screen, level, x, y); + } + // left + if (connectLeft) { + left.render(screen, level, x, y); + } + // right + if (connectRight) { + right.render(screen, level, x, y); + } + } + + @Override + public boolean hurt(Level level, int x, int y, Mob source, int dmg, Direction attackDir) { + hurt(level, x, y, dmg); + return true; + } + + @Override + public boolean interact(Level level, int xt, int yt, Player player, Item item, Direction attackDir) { + if (Game.isMode("minicraft.settings.mode.creative")) + return false; // Go directly to hurt method + if (item instanceof ToolItem) { + ToolItem tool = (ToolItem) item; + if (tool.type == type.getRequiredTool()) { + if (player.payStamina(4 - tool.level) && tool.payDurability()) { + int data = level.getData(xt, yt); + Sound.play("monsterhurt"); + level.dropItem(xt * 16 + 8, yt * 16 + 8, Items.get(name)); + level.setTile(xt, yt, Tiles.get((short) level.getData(xt, yt))); + AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.INSTANCE.trigger( + new AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.ItemUsedOnTileTriggerConditionHandler.ItemUsedOnTileTriggerConditions( + item, this, data, xt, yt, level.depth)); + return true; + } + } + } + return false; + } + + public void hurt(Level level, int x, int y, int dmg) { + if (Game.isMode("minicraft.settings.mode.creative")) { + level.add(new SmashParticle(x * 16, y * 16)); + Sound.play("monsterhurt"); + level.dropItem(x * 16 + 8, y * 16 + 8, Items.get(name)); + level.setTile(x, y, Tiles.get((short) level.getData(x, y))); + } + } +} diff --git a/src/client/java/minicraft/level/tile/FloorTile.java b/src/client/java/minicraft/level/tile/FloorTile.java index a3cbd60da..466cfafc0 100644 --- a/src/client/java/minicraft/level/tile/FloorTile.java +++ b/src/client/java/minicraft/level/tile/FloorTile.java @@ -15,15 +15,24 @@ public class FloorTile extends Tile { protected Material type; - protected FloorTile(Material type) { this(type, null); } + protected FloorTile(Material type) { + this(type, null); + } + protected FloorTile(Material type, String name) { - super((type == Material.Wood ? "Wood Planks" : type == Material.Obsidian ? "Obsidian" + (name == null ? "" : " "+name) : type.name() + " " + (name == null ? "Bricks" : name)), null); + super((type == Material.Wood ? "Wood Planks" : type == Material.Obsidian ? "Obsidian" + (name == null ? "" : " " + name) : type.name() + " " + (name == null ? "Bricks" : name)), null); this.type = type; maySpawn = true; switch (type) { - case Wood: sprite = new SpriteAnimation(SpriteType.Tile, "wood_floor"); break; - case Stone: sprite = new SpriteAnimation(SpriteType.Tile, "stone_floor"); break; - case Obsidian: sprite = new SpriteAnimation(SpriteType.Tile, "obsidian_floor"); break; + case Wood: + sprite = new SpriteAnimation(SpriteType.Tile, "wood_floor"); + break; + case Stone: + sprite = new SpriteAnimation(SpriteType.Tile, "stone_floor"); + break; + case Obsidian: + sprite = new SpriteAnimation(SpriteType.Tile, "obsidian_floor"); + break; } } @@ -40,11 +49,15 @@ public boolean interact(Level level, int xt, int yt, Player player, Item item, D } Item drop; switch (type) { - case Wood: drop = Items.get("Plank"); break; - default: drop = Items.get(type.name() + " Brick"); break; + case Wood: + drop = Items.get("Plank"); + break; + default: + drop = Items.get(type.name() + " Brick"); + break; } Sound.play("monsterhurt"); - level.dropItem(xt * 16 + 8, yt * 16 + 8, drop); + level.dropItem((xt << 4) + 8, (yt << 4) + 8, drop); AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.INSTANCE.trigger( new AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.ItemUsedOnTileTriggerConditionHandler.ItemUsedOnTileTriggerConditions( item, this, data, xt, yt, level.depth)); diff --git a/src/client/java/minicraft/level/tile/FlowerTile.java b/src/client/java/minicraft/level/tile/FlowerTile.java index bf09593a0..0fadc749e 100644 --- a/src/client/java/minicraft/level/tile/FlowerTile.java +++ b/src/client/java/minicraft/level/tile/FlowerTile.java @@ -19,11 +19,15 @@ public class FlowerTile extends Tile { private static final SpriteAnimation flowerSprite1 = new SpriteAnimation(SpriteType.Tile, "flower_shape1"); protected FlowerTile(String name) { - super(name, (SpriteAnimation) null); - connectsToGrass = true; + super(name, null); maySpawn = true; } + @Override + public boolean connectsToGrass(Level level, int x, int y) { + return true; + } + public boolean tick(Level level, int xt, int yt) { // TODO revise this method. if (random.nextInt(30) != 0) return false; // Skips every 31 tick. @@ -43,7 +47,7 @@ public boolean tick(Level level, int xt, int yt) { public void render(Screen screen, Level level, int x, int y) { Tiles.get("Grass").render(screen, level, x, y); int data = level.getData(x, y); - int shape = (data / 16) % 2; + int shape = (data >> 4) % 2; (shape == 0 ? flowerSprite0 : flowerSprite1).render(screen, level, x, y); } @@ -55,8 +59,8 @@ public boolean interact(Level level, int x, int y, Player player, Item item, Dir int data = level.getData(x, y); level.setTile(x, y, Tiles.get("Grass")); Sound.play("monsterhurt"); - level.dropItem(x * 16 + 8, y * 16 + 8, Items.get("Flower")); - level.dropItem(x * 16 + 8, y * 16 + 8, Items.get("Rose")); + level.dropItem((x << 4) + 8, (y << 4) + 8, Items.get("Flower")); + level.dropItem((x << 4) + 8, (y << 4) + 8, Items.get("Rose")); AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.INSTANCE.trigger( new AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.ItemUsedOnTileTriggerConditionHandler.ItemUsedOnTileTriggerConditions( item, this, data, x, y, level.depth)); @@ -68,8 +72,8 @@ public boolean interact(Level level, int x, int y, Player player, Item item, Dir } public boolean hurt(Level level, int x, int y, Mob source, int dmg, Direction attackDir) { - level.dropItem(x *16 + 8, y * 16 + 8, 0, 1, Items.get("Flower")); - level.dropItem(x *16 + 8, y * 16 + 8, 0, 1, Items.get("Rose")); + level.dropItem((x << 4) + 8, (y << 4) + 8, 0, 1, Items.get("Flower")); + level.dropItem((x << 4) + 8, (y << 4) + 8, 0, 1, Items.get("Rose")); level.setTile(x, y, Tiles.get("Grass")); return true; } diff --git a/src/client/java/minicraft/level/tile/GrassTile.java b/src/client/java/minicraft/level/tile/GrassTile.java index 5b14bd396..4e66b4118 100644 --- a/src/client/java/minicraft/level/tile/GrassTile.java +++ b/src/client/java/minicraft/level/tile/GrassTile.java @@ -14,16 +14,20 @@ import minicraft.util.AdvancementElement; public class GrassTile extends Tile { - private static SpriteAnimation sprite = new SpriteAnimation(SpriteType.Tile, "grass") - .setConnectChecker((tile, side) -> !side || tile.connectsToGrass) + private static final SpriteAnimation sprite = new SpriteAnimation(SpriteType.Tile, "grass") + .setConnectionChecker((level, x, y, tile, side) -> !side || tile.connectsToGrass(level, x, y)) .setSingletonWithConnective(true); protected GrassTile(String name) { super(name, sprite); - connectsToGrass = true; maySpawn = true; } + @Override + public boolean connectsToGrass(Level level, int x, int y) { + return true; + } + public boolean tick(Level level, int xt, int yt) { // TODO revise this method. if (random.nextInt(40) != 0) return false; @@ -55,7 +59,7 @@ public boolean interact(Level level, int xt, int yt, Player player, Item item, D level.setTile(xt, yt, Tiles.get("Dirt")); Sound.play("monsterhurt"); if (random.nextInt(5) == 0) { // 20% chance to drop Grass seeds - level.dropItem(xt * 16 + 8, yt * 16 + 8, 1, Items.get("Grass Seeds")); + level.dropItem((xt << 4) + 8, (yt << 4) + 8, 1, Items.get("Grass Seeds")); } AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.INSTANCE.trigger( new AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.ItemUsedOnTileTriggerConditionHandler.ItemUsedOnTileTriggerConditions( @@ -66,10 +70,10 @@ public boolean interact(Level level, int xt, int yt, Player player, Item item, D if (tool.type == ToolType.Hoe) { if (player.payStamina(4 - tool.level) && tool.payDurability()) { int data = level.getData(xt, yt); - level.setTile(xt, yt, Tiles.get("Dirt")); + level.setTile(xt, yt, Tiles.get("Farmland")); Sound.play("monsterhurt"); if (random.nextInt(5) != 0) { // 80% chance to drop Wheat seeds - level.dropItem(xt * 16 + 8, yt * 16 + 8, Items.get("Wheat Seeds")); + level.dropItem((xt << 4) + 8, (yt << 4) + 8, Items.get("Wheat Seeds")); } AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.INSTANCE.trigger( new AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.ItemUsedOnTileTriggerConditionHandler.ItemUsedOnTileTriggerConditions( diff --git a/src/client/java/minicraft/level/tile/HardRockTile.java b/src/client/java/minicraft/level/tile/HardRockTile.java index 07c18c4d2..84bc8f2b5 100644 --- a/src/client/java/minicraft/level/tile/HardRockTile.java +++ b/src/client/java/minicraft/level/tile/HardRockTile.java @@ -22,7 +22,7 @@ public class HardRockTile extends Tile { // Theoretically the full sprite should never be used, so we can use a placeholder private static SpriteAnimation sprite = new SpriteAnimation(SpriteType.Tile, "hardrock") - .setConnectChecker((tile, side) -> tile.getClass() == HardRockTile.class) + .setConnectionChecker((level, x, y, tile, side) -> tile instanceof HardRockTile) .setSingletonWithConnective(true); protected HardRockTile(String name) { @@ -39,7 +39,7 @@ public boolean hurt(Level level, int x, int y, Mob source, int dmg, Direction at } public boolean interact(Level level, int xt, int yt, Player player, Item item, Direction attackDir) { - if(Game.isMode("minicraft.settings.mode.creative")) + if (Game.isMode("minicraft.settings.mode.creative")) return false; // Go directly to hurt method if (item instanceof ToolItem) { ToolItem tool = (ToolItem) item; @@ -65,14 +65,14 @@ public void hurt(Level level, int x, int y, int dmg) { int damage = level.getData(x, y) + dmg; int hrHealth = 200; if (Game.isMode("minicraft.settings.mode.creative")) dmg = damage = hrHealth; - level.add(new SmashParticle(x * 16, y * 16)); + level.add(new SmashParticle(x << 4, y << 4)); Sound.play("monsterhurt"); - level.add(new TextParticle("" + dmg, x * 16 + 8, y * 16 + 8, Color.RED)); + level.add(new TextParticle("" + dmg, (x << 4) + 8, (y << 4) + 8, Color.RED)); if (damage >= hrHealth) { level.setTile(x, y, Tiles.get("dirt")); - level.dropItem(x * 16 + 8, y * 16 + 8, 1, 3, Items.get("Stone")); - level.dropItem(x * 16 + 8, y * 16 + 8, 0, 1, Items.get("Coal")); + level.dropItem((x << 4) + 8, (y << 4) + 8, 1, 3, Items.get("Stone")); + level.dropItem((x << 4) + 8, (y << 4) + 8, 0, 1, Items.get("Coal")); } else { level.setData(x, y, damage); } diff --git a/src/client/java/minicraft/level/tile/HoleTile.java b/src/client/java/minicraft/level/tile/HoleTile.java index c3b89f59c..a55474fd9 100644 --- a/src/client/java/minicraft/level/tile/HoleTile.java +++ b/src/client/java/minicraft/level/tile/HoleTile.java @@ -8,13 +8,21 @@ public class HoleTile extends Tile { private static SpriteAnimation sprite = new SpriteAnimation(SpriteType.Tile, "hole") - .setConnectChecker((tile, side) -> tile.connectsToLiquid()) + .setConnectionChecker((level, x, y, tile, side) -> tile.connectsToFluid(level, x, y)) .setSingletonWithConnective(true); protected HoleTile(String name) { super(name, sprite); - connectsToSand = true; - connectsToFluid = true; + } + + @Override + public boolean connectsToSand(Level level, int x, int y) { + return true; + } + + @Override + public boolean connectsToFluid(Level level, int x, int y) { + return true; } @Override diff --git a/src/client/java/minicraft/level/tile/InfiniteFallTile.java b/src/client/java/minicraft/level/tile/InfiniteFallTile.java index 19c798890..4b660d852 100644 --- a/src/client/java/minicraft/level/tile/InfiniteFallTile.java +++ b/src/client/java/minicraft/level/tile/InfiniteFallTile.java @@ -12,14 +12,17 @@ public class InfiniteFallTile extends Tile { protected InfiniteFallTile(String name) { - super(name, (SpriteAnimation)null); + super(name, (SpriteAnimation) null); } @Override - public void render(Screen screen, Level level, int x, int y) { } + public void render(Screen screen, Level level, int x, int y) { + } @Override - public boolean tick(Level level, int xt, int yt) { return false; } + public boolean tick(Level level, int xt, int yt) { + return false; + } @Override public boolean mayPass(Level level, int x, int y, Entity e) { diff --git a/src/client/java/minicraft/level/tile/LavaBrickTile.java b/src/client/java/minicraft/level/tile/LavaBrickTile.java index 13508f7db..5400df3ae 100644 --- a/src/client/java/minicraft/level/tile/LavaBrickTile.java +++ b/src/client/java/minicraft/level/tile/LavaBrickTile.java @@ -37,9 +37,11 @@ public boolean interact(Level level, int xt, int yt, Player player, Item item, D } public void bumpedInto(Level level, int x, int y, Entity entity) { - if(entity instanceof Mob) - ((Mob)entity).hurt(this, x, y, 3); + if (entity instanceof Mob) + ((Mob) entity).hurt(this, x, y, 3); } - public boolean mayPass(Level level, int x, int y, Entity e) { return e.canWool(); } + public boolean mayPass(Level level, int x, int y, Entity e) { + return e.canWool(); + } } diff --git a/src/client/java/minicraft/level/tile/LavaTile.java b/src/client/java/minicraft/level/tile/LavaTile.java index 6edf5716e..7ab019118 100644 --- a/src/client/java/minicraft/level/tile/LavaTile.java +++ b/src/client/java/minicraft/level/tile/LavaTile.java @@ -8,13 +8,21 @@ public class LavaTile extends Tile { private static SpriteAnimation sprite = new SpriteAnimation(SpriteType.Tile, "lava") - .setConnectChecker((tile, side) -> tile.connectsToFluid) + .setConnectionChecker((level, x, y, tile, side) -> tile.connectsToFluid(level, x, y)) .setSingletonWithConnective(true); protected LavaTile(String name) { super(name, sprite); - connectsToSand = true; - connectsToFluid = true; + } + + @Override + public boolean connectsToSand(Level level, int x, int y) { + return true; + } + + @Override + public boolean connectsToFluid(Level level, int x, int y) { + return true; } @Override diff --git a/src/client/java/minicraft/level/tile/MaterialTile.java b/src/client/java/minicraft/level/tile/MaterialTile.java index 53df6a95b..c3220f9c6 100644 --- a/src/client/java/minicraft/level/tile/MaterialTile.java +++ b/src/client/java/minicraft/level/tile/MaterialTile.java @@ -16,12 +16,16 @@ public class MaterialTile extends Tile { protected Material type; protected MaterialTile(Material type) { - super((type == Material.Stone ? "Stone" : type == Material.Obsidian ? "Raw Obsidian" :type.name()), (SpriteAnimation) null); + super((type == Material.Stone ? "Stone" : type == Material.Obsidian ? "Raw Obsidian" : type.name()), (SpriteAnimation) null); this.type = type; maySpawn = true; switch (type) { - case Stone: sprite = new SpriteAnimation(SpriteType.Tile, "stone"); break; - case Obsidian: sprite = new SpriteAnimation(SpriteType.Tile, "obsidian"); break; + case Stone: + sprite = new SpriteAnimation(SpriteType.Tile, "stone"); + break; + case Obsidian: + sprite = new SpriteAnimation(SpriteType.Tile, "obsidian"); + break; default: } } @@ -39,12 +43,17 @@ public boolean interact(Level level, int xt, int yt, Player player, Item item, D } Item drop; switch (type) { - case Stone: drop = Items.get("Stone"); break; - case Obsidian: drop = Items.get("Raw Obsidian"); break; - default: throw new IllegalStateException("Unexpected value: " + type); + case Stone: + drop = Items.get("Stone"); + break; + case Obsidian: + drop = Items.get("Raw Obsidian"); + break; + default: + throw new IllegalStateException("Unexpected value: " + type); } Sound.play("monsterhurt"); - level.dropItem(xt * 16 + 8, yt * 16 + 8, drop); + level.dropItem((xt << 4) + 8, (yt << 4) + 8, drop); AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.INSTANCE.trigger( new AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.ItemUsedOnTileTriggerConditionHandler.ItemUsedOnTileTriggerConditions( item, this, data, xt, yt, level.depth)); diff --git a/src/client/java/minicraft/level/tile/OreTile.java b/src/client/java/minicraft/level/tile/OreTile.java index 2bfe1506a..e34470f95 100644 --- a/src/client/java/minicraft/level/tile/OreTile.java +++ b/src/client/java/minicraft/level/tile/OreTile.java @@ -25,11 +25,11 @@ public class OreTile extends Tile { private final OreType type; public enum OreType { - Iron (Items.get("Iron Ore"), new SpriteAnimation(SpriteType.Tile, "iron_ore")), - Lapis (Items.get("Lapis"), new SpriteAnimation(SpriteType.Tile, "lapis_ore")), - Gold (Items.get("Gold Ore"), new SpriteAnimation(SpriteType.Tile, "gold_ore")), - Gem (Items.get("Gem"), new SpriteAnimation(SpriteType.Tile, "gem_ore")), - Cloud (Items.get("Cloud Ore"), new SpriteAnimation(SpriteType.Tile, "cloud_ore")); + Iron(Items.get("Iron Ore"), new SpriteAnimation(SpriteType.Tile, "iron_ore")), + Lapis(Items.get("Lapis"), new SpriteAnimation(SpriteType.Tile, "lapis_ore")), + Gold(Items.get("Gold Ore"), new SpriteAnimation(SpriteType.Tile, "gold_ore")), + Gem(Items.get("Gem"), new SpriteAnimation(SpriteType.Tile, "gem_ore")), + Cloud(Items.get("Cloud Ore"), new SpriteAnimation(SpriteType.Tile, "cloud_ore")); private final Item drop; public final SpriteAnimation sheet; @@ -42,11 +42,11 @@ public enum OreType { private Item getOre() { return drop.copy(); } - } + } protected OreTile(OreType o) { super((o == OreTile.OreType.Lapis ? "Lapis" : o == OreType.Cloud ? "Cloud Cactus" : o.name() + " Ore"), o.sheet); - this.type = o; + this.type = o; } public void render(Screen screen, Level level, int x, int y) { @@ -67,7 +67,7 @@ public boolean hurt(Level level, int x, int y, Mob source, int dmg, Direction at } public boolean interact(Level level, int xt, int yt, Player player, Item item, Direction attackDir) { - if(Game.isMode("minicraft.settings.mode.creative")) + if (Game.isMode("minicraft.settings.mode.creative")) return false; // Go directly to hurt method if (item instanceof ToolItem) { ToolItem tool = (ToolItem) item; @@ -85,19 +85,19 @@ public boolean interact(Level level, int xt, int yt, Player player, Item item, D return false; } - public Item getOre() { - return type.getOre(); - } + public Item getOre() { + return type.getOre(); + } public void hurt(Level level, int x, int y, int dmg) { int damage = level.getData(x, y) + dmg; int oreH = random.nextInt(10) * 4 + 20; if (Game.isMode("minicraft.settings.mode.creative")) dmg = damage = oreH; - level.add(new SmashParticle(x * 16, y * 16)); + level.add(new SmashParticle(x << 4, y << 4)); Sound.play("monsterhurt"); - level.add(new TextParticle("" + dmg, x * 16 + 8, y * 16 + 8, Color.RED)); + level.add(new TextParticle("" + dmg, (x << 4) + 8, (y << 4) + 8, Color.RED)); if (dmg > 0) { int count = random.nextInt(2); if (damage >= oreH) { @@ -110,10 +110,10 @@ public void hurt(Level level, int x, int y, int dmg) { } else { level.setData(x, y, damage); } - if (type.drop.equals(Items.get("gem"))){ + if (type.drop.equals(Items.get("gem"))) { AchievementsDisplay.setAchievement("minicraft.achievement.find_gem", true); } - level.dropItem(x * 16 + 8, y * 16 + 8, count, type.getOre()); + level.dropItem((x << 4) + 8, (y << 4) + 8, count, type.getOre()); } } diff --git a/src/client/java/minicraft/level/tile/PathTile.java b/src/client/java/minicraft/level/tile/PathTile.java index dea91f486..781604b40 100644 --- a/src/client/java/minicraft/level/tile/PathTile.java +++ b/src/client/java/minicraft/level/tile/PathTile.java @@ -13,30 +13,34 @@ import minicraft.util.AdvancementElement; public class PathTile extends Tile { - private static SpriteAnimation sprite = new SpriteAnimation(SpriteType.Tile, "path"); + private static SpriteAnimation sprite = new SpriteAnimation(SpriteType.Tile, "path"); - public PathTile(String name) { - super(name, sprite); - connectsToGrass = true; - maySpawn = true; - } + public PathTile(String name) { + super(name, sprite); + maySpawn = true; + } - public boolean interact(Level level, int xt, int yt, Player player, Item item, Direction attackDir) { - if (item instanceof ToolItem) { - ToolItem tool = (ToolItem) item; - if (tool.type == ToolType.Shovel) { - if (player.payStamina(4 - tool.level) && tool.payDurability()) { + @Override + public boolean connectsToGrass(Level level, int x, int y) { + return true; + } + + public boolean interact(Level level, int xt, int yt, Player player, Item item, Direction attackDir) { + if (item instanceof ToolItem) { + ToolItem tool = (ToolItem) item; + if (tool.type == ToolType.Shovel) { + if (player.payStamina(4 - tool.level) && tool.payDurability()) { int data = level.getData(xt, yt); - level.setTile(xt, yt, Tiles.get("Hole")); - Sound.play("monsterhurt"); - level.dropItem(xt * 16 + 8, yt * 16 + 8, Items.get("Dirt")); + level.setTile(xt, yt, Tiles.get("Hole")); + Sound.play("monsterhurt"); + level.dropItem((xt << 4) + 8, (yt << 4) + 8, Items.get("Dirt")); AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.INSTANCE.trigger( new AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.ItemUsedOnTileTriggerConditionHandler.ItemUsedOnTileTriggerConditions( item, this, data, xt, yt, level.depth)); - return true; - } - } - } - return false; - } + return true; + } + } + } + return false; + } } diff --git a/src/client/java/minicraft/level/tile/RockTile.java b/src/client/java/minicraft/level/tile/RockTile.java index b5f7e69b7..6fde9871f 100644 --- a/src/client/java/minicraft/level/tile/RockTile.java +++ b/src/client/java/minicraft/level/tile/RockTile.java @@ -24,7 +24,7 @@ public class RockTile extends Tile { private static SpriteAnimation sprite = new SpriteAnimation(SpriteType.Tile, "rock") - .setConnectChecker((tile, side) -> tile.getClass() == RockTile.class) + .setConnectionChecker((level, x, y, tile, side) -> tile instanceof RockTile) .setSingletonWithConnective(true); private boolean dropCoal = false; @@ -76,24 +76,24 @@ public void hurt(Level level, int x, int y, int dmg) { dropCoal = true; } - level.add(new SmashParticle(x * 16, y * 16)); + level.add(new SmashParticle(x << 4, y << 4)); Sound.play("monsterhurt"); - level.add(new TextParticle("" + dmg, x * 16 + 8, y * 16 + 8, Color.RED)); + level.add(new TextParticle("" + dmg, (x << 4) + 8, (y << 4) + 8, Color.RED)); if (damage >= maxHealth) { int stone = 1; if (dropCoal) { stone += random.nextInt(3) + 1; int coal = 1; - if(!Settings.get("diff").equals("minicraft.settings.difficulty.hard")) { + if (!Settings.get("diff").equals("minicraft.settings.difficulty.hard")) { coal += 1; } - level.dropItem(x * 16 + 8, y * 16 + 8, 0, coal, Items.get("Coal")); + level.dropItem((x << 4) + 8, (y << 4) + 8, 0, coal, Items.get("Coal")); } - level.dropItem(x * 16 + 8, y * 16 + 8, stone, Items.get("Stone")); + level.dropItem((x << 4) + 8, (y << 4) + 8, stone, Items.get("Stone")); level.setTile(x, y, Tiles.get("Dirt")); } else { level.setData(x, y, damage); diff --git a/src/client/java/minicraft/level/tile/SandTile.java b/src/client/java/minicraft/level/tile/SandTile.java index 2e2a036f8..960dcde72 100644 --- a/src/client/java/minicraft/level/tile/SandTile.java +++ b/src/client/java/minicraft/level/tile/SandTile.java @@ -18,15 +18,19 @@ public class SandTile extends Tile { private static SpriteAnimation sprite = new SpriteAnimation(SpriteType.Tile, "sand") - .setConnectChecker((tile, side) -> !side || tile.connectsToSand) + .setConnectionChecker((level, x, y, tile, side) -> !side || tile.connectsToSand(level, x, y)) .setSingletonWithConnective(true); protected SandTile(String name) { super(name, sprite); - connectsToSand = true; maySpawn = true; } + @Override + public boolean connectsToSand(Level level, int x, int y) { + return true; + } + public void render(Screen screen, Level level, int x, int y) { Tiles.get("dirt").render(screen, level, x, y); sprite.render(screen, level, x, y); @@ -38,23 +42,18 @@ public boolean tick(Level level, int x, int y) { public void steppedOn(Level level, int x, int y, Entity entity) { if (entity instanceof Mob) { - if (random.nextInt(3) == 0) { - int spawnX = entity.x - 8 + random.nextInt(5)-2; - int spawnY = entity.y - 8 + random.nextInt(5)-2; - for (Direction dir : Direction.values()) { - Tile neighbour = level.getTile(x + dir.getX(), y + dir.getY()); - if (neighbour != null) { - if (!(neighbour instanceof SandTile)) { // Particles only spawn on sand tiles. - if (dir.getX() < 0) // Offsets - if (entity.x%16 < 8) spawnX += 8 - entity.x%16; - if (dir.getX() > 0) - if (entity.x%16 > 7) spawnX -= entity.x%16 - 8; - if (dir.getY() < 0) - if (entity.y%16 < 8) spawnY += 8 - entity.y%16; - if (dir.getY() > 0) - if (entity.y%16 > 7) spawnY -= entity.y%16 - 8; - } - } + if (((Mob) entity).walkDist % 8 == 0) { // Mob animation changes by every 2^3 in walkDist. + int spawnX = entity.x - 4; // Shifting is done to ensure that the center of particle is located + int spawnY = entity.y - 4; // at the center of the mob. + switch (((Mob) entity).dir) { // Shifting along the orthogonal axis of direction. + case NONE: // UNKNOWN + return; + case UP: case DOWN: // y-axis + spawnX += (random.nextInt(2) + 2) * (((((Mob) entity).walkDist) >> 3) % 2 == 0 ? 1 : -1); + break; + case LEFT: case RIGHT: // x-axis + spawnY += (random.nextInt(2) + 2) * (((((Mob) entity).walkDist) >> 3) % 2 == 0 ? 1 : -1); + break; } level.add(new SandParticle(spawnX, spawnY)); @@ -70,7 +69,7 @@ public boolean interact(Level level, int xt, int yt, Player player, Item item, D int data = level.getData(xt, yt); level.setTile(xt, yt, Tiles.get("Hole")); Sound.play("monsterhurt"); - level.dropItem(xt * 16 + 8, yt * 16 + 8, Items.get("Sand")); + level.dropItem((xt << 4) + 8, (yt << 4) + 8, Items.get("Sand")); AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.INSTANCE.trigger( new AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.ItemUsedOnTileTriggerConditionHandler.ItemUsedOnTileTriggerConditions( item, this, data, xt, yt, level.depth)); diff --git a/src/client/java/minicraft/level/tile/SaplingTile.java b/src/client/java/minicraft/level/tile/SaplingTile.java index f000acf9e..c871d2841 100644 --- a/src/client/java/minicraft/level/tile/SaplingTile.java +++ b/src/client/java/minicraft/level/tile/SaplingTile.java @@ -9,7 +9,7 @@ import minicraft.level.Level; public class SaplingTile extends Tile { - private static SpriteAnimation sprite = new SpriteAnimation(SpriteType.Tile, "sapling"); + private static final SpriteAnimation sprite = new SpriteAnimation(SpriteType.Tile, "sapling"); private Tile onType; private Tile growsTo; @@ -18,12 +18,24 @@ protected SaplingTile(String name, Tile onType, Tile growsTo) { super(name, sprite); this.onType = onType; this.growsTo = growsTo; - connectsToSand = onType.connectsToSand; - connectsToGrass = onType.connectsToGrass; - connectsToFluid = onType.connectsToFluid; maySpawn = true; } + @Override + public boolean connectsToGrass(Level level, int x, int y) { + return onType.connectsToGrass(level, x, y); + } + + @Override + public boolean connectsToFluid(Level level, int x, int y) { + return onType.connectsToFluid(level, x, y); + } + + @Override + public boolean connectsToSand(Level level, int x, int y) { + return onType.connectsToSand(level, x, y); + } + public void render(Screen screen, Level level, int x, int y) { onType.render(screen, level, x, y); sprite.render(screen, level, x, y); diff --git a/src/client/java/minicraft/level/tile/SignTile.java b/src/client/java/minicraft/level/tile/SignTile.java new file mode 100644 index 000000000..88fb97ff5 --- /dev/null +++ b/src/client/java/minicraft/level/tile/SignTile.java @@ -0,0 +1,84 @@ +package minicraft.level.tile; + +import minicraft.core.Game; +import minicraft.core.Renderer; +import minicraft.core.io.Sound; +import minicraft.entity.Direction; +import minicraft.entity.Entity; +import minicraft.entity.mob.Mob; +import minicraft.entity.mob.Player; +import minicraft.gfx.Screen; +import minicraft.gfx.SpriteAnimation; +import minicraft.gfx.SpriteLinker; +import minicraft.item.Item; +import minicraft.item.Items; +import minicraft.item.ToolItem; +import minicraft.item.ToolType; +import minicraft.level.Level; +import minicraft.level.tile.entity.SignTileEntity; +import minicraft.screen.SignDisplay; +import minicraft.screen.SignDisplayMenu; +import minicraft.util.AdvancementElement; +import org.tinylog.Logger; + +public class SignTile extends Tile { + protected SignTile() { + super("Sign", new SpriteAnimation(SpriteLinker.SpriteType.Tile, "sign")); + } + + @Override + public boolean connectsToSand(Level level, int x, int y) { + return Tiles.get((short) level.getData(x, y)).connectsToSand(level, x, y); + } + + @Override + public boolean connectsToFluid(Level level, int x, int y) { + return Tiles.get((short) level.getData(x, y)).connectsToFluid(level, x, y); + } + + @Override + public boolean connectsToGrass(Level level, int x, int y) { + return Tiles.get((short) level.getData(x, y)).connectsToGrass(level, x, y); + } + + public void render(Screen screen, Level level, int x, int y) { + Tiles.get((short) level.getData(x, y)).render(screen, level, x, y); + sprite.render(screen, level, x, y); + } + + public boolean interact(Level level, int xt, int yt, Player player, Item item, Direction attackDir) { + if (item != null) { + if (item instanceof ToolItem && ((ToolItem) item).type == ToolType.Axe) { + int data = level.getData(xt, yt); + level.setTile(xt, yt, Tiles.get((short) data)); + SignDisplay.removeSign(level.depth, xt, yt); + Sound.play("monsterhurt"); + level.dropItem(xt*16+8, yt*16+8, Items.get("Sign")); + AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.INSTANCE.trigger( + new AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.ItemUsedOnTileTriggerConditionHandler.ItemUsedOnTileTriggerConditions( + item, this, data, xt, yt, level.depth)); + return true; + } + } else { // TODO Add a way to lock signs + Game.setDisplay(new SignDisplay(level, xt, yt)); + return true; + } + + return false; + } + + @Override + public boolean hurt(Level level, int x, int y, Mob source, int dmg, Direction attackDir) { + if (source instanceof Player) { + Game.setDisplay(new SignDisplay(level, x, y)); + return true; + } + + return false; + } + + @Override + public void onTileSet(Level level, int x, int y) { + level.add(new SignTileEntity(), x, y, true); + } +} diff --git a/src/client/java/minicraft/level/tile/Tile.java b/src/client/java/minicraft/level/tile/Tile.java index fe52cf1e1..68a53a053 100644 --- a/src/client/java/minicraft/level/tile/Tile.java +++ b/src/client/java/minicraft/level/tile/Tile.java @@ -41,9 +41,6 @@ public ToolType getRequiredTool() { public short id; - public boolean connectsToGrass = false; - public boolean connectsToSand = false; - public boolean connectsToFluid = false; public int light = 1; protected boolean maySpawn = false; @@ -55,26 +52,38 @@ protected Tile(String name, SpriteAnimation sprite) { } - /** This method is used by tiles to specify the default "data" they have in a level's data array. - Used for starting health, color/type of tile, etc. */ + /** + * This method is used by tiles to specify the default "data" they have in a level's data array. + * Used for starting health, color/type of tile, etc. + */ // At least, that was the idea at first... public int getDefaultData() { return 0; } - /** Render method, used in sub-classes */ + /** + * Render method, used in sub-classes + */ public void render(Screen screen, Level level, int x, int y) { sprite.render(screen, level, x, y); } - public boolean maySpawn() { return maySpawn; } + public boolean maySpawn() { + return maySpawn; + } + + public void onTileSet(Level level, int x, int y) {} - /** Returns if the player can walk on it, overrides in sub-classes */ + /** + * Returns if the player can walk on it, overrides in sub-classes + */ public boolean mayPass(Level level, int x, int y, Entity e) { return true; } - /** Gets the light radius of a tile, Bigger number = bigger circle */ + /** + * Gets the light radius of a tile, Bigger number = bigger circle + */ public int getLightRadius(Level level, int x, int y) { return 0; } @@ -89,7 +98,9 @@ public int getLightRadius(Level level, int x, int y) { * @param attackDir The direction of the player hitting. * @return If the damage was applied. */ - public boolean hurt(Level level, int x, int y, Mob source, int dmg, Direction attackDir) { return false; } + public boolean hurt(Level level, int x, int y, Mob source, int dmg, Direction attackDir) { + return false; + } /** * Hurt the tile with a specified amount of damage. @@ -98,16 +109,27 @@ public int getLightRadius(Level level, int x, int y) { * @param y Y position of the tile. * @param dmg The damage taken. */ - public void hurt(Level level, int x, int y, int dmg) {} + public void hurt(Level level, int x, int y, int dmg) { + } - /** What happens when you run into the tile (ex: run into a cactus) */ - public void bumpedInto(Level level, int xt, int yt, Entity entity) {} + /** + * What happens when you run into the tile (ex: run into a cactus) + */ + public void bumpedInto(Level level, int xt, int yt, Entity entity) { + } - /** Update method */ - public boolean tick(Level level, int xt, int yt) { return false; } + /** + * Update method + */ + public boolean tick(Level level, int xt, int yt) { + return false; + } - /** What happens when you are inside the tile (ex: lava) */ - public void steppedOn(Level level, int xt, int yt, Entity entity) {} + /** + * What happens when you are inside the tile (ex: lava) + */ + public void steppedOn(Level level, int xt, int yt, Entity entity) { + } /** * Called when you hit an item on a tile (ex: Pickaxe on rock). @@ -135,9 +157,20 @@ public boolean onExplode(Level level, int xt, int yt) { return false; } - /** Sees if the tile connects to a fluid. */ - public boolean connectsToLiquid() { return connectsToFluid; } + /** Whether the tile connects to grass tile in appearance. */ + public boolean connectsToGrass(Level level, int x, int y) { return false; } + /** Whether the tile connects to sand tile in appearance. */ + public boolean connectsToSand(Level level, int x, int y) { return false; } + + /** Whether the tile connects to fluid tile in appearance. */ + public boolean connectsToFluid(Level level, int x, int y) { return false; } + + /** + * @deprecated This should be planned to be removed as this method is not ideally used. + * The current only usage is in {@link Level#setTile(int, int, String)}. + */ + @Deprecated public int getData(String data) { try { return Integer.parseInt(data); @@ -146,6 +179,11 @@ public int getData(String data) { } } + /** + * @deprecated Similar to {@link #getData(String)}. Also, param {@code thisData} is unused. + * The current only usage is in {@link minicraft.item.TileItem#interactOn(Tile, Level, int, int, Player, Direction)}. + */ + @Deprecated public boolean matches(int thisData, String tileInfo) { return name.equals(tileInfo.split("_")[0]); } @@ -164,7 +202,7 @@ public static String getData(int depth, int x, int y) { int tiledata = curLevel.data[pos]; return lvlidx + ";" + pos + ";" + tileid + ";" + tiledata; - } catch(NullPointerException | IndexOutOfBoundsException ignored) { + } catch (NullPointerException | IndexOutOfBoundsException ignored) { } return ""; @@ -178,5 +216,7 @@ public boolean equals(Object other) { } @Override - public int hashCode() { return name.hashCode(); } + public int hashCode() { + return name.hashCode(); + } } diff --git a/src/client/java/minicraft/level/tile/Tiles.java b/src/client/java/minicraft/level/tile/Tiles.java index c5106a385..d9695a044 100644 --- a/src/client/java/minicraft/level/tile/Tiles.java +++ b/src/client/java/minicraft/level/tile/Tiles.java @@ -1,13 +1,21 @@ package minicraft.level.tile; import minicraft.core.CrashHandler; +import minicraft.level.tile.farming.CarrotTile; import minicraft.level.tile.farming.FarmTile; +import minicraft.level.tile.farming.HeavenlyBerriesTile; +import minicraft.level.tile.farming.HellishBerriesTile; import minicraft.level.tile.farming.PotatoTile; +import minicraft.level.tile.farming.TomatoTile; import minicraft.level.tile.farming.WheatTile; import minicraft.util.Logging; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; public final class Tiles { /// Idea: to save tile names while saving space, I could encode the names in base 64 in the save file...^M @@ -17,80 +25,94 @@ public final class Tiles { private static HashMap tiles = new HashMap<>(); + // Standard tile explosion blacklist + // Tiles (as IDs) included cannot be damaged by explosions such as by TNTs and creepers. + public static final Set explosionBlacklist; + public static void initTileList() { Logging.TILES.debug("Initializing tile list..."); - tiles.put((short)0, new GrassTile("Grass")); - tiles.put((short)1, new DirtTile("Dirt")); - tiles.put((short)2, new FlowerTile("Flower")); - tiles.put((short)3, new HoleTile("Hole")); - tiles.put((short)4, new StairsTile("Stairs Up", true)); - tiles.put((short)5, new StairsTile("Stairs Down", false)); - tiles.put((short)6, new WaterTile("Water")); + tiles.put((short) 0, new GrassTile("Grass")); + tiles.put((short) 1, new DirtTile("Dirt")); + tiles.put((short) 2, new FlowerTile("Flower")); + tiles.put((short) 3, new HoleTile("Hole")); + tiles.put((short) 4, new StairsTile("Stairs Up", true)); + tiles.put((short) 5, new StairsTile("Stairs Down", false)); + tiles.put((short) 6, new WaterTile("Water")); // This is out of order because of lava buckets - tiles.put((short)17, new LavaTile("Lava")); - - tiles.put((short)7, new RockTile("Rock")); - tiles.put((short)8, new TreeTile("Tree")); - tiles.put((short)9, new SaplingTile("Tree Sapling", Tiles.get("Grass"), Tiles.get("Tree"))); - tiles.put((short)10, new SandTile("Sand")); - tiles.put((short)11, new CactusTile("Cactus")); - tiles.put((short)12, new SaplingTile("Cactus Sapling", Tiles.get("Sand"), Tiles.get("Cactus"))); - tiles.put((short)13, new OreTile(OreTile.OreType.Iron)); - tiles.put((short)14, new OreTile(OreTile.OreType.Gold)); - tiles.put((short)15, new OreTile(OreTile.OreType.Gem)); - tiles.put((short)16, new OreTile(OreTile.OreType.Lapis)); - tiles.put((short)18, new LavaBrickTile("Lava Brick")); - tiles.put((short)19, new ExplodedTile("Explode")); - tiles.put((short)20, new FarmTile("Farmland")); - tiles.put((short)21, new WheatTile("Wheat")); - tiles.put((short)22, new HardRockTile("Hard Rock")); - tiles.put((short)23, new InfiniteFallTile("Infinite Fall")); - tiles.put((short)24, new CloudTile("Cloud")); - tiles.put((short)25, new OreTile(OreTile.OreType.Cloud)); - tiles.put((short)26, new DoorTile(Tile.Material.Wood)); - tiles.put((short)27, new DoorTile(Tile.Material.Stone)); - tiles.put((short)28, new DoorTile(Tile.Material.Obsidian)); - tiles.put((short)29, new FloorTile(Tile.Material.Wood)); - tiles.put((short)30, new FloorTile(Tile.Material.Stone)); - tiles.put((short)31, new FloorTile(Tile.Material.Obsidian)); - tiles.put((short)32, new WallTile(Tile.Material.Wood)); - tiles.put((short)33, new WallTile(Tile.Material.Stone)); - tiles.put((short)34, new WallTile(Tile.Material.Obsidian)); - tiles.put((short)35, new WoolTile(WoolTile.WoolType.NORMAL)); - tiles.put((short)36, new PathTile("Path")); - tiles.put((short)37, new WoolTile(WoolTile.WoolType.RED)); - tiles.put((short)38, new WoolTile(WoolTile.WoolType.BLUE)); - tiles.put((short)39, new WoolTile(WoolTile.WoolType.GREEN)); - tiles.put((short)40, new WoolTile(WoolTile.WoolType.YELLOW)); - tiles.put((short)41, new WoolTile(WoolTile.WoolType.BLACK)); - tiles.put((short)42, new PotatoTile("Potato")); - tiles.put((short)43, new MaterialTile(Tile.Material.Stone)); - tiles.put((short)44, new MaterialTile(Tile.Material.Obsidian)); - tiles.put((short)45, new DecorTile(Tile.Material.Stone)); - tiles.put((short)46, new DecorTile(Tile.Material.Obsidian)); - tiles.put((short)47, new BossWallTile()); - tiles.put((short)48, new BossFloorTile()); - tiles.put((short)49, new BossDoorTile()); + tiles.put((short) 17, new LavaTile("Lava")); + + tiles.put((short) 7, new RockTile("Rock")); + tiles.put((short) 8, new TreeTile("Tree")); + tiles.put((short) 9, new SaplingTile("Tree Sapling", Tiles.get("Grass"), Tiles.get("Tree"))); + tiles.put((short) 10, new SandTile("Sand")); + tiles.put((short) 11, new CactusTile("Cactus")); + tiles.put((short) 12, new SaplingTile("Cactus Sapling", Tiles.get("Sand"), Tiles.get("Cactus"))); + tiles.put((short) 13, new OreTile(OreTile.OreType.Iron)); + tiles.put((short) 14, new OreTile(OreTile.OreType.Gold)); + tiles.put((short) 15, new OreTile(OreTile.OreType.Gem)); + tiles.put((short) 16, new OreTile(OreTile.OreType.Lapis)); + tiles.put((short) 18, new LavaBrickTile("Lava Brick")); + tiles.put((short) 19, new ExplodedTile("Explode")); + tiles.put((short) 20, new FarmTile("Farmland")); + tiles.put((short) 21, new WheatTile("Wheat")); + tiles.put((short) 22, new HardRockTile("Hard Rock")); + tiles.put((short) 23, new InfiniteFallTile("Infinite Fall")); + tiles.put((short) 24, new CloudTile("Cloud")); + tiles.put((short) 25, new OreTile(OreTile.OreType.Cloud)); + tiles.put((short) 26, new DoorTile(Tile.Material.Wood)); + tiles.put((short) 27, new DoorTile(Tile.Material.Stone)); + tiles.put((short) 28, new DoorTile(Tile.Material.Obsidian)); + tiles.put((short) 29, new FloorTile(Tile.Material.Wood)); + tiles.put((short) 30, new FloorTile(Tile.Material.Stone)); + tiles.put((short) 31, new FloorTile(Tile.Material.Obsidian)); + tiles.put((short) 32, new WallTile(Tile.Material.Wood)); + tiles.put((short) 33, new WallTile(Tile.Material.Stone)); + tiles.put((short) 34, new WallTile(Tile.Material.Obsidian)); + tiles.put((short) 35, new WoolTile(WoolTile.WoolType.NORMAL)); + tiles.put((short) 36, new PathTile("Path")); + tiles.put((short) 37, new WoolTile(WoolTile.WoolType.RED)); + tiles.put((short) 38, new WoolTile(WoolTile.WoolType.BLUE)); + tiles.put((short) 39, new WoolTile(WoolTile.WoolType.GREEN)); + tiles.put((short) 40, new WoolTile(WoolTile.WoolType.YELLOW)); + tiles.put((short) 41, new WoolTile(WoolTile.WoolType.BLACK)); + tiles.put((short) 42, new PotatoTile("Potato")); + tiles.put((short) 43, new MaterialTile(Tile.Material.Stone)); + tiles.put((short) 44, new MaterialTile(Tile.Material.Obsidian)); + tiles.put((short) 45, new DecorTile(DecorTile.decorType.ORNATE_STONE)); + tiles.put((short) 46, new DecorTile(DecorTile.decorType.ORNATE_OBSIDIAN)); + tiles.put((short) 47, new BossWallTile()); + tiles.put((short) 48, new BossFloorTile()); + tiles.put((short) 49, new BossDoorTile()); + tiles.put((short) 50, new TomatoTile("Tomato")); + tiles.put((short) 51, new CarrotTile("Carrot")); + tiles.put((short) 52, new HeavenlyBerriesTile("Heavenly Berries")); + tiles.put((short) 53, new HellishBerriesTile("Hellish Berries")); + tiles.put((short) 54, new FenceTile(Tile.Material.Wood)); + tiles.put((short) 55, new FenceTile(Tile.Material.Stone)); + tiles.put((short) 56, new FenceTile(Tile.Material.Obsidian)); + tiles.put((short) 57, new TorchTile()); + tiles.put((short) 58, new SignTile()); + tiles.put((short) 59, new DecorTile(DecorTile.decorType.ORNATE_WOOD)); // WARNING: don't use this tile for anything! - tiles.put((short)255, new ConnectTile()); + tiles.put((short) 255, new ConnectTile()); - for(short i = 0; i < 256; i++) { - if(tiles.get(i) == null) continue; - tiles.get(i).id = (short)i; + for (short i = 0; i < 256; i++) { + if (tiles.get(i) == null) continue; + tiles.get(i).id = (short) i; } } - protected static void add(int id, Tile tile) { - tiles.put((short)id, tile); + static void add(int id, Tile tile) { + tiles.put((short) id, tile); Logging.TILES.debug("Adding " + tile.name + " to tile list with id " + id); tile.id = (short) id; } static { - for(int i = 0; i < 32768; i++) + for (int i = 0; i < 32768; i++) oldids.add(null); oldids.set(0, "grass"); @@ -179,9 +201,24 @@ protected static void add(int id, Tile tile) { oldids.set(53, "torch green wool"); oldids.set(54, "torch yellow wool"); oldids.set(55, "torch black wool"); + + explosionBlacklist = Collections.unmodifiableSet(new HashSet<>(Arrays.asList( + (short) 4, // Stairs Up + (short) 5, // Stairs Down + (short) 22, // Hard Rock + (short) 28, // Obsidian Door + (short) 31, // Obsidian + (short) 34, // Obsidian Wall + (short) 44, // Raw Obsidian + (short) 46, // Ornate Obsidian + (short) 47, // Boss Wall + (short) 48, // Boss Floor + (short) 49 // Boss Door + ))); } private static int overflowCheck = 0; + public static Tile get(String name) { //System.out.println("Getting from tile list: " + name); @@ -189,7 +226,7 @@ public static Tile get(String name) { overflowCheck++; - if(overflowCheck > 50) { + if (overflowCheck > 50) { CrashHandler.crashHandle(new StackOverflowError("Tiles#get: " + name), new CrashHandler.ErrorInfo("Tile fetching Stacking", CrashHandler.ErrorInfo.ErrorType.SERIOUS, "STACKOVERFLOW prevented in Tiles.get(), on: " + name)); } @@ -198,59 +235,39 @@ public static Tile get(String name) { Tile getting = null; - boolean isTorch = false; - if(name.startsWith("TORCH")) { - isTorch = true; - name = name.substring(6); // Cuts off torch prefix. - } - - if(name.contains("_")) { + if (name.contains("_")) { name = name.substring(0, name.indexOf("_")); } - for(Tile t: tiles.values()) { - if(t == null) continue; - if(t.name.equals(name)) { + for (Tile t : tiles.values()) { + if (t == null) continue; + if (t.name.equals(name)) { getting = t; break; } } - if(getting == null) { + if (getting == null) { Logging.TILES.info("Invalid tile requested: " + name); - getting = tiles.get((short)0); - } - - if(isTorch) { - getting = TorchTile.getTorchTile(getting); + getting = tiles.get((short) 0); } overflowCheck = 0; return getting; } - public static Tile get(int id) { + public static Tile get(short id) { //System.out.println("Requesting tile by id: " + id); - if(id < 0) id += 32768; - - if(tiles.get((short)id) != null) { - return tiles.get((short)id); - } - else if(id >= 32767) { - return TorchTile.getTorchTile(get(id - 32767)); - } - else { + if (tiles.get(id) != null) { + return tiles.get(id); + } else { Logging.TILES.info("Unknown tile id requested: " + id); - return tiles.get((short)0); + return tiles.get((short) 0); } } - public static boolean containsTile(int id) { - return tiles.get((short)id) != null; - } - public static String getName(String descriptName) { - if(!descriptName.contains("_")) return descriptName; + if (!descriptName.contains("_")) return descriptName; int data; String[] parts = descriptName.split("_"); descriptName = parts[0]; diff --git a/src/client/java/minicraft/level/tile/TorchTile.java b/src/client/java/minicraft/level/tile/TorchTile.java index 52353ac45..f60626698 100644 --- a/src/client/java/minicraft/level/tile/TorchTile.java +++ b/src/client/java/minicraft/level/tile/TorchTile.java @@ -11,35 +11,29 @@ import minicraft.item.PowerGloveItem; import minicraft.level.Level; import minicraft.util.AdvancementElement; -import org.tinylog.Logger; public class TorchTile extends Tile { - private Tile onType; + protected TorchTile() { + super("Torch", new SpriteAnimation(SpriteType.Tile, "torch")); + } - public static TorchTile getTorchTile(Tile onTile) { - int id = onTile.id & 0xFFFF; - if(id < 16384) id += 16384; - else Logger.tag("TorchTile").info("Tried to place torch on torch tile..."); + @Override + public boolean connectsToSand(Level level, int x, int y) { + return Tiles.get((short) level.getData(x, y)).connectsToSand(level, x, y); + } - if(Tiles.containsTile(id)) - return (TorchTile)Tiles.get(id); - else { - TorchTile tile = new TorchTile(onTile); - Tiles.add(id, tile); - return tile; - } + @Override + public boolean connectsToFluid(Level level, int x, int y) { + return Tiles.get((short) level.getData(x, y)).connectsToFluid(level, x, y); } - private TorchTile(Tile onType) { - super("Torch "+ onType.name, new SpriteAnimation(SpriteType.Tile, "torch")); - this.onType = onType; - this.connectsToSand = onType.connectsToSand; - this.connectsToGrass = onType.connectsToGrass; - this.connectsToFluid = onType.connectsToFluid; + @Override + public boolean connectsToGrass(Level level, int x, int y) { + return Tiles.get((short) level.getData(x, y)).connectsToGrass(level, x, y); } public void render(Screen screen, Level level, int x, int y) { - onType.render(screen, level, x, y); + Tiles.get((short) level.getData(x, y)).render(screen, level, x, y); sprite.render(screen, level, x, y); } @@ -48,11 +42,11 @@ public int getLightRadius(Level level, int x, int y) { } public boolean interact(Level level, int xt, int yt, Player player, Item item, Direction attackDir) { - if(item instanceof PowerGloveItem) { + if (item instanceof PowerGloveItem) { int data = level.getData(xt, yt); - level.setTile(xt, yt, this.onType); + level.setTile(xt, yt, Tiles.get((short) data)); Sound.play("monsterhurt"); - level.dropItem(xt*16+8, yt*16+8, Items.get("Torch")); + level.dropItem((xt << 4) + 8, (yt << 4) + 8, Items.get("Torch")); AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.INSTANCE.trigger( new AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.ItemUsedOnTileTriggerConditionHandler.ItemUsedOnTileTriggerConditions( item, this, data, xt, yt, level.depth)); diff --git a/src/client/java/minicraft/level/tile/TreeTile.java b/src/client/java/minicraft/level/tile/TreeTile.java index 895ad1fd4..6b9a76160 100644 --- a/src/client/java/minicraft/level/tile/TreeTile.java +++ b/src/client/java/minicraft/level/tile/TreeTile.java @@ -22,51 +22,88 @@ import minicraft.util.AdvancementElement; public class TreeTile extends Tile { - private static LinkedSprite treeSprite = new LinkedSprite(SpriteType.Tile, "tree"); - private static LinkedSprite treeSpriteFull = new LinkedSprite(SpriteType.Tile, "tree_full"); + private static final LinkedSprite oakSprite = new LinkedSprite(SpriteType.Tile, "oak"); + private static final LinkedSprite oakSpriteFull = new LinkedSprite(SpriteType.Tile, "oak_full"); + private static final LinkedSprite spruceSprite = new LinkedSprite(SpriteType.Tile, "spruce"); + private static final LinkedSprite spruceSpriteFull = new LinkedSprite(SpriteType.Tile, "spruce_full"); + private static final LinkedSprite birchSprite = new LinkedSprite(SpriteType.Tile, "birch"); + private static final LinkedSprite birchSpriteFull = new LinkedSprite(SpriteType.Tile, "birch_full"); + private static final LinkedSprite ashSprite = new LinkedSprite(SpriteType.Tile, "ash"); + private static final LinkedSprite ashSpriteFull = new LinkedSprite(SpriteType.Tile, "ash_full"); + private static final LinkedSprite aspenSprite = new LinkedSprite(SpriteType.Tile, "aspen"); + private static final LinkedSprite aspenSpriteFull = new LinkedSprite(SpriteType.Tile, "aspen_full"); + private static final LinkedSprite firSprite = new LinkedSprite(SpriteType.Tile, "fir"); + private static final LinkedSprite firSpriteFull = new LinkedSprite(SpriteType.Tile, "fir_full"); + private static final LinkedSprite willowSprite = new LinkedSprite(SpriteType.Tile, "willow"); + private static final LinkedSprite willowSpriteFull = new LinkedSprite(SpriteType.Tile, "willow_full"); + + public enum TreeType { + OAK(oakSprite, oakSpriteFull), + SPRUCE(spruceSprite, spruceSpriteFull), + BIRCH(birchSprite, birchSpriteFull), + ASH(ashSprite, ashSpriteFull), + ASPEN(aspenSprite, aspenSpriteFull), + FIR(firSprite, firSpriteFull), + WILLOW(willowSprite, willowSpriteFull); + + private final LinkedSprite treeSprite; + private final LinkedSprite treeSpriteFull; + + TreeType(LinkedSprite treeSprite, LinkedSprite treeSpriteFull) { + this.treeSprite = treeSprite; + this.treeSpriteFull = treeSpriteFull; + } + } protected TreeTile(String name) { super(name, null); - connectsToGrass = true; } + @Override + public boolean connectsToGrass(Level level, int x, int y) { + return true; + } + + @SuppressWarnings("PointlessArithmeticExpression") public void render(Screen screen, Level level, int x, int y) { Tiles.get("Grass").render(screen, level, x, y); - boolean u = level.getTile(x, y - 1) == this; - boolean l = level.getTile(x - 1, y) == this; - boolean r = level.getTile(x + 1, y) == this; - boolean d = level.getTile(x, y + 1) == this; - boolean ul = level.getTile(x - 1, y - 1) == this; - boolean ur = level.getTile(x + 1, y - 1) == this; - boolean dl = level.getTile(x - 1, y + 1) == this; - boolean dr = level.getTile(x + 1, y + 1) == this; - - Sprite sprite = treeSprite.getSprite(); - Sprite spriteFull = treeSpriteFull.getSprite(); - - if (u && ul && l) { - screen.render(x * 16 + 0, y * 16 + 0, spriteFull.spritePixels[0][1]); + TreeType thisType = level.treeTypes[x + y * level.w]; + // Checking whether the target direction has targeted the same TreeTile + boolean isUpTileSame = level.getTile(x, y - 1) == this && thisType == level.treeTypes[x + (y - 1) * level.w]; + boolean isLeftTileSame = level.getTile(x - 1, y) == this && thisType == level.treeTypes[(x - 1) + y * level.w]; + boolean isRightTileSame = level.getTile(x + 1, y) == this && thisType == level.treeTypes[(x + 1) + y * level.w]; + boolean isDownTileSame = level.getTile(x, y + 1) == this && thisType == level.treeTypes[x + (y + 1) * level.w]; + boolean isUpLeftTileSame = level.getTile(x - 1, y - 1) == this && thisType == level.treeTypes[(x - 1) + (y - 1) * level.w]; + boolean isUpRightTileSame = level.getTile(x + 1, y - 1) == this && thisType == level.treeTypes[(x + 1) + (y - 1) * level.w]; + boolean isDownLeftTileSame = level.getTile(x - 1, y + 1) == this && thisType == level.treeTypes[(x - 1) + (y + 1) * level.w]; + boolean isDownRightTileSame = level.getTile(x + 1, y + 1) == this && thisType == level.treeTypes[(x + 1) + (y + 1) * level.w]; + + Sprite sprite = level.treeTypes[x + y * level.w].treeSprite.getSprite(); + Sprite spriteFull = level.treeTypes[x + y * level.w].treeSpriteFull.getSprite(); + + if (isUpTileSame && isUpLeftTileSame && isLeftTileSame) { + screen.render((x << 4) + 0, (y << 4) + 0, spriteFull.spritePixels[0][1]); } else { - screen.render(x * 16 + 0, y * 16 + 0, sprite.spritePixels[0][0]); + screen.render((x << 4) + 0, (y << 4) + 0, sprite.spritePixels[0][0]); } - if (u && ur && r) { - screen.render(x * 16 + 8, y * 16 + 0, spriteFull.spritePixels[0][0]); + if (isUpTileSame && isUpRightTileSame && isRightTileSame) { + screen.render((x << 4) + 8, (y << 4) + 0, spriteFull.spritePixels[0][0]); } else { - screen.render(x * 16 + 8, y * 16 + 0, sprite.spritePixels[0][1]); + screen.render((x << 4) + 8, (y << 4) + 0, sprite.spritePixels[0][1]); } - if (d && dl && l) { - screen.render(x * 16 + 0, y * 16 + 8, spriteFull.spritePixels[1][1]); + if (isDownTileSame && isDownLeftTileSame && isLeftTileSame) { + screen.render((x << 4) + 0, (y << 4) + 8, spriteFull.spritePixels[1][1]); } else { - screen.render(x * 16 + 0, y * 16 + 8, sprite.spritePixels[1][0]); + screen.render((x << 4) + 0, (y << 4) + 8, sprite.spritePixels[1][0]); } - if (d && dr && r) { - screen.render(x * 16 + 8, y * 16 + 8, spriteFull.spritePixels[1][0]); + if (isDownTileSame && isDownRightTileSame && isRightTileSame) { + screen.render((x << 4) + 8, (y << 4) + 8, spriteFull.spritePixels[1][0]); } else { - screen.render(x * 16 + 8, y * 16 + 8, sprite.spritePixels[1][1]); + screen.render((x << 4) + 8, (y << 4) + 8, sprite.spritePixels[1][1]); } } @@ -91,7 +128,7 @@ public boolean hurt(Level level, int x, int y, Mob source, int dmg, Direction at @Override public boolean interact(Level level, int xt, int yt, Player player, Item item, Direction attackDir) { - if(Game.isMode("minicraft.settings.mode.creative")) + if (Game.isMode("minicraft.settings.mode.creative")) return false; // Go directly to hurt method if (item instanceof ToolItem) { ToolItem tool = (ToolItem) item; @@ -117,13 +154,13 @@ public void hurt(Level level, int x, int y, int dmg) { int treeHealth = 20; if (Game.isMode("minicraft.settings.mode.creative")) dmg = damage = treeHealth; - level.add(new SmashParticle(x*16, y*16)); + level.add(new SmashParticle(x * 16, y * 16)); Sound.play("monsterhurt"); level.add(new TextParticle("" + dmg, x * 16 + 8, y * 16 + 8, Color.RED)); if (damage >= treeHealth) { level.dropItem(x * 16 + 8, y * 16 + 8, 1, 3, Items.get("Wood")); - level.dropItem(x * 16 + 8, y * 16 + 8, 0, 2, Items.get("Acorn")); + level.dropItem(x * 16 + 8, y * 16 + 8, 0, 2, Items.get("Acorn")); level.setTile(x, y, Tiles.get("Grass")); AchievementsDisplay.setAchievement("minicraft.achievement.woodcutter", true); } else { diff --git a/src/client/java/minicraft/level/tile/WallTile.java b/src/client/java/minicraft/level/tile/WallTile.java index df986e62a..48466fd54 100644 --- a/src/client/java/minicraft/level/tile/WallTile.java +++ b/src/client/java/minicraft/level/tile/WallTile.java @@ -21,23 +21,32 @@ public class WallTile extends Tile { private static SpriteAnimation wood = new SpriteAnimation(SpriteType.Tile, "wood_wall") - .setConnectChecker((tile, side) -> tile.getClass() == WallTile.class); + .setConnectionChecker((level, x, y, tile, side) -> tile instanceof WallTile); private static SpriteAnimation stone = new SpriteAnimation(SpriteType.Tile, "stone_wall") - .setConnectChecker((tile, side) -> tile.getClass() == WallTile.class); + .setConnectionChecker((level, x, y, tile, side) -> tile instanceof WallTile); private static SpriteAnimation obsidian = new SpriteAnimation(SpriteType.Tile, "obsidian_wall") - .setConnectChecker((tile, side) -> tile.getClass() == WallTile.class); + .setConnectionChecker((level, x, y, tile, side) -> tile instanceof WallTile); private static final String obrickMsg = "minicraft.notification.defeat_air_wizard_first"; protected Material type; - protected WallTile(Material type) { this(type, null); } + protected WallTile(Material type) { + this(type, null); + } + protected WallTile(Material type, String name) { super(type.name() + " " + (name == null ? "Wall" : name), null); this.type = type; switch (type) { - case Wood: sprite = wood; break; - case Stone: sprite = stone; break; - case Obsidian: sprite = obsidian; break; + case Wood: + sprite = wood; + break; + case Stone: + sprite = stone; + break; + case Obsidian: + sprite = obsidian; + break; } } @@ -84,10 +93,10 @@ public void hurt(Level level, int x, int y, int dmg) { int sbwHealth = 100; if (Game.isMode("minicraft.settings.mode.creative")) dmg = damage = sbwHealth; - level.add(new SmashParticle(x * 16, y * 16)); + level.add(new SmashParticle(x << 4, y << 4)); Sound.play("monsterhurt"); - level.add(new TextParticle("" + dmg, x * 16 + 8, y * 16 + 8, Color.RED)); + level.add(new TextParticle("" + dmg, (x << 4) + 8, (y << 4) + 8, Color.RED)); if (damage >= sbwHealth) { String itemName = "", tilename = ""; switch (type) { // Get what tile to set and what item to drop @@ -108,7 +117,7 @@ public void hurt(Level level, int x, int y, int dmg) { } } - level.dropItem(x * 16 + 8, y * 16 + 8, 1, 3 - type.ordinal(), Items.get(itemName)); + level.dropItem((x << 4) + 8, (y << 4) + 8, 1, 3 - type.ordinal(), Items.get(itemName)); level.setTile(x, y, Tiles.get(tilename)); } else { level.setData(x, y, damage); diff --git a/src/client/java/minicraft/level/tile/WaterTile.java b/src/client/java/minicraft/level/tile/WaterTile.java index 09577816b..cf99612e0 100644 --- a/src/client/java/minicraft/level/tile/WaterTile.java +++ b/src/client/java/minicraft/level/tile/WaterTile.java @@ -8,12 +8,16 @@ public class WaterTile extends Tile { private static SpriteAnimation sprite = new SpriteAnimation(SpriteType.Tile, "water") - .setConnectChecker((tile, side) -> tile.connectsToFluid) + .setConnectionChecker((level, x, y, tile, side) -> tile.connectsToFluid(level, x, y)) .setSingletonWithConnective(true); protected WaterTile(String name) { super(name, sprite); - connectsToFluid = true; + } + + @Override + public boolean connectsToFluid(Level level, int x, int y) { + return true; } @Override @@ -35,17 +39,17 @@ public boolean tick(Level level, int xt, int yt) { if (random.nextBoolean()) xn += random.nextInt(2) * 2 - 1; else yn += random.nextInt(2) * 2 - 1; - if (level.getTile(xn, yn) == Tiles.get("Hole")) { + if (level.getTile(xn, yn) instanceof HoleTile) { level.setTile(xn, yn, this); } // These set only the non-diagonally adjacent lava tiles to obsidian for (int x = -1; x < 2; x++) { - if (level.getTile(xt + x, yt) == Tiles.get("Lava")) + if (level.getTile(xt + x, yt) instanceof LavaTile) level.setTile(xt + x, yt, Tiles.get("Raw Obsidian")); } for (int y = -1; y < 2; y++) { - if (level.getTile(xt, yt + y) == Tiles.get("lava")) + if (level.getTile(xt, yt + y) instanceof LavaTile) level.setTile(xt, yt + y, Tiles.get("Raw Obsidian")); } return false; diff --git a/src/client/java/minicraft/level/tile/WoolTile.java b/src/client/java/minicraft/level/tile/WoolTile.java index 0de6bc9af..f269e90b5 100644 --- a/src/client/java/minicraft/level/tile/WoolTile.java +++ b/src/client/java/minicraft/level/tile/WoolTile.java @@ -27,7 +27,7 @@ public boolean interact(Level level, int xt, int yt, Player player, Item item, D int data = level.getData(xt, yt); level.setTile(xt, yt, Tiles.get("Hole")); Sound.play("monsterhurt"); - level.dropItem(xt * 16 + 8, yt * 16 + 8, Items.get(name)); + level.dropItem((xt << 4) + 8, (yt << 4) + 8, Items.get(name)); AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.INSTANCE.trigger( new AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.ItemUsedOnTileTriggerConditionHandler.ItemUsedOnTileTriggerConditions( item, this, data, xt, yt, level.depth)); @@ -55,7 +55,6 @@ public enum WoolType { /** * Create a type of wool. - * * @param sprite The sprite for the type of wool. */ WoolType(String name, SpriteAnimation sprite) { diff --git a/src/client/java/minicraft/level/tile/entity/SignTileEntity.java b/src/client/java/minicraft/level/tile/entity/SignTileEntity.java new file mode 100644 index 000000000..719c7e7e5 --- /dev/null +++ b/src/client/java/minicraft/level/tile/entity/SignTileEntity.java @@ -0,0 +1,35 @@ +package minicraft.level.tile.entity; + +import minicraft.core.Game; +import minicraft.core.Renderer; +import minicraft.entity.Entity; +import minicraft.gfx.Screen; +import minicraft.screen.SignDisplayMenu; + +public class SignTileEntity extends Entity { + public SignTileEntity() { + super(8, 8); + } + + @Override + public void render(Screen screen) {} + + @Override + public boolean isSolid() { + return false; + } + + @Override + public void tick() { + int xt = x >> 4, yt = y >> 4; + if (Game.player.x >> 4 == xt && Game.player.y >> 4 == yt) { + if (Renderer.signDisplayMenu == null || Renderer.signDisplayMenu.differsFrom(level.depth, xt, yt)) { + Renderer.signDisplayMenu = new SignDisplayMenu(level, xt, yt); + } + } else { + if (Renderer.signDisplayMenu != null && Renderer.signDisplayMenu.matches(level.depth, xt, yt)) { + Renderer.signDisplayMenu = null; + } + } + } +} diff --git a/src/client/java/minicraft/level/tile/farming/CarrotTile.java b/src/client/java/minicraft/level/tile/farming/CarrotTile.java new file mode 100644 index 000000000..542fee7d6 --- /dev/null +++ b/src/client/java/minicraft/level/tile/farming/CarrotTile.java @@ -0,0 +1,28 @@ +package minicraft.level.tile.farming; + +import minicraft.gfx.Screen; +import minicraft.gfx.SpriteLinker.LinkedSprite; +import minicraft.gfx.SpriteLinker.SpriteType; +import minicraft.level.Level; +import minicraft.level.tile.Tiles; + +public class CarrotTile extends CropTile { + private final LinkedSprite[] spritStages = new LinkedSprite[] { + new LinkedSprite(SpriteType.Tile, "carrot_stage0"), + new LinkedSprite(SpriteType.Tile, "carrot_stage1"), + new LinkedSprite(SpriteType.Tile, "carrot_stage2"), + new LinkedSprite(SpriteType.Tile, "carrot_stage3") + }; + + public CarrotTile(String name) { + super(name, null); + } + + @Override + public void render(Screen screen, Level level, int x, int y) { + int age = (level.getData(x, y) >> 3) & maxAge; + Tiles.get("Farmland").render(screen, level, x, y); + int stage = (int) ((float) age / maxAge * 3); + screen.render(x * 16, y * 16, spritStages[stage]); + } +} diff --git a/src/client/java/minicraft/level/tile/farming/CropTile.java b/src/client/java/minicraft/level/tile/farming/CropTile.java new file mode 100644 index 000000000..6291fa75b --- /dev/null +++ b/src/client/java/minicraft/level/tile/farming/CropTile.java @@ -0,0 +1,177 @@ +package minicraft.level.tile.farming; + +import minicraft.core.io.Sound; +import minicraft.entity.Direction; +import minicraft.entity.Entity; +import minicraft.entity.mob.Mob; +import minicraft.entity.mob.Player; +import minicraft.entity.particle.Particle; +import minicraft.gfx.SpriteLinker; +import minicraft.item.Item; +import minicraft.item.Items; +import minicraft.item.StackableItem; +import minicraft.level.Level; +import minicraft.level.tile.Tile; +import minicraft.level.tile.Tiles; +import minicraft.level.tile.WaterTile; +import org.jetbrains.annotations.Nullable; + +import java.util.Arrays; +import java.util.Random; + +public class CropTile extends FarmTile { + protected final @Nullable String seed; + + protected int maxAge = 0b111; // Must be a bit mask. + + protected CropTile(String name, @Nullable String seed) { + super(name, null); + this.seed = seed; + } + + @Override + public boolean hurt(Level level, int x, int y, Mob source, int dmg, Direction attackDir) { + harvest(level, x, y, source); + return true; + } + + @Override + public boolean tick(Level level, int xt, int yt) { + int data = level.getData(xt, yt); + int moisture = data & 0b111; + boolean successful = false; + if (Arrays.stream(level.getAreaTiles(xt, yt, 4)).anyMatch(t -> t instanceof WaterTile)) { // Contains water. + if (moisture < 7 && random.nextInt(10) == 0) { // hydrating + level.setData(xt, yt, data = (data & ~0b111) + moisture++); + successful = true; + } + } else if (moisture > 0 && random.nextInt(10) == 0) { // drying + level.setData(xt, yt, data = (data & ~0b111) + moisture--); + successful = true; + } + + int fertilization = getFertilization(data); + int stage = (data >> 3) & maxAge; + if (stage < maxAge) { + double points = moisture > 0 ? 4 : 2; + for (int i = -1; i < 2; i++) + for (int j = -1; j < 2; j++) { + Tile t = level.getTile(xt + i, yt + j); + if ((i != 0 || j != 0) && t instanceof FarmTile) { + points += (level.getData(xt + i, yt + j) & 0b111) > 0 ? 0.75 : 0.25; + } + } + + // Checking whether the target direction has targeted the same CropTile + boolean up = level.getTile(xt, yt - 1) == this; + boolean down = level.getTile(xt, yt + 1) == this; + boolean left = level.getTile(xt - 1, yt) == this; + boolean right = level.getTile(xt + 1, yt) == this; + boolean upLeft = level.getTile(xt - 1, yt - 1) == this; + boolean downLeft = level.getTile(xt - 1, yt + 1) == this; + boolean upRight = level.getTile(xt + 1, yt - 1) == this; + boolean downRight = level.getTile(xt + 1, yt + 1) == this; + if (up && down && left && right && upLeft && downLeft && upRight && downRight) + points /= 2; + else { + if (up && down && left && right) + points *= 0.75; + if (up && (down && (left || right) || left && right) || down && left && right) // Either 3 of 4 directions. + points *= 0.85; + if (upLeft && (downRight || downLeft || upRight) || downLeft && (upRight || downRight) || upRight && downRight) // Either 2 of 4 directions. + points *= 0.9; + if (upLeft) points *= 0.98125; + if (downLeft) points *= 0.98125; + if (upRight) points *= 0.98125; + if (downRight) points *= 0.98125; + } + + if (random.nextInt((int) (100 / points) + 1) < (fertilization / 30 + 1)) // fertilization >= 0 + level.setData(xt, yt, data = (data & ~(maxAge << 3)) + ((stage + 1) << 3)); // Incrementing the stage by 1. + successful = true; + } + + if (fertilization > 0) { + level.setData(xt, yt, (data & (0b111 + (maxAge << 3))) + ((fertilization - 1) << (3 + (maxAge + 1) / 2))); + successful = true; + } + + return successful; + } + + private static final SpriteLinker.LinkedSprite particleSprite = new SpriteLinker.LinkedSprite(SpriteLinker.SpriteType.Entity, "glint"); + + @Override + public boolean interact(Level level, int xt, int yt, Player player, Item item, Direction attackDir) { + if (item instanceof StackableItem && item.getName().equalsIgnoreCase("Fertilizer")) { + ((StackableItem) item).count--; + Random random = new Random(); + for (int i = 0; i < 2; ++i) { + double x = (double) xt * 16 + 8 + (random.nextGaussian() * 0.5) * 8; + double y = (double) yt * 16 + 8 + (random.nextGaussian() * 0.5) * 8; + level.add(new Particle((int) x, (int) y, 120 + random.nextInt(21) - 40, particleSprite)); + } + int fertilization = getFertilization(level.getData(xt, yt)); + if (fertilization < 100) { // More fertilization, lower the buffer is applied. + fertilize(level, xt, yt, 40); + } else if (fertilization < 200) { + fertilize(level, xt, yt, 30); + } else if (fertilization < 300) { + fertilize(level, xt, yt, 25); + } else if (fertilization < 400) { + fertilize(level, xt, yt, 20); + } else { + fertilize(level, xt, yt, 10); + } + + return true; + } + + return super.interact(level, xt, yt, player, item, attackDir); + } + + /** + * Default harvest method, used for everything that doesn't really need any special behavior. + */ + protected void harvest(Level level, int x, int y, Entity entity) { + int data = level.getData(x, y); + int age = (data >> 3) & maxAge; + + if (seed != null) + level.dropItem(x * 16 + 8, y * 16 + 8, 1, Items.get(seed)); + + if (age == maxAge) { + level.dropItem(x * 16 + 8, y * 16 + 8, random.nextInt(3) + 2, Items.get(name)); + } else if (seed == null) { + level.dropItem(x * 16 + 8, y * 16 + 8, 1, Items.get(name)); + } + + if (age == maxAge && entity instanceof Player) { + ((Player) entity).addScore(random.nextInt(5) + 1); + } + + // Play sound. + Sound.play("monsterhurt"); + + level.setTile(x, y, Tiles.get("farmland"), data & 0b111); + } + + public int getFertilization(int data) { + return data >> (3 + (maxAge + 1) / 2); + } + + /** + * Fertilization: Each magnitude of fertilization (by 1) increases the chance of growth by 1/30. + * (The addition by fertilization is rounded down to the nearest integer in chance calculation) + * For example, if the chance is originally 10% (1/10), the final chance with 30 fertilization will be 20% (2/10). + */ + public void fertilize(Level level, int x, int y, int amount) { + int data = level.getData(x, y); + int fertilization = getFertilization(data); + fertilization += amount; + if (fertilization < 0) fertilization = 0; + if (fertilization > 511) fertilization = 511; // The maximum possible value to be reached. + // If this value exceeds 511, the final value would be greater than the hard maximum value that short can be. + level.setData(x, y, (data & (0b111 + (maxAge << 3))) + (fertilization << (3 + (maxAge + 1) / 2))); + } +} diff --git a/src/client/java/minicraft/level/tile/farming/FarmTile.java b/src/client/java/minicraft/level/tile/farming/FarmTile.java index 770cc0ead..6205714dd 100644 --- a/src/client/java/minicraft/level/tile/farming/FarmTile.java +++ b/src/client/java/minicraft/level/tile/farming/FarmTile.java @@ -2,9 +2,8 @@ import minicraft.core.io.Sound; import minicraft.entity.Direction; -import minicraft.entity.Entity; -import minicraft.entity.ItemEntity; import minicraft.entity.mob.Player; +import minicraft.gfx.Screen; import minicraft.gfx.SpriteAnimation; import minicraft.gfx.SpriteLinker.SpriteType; import minicraft.item.Item; @@ -13,49 +12,66 @@ import minicraft.level.Level; import minicraft.level.tile.Tile; import minicraft.level.tile.Tiles; +import minicraft.level.tile.WaterTile; import minicraft.util.AdvancementElement; +import java.util.Arrays; + public class FarmTile extends Tile { - private static SpriteAnimation sprite = new SpriteAnimation(SpriteType.Tile, "farmland"); - - public FarmTile(String name) { - super(name, sprite); - } - protected FarmTile(String name, SpriteAnimation sprite) { - super(name, sprite); - } - - @Override - public boolean interact(Level level, int xt, int yt, Player player, Item item, Direction attackDir) { - if (item instanceof ToolItem) { - ToolItem tool = (ToolItem) item; - if (tool.type == ToolType.Shovel) { - if (player.payStamina(4 - tool.level) && tool.payDurability()) { + private static final SpriteAnimation sprite = new SpriteAnimation(SpriteType.Tile, "farmland"); + private static final SpriteAnimation spriteMoist = new SpriteAnimation(SpriteType.Tile, "farmland_moist"); + + public FarmTile(String name) { + super(name, sprite); + } + + protected FarmTile(String name, SpriteAnimation sprite) { + super(name, sprite); + } + + @Override + public boolean interact(Level level, int xt, int yt, Player player, Item item, Direction attackDir) { + if (item instanceof ToolItem) { + ToolItem tool = (ToolItem) item; + if (tool.type == ToolType.Shovel) { + if (player.payStamina(4 - tool.level) && tool.payDurability()) { int data = level.getData(xt, yt); - level.setTile(xt, yt, Tiles.get("Dirt")); - Sound.play("monsterhurt"); + level.setTile(xt, yt, Tiles.get("Dirt")); + Sound.play("monsterhurt"); AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.INSTANCE.trigger( new AdvancementElement.AdvancementTrigger.ItemUsedOnTileTrigger.ItemUsedOnTileTriggerConditionHandler.ItemUsedOnTileTriggerConditions( item, this, data, xt, yt, level.depth)); - return true; - } - } - } - return false; - } - - @Override - public boolean tick(Level level, int xt, int yt) { - int age = level.getData(xt, yt); - if (age < 5) level.setData(xt, yt, age + 1); - return true; - } - - @Override - public void steppedOn(Level level, int xt, int yt, Entity entity) { - if (entity instanceof ItemEntity) return; - if (random.nextInt(60) != 0) return; - if (level.getData(xt, yt) < 5) return; - level.setTile(xt, yt, Tiles.get("Dirt")); - } + return true; + } + } + } + return false; + } + + @Override + public boolean tick(Level level, int xt, int yt) { + int moisture = level.getData(xt, yt) & 0b111; + if (Arrays.stream(level.getAreaTiles(xt, yt, 4)).anyMatch(t -> t instanceof WaterTile)) { // Contains water. + if (moisture < 7 && random.nextInt(10) == 0) { // hydrating + level.setData(xt, yt, moisture + 1); + return true; + } + } else if (moisture > 0 && random.nextInt(10) == 0) { // drying + level.setData(xt, yt, moisture - 1); + return true; + } else if (moisture == 0 && random.nextInt(10) == 0) { + level.setTile(xt, yt, Tiles.get("dirt")); + return true; + } + + return false; + } + + @Override + public void render(Screen screen, Level level, int x, int y) { + if ((level.getData(x, y) & 0b111) > 0) + spriteMoist.render(screen, level, x, y); + else + sprite.render(screen, level, x, y); + } } diff --git a/src/client/java/minicraft/level/tile/farming/HeavenlyBerriesTile.java b/src/client/java/minicraft/level/tile/farming/HeavenlyBerriesTile.java new file mode 100644 index 000000000..c4fc57100 --- /dev/null +++ b/src/client/java/minicraft/level/tile/farming/HeavenlyBerriesTile.java @@ -0,0 +1,27 @@ +package minicraft.level.tile.farming; + +import minicraft.gfx.Screen; +import minicraft.gfx.SpriteLinker; +import minicraft.level.Level; +import minicraft.level.tile.Tiles; + +public class HeavenlyBerriesTile extends CropTile { + private final SpriteLinker.LinkedSprite[] spritStages = new SpriteLinker.LinkedSprite[] { + new SpriteLinker.LinkedSprite(SpriteLinker.SpriteType.Tile, "heavenly_berries_stage0"), + new SpriteLinker.LinkedSprite(SpriteLinker.SpriteType.Tile, "heavenly_berries_stage1"), + new SpriteLinker.LinkedSprite(SpriteLinker.SpriteType.Tile, "heavenly_berries_stage2"), + new SpriteLinker.LinkedSprite(SpriteLinker.SpriteType.Tile, "heavenly_berries_stage3") + }; + + public HeavenlyBerriesTile(String name) { + super(name, null); + } + + @Override + public void render(Screen screen, Level level, int x, int y) { + int age = (level.getData(x, y) >> 3) & maxAge; + Tiles.get("Farmland").render(screen, level, x, y); + int stage = (int) ((float) age / maxAge * 3); + screen.render(x * 16, y * 16, spritStages[stage]); + } +} diff --git a/src/client/java/minicraft/level/tile/farming/HellishBerriesTile.java b/src/client/java/minicraft/level/tile/farming/HellishBerriesTile.java new file mode 100644 index 000000000..6d4f7bcb5 --- /dev/null +++ b/src/client/java/minicraft/level/tile/farming/HellishBerriesTile.java @@ -0,0 +1,27 @@ +package minicraft.level.tile.farming; + +import minicraft.gfx.Screen; +import minicraft.gfx.SpriteLinker; +import minicraft.level.Level; +import minicraft.level.tile.Tiles; + +public class HellishBerriesTile extends CropTile { + private final SpriteLinker.LinkedSprite[] spritStages = new SpriteLinker.LinkedSprite[] { + new SpriteLinker.LinkedSprite(SpriteLinker.SpriteType.Tile, "hellish_berries_stage0"), + new SpriteLinker.LinkedSprite(SpriteLinker.SpriteType.Tile, "hellish_berries_stage1"), + new SpriteLinker.LinkedSprite(SpriteLinker.SpriteType.Tile, "hellish_berries_stage2"), + new SpriteLinker.LinkedSprite(SpriteLinker.SpriteType.Tile, "hellish_berries_stage3") + }; + + public HellishBerriesTile(String name) { + super(name, null); + } + + @Override + public void render(Screen screen, Level level, int x, int y) { + int age = (level.getData(x, y) >> 3) & maxAge; + Tiles.get("Farmland").render(screen, level, x, y); + int stage = (int) ((float) age / maxAge * 3); + screen.render(x * 16, y * 16, spritStages[stage]); + } +} diff --git a/src/client/java/minicraft/level/tile/farming/PlantTile.java b/src/client/java/minicraft/level/tile/farming/PlantTile.java deleted file mode 100644 index 0712acb29..000000000 --- a/src/client/java/minicraft/level/tile/farming/PlantTile.java +++ /dev/null @@ -1,84 +0,0 @@ -package minicraft.level.tile.farming; - -import minicraft.core.io.Sound; -import minicraft.entity.Direction; -import minicraft.entity.Entity; -import minicraft.entity.ItemEntity; -import minicraft.entity.mob.Mob; -import minicraft.entity.mob.MobAi; -import minicraft.entity.mob.Player; -import minicraft.item.Items; -import minicraft.level.Level; -import minicraft.level.tile.Tile; -import minicraft.level.tile.Tiles; - -public class PlantTile extends FarmTile { - protected static int maxAge = 100; - - protected PlantTile(String name) { - super(name, null); - } - - @Override - public void steppedOn(Level level, int xt, int yt, Entity entity) { - if (entity instanceof MobAi) return; - if (entity instanceof ItemEntity) return; - if (random.nextInt(60) != 0) return; - if (level.getData(xt, yt) < 5) return; - harvest(level, xt, yt, entity); - } - - @Override - public boolean hurt(Level level, int x, int y, Mob source, int dmg, Direction attackDir) { - harvest(level, x, y, source); - return true; - } - - @Override - public boolean tick(Level level, int xt, int yt) { - if (random.nextInt(2) == 0) return false; - - int age = level.getData(xt, yt); - if (age < maxAge) { - if (!IfWater(level, xt, yt)) level.setData(xt, yt, age + 1); - else if (IfWater(level, xt, yt)) level.setData(xt, yt, age + 2); - return true; - } - - return false; - } - - protected boolean IfWater(Level level, int xs, int ys) { - Tile[] areaTiles = level.getAreaTiles(xs, ys, 1); - for(Tile t: areaTiles) - if(t == Tiles.get("Water")) - return true; - - return false; - } - - /** Default harvest method, used for everything that doesn't really need any special behavior. */ - protected void harvest(Level level, int x, int y, Entity entity) { - int age = level.getData(x, y); - - level.dropItem(x * 16 + 8, y * 16 + 8, 1, Items.get(name + " Seeds")); - - int count = 0; - if (age >= maxAge) { - count = random.nextInt(3) + 2; - } else if (age >= maxAge - maxAge / 5) { - count = random.nextInt(2) + 1; - } - - level.dropItem(x * 16 + 8, y * 16 + 8, count, Items.get(name)); - - if (age >= maxAge && entity instanceof Player) { - ((Player)entity).addScore(random.nextInt(5) + 1); - } - - // Play sound. - Sound.play("monsterhurt"); - - level.setTile(x, y, Tiles.get("Dirt")); - } -} diff --git a/src/client/java/minicraft/level/tile/farming/PotatoTile.java b/src/client/java/minicraft/level/tile/farming/PotatoTile.java index a4c96fd49..619dbf2fc 100644 --- a/src/client/java/minicraft/level/tile/farming/PotatoTile.java +++ b/src/client/java/minicraft/level/tile/farming/PotatoTile.java @@ -1,17 +1,13 @@ package minicraft.level.tile.farming; -import minicraft.core.io.Sound; -import minicraft.entity.Entity; -import minicraft.entity.mob.Player; import minicraft.gfx.Screen; import minicraft.gfx.SpriteLinker.LinkedSprite; import minicraft.gfx.SpriteLinker.SpriteType; -import minicraft.item.Items; import minicraft.level.Level; import minicraft.level.tile.Tiles; -public class PotatoTile extends PlantTile { - private LinkedSprite[] spritStages = new LinkedSprite[] { +public class PotatoTile extends CropTile { + private final LinkedSprite[] spritStages = new LinkedSprite[] { new LinkedSprite(SpriteType.Tile, "potato_stage0"), new LinkedSprite(SpriteType.Tile, "potato_stage1"), new LinkedSprite(SpriteType.Tile, "potato_stage2"), @@ -20,43 +16,15 @@ public class PotatoTile extends PlantTile { new LinkedSprite(SpriteType.Tile, "potato_stage5") }; - public PotatoTile(String name) { - super(name); - } - - static { - maxAge = 70; - } - - @Override - public void render(Screen screen, Level level, int x, int y) { - int age = level.getData(x, y); - int icon = age / (maxAge / 5); - - Tiles.get("Farmland").render(screen, level, x, y); - screen.render(x * 16, y * 16, spritStages[icon]); - } - - @Override - protected void harvest(Level level, int x, int y, Entity entity) { - int age = level.getData(x, y); - - int count = 0; - if (age >= maxAge) { - count = random.nextInt(3) + 2; - } else if (age >= maxAge - maxAge / 5) { - count = random.nextInt(2); - } - - level.dropItem(x * 16 + 8, y * 16 + 8, count + 1, Items.get("Potato")); - - if (age >= maxAge && entity instanceof Player) { - ((Player)entity).addScore(random.nextInt(4) + 1); - } - - // Play sound. - Sound.play("monsterhurt"); - - level.setTile(x, y, Tiles.get("Dirt")); - } + public PotatoTile(String name) { + super(name, null); + } + + @Override + public void render(Screen screen, Level level, int x, int y) { + int age = (level.getData(x, y) >> 3) & maxAge; + Tiles.get("Farmland").render(screen, level, x, y); + int stage = (int) ((float) age / maxAge * 5); + screen.render(x << 4, y << 4, spritStages[stage]); + } } diff --git a/src/client/java/minicraft/level/tile/farming/TomatoTile.java b/src/client/java/minicraft/level/tile/farming/TomatoTile.java new file mode 100644 index 000000000..a8329ae63 --- /dev/null +++ b/src/client/java/minicraft/level/tile/farming/TomatoTile.java @@ -0,0 +1,28 @@ +package minicraft.level.tile.farming; + +import minicraft.gfx.Screen; +import minicraft.gfx.SpriteLinker.LinkedSprite; +import minicraft.gfx.SpriteLinker.SpriteType; +import minicraft.level.Level; +import minicraft.level.tile.Tiles; + +public class TomatoTile extends CropTile { + private final LinkedSprite[] spritStages = new LinkedSprite[] { + new LinkedSprite(SpriteType.Tile, "tomato_stage0"), + new LinkedSprite(SpriteType.Tile, "tomato_stage1"), + new LinkedSprite(SpriteType.Tile, "tomato_stage2"), + new LinkedSprite(SpriteType.Tile, "tomato_stage3") + }; + + public TomatoTile(String name) { + super(name, "tomato seeds"); + } + + @Override + public void render(Screen screen, Level level, int x, int y) { + int age = (level.getData(x, y) >> 3) & maxAge; + Tiles.get("Farmland").render(screen, level, x, y); + int stage = (int) ((float) age / maxAge * 3); + screen.render(x * 16, y * 16, spritStages[stage]); + } +} diff --git a/src/client/java/minicraft/level/tile/farming/WheatTile.java b/src/client/java/minicraft/level/tile/farming/WheatTile.java index f5f3c6cfb..31fb0fe5a 100644 --- a/src/client/java/minicraft/level/tile/farming/WheatTile.java +++ b/src/client/java/minicraft/level/tile/farming/WheatTile.java @@ -6,8 +6,8 @@ import minicraft.level.Level; import minicraft.level.tile.Tiles; -public class WheatTile extends PlantTile { - private LinkedSprite[] spritStages = new LinkedSprite[] { +public class WheatTile extends CropTile { + private final LinkedSprite[] spritStages = new LinkedSprite[] { new LinkedSprite(SpriteType.Tile, "wheat_stage0"), new LinkedSprite(SpriteType.Tile, "wheat_stage1"), new LinkedSprite(SpriteType.Tile, "wheat_stage2"), @@ -17,15 +17,14 @@ public class WheatTile extends PlantTile { }; public WheatTile(String name) { - super(name); + super(name, "wheat seeds"); } @Override public void render(Screen screen, Level level, int x, int y) { - int age = level.getData(x, y); - int icon = age / (maxAge / 5); - + int age = (level.getData(x, y) >> 3) & maxAge; Tiles.get("Farmland").render(screen, level, x, y); - screen.render(x * 16, y * 16, spritStages[icon]); + int stage = (int) ((float) age / maxAge * 5); + screen.render(x << 4, y << 4, spritStages[stage]); } } diff --git a/src/client/java/minicraft/network/Analytics.java b/src/client/java/minicraft/network/Analytics.java index d922454ef..94222a2a4 100644 --- a/src/client/java/minicraft/network/Analytics.java +++ b/src/client/java/minicraft/network/Analytics.java @@ -50,9 +50,14 @@ public enum Analytics { this.token = token; } - @Nullable public Future> ping() { return ping(1); } - @Nullable public Future> ping(int value) { - final String url = "https://pingdat.io?t="+token+"&v="+value; + @Nullable + public Future> ping() { + return ping(1); + } + + @Nullable + public Future> ping(int value) { + final String url = "https://pingdat.io?t=" + token + "&v=" + value; return Unirest.get(url).asEmptyAsync(new Callback() { @Override diff --git a/src/client/java/minicraft/network/MinicraftProtocol.java b/src/client/java/minicraft/network/MinicraftProtocol.java index 044e86f2f..d5473b788 100644 --- a/src/client/java/minicraft/network/MinicraftProtocol.java +++ b/src/client/java/minicraft/network/MinicraftProtocol.java @@ -5,12 +5,12 @@ import java.util.List; public interface MinicraftProtocol { - + int PORT = 4225; - + enum InputType { INVALID, PING, USERNAMES, LOGIN, GAME, INIT, LOAD, TILES, ENTITIES, TILE, ENTITY, PLAYER, MOVE, ADD, REMOVE, DISCONNECT, SAVE, NOTIFY, INTERACT, PUSH, PICKUP, CHESTIN, CHESTOUT, ADDITEMS, BED, POTION, HURT, DIE, RESPAWN, DROP, STAMINA, SHIRT, STOPFISHING; - + public static final InputType[] values = InputType.values(); public static final List serverOnly = Arrays.asList(INIT, TILES, ENTITIES, ADD, REMOVE, HURT, GAME, ADDITEMS, STAMINA, STOPFISHING); public static final List entityUpdates = Arrays.asList(ENTITY, ADD, REMOVE); diff --git a/src/client/java/minicraft/network/Network.java b/src/client/java/minicraft/network/Network.java index ff181f41c..e179f00e8 100644 --- a/src/client/java/minicraft/network/Network.java +++ b/src/client/java/minicraft/network/Network.java @@ -16,7 +16,8 @@ import java.util.Random; public class Network extends Game { - private Network() {} + private Network() { + } private static final Random random = new Random(); @@ -24,7 +25,9 @@ private Network() {} @Nullable - public static VersionInfo getLatestVersion() { return latestVersion; } + public static VersionInfo getLatestVersion() { + return latestVersion; + } public static void findLatestVersion(Action callback) { new Thread(() -> { @@ -49,9 +52,9 @@ public static void findLatestVersion(Action callback) { @Nullable public static Entity getEntity(int eid) { - for (Level level: levels) { + for (Level level : levels) { if (level == null) continue; - for (Entity e: level.getEntityArray()) + for (Entity e : level.getEntityArray()) if (e.eid == eid) return e; } @@ -77,9 +80,9 @@ public static boolean idIsAvailable(int eid) { if (eid == 0) return false; // This is reserved for the main player... kind of... if (eid < 0) return false; // ID's must be positive numbers. - for (Level level: levels) { + for (Level level : levels) { if (level == null) continue; - for (Entity e: level.getEntityArray()) { + for (Entity e : level.getEntityArray()) { if (e.eid == eid) return false; } diff --git a/src/client/java/minicraft/saveload/LegacyLoad.java b/src/client/java/minicraft/saveload/LegacyLoad.java index 46dcb4f5b..d79df91ac 100644 --- a/src/client/java/minicraft/saveload/LegacyLoad.java +++ b/src/client/java/minicraft/saveload/LegacyLoad.java @@ -112,7 +112,8 @@ public void loadFromFile(String filename) { try { br = new BufferedReader(new FileReader(filename)); - String curLine;StringBuilder total = new StringBuilder(); + String curLine; + StringBuilder total = new StringBuilder(); ArrayList curData; while ((curLine = br.readLine()) != null) total.append(curLine); @@ -166,8 +167,8 @@ protected void updateUnlocks(File file) { try { java.io.BufferedWriter writer = new java.io.BufferedWriter(new java.io.FileWriter(path)); - for (String unlock: data) { - writer.write(","+unlock); + for (String unlock : data) { + writer.write("," + unlock); } writer.flush(); writer.close(); @@ -195,8 +196,7 @@ public void loadGame(String filename) { Settings.setIdx("diff", Integer.parseInt(data.get(3))); AirWizard.beaten = Boolean.parseBoolean(data.get(4)); } - } - else { + } else { if (data.size() == 5) { worldVer = new Version("1.9"); Updater.setTime(Integer.parseInt(data.get(0))); @@ -231,8 +231,8 @@ public void loadWorld(String filename) { for (int y = 0; y < lvlh - 1; y++) { int tileArrIdx = y + x * lvlw; int tileidx = x + y * lvlw; // The tiles are saved with x outer loop, and y inner loop, meaning that the list reads down, then right one, rather than right, then down one. - tiles[tileArrIdx] = Tiles.get(Tiles.oldids.get(Integer.parseInt(data.get(tileidx + 3)))).id; - tdata[tileArrIdx] = Short.parseShort(extradata.get(tileidx)); + Load.loadTile(tiles, tdata, tileArrIdx, Tiles.oldids.get(Integer.parseInt(data.get(tileidx + 3))), + extradata.get(tileidx)); } } @@ -256,7 +256,7 @@ public void loadPlayer(String filename, Player player) { if (data.size() >= 14) { if (worldVer == null) worldVer = new Version("1.9.1-pre1"); player.armorDamageBuffer = Integer.parseInt(data.get(13)); - player.curArmor = (ArmorItem)Items.get(data.get(14)); + player.curArmor = (ArmorItem) Items.get(data.get(14)); } else player.armor = 0; Game.currentLevel = Integer.parseInt(data.get(8)); @@ -276,8 +276,7 @@ public void loadPlayer(String filename, Player player) { mode = Integer.parseInt(modedata.substring(0, modedata.indexOf(";"))); if (mode == 4) Updater.scoreTime = Integer.parseInt(modedata.substring(modedata.indexOf(";") + 1)); - } - else { + } else { mode = Integer.parseInt(modedata); if (mode == 4) Updater.scoreTime = 300; } @@ -287,7 +286,7 @@ public void loadPlayer(String filename, Player player) { boolean hasEffects; int potionIdx = 10; if (oldSave) { - hasEffects = data.size() > 10 && data.get(data.size()-2).contains("PotionEffects["); + hasEffects = data.size() > 10 && data.get(data.size() - 2).contains("PotionEffects["); potionIdx = data.size() - 2; } else hasEffects = !data.get(10).equals("PotionEffects[]"); // Newer save @@ -303,9 +302,9 @@ public void loadPlayer(String filename, Player player) { } } - String colors = data.get(oldSave ? data.size() -1 : 11).replace("[", "").replace("]", ""); + String colors = data.get(oldSave ? data.size() - 1 : 11).replace("[", "").replace("]", ""); String[] color = colors.split(";"); - player.shirtColor = Integer.parseInt(color[0]+color[1]+color[2]); + player.shirtColor = Integer.parseInt(color[0] + color[1] + color[2]); } public void loadInventory(String filename, Inventory inventory) { @@ -330,7 +329,7 @@ public void loadItemToInventory(String item, Inventory inventory) { if (item.contains(";")) { String[] curData = item.split(";"); String itemName = curData[0]; - if(oldSave) itemName = subOldName(itemName); + if (oldSave) itemName = subOldName(itemName); //System.out.println("Item to fetch: " + itemName + "; count=" + curData[1]); Item newItem = Items.get(itemName); @@ -345,11 +344,7 @@ public void loadItemToInventory(String item, Inventory inventory) { } private void loadItem(Inventory inventory, Item item) { - int total = 1; - if (item instanceof StackableItem) total = ((StackableItem) item).count; - int loaded = inventory.add(item); - - if (loaded < total) { + if (inventory.add(item) != null) { deathChest.getInventory().add(item.copy()); } } @@ -379,23 +374,24 @@ public void loadEntities(String filename, Player player) { int mobLvl = 0; try { if (Class.forName("EnemyMob").isAssignableFrom(Class.forName(entityName))) - mobLvl = Integer.parseInt(info.get(info.size()-2)); - } catch (ClassNotFoundException ignored) {} + mobLvl = Integer.parseInt(info.get(info.size() - 2)); + } catch (ClassNotFoundException ignored) { + } Entity newEntity = getEntity(entityName, player, mobLvl); if (newEntity != null) { // the method never returns null, but... int currentlevel; if (newEntity instanceof Mob) { - Mob mob = (Mob)newEntity; + Mob mob = (Mob) newEntity; mob.health = Integer.parseInt(info.get(2)); - currentlevel = Integer.parseInt(info.get(info.size()-1)); + currentlevel = Integer.parseInt(info.get(info.size() - 1)); World.levels[currentlevel].add(mob, x, y); } else if (newEntity instanceof Chest) { - Chest chest = (Chest)newEntity; + Chest chest = (Chest) newEntity; boolean isDeathChest = chest instanceof DeathChest; boolean isDungeonChest = chest instanceof DungeonChest; - List chestInfo = info.subList(2, info.size()-1); + List chestInfo = info.subList(2, info.size() - 1); int endIdx = chestInfo.size() - (isDeathChest || isDungeonChest ? 1 : 0); for (int idx = 0; idx < endIdx; idx++) { @@ -406,13 +402,13 @@ public void loadEntities(String filename, Player player) { } if (isDeathChest) { - ((DeathChest)chest).time = Integer.parseInt(chestInfo.get(chestInfo.size()-1).replace("tl;", "")); // "tl;" is only for old save support + ((DeathChest) chest).time = Integer.parseInt(chestInfo.get(chestInfo.size() - 1).replace("tl;", "")); // "tl;" is only for old save support } else if (isDungeonChest) { - ((DungeonChest)chest).setLocked(Boolean.parseBoolean(chestInfo.get(chestInfo.size()-1))); + ((DungeonChest) chest).setLocked(Boolean.parseBoolean(chestInfo.get(chestInfo.size() - 1))); } currentlevel = Integer.parseInt(info.get(info.size() - 1)); - World.levels[currentlevel].add(chest instanceof DeathChest ? chest : chest instanceof DungeonChest ? (DungeonChest)chest : chest, x, y); + World.levels[currentlevel].add(chest instanceof DeathChest ? chest : chest instanceof DungeonChest ? (DungeonChest) chest : chest, x, y); } else if (newEntity instanceof Spawner) { MobAi mob = (MobAi) getEntity(info.get(2), player, Integer.parseInt(info.get(3))); currentlevel = Integer.parseInt(info.get(info.size() - 1)); @@ -428,35 +424,61 @@ public void loadEntities(String filename, Player player) { public Entity getEntity(String string, Player player, int mobLevel) { switch (string) { - case "Player": return player; - case "Cow": return new Cow(); - case "Sheep": return new Sheep(); - case "Pig": return new Pig(); - case "Zombie": return new Zombie(mobLevel); - case "Slime": return new Slime(mobLevel); - case "Creeper": return new Creeper(mobLevel); - case "Skeleton": return new Skeleton(mobLevel); - case "Knight": return new Knight(mobLevel); - case "Snake": return new Snake(mobLevel); + case "Player": + return player; + case "Cow": + return new Cow(); + case "Sheep": + return new Sheep(); + case "Pig": + return new Pig(); + case "Zombie": + return new Zombie(mobLevel); + case "Slime": + return new Slime(mobLevel); + case "Creeper": + return new Creeper(mobLevel); + case "Skeleton": + return new Skeleton(mobLevel); + case "Knight": + return new Knight(mobLevel); + case "Snake": + return new Snake(mobLevel); case "AirWizard": if (mobLevel > 1) return null; return new AirWizard(); - case "Spawner": return new Spawner(new Zombie(1)); - case "Workbench": return new Crafter(Crafter.Type.Workbench); - case "Chest": return new Chest(); - case "DeathChest": return new DeathChest(); - case "DungeonChest": return new DungeonChest(false); - case "Anvil": return new Crafter(Crafter.Type.Anvil); - case "Enchanter": return new Crafter(Crafter.Type.Enchanter); - case "Loom": return new Crafter(Crafter.Type.Loom); - case "Furnace": return new Crafter(Crafter.Type.Furnace); - case "Oven": return new Crafter(Crafter.Type.Oven); - case "Bed": return new Bed(); - case "Tnt": return new Tnt(); - case "Lantern": return new Lantern(Lantern.Type.NORM); - case "IronLantern": return new Lantern(Lantern.Type.IRON); - case "GoldLantern": return new Lantern(Lantern.Type.GOLD); - default : Logger.tag("SaveLoad/LegacyLoad").warn("Unknown or outdated entity requested: " + string); + case "Spawner": + return new Spawner(new Zombie(1)); + case "Workbench": + return new Crafter(Crafter.Type.Workbench); + case "Chest": + return new Chest(); + case "DeathChest": + return new DeathChest(); + case "DungeonChest": + return new DungeonChest(null); + case "Anvil": + return new Crafter(Crafter.Type.Anvil); + case "Enchanter": + return new Crafter(Crafter.Type.Enchanter); + case "Loom": + return new Crafter(Crafter.Type.Loom); + case "Furnace": + return new Crafter(Crafter.Type.Furnace); + case "Oven": + return new Crafter(Crafter.Type.Oven); + case "Bed": + return new Bed(); + case "Tnt": + return new Tnt(); + case "Lantern": + return new Lantern(Lantern.Type.NORM); + case "IronLantern": + return new Lantern(Lantern.Type.IRON); + case "GoldLantern": + return new Lantern(Lantern.Type.GOLD); + default: + Logger.tag("SaveLoad/LegacyLoad").warn("Unknown or outdated entity requested: " + string); return null; } } diff --git a/src/client/java/minicraft/saveload/Load.java b/src/client/java/minicraft/saveload/Load.java index 03b06c5b2..787be58dc 100644 --- a/src/client/java/minicraft/saveload/Load.java +++ b/src/client/java/minicraft/saveload/Load.java @@ -3,6 +3,7 @@ import minicraft.core.Game; import minicraft.core.Updater; import minicraft.core.World; +import minicraft.core.io.FileHandler; import minicraft.core.io.Localization; import minicraft.core.io.Settings; import minicraft.entity.Arrow; @@ -39,6 +40,7 @@ import minicraft.entity.particle.SmashParticle; import minicraft.entity.particle.TextParticle; import minicraft.gfx.Color; +import minicraft.gfx.Point; import minicraft.item.ArmorItem; import minicraft.item.Inventory; import minicraft.item.Item; @@ -57,6 +59,7 @@ import minicraft.screen.PopupDisplay; import minicraft.screen.QuestsDisplay; import minicraft.screen.ResourcePackDisplay; +import minicraft.screen.SignDisplay; import minicraft.screen.SkinDisplay; import minicraft.screen.TutorialDisplayHandler; import minicraft.screen.entry.ListEntry; @@ -77,12 +80,18 @@ import java.nio.file.Files; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; +import java.util.AbstractMap; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Stack; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Predicate; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; public class Load { @@ -105,7 +114,10 @@ public class Load { extradata = new ArrayList<>(); } - public Load(String worldname) { this(worldname, true); } + public Load(String worldname) { + this(worldname, true); + } + public Load(String worldname, boolean loadGame) { loadFromFile(location + "/saves/" + worldname + "/Game" + extension); if (data.get(0).contains(".")) worldVer = new Version(data.get(0)); @@ -121,7 +133,7 @@ public Load(String worldname, boolean loadGame) { else { location += "/saves/" + worldname + "/"; - percentInc = 5 + World.levels.length-1; // For the methods below, and world. + percentInc = 5 + World.levels.length - 1; // For the methods below, and world. percentInc = 100f / percentInc; @@ -191,12 +203,16 @@ public Load(String worldname, boolean loadGame) { } } - public Load() { this(Game.VERSION); } + public Load() { + this(Game.VERSION); + } + public Load(Version worldVersion) { - this(false); + this(false, false); worldVer = worldVersion; } - public Load(boolean loadConfig) { + + public Load(boolean loadConfig, boolean partialLoad) { if (!loadConfig) return; boolean resave = false; @@ -205,11 +221,11 @@ public Load(boolean loadConfig) { // Check if Preferences.json exists. (new version) if (new File(location + "Preferences.json").exists()) { - loadPrefs("Preferences"); + loadPrefs("Preferences", partialLoad); // Check if Preferences.miniplussave exists. (old version) } else if (new File(location + "Preferences" + extension).exists()) { - loadPrefsOld("Preferences"); + loadPrefsOld("Preferences", partialLoad); Logging.SAVELOAD.info("Upgrading preferences to JSON."); resave = true; @@ -219,6 +235,8 @@ public Load(boolean loadConfig) { resave = true; } + if (partialLoad) return; // Partial loading only loads partial preferences + // Load unlocks. (new version) File testFileOld = new File(location + "unlocks" + extension); File testFile = new File(location + "Unlocks" + extension); @@ -248,7 +266,9 @@ public Load(boolean loadConfig) { } } - public Version getWorldVersion() { return worldVer; } + public Version getWorldVersion() { + return worldVer; + } public static ArrayList loadFile(String filename) throws IOException { ArrayList lines = new ArrayList<>(); @@ -292,7 +312,9 @@ private void loadFromFile(String filename) { LoadingDisplay.progress(percentInc); } - /** Source: Note: This method is copied from MiniMods. */ + /** + * Source: Note: This method is copied from MiniMods. + */ private static ArrayList splitUnwrappedCommas(String input) { ArrayList out = new ArrayList<>(); int lastIdx = 0; @@ -315,21 +337,24 @@ private static ArrayList splitUnwrappedCommas(String input) { if (ch == commaChar && bracketCounter.isEmpty()) { String str = input.substring(lastIdx + (input.charAt(lastIdx) == commaChar ? 1 : 0), i).trim(); lastIdx = i; - if (!str.isEmpty()) out.add(str); + out.add(str); // Empty strings are expected. } else if (ch == openBracket0) { bracketCounter.push(0); } else if (ch == closeBracket0) { - if (checkDiff.test(0)) throw new RuntimeException(String.format("Invalid closing char %s index %s. Input: \"%s\"", ch, i, input)); + if (checkDiff.test(0)) + throw new RuntimeException(String.format("Invalid closing char %s index %s. Input: \"%s\"", ch, i, input)); bracketCounter.pop(); } else if (ch == openBracket1) { bracketCounter.push(1); } else if (ch == closeBracket1) { - if (checkDiff.test(1)) throw new RuntimeException(String.format("Invalid closing char %s index %s. Input: \"%s\"", ch, i, input)); + if (checkDiff.test(1)) + throw new RuntimeException(String.format("Invalid closing char %s index %s. Input: \"%s\"", ch, i, input)); bracketCounter.pop(); } else if (ch == openBracket2) { bracketCounter.push(2); } else if (ch == closeBracket2) { - if (checkDiff.test(2)) throw new RuntimeException(String.format("Invalid closing char %s index %s. Input: \"%s\"", ch, i, input)); + if (checkDiff.test(2)) + throw new RuntimeException(String.format("Invalid closing char %s index %s. Input: \"%s\"", ch, i, input)); bracketCounter.pop(); } } @@ -425,11 +450,11 @@ private void loadMode(String modedata) { Settings.setIdx("mode", mode); } - private void loadPrefsOld(String filename) { + private void loadPrefsOld(String filename, boolean partialLoad) { loadFromFile(location + filename + extension); Version prefVer = new Version("2.0.2"); // the default, b/c this doesn't really matter much being specific past this if it's not set below. - if(!data.get(2).contains(";")) // signifies that this file was last written to by a version after 2.0.2. + if (!data.get(2).contains(";")) // signifies that this file was last written to by a version after 2.0.2. prefVer = new Version(data.remove(0)); Settings.set("sound", Boolean.parseBoolean(data.remove(0))); @@ -438,15 +463,18 @@ private void loadPrefsOld(String filename) { if (prefVer.compareTo(new Version("2.0.4-dev2")) >= 0) Settings.set("fps", Integer.parseInt(data.remove(0))); - if (prefVer.compareTo(new Version("2.0.7-dev5")) >= 0) + if (partialLoad) return; // Partial loading only loads basic settings. + + if (prefVer.compareTo(new Version("2.0.7-dev5")) >= 0) { data.remove(0); // Numeral skin indices are replaced. + } List subdata; if (prefVer.compareTo(new Version("2.0.3-dev1")) < 0) { subdata = data; } else { MultiplayerDisplay.savedIP = data.remove(0); - if(prefVer.compareTo(new Version("2.0.3-dev3")) > 0) { + if (prefVer.compareTo(new Version("2.0.3-dev3")) > 0) { MultiplayerDisplay.savedUUID = data.remove(0); MultiplayerDisplay.savedUsername = data.remove(0); } @@ -503,7 +531,7 @@ private void loadPrefsOld(String filename) { } } - private void loadPrefs(String filename) { + private void loadPrefs(String filename, boolean partialLoad) { JSONObject json; try { json = new JSONObject(loadFromFile(location + filename + ".json", false)); @@ -520,6 +548,9 @@ private void loadPrefs(String filename) { Settings.set("autosave", json.getBoolean("autosave")); Settings.set("fps", json.getInt("fps")); Settings.set("showquests", json.optBoolean("showquests", true)); + if (json.has("hwa")) Settings.set("hwa", json.getBoolean("hwa")); // Default should have been configured + + if (partialLoad) return; // Partial loading only loads basic settings. if (json.has("lang")) { String lang = json.getString("lang"); @@ -558,7 +589,7 @@ private void loadPrefs(String filename) { private void loadUnlocksOld(String filename) { loadFromFile(location + filename + extension); - for (String unlock: data) { + for (String unlock : data) { unlock = unlock.replace("HOURMODE", "H_ScoreTime").replace("MINUTEMODE", "M_ScoreTime").replace("M_ScoreTime", "_ScoreTime").replace("2H_ScoreTime", "120_ScoreTime"); if (unlock.contains("_ScoreTime")) @@ -585,8 +616,8 @@ private void loadUnlocks(String filename) { } private void loadWorld(String filename) { - for(int l = World.maxLevelDepth; l >= World.minLevelDepth; l--) { - LoadingDisplay.setMessage(Level.getDepthString(l)); + for (int l = World.maxLevelDepth; l >= World.minLevelDepth; l--) { + LoadingDisplay.setMessage(Level.getDepthString(l), false); int lvlidx = World.lvlIdx(l); loadFromFile(location + filename + lvlidx + extension); @@ -635,7 +666,7 @@ private void loadWorld(String filename) { default: tilename = "Wool"; } - } else if (l == World.minLevelDepth+1 && tilename.equalsIgnoreCase("Lapis") && worldVer.compareTo(new Version("2.0.3-dev6")) < 0) { + } else if (l == World.minLevelDepth + 1 && tilename.equalsIgnoreCase("Lapis") && worldVer.compareTo(new Version("2.0.3-dev6")) < 0) { if (Math.random() < 0.8) // don't replace *all* the lapis tilename = "Gem Ore"; } else if (tilename.equalsIgnoreCase("Cloud Cactus")) { @@ -651,29 +682,35 @@ private void loadWorld(String filename) { } } - tiles[tileArrIdx] = Tiles.get(tilename).id; - tdata[tileArrIdx] = Short.parseShort(extradata.get(tileidx)); + loadTile(tiles, tdata, tileArrIdx, tilename, extradata.get(tileidx)); } } - Level parent = World.levels[World.lvlIdx(l+1)]; + Level parent = World.levels[World.lvlIdx(l + 1)]; World.levels[lvlidx] = new Level(lvlw, lvlh, seed, l, parent, false); Level curLevel = World.levels[lvlidx]; curLevel.tiles = tiles; curLevel.data = tdata; + // Tile initialization + for (int x = 0; x < curLevel.w; ++x) { + for (int y = 0; y < curLevel.h; ++y) { + Tiles.get(curLevel.tiles[x + y * curLevel.w]).onTileSet(curLevel, x, y); + } + } + if (Logging.logLevel) curLevel.printTileLocs(Tiles.get("Stairs Down")); if (parent == null) continue; /// confirm that there are stairs in all the places that should have stairs. - for (minicraft.gfx.Point p: parent.getMatchingTiles(Tiles.get("Stairs Down"))) { + for (minicraft.gfx.Point p : parent.getMatchingTiles(Tiles.get("Stairs Down"))) { if (curLevel.getTile(p.x, p.y) != Tiles.get("Stairs Up")) { curLevel.printLevelLoc("INCONSISTENT STAIRS detected; placing stairsUp", p.x, p.y); curLevel.setTile(p.x, p.y, Tiles.get("Stairs Up")); } } - for (minicraft.gfx.Point p: curLevel.getMatchingTiles(Tiles.get("Stairs Up"))) { + for (minicraft.gfx.Point p : curLevel.getMatchingTiles(Tiles.get("Stairs Up"))) { if (parent.getTile(p.x, p.y) != Tiles.get("Stairs Down")) { parent.printLevelLoc("INCONSISTENT STAIRS detected; placing stairsDown", p.x, p.y); parent.setTile(p.x, p.y, Tiles.get("Stairs Down")); @@ -683,7 +720,7 @@ private void loadWorld(String filename) { LoadingDisplay.setMessage("minicraft.displays.loading.message.quests"); - if (new File(location+"Quests.json").exists()){ + if (new File(location + "Quests.json").exists()) { Logging.SAVELOAD.warn("Quest.json exists and it has been deprecated; renaming..."); try { Files.move(Paths.get(location, "Quests.json"), Paths.get(location, "Quests.json_old"), StandardCopyOption.REPLACE_EXISTING); @@ -693,7 +730,7 @@ private void loadWorld(String filename) { } boolean advancementsLoadSucceeded = false; - if (new File(location+"advancements.json").exists()) { + if (new File(location + "advancements.json").exists()) { try { JSONObject questsObj = new JSONObject(loadFromFile(location + "advancements.json", true)); @SuppressWarnings("unused") @@ -714,6 +751,48 @@ private void loadWorld(String filename) { AdvancementElement.resetRecipeUnlockingElements(); QuestsDisplay.resetGameQuests(); } + + boolean signsLoadSucceeded = false; + if (new File(location+"signs.json").exists()) { + try { + JSONObject fileObj = new JSONObject(loadFromFile(location + "signs.json", true)); + @SuppressWarnings("unused") + Version dataVersion = new Version(fileObj.getString("Version")); + JSONArray dataObj = fileObj.getJSONArray("signs"); + HashMap, List> signTexts = new HashMap<>(); + for (int i = 0; i < dataObj.length(); i++) { + JSONObject signObj = dataObj.getJSONObject(i); + signTexts.put( + new AbstractMap.SimpleImmutableEntry<>(signObj.getInt("level"), new Point(signObj.getInt("x"), signObj.getInt("y"))), + signObj.getJSONArray("lines").toList().stream().map(e -> (String) e).collect(Collectors.toList()) + ); + } + + SignDisplay.loadSignTexts(signTexts); + signsLoadSucceeded = true; + } catch (IOException e) { + Logging.SAVELOAD.error(e, "Unable to load signs.json, reset sign data instead."); + } + } else { + Logging.SAVELOAD.debug("signs.json not found, reset sign data instead."); + } + + if (!signsLoadSucceeded) { + SignDisplay.resetSignTexts(); + } + } + + private static final Pattern OLD_TORCH_TILE_REGEX = Pattern.compile("TORCH ([\\w ]+)"); + + public static void loadTile(short[] tiles, short[] data, int idx, String tileName, String tileData) { + Matcher matcher; + if ((matcher = OLD_TORCH_TILE_REGEX.matcher(tileName.toUpperCase())).matches()) { + tiles[idx] = 57; // ID of TORCH tile + data[idx] = Tiles.get(matcher.group(1)).id; + } else { + tiles[idx] = Tiles.get(tileName).id; + data[idx] = Short.parseShort(tileData); + } } public void loadPlayer(String filename, Player player) { @@ -721,6 +800,7 @@ public void loadPlayer(String filename, Player player) { loadFromFile(location + filename + extension); loadPlayer(player, data); } + public void loadPlayer(Player player, List origData) { List data = new ArrayList<>(origData); player.x = Integer.parseInt(data.remove(0)); @@ -735,12 +815,11 @@ public void loadPlayer(Player player, List origData) { player.armor = Integer.parseInt(data.remove(0)); if (worldVer.compareTo(new Version("2.0.5-dev5")) >= 0 || player.armor > 0 || worldVer.compareTo(new Version("2.0.5-dev4")) == 0 && data.size() > 5) { - if(worldVer.compareTo(new Version("2.0.4-dev7")) < 0) { + if (worldVer.compareTo(new Version("2.0.4-dev7")) < 0) { // Reverse order b/c we are taking from the end - player.curArmor = (ArmorItem) Items.get(data.remove(data.size()-1)); - player.armorDamageBuffer = Integer.parseInt(data.remove(data.size()-1)); - } - else { + player.curArmor = (ArmorItem) Items.get(data.remove(data.size() - 1)); + player.armorDamageBuffer = Integer.parseInt(data.remove(data.size() - 1)); + } else { player.armorDamageBuffer = Integer.parseInt(data.remove(0)); player.curArmor = (ArmorItem) Items.get(data.remove(0), true); } @@ -750,13 +829,14 @@ public void loadPlayer(Player player, List origData) { if (worldVer.compareTo(new Version("2.0.4-dev7")) < 0) { int arrowCount = Integer.parseInt(data.remove(0)); if (worldVer.compareTo(new Version("2.0.1-dev1")) < 0) - player.getInventory().add(Items.get("arrow"), arrowCount); + player.getInventory().add(Items.get("arrow"), arrowCount).forEach(deathChest.getInventory()::add); } Game.currentLevel = Integer.parseInt(data.remove(0)); Level level = World.levels[Game.currentLevel]; - if (!player.isRemoved()) player.remove(); // Removes the user player from the level, in case they would be added twice. - if(level != null) + if (!player.isRemoved()) + player.remove(); // Removes the user player from the level, in case they would be added twice. + if (level != null) level.add(player); else Logging.SAVELOAD.trace("Game level to add player {} to is null.", player); @@ -794,8 +874,7 @@ public void loadPlayer(Player player, List origData) { for (int i = 0; i < 3; i++) colors[i] = Integer.parseInt(String.valueOf(color.charAt(i))); player.shirtColor = Color.get(1, colors[0] * 51, colors[1] * 51, colors[2] * 51); - } - else + } else player.shirtColor = Integer.parseInt(data.remove(0)); // Just delete the slot reserved for loading legacy skins. @@ -814,6 +893,20 @@ public void loadPlayer(Player player, List origData) { costs[j] = costsJson.getString(j); } + // Skipping removed vanilla recipes + if (worldVer.compareTo(new Version("2.2.0-dev6")) <= 0) { + // Iron Ore * 4 + Coal * 1 => Iron * 1 + if (key.equalsIgnoreCase("iron_1") && + costs.length == 2 && costs[0].equalsIgnoreCase("iron Ore_4") && + costs[1].equalsIgnoreCase("coal_1")) + continue; + // Gold Ore * 4 + Coal * 1 => Gold * 1 + if (key.equalsIgnoreCase("gold_1") && + costs.length == 2 && costs[0].equalsIgnoreCase("gold Ore_4") && + costs[1].equalsIgnoreCase("coal_1")) + continue; + } + recipes.add(new Recipe(key, costs)); } @@ -865,6 +958,7 @@ public void loadInventory(String filename, Inventory inventory) { loadFromFile(location + filename + extension); loadInventory(inventory, data); } + public void loadInventory(Inventory inventory, List data) { inventory.clearInv(); @@ -901,11 +995,7 @@ public void loadInventory(Inventory inventory, List data) { } private void loadItem(Inventory inventory, Item item) { - int total = 1; - if (item instanceof StackableItem) total = ((StackableItem) item).count; - int loaded = inventory.add(item); - - if (loaded < total) { + if (inventory.add(item) != null) { deathChest.getInventory().add(item.copy()); } } @@ -962,7 +1052,7 @@ public static Entity loadEntity(String entityData, Version worldVer, boolean isL int awID = Integer.parseInt(info.get(2)); Entity sparkOwner = Network.getEntity(awID); if (sparkOwner instanceof AirWizard) - newEntity = new Spark((AirWizard)sparkOwner, x, y); + newEntity = new Spark((AirWizard) sparkOwner, x, y); else { Logging.SAVELOAD.error("Failed to load Spark; owner id doesn't point to a correct entity"); return null; @@ -972,22 +1062,23 @@ public static Entity loadEntity(String entityData, Version worldVer, boolean isL if (!Crafter.names.contains(entityName)) { // Entity missing debugging try { Class.forName("minicraft.entity.mob." + entityName); - } catch (ClassNotFoundException ignored) {} + } catch (ClassNotFoundException ignored) { + } } // Check for level of AirWizard - if(entityName.equals("AirWizard")) { + if (entityName.equals("AirWizard")) { mobLvl = Integer.parseInt(stuff[3]); } - newEntity = getEntity(entityName.substring(entityName.lastIndexOf(".")+1), mobLvl); + newEntity = getEntity(entityName.substring(entityName.lastIndexOf(".") + 1), mobLvl); } if (entityName.equals("FireSpark") && !isLocalSave) { int obID = Integer.parseInt(info.get(2)); Entity sparkOwner = Network.getEntity(obID); if (sparkOwner instanceof ObsidianKnight) - newEntity = new FireSpark((ObsidianKnight)sparkOwner, x, y); + newEntity = new FireSpark((ObsidianKnight) sparkOwner, x, y); else { Logging.SAVELOAD.error("Failed to load FireSpark; owner id doesn't point to a correct entity"); return null; @@ -998,7 +1089,7 @@ public static Entity loadEntity(String entityData, Version worldVer, boolean isL return null; if (newEntity instanceof Mob) { // This is structured the same way as in Save.java. - Mob mob = (Mob)newEntity; + Mob mob = (Mob) newEntity; mob.health = Integer.parseInt(info.get(2)); Class c = null; @@ -1010,7 +1101,7 @@ public static Entity loadEntity(String entityData, Version worldVer, boolean isL if (EnemyMob.class.isAssignableFrom(c)) { EnemyMob enemyMob = ((EnemyMob) mob); - enemyMob.lvl = Integer.parseInt(info.get(info.size()-2)); + enemyMob.lvl = Integer.parseInt(info.get(info.size() - 2)); if (enemyMob.lvl == 0) { Logging.SAVELOAD.debug("Level 0 mob: " + entityName); @@ -1034,10 +1125,10 @@ public static Entity loadEntity(String entityData, Version worldVer, boolean isL newEntity = mob; } else if (newEntity instanceof Chest) { - Chest chest = (Chest)newEntity; + Chest chest = (Chest) newEntity; boolean isDeathChest = chest instanceof DeathChest; boolean isDungeonChest = chest instanceof DungeonChest; - List chestInfo = info.subList(2, info.size()-1); + List chestInfo = info.subList(2, info.size() - 1); int endIdx = chestInfo.size() - (isDeathChest || isDungeonChest ? 1 : 0); for (int idx = 0; idx < endIdx; idx++) { @@ -1051,10 +1142,11 @@ public static Entity loadEntity(String entityData, Version worldVer, boolean isL } if (isDeathChest) { - ((DeathChest)chest).time = Integer.parseInt(chestInfo.get(chestInfo.size()-1)); + ((DeathChest) chest).time = Integer.parseInt(chestInfo.get(chestInfo.size() - 1)); } else if (isDungeonChest) { - ((DungeonChest)chest).setLocked(Boolean.parseBoolean(chestInfo.get(chestInfo.size()-1))); - if (((DungeonChest)chest).isLocked()) World.levels[Integer.parseInt(info.get(info.size()-1))].chestCount++; + ((DungeonChest) chest).setLocked(Boolean.parseBoolean(chestInfo.get(chestInfo.size() - 1))); + if (((DungeonChest) chest).isLocked()) + World.levels[Integer.parseInt(info.get(info.size() - 1))].chestCount++; } newEntity = chest; @@ -1072,7 +1164,7 @@ public static Entity loadEntity(String entityData, Version worldVer, boolean isL if (!isLocalSave) { if (newEntity instanceof Arrow) { int ownerID = Integer.parseInt(info.get(2)); - Mob m = (Mob)Network.getEntity(ownerID); + Mob m = (Mob) Network.getEntity(ownerID); if (m != null) { Direction dir = Direction.values[Integer.parseInt(info.get(3))]; int dmg = Integer.parseInt(info.get(5)); @@ -1100,7 +1192,7 @@ public static Entity loadEntity(String entityData, Version worldVer, boolean isL if (newEntity instanceof ItemEntity && eid == -1) Logging.SAVELOAD.warn("Item entity was loaded with no eid"); - int curLevel = Integer.parseInt(info.get(info.size()-1)); + int curLevel = Integer.parseInt(info.get(info.size() - 1)); if (World.levels[curLevel] != null) { World.levels[curLevel].add(newEntity, x, y); } @@ -1111,41 +1203,73 @@ public static Entity loadEntity(String entityData, Version worldVer, boolean isL @Nullable private static Entity getEntity(String string, int mobLevel) { switch (string) { - case "Player": return null; - case "RemotePlayer": return null; - case "Cow": return new Cow(); - case "Sheep": return new Sheep(); - case "Pig": return new Pig(); - case "Zombie": return new Zombie(mobLevel); - case "Slime": return new Slime(mobLevel); - case "Creeper": return new Creeper(mobLevel); - case "Skeleton": return new Skeleton(mobLevel); - case "Knight": return new Knight(mobLevel); - case "Snake": return new Snake(mobLevel); + case "Player": + return null; + case "RemotePlayer": + return null; + case "Cow": + return new Cow(); + case "Sheep": + return new Sheep(); + case "Pig": + return new Pig(); + case "Zombie": + return new Zombie(mobLevel); + case "Slime": + return new Slime(mobLevel); + case "Creeper": + return new Creeper(mobLevel); + case "Skeleton": + return new Skeleton(mobLevel); + case "Knight": + return new Knight(mobLevel); + case "Snake": + return new Snake(mobLevel); case "AirWizard": if (mobLevel > 1) return null; return new AirWizard(); - case "Spawner": return new Spawner(new Zombie(1)); - case "Workbench": return new Crafter(Crafter.Type.Workbench); - case "Chest": return new Chest(); - case "DeathChest": return new DeathChest(); - case "DungeonChest": return new DungeonChest(false); - case "Anvil": return new Crafter(Crafter.Type.Anvil); - case "Enchanter": return new Crafter(Crafter.Type.Enchanter); - case "Loom": return new Crafter(Crafter.Type.Loom); - case "Furnace": return new Crafter(Crafter.Type.Furnace); - case "Oven": return new Crafter(Crafter.Type.Oven); - case "Bed": return new Bed(); - case "Tnt": return new Tnt(); - case "Lantern": return new Lantern(Lantern.Type.NORM); - case "Arrow": return new Arrow(new Skeleton(0), 0, 0, Direction.NONE, 0); - case "ItemEntity": return new ItemEntity(Items.get("unknown"), 0, 0); - case "FireParticle": return new FireParticle(0, 0); - case "SmashParticle": return new SmashParticle(0, 0); - case "TextParticle": return new TextParticle("", 0, 0, 0); - case "KnightStatue": return new KnightStatue(0); - case "ObsidianKnight": return new ObsidianKnight(0); - default : Logging.SAVELOAD.error("LOAD ERROR: Unknown or outdated entity requested: " + string); + case "Spawner": + return new Spawner(new Zombie(1)); + case "Workbench": + return new Crafter(Crafter.Type.Workbench); + case "Chest": + return new Chest(); + case "DeathChest": + return new DeathChest(); + case "DungeonChest": + return new DungeonChest(null); + case "Anvil": + return new Crafter(Crafter.Type.Anvil); + case "Enchanter": + return new Crafter(Crafter.Type.Enchanter); + case "Loom": + return new Crafter(Crafter.Type.Loom); + case "Furnace": + return new Crafter(Crafter.Type.Furnace); + case "Oven": + return new Crafter(Crafter.Type.Oven); + case "Bed": + return new Bed(); + case "Tnt": + return new Tnt(); + case "Lantern": + return new Lantern(Lantern.Type.NORM); + case "Arrow": + return new Arrow(new Skeleton(0), 0, 0, Direction.NONE, 0); + case "ItemEntity": + return new ItemEntity(Items.get("unknown"), 0, 0); + case "FireParticle": + return new FireParticle(0, 0); + case "SmashParticle": + return new SmashParticle(0, 0); + case "TextParticle": + return new TextParticle("", 0, 0, 0); + case "KnightStatue": + return new KnightStatue(0); + case "ObsidianKnight": + return new ObsidianKnight(0); + default: + Logging.SAVELOAD.error("LOAD ERROR: Unknown or outdated entity requested: " + string); return null; } } diff --git a/src/client/java/minicraft/saveload/Save.java b/src/client/java/minicraft/saveload/Save.java index a5096b15e..43d827550 100644 --- a/src/client/java/minicraft/saveload/Save.java +++ b/src/client/java/minicraft/saveload/Save.java @@ -26,6 +26,7 @@ import minicraft.entity.mob.Sheep; import minicraft.entity.particle.Particle; import minicraft.entity.particle.TextParticle; +import minicraft.gfx.Point; import minicraft.item.Inventory; import minicraft.item.Item; import minicraft.item.PotionType; @@ -36,6 +37,7 @@ import minicraft.screen.MultiplayerDisplay; import minicraft.screen.QuestsDisplay; import minicraft.screen.ResourcePackDisplay; +import minicraft.screen.SignDisplay; import minicraft.screen.SkinDisplay; import minicraft.screen.TutorialDisplayHandler; import minicraft.screen.WorldSelectDisplay; @@ -50,6 +52,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; +import java.util.Map; public class Save { @@ -96,7 +99,7 @@ private Save(File worldFolder) { * @param worldname The name of the world. */ public Save(String worldname) { - this(new File(Game.gameDir+"/saves/" + worldname + "/")); + this(new File(Game.gameDir + "/saves/" + worldname + "/")); writeGame("Game"); writeWorld("Level"); @@ -111,9 +114,11 @@ public Save(String worldname) { Updater.saving = false; } - /** This will save the settings in the settings menu. */ + /** + * This will save the settings in the settings menu. + */ public Save() { - this(new File(Game.gameDir+"/")); + this(new File(Game.gameDir + "/")); Logging.SAVELOAD.debug("Writing preferences and unlocks..."); writePrefs(); writeUnlocks(); @@ -121,7 +126,7 @@ public Save() { public Save(Player player, boolean writePlayer) { // This is simply for access to writeToFile. - this(new File(Game.gameDir+"/saves/"+WorldSelectDisplay.getWorldName() + "/")); + this(new File(Game.gameDir + "/saves/" + WorldSelectDisplay.getWorldName() + "/")); if (writePlayer) { writePlayer("Player", player); writeInventory("Inventory", player); @@ -144,7 +149,7 @@ public void writeToFile(String filename, List savedata) { data.clear(); LoadingDisplay.progress(7); - if(LoadingDisplay.getPercentage() > 100) { + if (LoadingDisplay.getPercentage() > 100) { LoadingDisplay.setPercentage(100); } @@ -201,6 +206,7 @@ private void writePrefs() { json.put("keymap", new JSONArray(Game.input.getKeyPrefs())); json.put("resourcePacks", new JSONArray(ResourcePackDisplay.getLoadedPacks())); json.put("showquests", String.valueOf(Settings.get("showquests"))); + json.put("hwa", String.valueOf(Settings.get("hwa"))); // Save json try { @@ -257,17 +263,36 @@ private void writeWorld(String filename) { writeToFile(location + filename + l + "data" + extension, data); } - JSONObject fileObj = new JSONObject(); - fileObj.put("Version", Game.VERSION.toString()); - TutorialDisplayHandler.save(fileObj); - AdvancementElement.saveRecipeUnlockingElements(fileObj); - QuestsDisplay.save(fileObj); + { // Advancements + JSONObject fileObj = new JSONObject(); + fileObj.put("Version", Game.VERSION.toString()); + TutorialDisplayHandler.save(fileObj); + AdvancementElement.saveRecipeUnlockingElements(fileObj); + QuestsDisplay.save(fileObj); + try { + writeJSONToFile(location + "advancements.json", fileObj.toString(4)); + } catch (IOException e) { + e.printStackTrace(); + Logging.SAVELOAD.error("Unable to write advancements.json."); + } + } - try { - writeJSONToFile(location + "advancements.json", fileObj.toString(4)); - } catch (IOException e) { - e.printStackTrace(); - Logging.SAVELOAD.error("Unable to write advancements.json."); + { // Sign Data + JSONObject fileObj = new JSONObject(); + fileObj.put("Version", Game.VERSION.toString()); + JSONArray dataObj = new JSONArray(); + SignDisplay.getSignTexts().forEach((key, value) -> dataObj.put(new JSONObject() + .put("level", key.getKey()) + .put("x", key.getValue().x) + .put("y", key.getValue().y) + .put("lines", value))); + fileObj.put("signs", dataObj); + try { + writeJSONToFile(location + "signs.json", fileObj.toString(4)); + } catch (IOException e) { + e.printStackTrace(); + Logging.SAVELOAD.error("Unable to write signs.json."); + } } } @@ -294,7 +319,7 @@ public static void writePlayer(Player player, List data) { StringBuilder subdata = new StringBuilder("PotionEffects["); - for (java.util.Map.Entry potion: player.potioneffects.entrySet()) + for (java.util.Map.Entry potion : player.potioneffects.entrySet()) subdata.append(potion.getKey()).append(";").append(potion.getValue()).append(":"); if (player.potioneffects.size() > 0) @@ -317,6 +342,7 @@ private void writeInventory(String filename, Player player) { writeInventory(player, data); writeToFile(location + filename + extension, data); } + public static void writeInventory(Player player, List data) { data.clear(); if (player.activeItem != null) { @@ -333,7 +359,7 @@ public static void writeInventory(Player player, List data) { private void writeEntities(String filename) { LoadingDisplay.setMessage("minicraft.displays.loading.message.entities"); for (int l = 0; l < World.levels.length; l++) { - for (Entity e: World.levels[l].getEntitiesToSave()) { + for (Entity e : World.levels[l].getEntitiesToSave()) { String saved = writeEntity(e, true); if (saved.length() > 0) data.add(saved); @@ -345,19 +371,19 @@ private void writeEntities(String filename) { public static String writeEntity(Entity e, boolean isLocalSave) { String name = e.getClass().getName(); - name = name.substring(name.lastIndexOf('.')+1); + name = name.substring(name.lastIndexOf('.') + 1); StringBuilder extradata = new StringBuilder(); // Don't even write ItemEntities or particle effects; Spark... will probably is saved, eventually; it presents an unfair cheat to remove the sparks by reloading the Game. - if (isLocalSave && (e instanceof ItemEntity || e instanceof Arrow || e instanceof Spark || e instanceof FireSpark || e instanceof Particle)) // Write these only when sending a world, not writing it. (RemotePlayers are saved separately, when their info is received.) + if (isLocalSave && (e instanceof ItemEntity || e instanceof Arrow || e instanceof Spark || e instanceof FireSpark || e instanceof Particle)) // Write these only when sending a world, not writing it. (RemotePlayers are saved separately, when their info is received.) return ""; if (!isLocalSave) extradata.append(":").append(e.eid); if (e instanceof Mob) { - Mob m = (Mob)e; + Mob m = (Mob) e; extradata.append(":").append(m.health); if (e instanceof EnemyMob) extradata.append(":").append(((EnemyMob) m).lvl); @@ -366,21 +392,21 @@ else if (e instanceof Sheep) } if (e instanceof Chest) { - Chest chest = (Chest)e; + Chest chest = (Chest) e; - for(int ii = 0; ii < chest.getInventory().invSize(); ii++) { + for (int ii = 0; ii < chest.getInventory().invSize(); ii++) { Item item = chest.getInventory().get(ii); extradata.append(":").append(item.getData()); } - if(chest instanceof DeathChest) extradata.append(":").append(((DeathChest) chest).time); - if(chest instanceof DungeonChest) extradata.append(":").append(((DungeonChest) chest).isLocked()); + if (chest instanceof DeathChest) extradata.append(":").append(((DeathChest) chest).time); + if (chest instanceof DungeonChest) extradata.append(":").append(((DungeonChest) chest).isLocked()); } if (e instanceof Spawner) { - Spawner egg = (Spawner)e; + Spawner egg = (Spawner) e; String mobname = egg.mob.getClass().getName(); - mobname = mobname.substring(mobname.lastIndexOf(".")+1); + mobname = mobname.substring(mobname.lastIndexOf(".") + 1); extradata.append(":").append(mobname).append(":").append(egg.mob instanceof EnemyMob ? ((EnemyMob) egg.mob).lvl : 1); } @@ -389,7 +415,7 @@ else if (e instanceof Sheep) } if (e instanceof Crafter) { - name = ((Crafter)e).type.name(); + name = ((Crafter) e).type.name(); } if (e instanceof KnightStatue) { diff --git a/src/client/java/minicraft/saveload/Version.java b/src/client/java/minicraft/saveload/Version.java index 247a8318c..4e10f2d8e 100644 --- a/src/client/java/minicraft/saveload/Version.java +++ b/src/client/java/minicraft/saveload/Version.java @@ -7,7 +7,10 @@ public class Version implements Comparable { private int make, major, minor, dev; private boolean valid = true; - public Version(String version) { this(version, true); } + public Version(String version) { + this(version, true); + } + private Version(String version, boolean printError) { String[] nums = version.split("\\."); try { @@ -39,8 +42,13 @@ private Version(String version, boolean printError) { } } - public boolean isValid() { return valid; } - public static boolean isValid(String version) { return new Version(version, false).isValid(); } + public boolean isValid() { + return valid; + } + + public static boolean isValid(String version) { + return new Version(version, false).isValid(); + } /** * The returned value of this method (-1, 0, or 1) is determined by whether this object is less than, equal to, or greater than the specified object, ov. @@ -56,7 +64,7 @@ public int compareTo(@NotNull Version ov) { * (this.compareTo(new Version("1.0.0") < 0 is the same as this < 1.0.0) * @param ov The version to compare to. * @param ignoreDev If we should ignore dev versions in this comparison. - */ + */ public int compareTo(@NotNull Version ov, boolean ignoreDev) { if (make != ov.make) return Integer.compare(make, ov.make); if (major != ov.major) return Integer.compare(major, ov.major); @@ -73,7 +81,11 @@ public int compareTo(@NotNull Version ov, boolean ignoreDev) { } @Override - public String toString() { return make + "." + major + "." + minor + (dev == 0 ? "" : "-dev" + dev); } + public String toString() { + return make + "." + major + "." + minor + (dev == 0 ? "" : "-dev" + dev); + } - public int[] toArray() { return new int[]{ make, major, minor, dev }; } + public int[] toArray() { + return new int[] { make, major, minor, dev }; + } } diff --git a/src/client/java/minicraft/screen/AchievementsDisplay.java b/src/client/java/minicraft/screen/AchievementsDisplay.java index aceab7e75..6703280f3 100644 --- a/src/client/java/minicraft/screen/AchievementsDisplay.java +++ b/src/client/java/minicraft/screen/AchievementsDisplay.java @@ -30,200 +30,201 @@ public class AchievementsDisplay extends Display { - private static final HashMap achievements = new HashMap<>(); - - private static Achievement selectedAchievement; - private static int achievementScore; - - static { - // Get achievements from a json file stored in resources. Relative to project root. - try (InputStream stream = Game.class.getResourceAsStream("/resources/achievements.json")) { - if (stream != null) { - BufferedReader reader = new BufferedReader(new InputStreamReader(stream)); - - // Read lines and combine into a string. - String achievementsJson = reader.lines().collect(Collectors.joining("\n")); - - // Load json. - JSONArray json = new JSONArray(achievementsJson); - for (Object object : json) { - JSONObject obj = (JSONObject) object; - - // Create an achievement with the data. - Achievement a = new Achievement( - Localization.getLocalized(obj.getString("id")), - obj.getString("desc"), - obj.getInt("score") - ); - - achievements.put(obj.getString("id"), a); - } - } else { - Logging.ACHIEVEMENT.error("Could not find achievements json."); - } - } catch (IOException ex) { - Logging.ACHIEVEMENT.error("Could not read achievements from json file."); - ex.printStackTrace(); - } catch (JSONException e) { - Logging.ACHIEVEMENT.error("Achievements json contains invalid json."); - } - } - - public AchievementsDisplay() { - super(true, true, - new Menu.Builder(false, 2, RelPos.CENTER, getAchievemensAsEntries()).setSize(48, 48).createMenu(), - new Menu.Builder(false, 2, RelPos.BOTTOM, new StringEntry("")).setSize(200, 32).setPositioning(new Point(Screen.w / 2, Screen.h / 2 + 32), RelPos.BOTTOM).createMenu()); - } - - @Override - public void init(@Nullable Display parent) { - super.init(parent); - if (achievements.isEmpty()) { - Game.setDisplay(new TitleDisplay()); - Logging.ACHIEVEMENT.error("Could not open achievements menu because no achievements could be found."); - return; - } - - ListEntry curEntry = menus[0].getCurEntry(); - if (curEntry instanceof SelectEntry) { - selectedAchievement = achievements.get(((SelectEntry) curEntry).getText()); - } - } - - @Override - public void onExit() { - // Play confirm sound. - Sound.play("confirm"); - new Save(); - } - - @Override + private static final HashMap achievements = new HashMap<>(); + + private static Achievement selectedAchievement; + private static int achievementScore; + + static { + // Get achievements from a json file stored in resources. Relative to project root. + try (InputStream stream = Game.class.getResourceAsStream("/resources/achievements.json")) { + if (stream != null) { + BufferedReader reader = new BufferedReader(new InputStreamReader(stream)); + + // Read lines and combine into a string. + String achievementsJson = reader.lines().collect(Collectors.joining("\n")); + + // Load json. + JSONArray json = new JSONArray(achievementsJson); + for (Object object : json) { + JSONObject obj = (JSONObject) object; + + // Create an achievement with the data. + Achievement a = new Achievement( + Localization.getLocalized(obj.getString("id")), + obj.getString("desc"), + obj.getInt("score") + ); + + achievements.put(obj.getString("id"), a); + } + } else { + Logging.ACHIEVEMENT.error("Could not find achievements json."); + } + } catch (IOException ex) { + Logging.ACHIEVEMENT.error("Could not read achievements from json file."); + ex.printStackTrace(); + } catch (JSONException e) { + Logging.ACHIEVEMENT.error("Achievements json contains invalid json."); + } + } + + public AchievementsDisplay() { + super(true, true, + new Menu.Builder(false, 2, RelPos.CENTER, getAchievemensAsEntries()).setSize(48, 48).createMenu(), + new Menu.Builder(false, 2, RelPos.BOTTOM, new StringEntry("")).setSize(200, 32).setPositioning(new Point(Screen.w / 2, Screen.h / 2 + 32), RelPos.BOTTOM).createMenu()); + } + + @Override + public void init(@Nullable Display parent) { + super.init(parent); + if (achievements.isEmpty()) { + Game.setDisplay(new TitleDisplay()); + Logging.ACHIEVEMENT.error("Could not open achievements menu because no achievements could be found."); + return; + } + + ListEntry curEntry = menus[0].getCurEntry(); + if (curEntry instanceof SelectEntry) { + selectedAchievement = achievements.get(((SelectEntry) curEntry).getText()); + } + } + + @Override + public void onExit() { + // Play confirm sound. + Sound.play("confirm"); + new Save(); + } + + @Override public void tick(InputHandler input) { super.tick(input); - ListEntry curEntry = menus[0].getCurEntry(); - if (curEntry instanceof SelectEntry) { - selectedAchievement = achievements.get(((SelectEntry) curEntry).getText()); - } - } - - @Override - public void render(Screen screen) { - super.render(screen); - - // Title. - Font.drawCentered(Localization.getLocalized("minicraft.displays.achievements"), screen, 8, Color.WHITE); - - // Achievement score. - Font.drawCentered(Localization.getLocalized("minicraft.displays.achievements.display.score", achievementScore), screen, 32, Color.GRAY); - - if (selectedAchievement != null) { - - // Render Achievement Info. - if (selectedAchievement.getUnlocked()) { - Font.drawCentered(Localization.getLocalized("minicraft.displays.achievements.display.achieved"), screen, 48, Color.GREEN); - } else { - Font.drawCentered(Localization.getLocalized("minicraft.displays.achievements.display.not_achieved"), screen, 48, Color.RED); - } - - // Achievement description. - menus[1].setEntries(StringEntry.useLines(Font.getLines(Localization.getLocalized(selectedAchievement.description), menus[1].getBounds().getSize().width, menus[1].getBounds().getSize().height, 2))); - } - - // Help text. - Font.drawCentered(Localization.getLocalized("minicraft.displays.achievements.display.help", Game.input.getMapping("cursor-down"), Game.input.getMapping("cursor-up")), screen, Screen.h - 8, Color.DARK_GRAY); - } - - /** - * Use this to lock or unlock an achievement. - * @param id Achievement ID. - * @param unlocked Whether this achievement should be locked or unlocked. - * @return True if setting the achievement was successful. - */ - public static boolean setAchievement(String id, boolean unlocked) { - return setAchievement(id, unlocked, true, false); - } - public static boolean setAchievement(boolean allowCreative, String id, boolean unlocked) { return setAchievement(id, unlocked, true, allowCreative); } + ListEntry curEntry = menus[0].getCurEntry(); + if (curEntry instanceof SelectEntry) { + selectedAchievement = achievements.get(((SelectEntry) curEntry).getText()); + } + } + + @Override + public void render(Screen screen) { + super.render(screen); + + // Title. + Font.drawCentered(Localization.getLocalized("minicraft.displays.achievements"), screen, 8, Color.WHITE); + + // Achievement score. + Font.drawCentered(Localization.getLocalized("minicraft.displays.achievements.display.score", achievementScore), screen, 32, Color.GRAY); + + if (selectedAchievement != null) { + + // Render Achievement Info. + if (selectedAchievement.getUnlocked()) { + Font.drawCentered(Localization.getLocalized("minicraft.displays.achievements.display.achieved"), screen, 48, Color.GREEN); + } else { + Font.drawCentered(Localization.getLocalized("minicraft.displays.achievements.display.not_achieved"), screen, 48, Color.RED); + } + + // Achievement description. + menus[1].setEntries(StringEntry.useLines(Font.getLines(Localization.getLocalized(selectedAchievement.description), menus[1].getBounds().getSize().width, menus[1].getBounds().getSize().height, 2))); + } + + // Help text. + Font.drawCentered(Localization.getLocalized("minicraft.displays.achievements.display.help", Game.input.getMapping("cursor-down"), Game.input.getMapping("cursor-up")), screen, Screen.h - 8, Color.DARK_GRAY); + } + + /** + * Use this to lock or unlock an achievement. + * @param id Achievement ID. + * @param unlocked Whether this achievement should be locked or unlocked. + * @return True if setting the achievement was successful. + */ + public static boolean setAchievement(String id, boolean unlocked) { + return setAchievement(id, unlocked, true, false); + } + + public static boolean setAchievement(boolean allowCreative, String id, boolean unlocked) { + return setAchievement(id, unlocked, true, allowCreative); + } private static boolean setAchievement(String id, boolean unlocked, boolean save, boolean allowCreative) { - Achievement a = achievements.get(id); + Achievement a = achievements.get(id); // Return if it is in creative mode if (!allowCreative && Game.isMode("minicraft.settings.mode.creative")) return false; - // Return if we didn't find any achievements. - if (a == null) return false; - - if (a.getUnlocked() && unlocked) return false; // Return if it is already unlocked. - if (!a.getUnlocked() && !unlocked) return false; // Return if it is already locked. - - // Make the achievement unlocked in memory. - a.setUnlocked(unlocked); - Logging.ACHIEVEMENT.debug("Updating data of achievement with id: {}.", id); - - // Add or subtract from score - if (unlocked) { - achievementScore += a.score; - - // Tells the player that they got an achievement. - Game.notifications.add(Localization.getLocalized("minicraft.notification.achievement_unlocked", Localization.getLocalized(id))); - } - else - achievementScore -= a.score; - - // Save the new list of achievements stored in memory. - if (save) new Save(); - - return true; - } - - /** - * Gets an array of all the unlocked achievements. - * @return A string array with each unlocked achievement's id in it. - */ - public static String[] getUnlockedAchievements() { - ArrayList strings = new ArrayList<>(); - - for (String id : achievements.keySet()) { - if (achievements.get(id).getUnlocked()) { - strings.add(id); - } - } - - return strings.toArray(new String[0]); - } - - public static List getAchievemensAsEntries() { - List l = new ArrayList<>(); - for (String id : achievements.keySet()) { - // Add entry to list. - l.add(new SelectEntry(id, null, true) - { - /** - * Change the color of the selection. - */ - @Override - public int getColor(boolean isSelected) { - if (achievements.get(id).getUnlocked()) { - return Color.GREEN; - } else { - return Color.WHITE; - } - } - }); - } - - return l; - } - - /** - * Unlocks a list of achievements. - * @param unlockedAchievements An array of all the achievements we want to load, ids. - */ - public static void unlockAchievements(JSONArray unlockedAchievements) { - for (Object id : unlockedAchievements.toList()) { - if (!setAchievement(id.toString(), true, false, false)) { - Logging.ACHIEVEMENT.warn("Could not load unlocked achievement with name {}.", id.toString()); - } - } - } + // Return if we didn't find any achievements. + if (a == null) return false; + + if (a.getUnlocked() && unlocked) return false; // Return if it is already unlocked. + if (!a.getUnlocked() && !unlocked) return false; // Return if it is already locked. + + // Make the achievement unlocked in memory. + a.setUnlocked(unlocked); + Logging.ACHIEVEMENT.debug("Updating data of achievement with id: {}.", id); + + // Add or subtract from score + if (unlocked) { + achievementScore += a.score; + + // Tells the player that they got an achievement. + Game.notifications.add(Localization.getLocalized("minicraft.notification.achievement_unlocked", Localization.getLocalized(id))); + } else + achievementScore -= a.score; + + // Save the new list of achievements stored in memory. + if (save) new Save(); + + return true; + } + + /** + * Gets an array of all the unlocked achievements. + * @return A string array with each unlocked achievement's id in it. + */ + public static String[] getUnlockedAchievements() { + ArrayList strings = new ArrayList<>(); + + for (String id : achievements.keySet()) { + if (achievements.get(id).getUnlocked()) { + strings.add(id); + } + } + + return strings.toArray(new String[0]); + } + + public static List getAchievemensAsEntries() { + List l = new ArrayList<>(); + for (String id : achievements.keySet()) { + // Add entry to list. + l.add(new SelectEntry(id, null, true) { + /** + * Change the color of the selection. + */ + @Override + public int getColor(boolean isSelected) { + if (achievements.get(id).getUnlocked()) { + return Color.GREEN; + } else { + return Color.WHITE; + } + } + }); + } + + return l; + } + + /** + * Unlocks a list of achievements. + * @param unlockedAchievements An array of all the achievements we want to load, ids. + */ + public static void unlockAchievements(JSONArray unlockedAchievements) { + for (Object id : unlockedAchievements.toList()) { + if (!setAchievement(id.toString(), true, false, false)) { + Logging.ACHIEVEMENT.warn("Could not load unlocked achievement with name {}.", id.toString()); + } + } + } } diff --git a/src/client/java/minicraft/screen/BookDisplay.java b/src/client/java/minicraft/screen/BookDisplay.java index 0b462add1..d46684d82 100644 --- a/src/client/java/minicraft/screen/BookDisplay.java +++ b/src/client/java/minicraft/screen/BookDisplay.java @@ -18,7 +18,7 @@ public class BookDisplay extends Display { private static final String defaultBook = "This book has no text."; private static final int spacing = 3; - private static final int minX = 15, maxX = 15+8 * 32, minY = 8*5, maxY = 8*5 + 8*16; + private static final int minX = 15, maxX = 15 + 8 * 32, minY = 8 * 5, maxY = 8 * 5 + (8 << 4); // First array is page and second is line. private String[][] lines; @@ -28,9 +28,12 @@ public class BookDisplay extends Display { private final boolean showPageCount; private final int pageOffset; - public BookDisplay(String book) { this(book, false); } + public BookDisplay(String book) { + this(book, false); + } + public BookDisplay(String book, boolean hasTitle) {// this(book, hasTitle, !hasTitle); } - //public BookDisplay(String book, boolean hasTitle, boolean hideCountIfOnePage) { + //public BookDisplay(String book, boolean hasTitle, boolean hideCountIfOnePage) { page = 0; if (book == null) { @@ -42,11 +45,11 @@ public class BookDisplay extends Display { ArrayList pages = new ArrayList<>(); String[] splitContents = book.split("\0"); - for (String content: splitContents) { - String[] remainder = {content}; - while (remainder[remainder.length-1].length() > 0) { - remainder = Font.getLines(remainder[remainder.length-1], maxX-minX, maxY-minY, spacing, true); - pages.add(Arrays.copyOf(remainder, remainder.length-1)); // Removes the last element of remainder, which is the leftover. + for (String content : splitContents) { + String[] remainder = { content }; + while (remainder[remainder.length - 1].length() > 0) { + remainder = Font.getLines(remainder[remainder.length - 1], maxX - minX, maxY - minY, spacing, true); + pages.add(Arrays.copyOf(remainder, remainder.length - 1)); // Removes the last element of remainder, which is the leftover. } } @@ -58,31 +61,32 @@ public class BookDisplay extends Display { Menu.Builder builder = new Menu.Builder(true, spacing, RelPos.CENTER); Menu pageCount = builder // The small rect for the title - .setPositioning(new Point(Screen.w/2, 0), RelPos.BOTTOM) + .setPositioning(new Point(Screen.w / 2, 0), RelPos.BOTTOM) .setEntries(StringEntry.useLines(Color.BLACK, "Page", hasTitle ? "Title" : "1/" + lines.length)) .setSelection(1) .createMenu(); builder - .setPositioning(new Point(Screen.w/2, pageCount.getBounds().getBottom() + spacing), RelPos.BOTTOM) - .setSize(maxX-minX + MinicraftImage.boxWidth*2, maxY-minY + MinicraftImage.boxWidth*2) + .setPositioning(new Point(Screen.w / 2, pageCount.getBounds().getBottom() + spacing), RelPos.BOTTOM) + .setSize(maxX - minX + MinicraftImage.boxWidth * 2, maxY - minY + MinicraftImage.boxWidth * 2) .setShouldRender(false); menus = new Menu[lines.length + pageOffset]; if (showPageCount) menus[0] = pageCount; for (int i = 0; i < lines.length; i++) { - menus[i+pageOffset] = builder.setEntries(StringEntry.useLines(Color.WHITE, lines[i])).createMenu(); + menus[i + pageOffset] = builder.setEntries(StringEntry.useLines(Color.WHITE, lines[i])).createMenu(); } - menus[page+pageOffset].shouldRender = true; + menus[page + pageOffset].shouldRender = true; } private void turnPage(int dir) { if (page + dir >= 0 && page + dir < lines.length) { - menus[page+pageOffset].shouldRender = false; + menus[page + pageOffset].shouldRender = false; page += dir; - if (showPageCount) menus[0].updateSelectedEntry(new StringEntry(page == 0 && hasTitle ? "Title" : (page + 1) + "/" + lines.length, Color.BLACK)); - menus[page+pageOffset].shouldRender = true; + if (showPageCount) + menus[0].updateSelectedEntry(new StringEntry(page == 0 && hasTitle ? "Title" : (page + 1) + "/" + lines.length, Color.BLACK)); + menus[page + pageOffset].shouldRender = true; } } diff --git a/src/client/java/minicraft/screen/ContainerDisplay.java b/src/client/java/minicraft/screen/ContainerDisplay.java index dda07468c..05da5855e 100644 --- a/src/client/java/minicraft/screen/ContainerDisplay.java +++ b/src/client/java/minicraft/screen/ContainerDisplay.java @@ -2,11 +2,18 @@ import com.studiohartman.jamepad.ControllerButton; import minicraft.core.Game; +import minicraft.core.Renderer; import minicraft.core.io.InputHandler; +import minicraft.core.io.Localization; import minicraft.entity.ItemHolder; import minicraft.entity.furniture.Chest; import minicraft.entity.mob.Player; +import minicraft.gfx.Color; +import minicraft.gfx.Font; +import minicraft.gfx.MinicraftImage; +import minicraft.gfx.Rectangle; import minicraft.gfx.Screen; +import minicraft.gfx.SpriteLinker; import minicraft.item.Inventory; import minicraft.item.Item; import minicraft.item.StackableItem; @@ -15,23 +22,28 @@ public class ContainerDisplay extends Display { private static final int padding = 10; + private final MinicraftImage counterSheet = + Renderer.spriteLinker.getSheet(SpriteLinker.SpriteType.Gui, "inventory_counter"); + private Player player; private Chest chest; public ContainerDisplay(Player player, Chest chest) { - super(new InventoryMenu(chest, chest.getInventory(), chest.name, RelPos.LEFT), new InventoryMenu(player, player.getInventory(), "minicraft.display.menus.inventory", RelPos.RIGHT)); - //pInv = player.getInventory(); - //cInv = chest.getInventory(); + menus = new Menu[] { + new InventoryMenu(player, player.getInventory(), "minicraft.display.menus.inventory", RelPos.RIGHT, this::update), + new InventoryMenu(chest, chest.getInventory(), chest.name, RelPos.LEFT, this::update) + }; this.player = player; this.chest = chest; onScreenKeyboardMenu = OnScreenKeyboardMenu.checkAndCreateMenu(); - if (onScreenKeyboardMenu != null) + if (onScreenKeyboardMenu != null) { onScreenKeyboardMenu.setVisible(false); + } menus[1].translate(menus[0].getBounds().getWidth() + padding, 0); - if(menus[0].getNumOptions() == 0) onSelectionChange(0, 1); + if (menus[1].getNumOptions() == 0) onSelectionChange(1, 0); } OnScreenKeyboardMenu onScreenKeyboardMenu; @@ -39,21 +51,211 @@ public ContainerDisplay(Player player, Chest chest) { @Override protected void onSelectionChange(int oldSel, int newSel) { super.onSelectionChange(oldSel, newSel); - if(oldSel == newSel) return; // this also serves as a protection against access to menus[0] when such may not exist. + + if (oldSel == newSel) + return; // this also serves as a protection against access to menus[0] when such may not exist. + int shift = 0; - if(newSel == 0) shift = padding - menus[0].getBounds().getLeft(); - if(newSel == 1) shift = (Screen.w - padding) - menus[1].getBounds().getRight(); - for(Menu m: menus) + + if (newSel == 0) shift = padding - menus[0].getBounds().getLeft(); + if (newSel == 1) shift = (Screen.w - padding) - menus[1].getBounds().getRight(); + + for (Menu m : menus) { m.translate(shift, 0); + } } - private int getOtherIdx() { return selection ^ 1; } + private int getOtherIdx() { + return selection ^ 1; + } @Override public void render(Screen screen) { super.render(screen); - if (onScreenKeyboardMenu != null) + if (onScreenKeyboardMenu != null) { onScreenKeyboardMenu.render(screen); + } + + // It would be better if this could be made into InventoryMenu, but not possible at the moment. + if (selection == 0) { + // LHS is focused + Rectangle boundsLeft = menus[0].getBounds(); + int sizeLeft = player.getInventory().invSize(); + int capLeft = player.getInventory().getMaxSlots(); + // Expanded counter + if (sizeLeft < 10) { // At the moment at most just 2 digits and always 2 digits for capacity (no worry yet) + // Background + screen.render(boundsLeft.getRight() + 2 - (23 - 5), boundsLeft.getTop() - 3, + 12, 12, 3, 13, counterSheet); + // Skips the middle part as that is for more digits + screen.render(boundsLeft.getRight() + 2 - 15, boundsLeft.getTop() - 3, + 20, 12, 15, 13, counterSheet); + + // Digits + renderCounterNumber(screen, boundsLeft.getRight() + 2 - 16, boundsLeft.getTop() - 1, + 5, 5, 7, sizeLeft, colorByHeaviness(calculateHeaviness(sizeLeft, capLeft), true)); + renderCounterNumber(screen, boundsLeft.getRight() + 2 - 10, boundsLeft.getTop() + 3, + 0, 4, 5, capLeft, Color.GRAY); + } else { + // Background + screen.render(boundsLeft.getRight() + 2 - 23, boundsLeft.getTop() - 3, + 12, 12, 23, 13, counterSheet); + + // Digits + renderCounterNumber(screen, boundsLeft.getRight() + 2 - 21, boundsLeft.getTop() - 1, + 5, 5, 7, sizeLeft, colorByHeaviness(calculateHeaviness(sizeLeft, capLeft), true)); + renderCounterNumber(screen, boundsLeft.getRight() + 2 - 10, boundsLeft.getTop() + 3, + 0, 4, 5, capLeft, Color.GRAY); + } + + // RHS is not focused + Rectangle boundsRight = menus[1].getBounds(); + int sizeRight = chest.getInventory().invSize(); + int capRight = chest.getInventory().getMaxSlots(); + // Minimized counter + if (sizeRight < 10) { // no worry yet, really + // Background + screen.render(boundsRight.getLeft() + 4, boundsRight.getTop() - 1, + 0, 12, 4, 9, counterSheet); + // Skips the middle part as that is for more digits + screen.render(boundsRight.getLeft() + 8, boundsRight.getTop() - 1, + 8, 12, 4, 9, counterSheet); + + // Digits + renderCounterNumber(screen, boundsRight.getLeft() + 4 + 2, boundsRight.getTop() + 1, + 0, 4, 5, sizeRight, fadeColor(colorByHeaviness(calculateHeaviness(sizeRight, capRight), false))); + } else { + // Background + screen.render(boundsRight.getLeft() + 4, boundsRight.getTop() - 1, + 0, 12, 12, 9, counterSheet); + + // Digits + renderCounterNumber(screen, boundsRight.getLeft() + 4 + 2, boundsRight.getTop() + 1, + 0, 4, 5, sizeRight, fadeColor(colorByHeaviness(calculateHeaviness(sizeRight, capRight), false))); + } + } else { // assert selection == 1 + // LHS is not focused + Rectangle boundsLeft = menus[0].getBounds(); + int sizeLeft = player.getInventory().invSize(); + int capLeft = player.getInventory().getMaxSlots(); + // Minimized counter + if (sizeLeft < 10) { + // Background + screen.render(boundsLeft.getRight() - 4 - 8, boundsLeft.getTop() - 1, + 0, 12, 4, 9, counterSheet); + // Skips the middle part as that is for more digits + screen.render(boundsLeft.getRight() - 4 - 4, boundsLeft.getTop() - 1, + 8, 12, 4, 9, counterSheet); + + // Digits + renderCounterNumber(screen, boundsLeft.getRight() - 4 - 6, boundsLeft.getTop() + 1, + 0, 4, 5, sizeLeft, fadeColor(colorByHeaviness(calculateHeaviness(sizeLeft, capLeft), false))); + } else { + // Background + screen.render(boundsLeft.getRight() - 4 - 12, boundsLeft.getTop() - 1, + 0, 12, 12, 9, counterSheet); + + // Digits + renderCounterNumber(screen, boundsLeft.getRight() - 4 - 10, boundsLeft.getTop() + 1, + 0, 4, 5, sizeLeft, fadeColor(colorByHeaviness(calculateHeaviness(sizeLeft, capLeft), false))); + } + + // RHS is focused + Rectangle boundsRight = menus[1].getBounds(); + int sizeRight = chest.getInventory().invSize(); + int capRight = chest.getInventory().getMaxSlots(); + // Expanded counter (background horizontally mirrored) + if (sizeRight < 10) { + // Background + screen.render(boundsRight.getLeft() - 2 + (20 - 5), boundsRight.getTop() - 3, + 12, 12, 3, 13, counterSheet, 1); + // Skips the middle part as that is for more digits + screen.render(boundsRight.getLeft() - 2, boundsRight.getTop() - 3, + 20, 12, 15, 13, counterSheet, 1); + + // Digits + renderCounterNumber(screen, boundsRight.getLeft() - 2 + 11, boundsRight.getTop() - 1, + 5, 5, 7, sizeRight, colorByHeaviness(calculateHeaviness(sizeRight, capRight), true)); + renderCounterNumber(screen, boundsRight.getLeft(), boundsRight.getTop() + 3, + 0, 4, 5, capRight, Color.GRAY); + } else { + // Background + screen.render(boundsRight.getLeft() - 2, boundsRight.getTop() - 3, + 12, 12, 23, 13, counterSheet, 1); + + // Digits + renderCounterNumber(screen, boundsRight.getLeft() - 2 + 11, boundsRight.getTop() - 1, + 5, 5, 7, sizeRight, colorByHeaviness(calculateHeaviness(sizeRight, capRight), true)); + renderCounterNumber(screen, boundsRight.getLeft(), boundsRight.getTop() + 3, + 0, 4, 5, capRight, Color.GRAY); + } + } + } + + // xp, yp - x, y target pixel; ys - y source pixel; w, h - w, h of a digit sprite; n - number to render + private void renderCounterNumber(Screen screen, int xp, int yp, int ys, int w, int h, int n, int color) { + String display = String.valueOf(n); + for (int i = 0; i < display.length(); ++i) { + screen.render(xp + i * w, yp, w * (display.charAt(i) - '0'), ys, w, h, counterSheet, 0, color); + } + } + + // Gives a percentage of heaviness according to size and capacity. + // n <= cap && n >= 0 && cap > 0 + private float calculateHeaviness(int n, int cap) { + // Formula: -(x - 1)^2 + 1 # always positive as (co-)domain=[0,1] + float inner = (float) n / cap - 1; + return constrainDecimal(-(inner * inner) + 1); + } + + // Constrain any possible floating point calculation error causing potential issues + private float constrainDecimal(float val) { + if (val > 1) return 1; + if (val < 0) return 0; + return val; + } + + // Main color means more vibrant color, i.e. with greenness; else with whiteness instead + // Colors here are calculated as two phases as of the property of RGB space. + private int colorByHeaviness(float val, boolean main) { + if (main) { + if (val < .5) { + // From green (0) to yellow (.5) linearly + return ((int) (val / .5F * 255) << 16) | 0x100FF00; + } else { + // From yellow (.5) to red (1) linearly + return ((int) ((1 - val) / .5F * 255) << 8) | 0x1FF0000; + } + } else { + if (val < .3) { + // From white (0) to yellow (.3) linearly + return (int) (val / .3F * 255) | 0x1FFFF00; + } else { + // From yellow (.3) to red (1) linearly + return ((int) ((1 - val) / .7F * 255) << 8) | 0x1FF0000; + } + } + } + + /** + * Fading required color on counter background. Counter background here is hardcoded as #2A3299 while + * fading alpha (opacity) of the color is hardcoded as 35%. + */ + private int fadeColor(int color) { + /* + * Z = X + (Y - X) * P # Source: https://stackoverflow.com/a/12228643 + * where Z: new color value, X: background, Y: overlay color value, P: overlay opacity + */ + final float P = .35F; + int r = (color >> 16) & 0xFF; + int g = (color >> 8) & 0xFF; + int b = color & 0xFF; + + // New color values + int nr = 0x2A + (int) ((r - 0x2A) * P); + int ng = 0x32 + (int) ((g - 0x32) * P); + int nb = 0x99 + (int) ((b - 0x99) * P); + return 0x1000000 | (nr << 16) | (ng << 8) | nb; } @Override @@ -77,14 +279,14 @@ public void tick(InputHandler input) { try { onScreenKeyboardMenu.tick(input); } catch (OnScreenKeyboardMenu.OnScreenKeyboardMenuTickActionCompleted | - OnScreenKeyboardMenu.OnScreenKeyboardMenuBackspaceButtonActed e) { + OnScreenKeyboardMenu.OnScreenKeyboardMenuBackspaceButtonActed e) { acted = true; } if (!acted) curMenu.tick(input); - if (input.getKey("menu").clicked || chest.isRemoved()) { + if (input.getMappedKey("menu").isClicked() || chest.isRemoved()) { Game.setDisplay(null); return; } @@ -99,16 +301,17 @@ public void tick(InputHandler input) { } if (mainMethod || !onScreenKeyboardMenu.isVisible()) - if (input.inputPressed("attack") || input.getKey("shift-enter").clicked) { + if (input.inputPressed("attack")) { if (curMenu.getEntries().length == 0) return; + // switch inventories Inventory from, to; - if(selection == 0) { - from = chest.getInventory(); - to = player.getInventory(); - } else { + if (selection == 0) { from = player.getInventory(); to = chest.getInventory(); + } else { + from = chest.getInventory(); + to = player.getInventory(); } int toSel = menus[otherIdx].getSelection(); @@ -116,30 +319,28 @@ public void tick(InputHandler input) { Item fromItem = from.get(fromSel); - boolean transferAll = input.getKey("shift-enter").clicked || !(fromItem instanceof StackableItem) || ((StackableItem)fromItem).count == 1; + boolean transferAll = input.getMappedKey("shift").isDown() || !(fromItem instanceof StackableItem) || ((StackableItem) fromItem).count == 1; Item toItem = fromItem.copy(); if (fromItem instanceof StackableItem) { int move = 1; if (!transferAll) { - ((StackableItem)toItem).count = 1; + ((StackableItem) toItem).count = 1; } else { - move = ((StackableItem)fromItem).count; + move = ((StackableItem) toItem).count; } - int moved = to.add(toSel, toItem); - if (moved < move) { - ((StackableItem)fromItem).count -= moved; + if (to.add(toItem) != null) { + ((StackableItem)fromItem).count -= move - ((StackableItem) toItem).count; } else if (!transferAll) { - ((StackableItem)fromItem).count--; + ((StackableItem) fromItem).count--; } else { from.remove(fromSel); } update(); } else { - int moved = to.add(toSel, toItem); - if (moved == 1) { + if (to.add(toItem) == null) { from.remove(fromSel); update(); } @@ -147,9 +348,13 @@ public void tick(InputHandler input) { } } + /** @deprecated This method is no longer in use by the removal of multiplayer system. + * Also, the game is paused when the display is shown, so it is not possible for the player to pickup items during this period. */ + @Deprecated public void onInvUpdate(ItemHolder holder) { - if(holder == player || holder == chest) + if (holder == player || holder == chest) { update(); + } } private void update() { diff --git a/src/client/java/minicraft/screen/ControlsDisplay.java b/src/client/java/minicraft/screen/ControlsDisplay.java index 842105ba0..8e028156a 100644 --- a/src/client/java/minicraft/screen/ControlsDisplay.java +++ b/src/client/java/minicraft/screen/ControlsDisplay.java @@ -22,7 +22,7 @@ public class ControlsDisplay extends Display { public ControlsDisplay() { super(true, true, new Menu.Builder(false, 0, RelPos.CENTER) .setSelectable(true) - .setPositioning(new Point(Screen.w/2, 20), RelPos.BOTTOM) + .setPositioning(new Point(Screen.w / 2, 20), RelPos.BOTTOM) .setDisplayLength(17) .createMenu() ); @@ -51,7 +51,7 @@ private void initControllerControls() { } private void switchingControls() { - menus[0].setEntries(displaying == 0? keyControls: controllerControls); + menus[0].setEntries(displaying == 0 ? keyControls : controllerControls); menus[0].setSelection(0); } @@ -60,7 +60,7 @@ public void render(Screen screen) { super.render(screen); Font.drawCentered(Localization.getLocalized("minicraft.displays.controls"), screen, 0, Color.WHITE); - Font.drawCentered(Localization.getLocalized(displaying == 0? "minicraft.displays.controls.display.keyboard": "minicraft.displays.controls.display.controller"), screen, 10, Color.WHITE); + Font.drawCentered(Localization.getLocalized(displaying == 0 ? "minicraft.displays.controls.display.keyboard" : "minicraft.displays.controls.display.controller"), screen, 10, Color.WHITE); if (displaying == 0) { // If displaying keyboard mappings. Font.drawCentered(Localization.getLocalized("minicraft.displays.controls.display.keyboard.desc"), screen, Screen.h - 16, Color.GRAY); diff --git a/src/client/java/minicraft/screen/CraftingDisplay.java b/src/client/java/minicraft/screen/CraftingDisplay.java index 1957c3f62..b6635a8e1 100644 --- a/src/client/java/minicraft/screen/CraftingDisplay.java +++ b/src/client/java/minicraft/screen/CraftingDisplay.java @@ -36,9 +36,12 @@ public class CraftingDisplay extends Display { private static final HashSet unlockedRecipes = new HashSet<>(); - public CraftingDisplay(List recipes, String title, Player player) { this(recipes, title, player, false); } + public CraftingDisplay(List recipes, String title, Player player) { + this(recipes, title, player, false); + } + public CraftingDisplay(List recipes, String title, Player player, boolean isPersonal) { - for(Recipe recipe: recipes) + for (Recipe recipe : recipes) recipe.checkCanCraft(player); this.player = player; this.title = title; @@ -59,10 +62,10 @@ private void refreshDisplayRecipes() { List recipes = availableRecipes.stream().filter(unlockedRecipes::contains).collect(Collectors.toList()); recipeMenu = new RecipeMenu(recipes, title, player); this.recipes = recipes.toArray(new Recipe[0]); - itemCountMenu.setPositioning(new Point(recipeMenu.getBounds().getRight()+MinicraftImage.boxWidth, recipeMenu.getBounds().getTop()), RelPos.BOTTOM_RIGHT); + itemCountMenu.setPositioning(new Point(recipeMenu.getBounds().getRight() + MinicraftImage.boxWidth, recipeMenu.getBounds().getTop()), RelPos.BOTTOM_RIGHT); costsMenu.setPositioning(new Point(itemCountMenu.createMenu().getBounds().getLeft(), recipeMenu.getBounds().getBottom()), RelPos.TOP_RIGHT); - menus = new Menu[] {recipeMenu, itemCountMenu.createMenu(), costsMenu.createMenu()}; + menus = new Menu[] { recipeMenu, itemCountMenu.createMenu(), costsMenu.createMenu() }; refreshData(); onScreenKeyboardMenu = OnScreenKeyboardMenu.checkAndCreateMenu(); @@ -94,7 +97,7 @@ private ItemListing[] getCurItemCosts() { if (recipes.length == 0) return new ItemListing[0]; Map costMap = recipes[recipeMenu.getSelection()].getCosts(); - for(String itemName: costMap.keySet()) { + for (String itemName : costMap.keySet()) { Item cost = Items.get(itemName); costList.add(new ItemListing(cost, player.getInventory().count(cost) + "/" + costMap.get(itemName))); } @@ -127,14 +130,14 @@ public void tick(InputHandler input) { try { onScreenKeyboardMenu.tick(input); } catch (OnScreenKeyboardMenu.OnScreenKeyboardMenuTickActionCompleted | - OnScreenKeyboardMenu.OnScreenKeyboardMenuBackspaceButtonActed e) { + OnScreenKeyboardMenu.OnScreenKeyboardMenuBackspaceButtonActed e) { acted = true; } if (!acted) recipeMenu.tick(input); - if (input.getKey("menu").clicked || (isPersonalCrafter && input.inputPressed("craft"))) { + if (input.getMappedKey("menu").isClicked() || (isPersonalCrafter && input.inputPressed("craft"))) { Game.exitDisplay(); return; } @@ -160,12 +163,12 @@ public void tick(InputHandler input) { if (recipes.length == 0) return; Recipe selectedRecipe = recipes[recipeMenu.getSelection()]; if (selectedRecipe.getCanCraft()) { - if (selectedRecipe.getProduct().equals(Items.get("Workbench"))){ - AchievementsDisplay.setAchievement("minicraft.achievement.benchmarking",true); - } else if (selectedRecipe.getProduct().equals(Items.get("Plank"))){ - AchievementsDisplay.setAchievement("minicraft.achievement.planks",true); - } else if (selectedRecipe.getProduct().equals(Items.get("Wood Door"))){ - AchievementsDisplay.setAchievement("minicraft.achievement.doors",true); + if (selectedRecipe.getProduct().equals(Items.get("Workbench"))) { + AchievementsDisplay.setAchievement("minicraft.achievement.benchmarking", true); + } else if (selectedRecipe.getProduct().equals(Items.get("Plank"))) { + AchievementsDisplay.setAchievement("minicraft.achievement.planks", true); + } else if (selectedRecipe.getProduct().equals(Items.get("Wood Door"))) { + AchievementsDisplay.setAchievement("minicraft.achievement.doors", true); } else if (selectedRecipe.getProduct().equals(Items.get("Rock Sword")) || selectedRecipe.getProduct().equals(Items.get("Rock Pickaxe")) || selectedRecipe.getProduct().equals(Items.get("Rock Axe")) || diff --git a/src/client/java/minicraft/screen/Display.java b/src/client/java/minicraft/screen/Display.java index e2528438e..9e45a0417 100644 --- a/src/client/java/minicraft/screen/Display.java +++ b/src/client/java/minicraft/screen/Display.java @@ -16,11 +16,26 @@ public class Display { private final boolean canExit, clearScreen; - public Display() { this(new Menu[0]); } - public Display(Menu... menus) { this(false, true, menus); } - public Display(boolean clearScreen) { this(clearScreen, true, new Menu[0]); } - public Display(boolean clearScreen, Menu... menus) { this(clearScreen, true, menus); } - public Display(boolean clearScreen, boolean canExit) { this(clearScreen, canExit, new Menu[0]); } + public Display() { + this(new Menu[0]); + } + + public Display(Menu... menus) { + this(false, true, menus); + } + + public Display(boolean clearScreen) { + this(clearScreen, true, new Menu[0]); + } + + public Display(boolean clearScreen, Menu... menus) { + this(clearScreen, true, menus); + } + + public Display(boolean clearScreen, boolean canExit) { + this(clearScreen, canExit, new Menu[0]); + } + public Display(boolean clearScreen, boolean canExit, Menu... menus) { this.menus = menus; this.canExit = canExit; @@ -29,7 +44,10 @@ public Display(boolean clearScreen, boolean canExit, Menu... menus) { } private boolean setParent = false; - /** Called during {@link Game#setDisplay} */ + + /** + * Called during {@link Game#setDisplay} + */ public void init(@Nullable Display parent) { if (!setParent) { setParent = true; @@ -37,9 +55,12 @@ public void init(@Nullable Display parent) { } } - public void onExit() {} + public void onExit() { + } - public Display getParent() { return parent; } + public Display getParent() { + return parent; + } public void tick(InputHandler input) { @@ -55,9 +76,9 @@ public void tick(InputHandler input) { if (menus.length > 1 && menus[selection].isSelectable()) { // If menu set is unselectable, it must have been intentional, so prevent the user from setting it back. int prevSel = selection; - String shift = menus[selection].getCurEntry() instanceof ArrayEntry ? "shift-" : ""; - if (input.getKey(shift+"left").clicked || input.leftTriggerPressed()) selection--; - if (input.getKey(shift+"right").clicked || input.rightTriggerPressed()) selection++; + String shift = menus[selection].getCurEntry() instanceof ArrayEntry ? "shift+" : ""; + if (input.getMappedKey(shift + "cursor-left").isClicked() || input.leftTriggerPressed()) selection--; + if (input.getMappedKey(shift + "cursor-right").isClicked() || input.rightTriggerPressed()) selection++; if (prevSel != selection) { Sound.play("select"); @@ -68,7 +89,7 @@ public void tick(InputHandler input) { selection += delta; if (selection < 0) selection = menus.length - 1; selection = selection % menus.length; - } while(!menus[selection].isSelectable() && selection != prevSel); + } while (!menus[selection].isSelectable() && selection != prevSel); changedSelection = prevSel != selection; } @@ -100,7 +121,7 @@ else if (setParent && parent != null) { do { idx++; idx = idx % menus.length; - if(menus[idx].shouldRender()) + if (menus[idx].shouldRender()) menus[idx].render(screen); } while (idx != selection); } diff --git a/src/client/java/minicraft/screen/EndGameDisplay.java b/src/client/java/minicraft/screen/EndGameDisplay.java index d1edc8972..79ccf0322 100644 --- a/src/client/java/minicraft/screen/EndGameDisplay.java +++ b/src/client/java/minicraft/screen/EndGameDisplay.java @@ -30,7 +30,7 @@ public class EndGameDisplay extends Display { static { int maxLength = 0; - for (String s: scoredItems) + for (String s : scoredItems) maxLength = Math.max(maxLength, s.length()); } @@ -38,7 +38,7 @@ public EndGameDisplay() { super(false, false); displayTimer = Updater.normSpeed; // wait 3 seconds before rendering the menu. - inputDelay = Updater.normSpeed/2; // wait a half-second after rendering before allowing user input. + inputDelay = Updater.normSpeed / 2; // wait a half-second after rendering before allowing user input. ArrayList entries = new ArrayList<>(); @@ -48,7 +48,7 @@ public EndGameDisplay() { entries.add(new StringEntry("minicraft.displays.end_game.display.bonuses", Color.YELLOW)); finalScore = Game.player.getScore(); - for(String item: scoredItems) + for (String item : scoredItems) addBonus(item); entries.add(new StringEntry(Localization.getLocalized("minicraft.displays.end_game.display.final_score", finalScore))); @@ -78,7 +78,7 @@ public void tick(InputHandler input) { @Override public void render(Screen screen) { - if(displayTimer <= 0) + if (displayTimer <= 0) super.render(screen); } diff --git a/src/client/java/minicraft/screen/InfoDisplay.java b/src/client/java/minicraft/screen/InfoDisplay.java index 7e1feb2c3..a4f63eddb 100644 --- a/src/client/java/minicraft/screen/InfoDisplay.java +++ b/src/client/java/minicraft/screen/InfoDisplay.java @@ -4,6 +4,7 @@ import minicraft.core.Updater; import minicraft.core.io.InputHandler; import minicraft.core.io.Localization; +import minicraft.gfx.Color; import minicraft.gfx.MinicraftImage; import minicraft.gfx.Point; import minicraft.screen.entry.StringEntry; @@ -12,17 +13,17 @@ public class InfoDisplay extends Display { public InfoDisplay() { //noinspection SuspiciousNameCombination - super(new Menu.Builder(true, 4, RelPos.LEFT, StringEntry.useLines( + super(new Menu.Builder(true, 4, RelPos.LEFT, StringEntry.useLines(Color.WHITE, false, "----------------------------", Localization.getLocalized("minicraft.displays.info.display.time", getTimeString()), Localization.getLocalized("minicraft.displays.info.display.score", Game.player.getScore()), "----------------------------", Localization.getLocalized("minicraft.displays.info.display.exit_help", Game.input.getMapping("select"), Game.input.getMapping("exit")) )) - .setTitle("minicraft.displays.info.title") - .setTitlePos(RelPos.TOP_LEFT) - .setPositioning(new Point(MinicraftImage.boxWidth, MinicraftImage.boxWidth), RelPos.BOTTOM_RIGHT) - .createMenu() + .setTitle("minicraft.displays.info.title") + .setTitlePos(RelPos.TOP_LEFT) + .setPositioning(new Point(MinicraftImage.boxWidth, MinicraftImage.boxWidth), RelPos.BOTTOM_RIGHT) + .createMenu() ); } diff --git a/src/client/java/minicraft/screen/InventoryMenu.java b/src/client/java/minicraft/screen/InventoryMenu.java index 21bb8df9f..34fa9c927 100644 --- a/src/client/java/minicraft/screen/InventoryMenu.java +++ b/src/client/java/minicraft/screen/InventoryMenu.java @@ -1,28 +1,43 @@ package minicraft.screen; +import minicraft.core.Action; import minicraft.core.io.InputHandler; import minicraft.entity.Entity; import minicraft.item.Inventory; import minicraft.item.Item; import minicraft.item.StackableItem; import minicraft.screen.entry.ItemEntry; +import org.jetbrains.annotations.Nullable; class InventoryMenu extends ItemListMenu { + private final RelPos entryPos; // Used for copy constructor + private final String title; // Used for copy constructor private final Inventory inv; private final Entity holder; - protected boolean creativeInv = false; + private final boolean creativeInv; + private final @Nullable Action onStackUpdateListener; // The length of the entry shown may change when there is an update to the stack. - InventoryMenu(Entity holder, Inventory inv, String title, RelPos entryPos) { + InventoryMenu(Entity holder, Inventory inv, String title, RelPos entryPos, @Nullable Action onStackUpdateListener) { this(holder, inv, title, entryPos, false, onStackUpdateListener); } + InventoryMenu(Entity holder, Inventory inv, String title, RelPos entryPos, boolean creativeInv) { this(holder, inv, title, entryPos, creativeInv, null); } + InventoryMenu(Entity holder, Inventory inv, String title, RelPos entryPos, boolean creativeInv, @Nullable Action onStackUpdateListener) { super(ItemListMenu.getBuilder(entryPos), ItemEntry.useItems(inv.getItems()), title); this.inv = inv; this.holder = holder; + this.title = title; + this.entryPos = entryPos; + this.creativeInv = creativeInv; + this.onStackUpdateListener = onStackUpdateListener; } InventoryMenu(InventoryMenu model) { - super(ItemListMenu.getBuilder(), ItemEntry.useItems(model.inv.getItems()), model.getTitle()); + super(ItemListMenu.getBuilder(model.entryPos), ItemEntry.useItems(model.inv.getItems()), model.title); this.inv = model.inv; this.holder = model.holder; + this.creativeInv = model.creativeInv; + this.title = model.title; + this.entryPos = model.entryPos; + this.onStackUpdateListener = model.onStackUpdateListener; setSelection(model.getSelection()); } @@ -32,20 +47,24 @@ public void tick(InputHandler input) { boolean dropOne = input.inputPressed("drop-one"); - if(getNumOptions() > 0 && (dropOne || input.inputPressed("drop-stack"))) { - ItemEntry entry = ((ItemEntry)getCurEntry()); - if(entry == null) return; + if (getNumOptions() > 0 && (dropOne || input.inputPressed("drop-stack"))) { + ItemEntry entry = ((ItemEntry) getCurEntry()); + if (entry == null) return; Item invItem = entry.getItem(); Item drop = invItem.copy(); if (!creativeInv) { - if (dropOne && drop instanceof StackableItem && ((StackableItem)drop).count > 1) { - // just drop one from the stack - ((StackableItem)drop).count = 1; - ((StackableItem)invItem).count--; - } else { + if (!dropOne || !(drop instanceof StackableItem) || ((StackableItem) drop).count <= 1) { // drop the whole item. removeSelectedEntry(); + } else { + // just drop one from the stack + ((StackableItem) drop).count = 1; + ((StackableItem) invItem).count--; + } + + if (onStackUpdateListener != null) { + onStackUpdateListener.act(); } } diff --git a/src/client/java/minicraft/screen/ItemListMenu.java b/src/client/java/minicraft/screen/ItemListMenu.java index 6fea47075..2b7c96df9 100644 --- a/src/client/java/minicraft/screen/ItemListMenu.java +++ b/src/client/java/minicraft/screen/ItemListMenu.java @@ -5,7 +5,10 @@ class ItemListMenu extends Menu { - static Builder getBuilder() { return getBuilder(RelPos.LEFT); } + static Builder getBuilder() { + return getBuilder(RelPos.LEFT); + } + static Builder getBuilder(RelPos entryPos) { return new Builder(true, 0, entryPos) .setPositioning(new Point(9, 9), RelPos.BOTTOM_RIGHT) diff --git a/src/client/java/minicraft/screen/KeyInputDisplay.java b/src/client/java/minicraft/screen/KeyInputDisplay.java index 4c4de4c6e..cb346bb4e 100644 --- a/src/client/java/minicraft/screen/KeyInputDisplay.java +++ b/src/client/java/minicraft/screen/KeyInputDisplay.java @@ -48,7 +48,7 @@ public KeyInputDisplay() { super(true); builder = new Menu.Builder(false, 0, RelPos.CENTER, getEntries()) .setTitle("minicraft.displays.key_input.title") - .setPositioning(new Point(Screen.w/2, Screen.h - Font.textHeight()*5), RelPos.TOP); + .setPositioning(new Point(Screen.w / 2, Screen.h - Font.textHeight() * 5), RelPos.TOP); menus = new Menu[] { builder.createMenu() @@ -76,7 +76,7 @@ public void tick(InputHandler input) { Game.setDisplay(new PopupDisplay(new PopupDisplay.PopupConfig(null, callbacks, 4), StringEntry.useLines(Color.YELLOW, "minicraft.displays.key_input.popup_display.press_key_sequence"))); - } else if (input.getKey("shift-d").clicked) { + } else if (input.getMappedKey("shift-d").isClicked()) { ArrayList callbacks = new ArrayList<>(); callbacks.add(new PopupDisplay.PopupActionCallback("select", popup -> { input.resetKeyBindings(); @@ -103,7 +103,7 @@ public void render(Screen screen) { Localization.getLocalized("minicraft.displays.key_input.display.help.3", Game.input.getMapping("exit")) }; - for(int i = 0; i < lines.length; i++) - Font.drawCentered(lines[i], screen, Screen.h-Font.textHeight()*(4-i), Color.WHITE); + for (int i = 0; i < lines.length; i++) + Font.drawCentered(lines[i], screen, Screen.h - Font.textHeight() * (4 - i), Color.WHITE); } } diff --git a/src/client/java/minicraft/screen/LanguageSettingsDisplay.java b/src/client/java/minicraft/screen/LanguageSettingsDisplay.java index 90e9ec81f..f5696ff68 100644 --- a/src/client/java/minicraft/screen/LanguageSettingsDisplay.java +++ b/src/client/java/minicraft/screen/LanguageSettingsDisplay.java @@ -14,7 +14,7 @@ import java.util.Map; public class LanguageSettingsDisplay extends Display { - private Map.Entry ,Integer> getEntries() { + private Map.Entry, Integer> getEntries() { Localization.LocaleInformation[] locales = Localization.getLocales(); ArrayList list = new ArrayList<>(Arrays.asList(locales)); list.sort((a, b) -> { // Debug language is always on top. @@ -44,12 +44,12 @@ public int getColor(boolean isSelected) { public LanguageSettingsDisplay() { super(true); - Map.Entry ,Integer> entries = getEntries(); + Map.Entry, Integer> entries = getEntries(); menus = new Menu[] { new Menu.Builder(false, 2, RelPos.CENTER, entries.getKey()) .setTitle("minicraft.displays.language_settings.title") .setSelectable(true) - .setPositioning(new Point(Screen.w/2, 10), RelPos.BOTTOM) + .setPositioning(new Point(Screen.w / 2, 10), RelPos.BOTTOM) .setSize(Screen.w, Screen.h - 30) .setSelection(entries.getValue()) .createMenu() diff --git a/src/client/java/minicraft/screen/LevelTransitionDisplay.java b/src/client/java/minicraft/screen/LevelTransitionDisplay.java index 7681c5141..6f8a3a970 100644 --- a/src/client/java/minicraft/screen/LevelTransitionDisplay.java +++ b/src/client/java/minicraft/screen/LevelTransitionDisplay.java @@ -17,24 +17,26 @@ public class LevelTransitionDisplay extends Display { private LinkedSprite hudSheet = new LinkedSprite(SpriteType.Gui, "hud"); public LevelTransitionDisplay(int dir) { - super(false,false); + super(false, false); this.dir = dir; } @Override public void tick(InputHandler input) { time++; // Ticks up 2 times per tick - if (time == DURATION/2) World.changeLevel(dir); // When time equals 30, it will change the level + if (time == DURATION / 2) World.changeLevel(dir); // When time equals 30, it will change the level if (time == DURATION) Game.setDisplay(null); // When time equals 60, it will get out of this menu } public void render(Screen screen) { for (int x = 0; x < 200; x++) { // Loop however many times depending on the width (It's divided by 3 because the pixels are scaled up by 3) for (int y = 0; y < 150; y++) { // Loop however many times depending on the height (It's divided by 3 because the pixels are scaled up by 3) - int dd = (y + x % 2 * 2 + x / 3) - time*2; // Used as part of the positioning. + int dd = (y + x % 2 * 2 + x / 3) - time * 2; // Used as part of the positioning. if (dd < 0 && dd > -30) { - if (dir > 0) screen.render(x * 8, y * 8, 5, 2, 0, hudSheet.getSheet()); // If the direction is upwards then render the squares going up - else screen.render(x * 8, Screen.h - y * 8 - 8, 5, 2, 0, hudSheet.getSheet()); // If the direction is negative, then the squares will go down. + if (dir > 0) + screen.render(x * 8, y * 8, 5, 2, 0, hudSheet.getSheet()); // If the direction is upwards then render the squares going up + else + screen.render(x * 8, Screen.h - y * 8 - 8, 5, 2, 0, hudSheet.getSheet()); // If the direction is negative, then the squares will go down. } } } diff --git a/src/client/java/minicraft/screen/LoadingDisplay.java b/src/client/java/minicraft/screen/LoadingDisplay.java index 62c2e20d6..00e861791 100644 --- a/src/client/java/minicraft/screen/LoadingDisplay.java +++ b/src/client/java/minicraft/screen/LoadingDisplay.java @@ -18,6 +18,7 @@ public class LoadingDisplay extends Display { private static float percentage = 0; private static String progressType = ""; + private static boolean localizeProgressType = true; private final Timer t; private final Ellipsis ellipsis = new SmoothEllipsis(new TimeUpdater()); @@ -49,6 +50,7 @@ public void init(Display parent) { super.init(parent); percentage = 0; progressType = "minicraft.displays.loading.message.world"; + localizeProgressType = true; if (WorldSelectDisplay.hasLoadedWorld()) msg = "minicraft.displays.loading.message.loading"; else @@ -62,6 +64,7 @@ public void onExit() { if (!WorldSelectDisplay.hasLoadedWorld()) { msg = "minicraft.displays.loading.message.saving"; progressType = "minicraft.displays.loading.message.world"; + localizeProgressType = true; new Save(WorldSelectDisplay.getWorldName()); Game.notifications.clear(); } @@ -70,8 +73,19 @@ public void onExit() { public static void setPercentage(float percent) { percentage = percent; } - public static float getPercentage() { return percentage; } - public static void setMessage(String progressType) { LoadingDisplay.progressType = progressType; } + + public static float getPercentage() { + return percentage; + } + + public static void setMessage(String progressType) { + setMessage(progressType, true); + } + + public static void setMessage(String progressType, boolean localize) { + LoadingDisplay.progressType = progressType; + localizeProgressType = localize; + } public static void progress(float amt) { percentage = Math.min(100, percentage + amt); @@ -82,7 +96,8 @@ public void render(Screen screen) { super.render(screen); int percent = Math.round(percentage); Font.drawParagraph(screen, new FontStyle(Color.RED), 6, - Localization.getLocalized(msg) + (progressType.length() > 0 ? " " + Localization.getLocalized(progressType) : "") + ellipsis.updateAndGet(), + Localization.getLocalized(msg) + (progressType.length() > 0 ? " " + (localizeProgressType ? Localization.getLocalized(progressType) : progressType) : "") + + ellipsis.updateAndGet(), percent + "%" ); } diff --git a/src/client/java/minicraft/screen/Menu.java b/src/client/java/minicraft/screen/Menu.java index 21738dbad..ca402bc4a 100644 --- a/src/client/java/minicraft/screen/Menu.java +++ b/src/client/java/minicraft/screen/Menu.java @@ -70,7 +70,9 @@ public class Menu { private LinkedSprite hudSheet = new LinkedSprite(SpriteType.Gui, "hud"); - private Menu() {} + private Menu() { + } + protected Menu(Menu m) { entries.addAll(m.entries); spacing = m.spacing; @@ -100,17 +102,17 @@ protected Menu(Menu m) { public void init() { - if(entries.size() == 0) { + if (entries.size() == 0) { selection = 0; dispSelection = 0; offset = 0; return; } - selection = Math.min(selection, entries.size()-1); + selection = Math.min(selection, entries.size() - 1); selection = Math.max(0, selection); - if(!entries.get(selection).isSelectable()) { + if (!entries.get(selection).isSelectable()) { int prevSel = selection; do { selection++; @@ -120,46 +122,76 @@ public void init() { } dispSelection = selection; - dispSelection = Math.min(dispSelection, displayLength-1); + dispSelection = Math.min(dispSelection, displayLength - 1); dispSelection = Math.max(0, dispSelection); doScroll(); } void setSelection(int idx) { - if(idx >= entries.size()) + if (idx >= entries.size()) idx = entries.size() - 1; - if(idx < 0) idx = 0; + if (idx < 0) idx = 0; this.selection = idx; doScroll(); } - int getSelection() { return selection; } - int getDispSelection() { return dispSelection; } - ListEntry[] getEntries() { return entries.toArray(new ListEntry[0]); } + int getSelection() { + return selection; + } + + int getDispSelection() { + return dispSelection; + } + + ListEntry[] getEntries() { + return entries.toArray(new ListEntry[0]); + } + protected void setEntries(ListEntry[] entries) { this.entries.clear(); this.entries.addAll(0, Arrays.asList(entries)); } + protected void setEntries(List entries) { this.entries.clear(); this.entries.addAll(entries); } - @Nullable ListEntry getCurEntry() { return entries.size() == 0 ? null : entries.get(selection); } - int getNumOptions() { return entries.size(); } - Rectangle getBounds() { return new Rectangle(bounds); } - String getTitle() { return title; } + @Nullable ListEntry getCurEntry() { + return entries.size() == 0 ? null : entries.get(selection); + } + + int getNumOptions() { + return entries.size(); + } + + Rectangle getBounds() { + return new Rectangle(bounds); + } + + String getTitle() { + return title; + } + + boolean isSelectable() { + return selectable; + } - boolean isSelectable() { return selectable; } - boolean shouldRender() { return shouldRender; } + boolean shouldRender() { + return shouldRender; + } - public boolean isSearcherBarActive() { return searcherBarActive; } + public boolean isSearcherBarActive() { + return searcherBarActive; + } - /** @noinspection SameParameterValue*/ + /** + * @noinspection SameParameterValue + */ void translate(int xoff, int yoff) { bounds.translate(xoff, yoff); entryBounds.translate(xoff, yoff); @@ -167,23 +199,23 @@ void translate(int xoff, int yoff) { } public void tick(InputHandler input) { - if(!selectable || entries.size() == 0) return; + if (!selectable || entries.size() == 0) return; int prevSel = selection; if (input.inputPressed("cursor-up")) selection--; if (input.inputPressed("cursor-down")) selection++; - if (input.getKey("shift-cursor-up").clicked && selectionSearcher == 0) selectionSearcher -= 2; - if (input.getKey("shift-cursor-down").clicked && selectionSearcher == 0) selectionSearcher += 2; + if (input.getMappedKey("shift+cursor-up").isClicked() && selectionSearcher == 0) selectionSearcher -= 2; + if (input.getMappedKey("shift+cursor-down").isClicked() && selectionSearcher == 0) selectionSearcher += 2; if (prevSel != selection && selectionSearcher != 0) selection = prevSel; if (useSearcherBar) { - if (input.getKey("searcher-bar").clicked) { + if (input.getMappedKey("searcher-bar").isClicked()) { searcherBarActive = !searcherBarActive; input.addKeyTyped("", null); // clear pressed key } if (!listSearcher.isEmpty() && selectionSearcher == 0) { - int speed = input.getKey("PAGE-UP").clicked ? -1 : input.getKey("PAGE-DOWN").clicked ? 1 : 0; + int speed = input.getMappedKey("PAGE-UP").isClicked() ? -1 : input.getMappedKey("PAGE-DOWN").isClicked() ? 1 : 0; if (speed != 0) { int listPosition = listPositionSearcher + speed; if (listPosition < 0) { @@ -199,13 +231,7 @@ public void tick(InputHandler input) { if (searcherBarActive) { String typingSearcher = input.addKeyTyped(this.typingSearcher, null); - for (String pressedKey : input.getAllPressedKeys()) { - if (pressedKey.equals("ENTER")) { - continue; - } - - input.getKey(pressedKey).clicked = false; - } + input.maskInput(k -> !k.equals("ENTER")); // check if word was updated if (typingSearcher.length() <= Menu.LIMIT_TYPING_SEARCHER && typingSearcher.length() != this.typingSearcher.length()) { @@ -244,7 +270,7 @@ public void tick(InputHandler input) { int delta = selection - prevSel; selection = prevSel; - if(delta == 0) { + if (delta == 0) { entries.get(selection).tick(input); // only ticks the entry on a frame where the selection cursor has not moved. return; } else @@ -254,13 +280,13 @@ public void tick(InputHandler input) { selection += delta; if (selection < 0) selection = entries.size() - 1; selection = selection % entries.size(); - } while(!entries.get(selection).isSelectable() && selection != prevSel); + } while (!entries.get(selection).isSelectable() && selection != prevSel); // update offset and selection displayed dispSelection += selection - prevSel; - if(dispSelection < 0) dispSelection = 0; - if(dispSelection >= displayLength) dispSelection = displayLength - 1; + if (dispSelection < 0) dispSelection = 0; + if (dispSelection >= displayLength) dispSelection = displayLength - 1; doScroll(); } @@ -272,20 +298,20 @@ private void doScroll() { int offset = this.offset; // for scrolling up - while((dispSelection < padding || !wrap && offset + displayLength > entries.size()) && (wrap || offset > 0)) { + while ((dispSelection < padding || !wrap && offset + displayLength > entries.size()) && (wrap || offset > 0)) { offset--; dispSelection++; } // for scrolling down - while((displayLength - dispSelection <= padding || !wrap && offset < 0) && (wrap || offset + displayLength < entries.size())) { + while ((displayLength - dispSelection <= padding || !wrap && offset < 0) && (wrap || offset + displayLength < entries.size())) { offset++; dispSelection--; } // only useful when wrap is true - if(offset < 0) offset += entries.size(); - if(offset > 0) offset = offset % entries.size(); + if (offset < 0) offset += entries.size(); + if (offset > 0) offset = offset % entries.size(); this.offset = offset; } @@ -294,15 +320,17 @@ public void render(Screen screen) { renderFrame(screen); // render the title - if(title.length() > 0) { + if (title.length() > 0) { if (drawVertically) { for (int i = 0; i < title.length(); i++) { - if (hasFrame) screen.render(titleLoc.x, titleLoc.y + i * Font.textHeight(), 3, 6, 0, hudSheet.getSheet()); + if (hasFrame) + screen.render(titleLoc.x, titleLoc.y + i * Font.textHeight(), 3, 6, 0, hudSheet.getSheet()); Font.draw(title.substring(i, i + 1), screen, titleLoc.x, titleLoc.y + i * Font.textHeight(), titleColor); } } else { for (int i = 0; i < title.length(); i++) { - if (hasFrame) screen.render(titleLoc.x + i * Font.textWidth(" "), titleLoc.y, 3, 6, 0, hudSheet.getSheet()); + if (hasFrame) + screen.render(titleLoc.x + i * Font.textWidth(" "), titleLoc.y, 3, 6, 0, hudSheet.getSheet()); Font.draw(title.substring(i, i + 1), screen, titleLoc.x + i * Font.textWidth(" "), titleLoc.y, titleColor); } } @@ -331,18 +359,18 @@ public void render(Screen screen) { // render the options int y = entryBounds.getTop(); boolean special = wrap && entries.size() < displayLength; - if(special) { + if (special) { int diff = displayLength - entries.size(); // we have to account for this many entry heights. - int extra = diff*(ListEntry.getHeight() + spacing) / 2; + int extra = diff * (ListEntry.getHeight() + spacing) / 2; y += extra; } - for(int i = offset; i < (wrap ? offset + displayLength : Math.min(offset + displayLength, entries.size())); i++) { - if(special && i-offset >= entries.size()) break; + for (int i = offset; i < (wrap ? offset + displayLength : Math.min(offset + displayLength, entries.size())); i++) { + if (special && i - offset >= entries.size()) break; int idx = i % entries.size(); ListEntry entry = entries.get(idx); - if(!(entry instanceof BlankEntry)) { + if (!(entry instanceof BlankEntry)) { Point pos = entryPos.positionRect(new Dimension(entry.getWidth(), ListEntry.getHeight()), new Rectangle(entryBounds.getLeft(), y, entryBounds.getWidth(), ListEntry.getHeight(), Rectangle.CORNER_DIMS)); boolean selected = idx == selection; if (searcherBarActive && useSearcherBar) { @@ -361,18 +389,21 @@ public void render(Screen screen) { } } - void updateSelectedEntry(ListEntry newEntry) { updateEntry(selection, newEntry); } + void updateSelectedEntry(ListEntry newEntry) { + updateEntry(selection, newEntry); + } + void updateEntry(int idx, ListEntry newEntry) { - if(idx >= 0 && idx < entries.size()) + if (idx >= 0 && idx < entries.size()) entries.set(idx, newEntry); } public void removeSelectedEntry() { entries.remove(selection); - if(selection >= entries.size()) + if (selection >= entries.size()) selection = entries.size() - 1; - if(selection < 0) + if (selection < 0) selection = 0; doScroll(); @@ -383,10 +414,10 @@ public void setColors(Menu model) { } private void renderFrame(Screen screen) { - if(!hasFrame) return; + if (!hasFrame) return; - int bottom = bounds.getBottom()-MinicraftImage.boxWidth; - int right = bounds.getRight()-MinicraftImage.boxWidth; + int bottom = bounds.getBottom() - MinicraftImage.boxWidth; + int right = bounds.getRight() - MinicraftImage.boxWidth; for (int y = bounds.getTop(); y <= bottom; y += MinicraftImage.boxWidth) { // loop through the height of the bounds for (int x = bounds.getLeft(); x <= right; x += MinicraftImage.boxWidth) { // loop through the width of the bounds @@ -394,42 +425,47 @@ private void renderFrame(Screen screen) { boolean xend = x == bounds.getLeft() || x == right; boolean yend = y == bounds.getTop() || y == bottom; int spriteoffset = (xend && yend ? 0 : (yend ? 1 : (xend ? 2 : 3))); // determines which sprite to use - int mirrors = ( x == right ? 1 : 0 ) + ( y == bottom ? 2 : 0 ); // gets mirroring + int mirrors = (x == right ? 1 : 0) + (y == bottom ? 2 : 0); // gets mirroring screen.render(x, y, spriteoffset, 6, mirrors, hudSheet.getSheet()); - if(x < right && x + MinicraftImage.boxWidth > right) + if (x < right && x + MinicraftImage.boxWidth > right) x = right - MinicraftImage.boxWidth; } - if(y < bottom && y + MinicraftImage.boxWidth > bottom) + if (y < bottom && y + MinicraftImage.boxWidth > bottom) y = bottom - MinicraftImage.boxWidth; } } - // This needs to be in the Menu class, to have access to the private constructor and fields. public static class Builder { - private static final Point center = new Point(Screen.w/2, Screen.h/2); + private static final Point center = new Point(Screen.w / 2, Screen.h / 2); private Menu menu; private boolean setSelectable = false; private float padding = 1; - @NotNull private RelPos titlePos = RelPos.TOP; + @NotNull + private RelPos titlePos = RelPos.TOP; private boolean fullTitleColor = false, setTitleColor = false; private int titleCol = Color.YELLOW; - @NotNull private Point anchor = center; - @NotNull private RelPos menuPos = RelPos.CENTER; + @NotNull + private Point anchor = center; + @NotNull + private RelPos menuPos = RelPos.CENTER; private Dimension menuSize = null; private boolean searcherBar; - public Builder(boolean hasFrame, int entrySpacing, RelPos entryPos, ListEntry... entries) { this(hasFrame, entrySpacing, entryPos, Arrays.asList(entries)); } + public Builder(boolean hasFrame, int entrySpacing, RelPos entryPos, ListEntry... entries) { + this(hasFrame, entrySpacing, entryPos, Arrays.asList(entries)); + } + public Builder(boolean hasFrame, int entrySpacing, RelPos entryPos, List entries) { menu = new Menu(); setEntries(entries); @@ -438,7 +474,10 @@ public Builder(boolean hasFrame, int entrySpacing, RelPos entryPos, List entries) { menu.entries.clear(); menu.entries.addAll(entries); @@ -451,8 +490,15 @@ public Builder setPositioning(Point anchor, RelPos menuPos) { return this; } - public Builder setSize(int width, int height) { menuSize = new Dimension(width, height); return this; } - public Builder setMenuSize(Dimension d) { menuSize = d; return this; } // can be used to set the size to null + public Builder setSize(int width, int height) { + menuSize = new Dimension(width, height); + return this; + } + + public Builder setMenuSize(Dimension d) { + menuSize = d; + return this; + } // can be used to set the size to null public Builder setBounds(Rectangle rect) { menuSize = rect.getSize(); @@ -460,20 +506,32 @@ public Builder setBounds(Rectangle rect) { return this; } - public Builder setDisplayLength(int numEntries) { menu.displayLength = numEntries; return this; } + public Builder setDisplayLength(int numEntries) { + menu.displayLength = numEntries; + return this; + } - public Builder setTitlePos(RelPos rp) { titlePos = (rp == null ? RelPos.TOP : rp); return this; } + public Builder setTitlePos(RelPos rp) { + titlePos = (rp == null ? RelPos.TOP : rp); + return this; + } - public Builder setTitle(String title) { menu.title = title; return this; } + public Builder setTitle(String title) { + menu.title = title; + return this; + } + + public Builder setTitle(String title, int color) { + return setTitle(title, color, false); + } - public Builder setTitle(String title, int color) { return setTitle(title, color, false); } public Builder setTitle(String title, int color, boolean fullColor) { menu.title = title; fullTitleColor = fullColor; setTitleColor = true; - if(fullColor) // this means that the color is the full 4 parts, abcd. Otherwise, it is assumed it is only the main component, the one that matters. + if (fullColor) // this means that the color is the full 4 parts, abcd. Otherwise, it is assumed it is only the main component, the one that matters. menu.titleColor = color; else titleCol = color; @@ -481,7 +539,10 @@ public Builder setTitle(String title, int color, boolean fullColor) { return this; } - public Builder setFrame(boolean hasFrame) { menu.hasFrame = hasFrame; return this; } + public Builder setFrame(boolean hasFrame) { + menu.hasFrame = hasFrame; + return this; + } public Builder setScrollPolicies(float padding, boolean wrap) { @@ -490,7 +551,10 @@ public Builder setScrollPolicies(float padding, boolean wrap) { return this; } - public Builder setShouldRender(boolean render) { menu.shouldRender = render; return this; } + public Builder setShouldRender(boolean render) { + menu.shouldRender = render; + return this; + } public Builder setSelectable(boolean selectable) { setSelectable = true; @@ -498,7 +562,11 @@ public Builder setSelectable(boolean selectable) { return this; } - public Builder setSelection(int sel) { menu.selection = sel; return this; } + public Builder setSelection(int sel) { + menu.selection = sel; + return this; + } + public Builder setSelection(int sel, int dispSel) { menu.selection = sel; menu.dispSelection = dispSel; @@ -515,17 +583,18 @@ public Menu createMenu() { // this way, I don't have to reference all the variables to a different var. return copy().createMenu(this); } + private Menu createMenu(Builder b) { - if(b == this) + if (b == this) return copy().createMenu(this); menu.title = Localization.getLocalized(menu.title); // set default selectability - if(!setSelectable) { - for(ListEntry entry: menu.entries) { + if (!setSelectable) { + for (ListEntry entry : menu.entries) { menu.selectable = menu.selectable || entry.isSelectable(); - if(menu.selectable) + if (menu.selectable) break; } } @@ -535,8 +604,8 @@ private Menu createMenu(Builder b) { menu.drawVertically = titlePos == RelPos.LEFT || titlePos == RelPos.RIGHT; Dimension titleDim = menu.drawVertically ? - new Dimension(Font.textHeight()*2, Font.textWidth(menu.title)) : - new Dimension(Font.textWidth(menu.title), Font.textHeight()*2); + new Dimension(Font.textHeight() * 2, Font.textWidth(menu.title)) : + new Dimension(Font.textWidth(menu.title), Font.textHeight() * 2); // find the area used by the title and/or frame, that can't be used by the entries @@ -553,7 +622,7 @@ private Menu createMenu(Builder b) { */ Insets border; - if(menu.hasFrame) + if (menu.hasFrame) border = new Insets(MinicraftImage.boxWidth); // add frame insets else { border = new Insets(); @@ -573,39 +642,38 @@ else if (c.xIndex == 2) // must be center right } } - if(menu.isSelectable()) { + if (menu.isSelectable()) { // add spacing for selection cursors border.left += MinicraftImage.boxWidth * 2; border.right += MinicraftImage.boxWidth * 2; } - if(menu.wrap && menu.displayLength > 0) + if (menu.wrap && menu.displayLength > 0) menu.displayLength = Math.min(menu.displayLength, menu.entries.size()); // I have anchor and menu's relative position to it, and may or may not have size. Dimension entrySize; - if(menuSize == null) { + if (menuSize == null) { int width = titleDim.width; - for(ListEntry entry: menu.entries) { + for (ListEntry entry : menu.entries) { int entryWidth = entry.getWidth(); - if(menu.isSelectable() && !entry.isSelectable()) + if (menu.isSelectable() && !entry.isSelectable()) entryWidth = Math.max(0, entryWidth - MinicraftImage.boxWidth * 4); width = Math.max(width, entryWidth); } - if(menu.displayLength > 0) { // has been set; use to determine entry bounds + if (menu.displayLength > 0) { // has been set; use to determine entry bounds int height = (ListEntry.getHeight() + menu.spacing) * menu.displayLength - menu.spacing; entrySize = new Dimension(width, height); - } - else { + } else { // no set size; just keep going to the edges of the screen int maxHeight; - if(menuPos.yIndex == 0) // anchor is lowest down coordinate (highest y value) + if (menuPos.yIndex == 0) // anchor is lowest down coordinate (highest y value) maxHeight = anchor.y; - else if(menuPos.yIndex == 2) + else if (menuPos.yIndex == 2) maxHeight = Screen.h - anchor.y; else // is centered; take the lowest value of the other two, and double it maxHeight = Math.min(anchor.y, Screen.h - anchor.y) * 2; @@ -620,13 +688,12 @@ else if(menuPos.yIndex == 2) } menuSize = border.addTo(entrySize); - } - else // menuSize was set manually + } else // menuSize was set manually entrySize = border.subtractFrom(menuSize); // set default max display length (needs size first) - if(menu.displayLength <= 0 && menu.entries.size() > 0) + if (menu.displayLength <= 0 && menu.entries.size() > 0) menu.displayLength = (entrySize.height + menu.spacing) / (ListEntry.getHeight() + menu.spacing); // based on the menu centering, and the anchor, determine the upper-left point from which to draw the menu. @@ -636,14 +703,14 @@ else if(menuPos.yIndex == 2) menu.titleLoc = titlePos.positionRect(titleDim, menu.bounds); - if(titlePos.xIndex == 0 && titlePos.yIndex != 1) + if (titlePos.xIndex == 0 && titlePos.yIndex != 1) menu.titleLoc.x += MinicraftImage.boxWidth; - if(titlePos.xIndex == 2 && titlePos.yIndex != 1) + if (titlePos.xIndex == 2 && titlePos.yIndex != 1) menu.titleLoc.x -= MinicraftImage.boxWidth; // set the menu title color - if(menu.title.length() > 0) { - if(fullTitleColor) + if (menu.title.length() > 0) { + if (fullTitleColor) menu.titleColor = titleCol; else { if (!setTitleColor) titleCol = menu.hasFrame ? Color.YELLOW : Color.WHITE; @@ -651,9 +718,9 @@ else if(menuPos.yIndex == 2) } } - if(padding < 0) padding = 0; - if(padding > 1) padding = 1; - menu.padding = (int)Math.floor(padding * menu.displayLength / 2); + if (padding < 0) padding = 0; + if (padding > 1) padding = 1; + menu.padding = (int) Math.floor(padding * menu.displayLength / 2); menu.useSearcherBar = searcherBar; @@ -685,6 +752,6 @@ public Builder copy() { } public String toString() { - return title+"-Menu["+bounds+"]"; + return title + "-Menu[" + bounds + "]"; } } diff --git a/src/client/java/minicraft/screen/MultiplayerDisplay.java b/src/client/java/minicraft/screen/MultiplayerDisplay.java index c130957f8..3a2a1c68c 100644 --- a/src/client/java/minicraft/screen/MultiplayerDisplay.java +++ b/src/client/java/minicraft/screen/MultiplayerDisplay.java @@ -18,12 +18,14 @@ import minicraft.network.Analytics; import minicraft.util.Logging; -/** @deprecated As multiplayer mode removed. This class is not localized. */ +/** + * @deprecated As multiplayer mode removed. This class is not localized. + */ @Deprecated public class MultiplayerDisplay extends Display { private static final String domain = "https://playminicraft.com"; - private static final String apiDomain = domain+"/api"; + private static final String apiDomain = domain + "/api"; public static String savedIP = ""; public static String savedUUID = ""; @@ -48,15 +50,19 @@ private enum State { private State curState; - public MultiplayerDisplay() { this(true); } + public MultiplayerDisplay() { + this(true); + } + public MultiplayerDisplay(boolean pingSite) { - if(savedUUID == null) savedUUID = ""; - if(email == null) email = ""; - if(savedUsername == null) savedUsername = ""; + if (savedUUID == null) savedUUID = ""; + if (email == null) email = ""; + if (savedUsername == null) savedUsername = ""; - if(pingSite) - contactAccountServer(() -> {}); + if (pingSite) + contactAccountServer(() -> { + }); } private void contactAccountServer(Action sitePingCallback) { @@ -65,23 +71,23 @@ private void contactAccountServer(Action sitePingCallback) { Unirest.get(domain).asEmptyAsync(new Callback() { @Override public void completed(HttpResponse response) { - if(response.getStatus() == 200) + if (response.getStatus() == 200) online = true; else System.err.println("Warning: Minicraft site ping returned status code " + response.getStatus()); - if(savedUUID.length() > 0) { + if (savedUUID.length() > 0) { setWaitMessage("attempting log in"); fetchName(savedUUID); } - if(curState == State.ERROR) + if (curState == State.ERROR) return; // at this point, the game is online, and either the player could log in automatically, or has to enter their // email and password. - if(savedUsername.length() == 0 || savedUUID.length() == 0) + if (savedUsername.length() == 0 || savedUUID.length() == 0) curState = State.LOGIN; // the player must log in manually. else { typing = savedIP; @@ -93,8 +99,8 @@ public void completed(HttpResponse response) { @Override public void failed(UnirestException e) { - System.err.println("Website ping failed: "+e.getMessage()); - if(!e.getMessage().equalsIgnoreCase("connection reset by peer")) + System.err.println("Website ping failed: " + e.getMessage()); + if (!e.getMessage().equalsIgnoreCase("connection reset by peer")) e.printStackTrace(); cancelled(); } @@ -102,7 +108,7 @@ public void failed(UnirestException e) { @Override public void cancelled() { System.err.println("Website ping cancelled."); - if(savedUsername.length() == 0 || savedUUID.length() == 0) { + if (savedUsername.length() == 0 || savedUUID.length() == 0) { // couldn't validate username, and can't enter offline mode b/c there is no username setError("could not connect to playminicraft account server, but no login data saved; cannot enter offline mode.", false); return; @@ -117,7 +123,8 @@ public void cancelled() { } @Override - public void tick(InputHandler input) {} + public void tick(InputHandler input) { + } private void fetchName(String uuid) { Analytics.LoginAttempt.ping(); @@ -125,16 +132,16 @@ private void fetchName(String uuid) { HttpResponse response = null; try { - response = Unirest.post(apiDomain+"/fetch-name") - .field("uuid", savedUUID) - .asJson(); + response = Unirest.post(apiDomain + "/fetch-name") + .field("uuid", savedUUID) + .asJson(); } catch (UnirestException e) { e.printStackTrace(); } - if(response != null) { + if (response != null) { kong.unirest.json.JSONObject json = response.getBody().getObject(); - switch(json.getString("status")) { + switch (json.getString("status")) { case "error": setError("problem with saved login data; please exit and login again.", false); savedUUID = ""; @@ -161,9 +168,12 @@ public void setLoadingMessage(String msg) { loadingMessage = msg; } - public void setError(String msg) { setError(msg, true); } + public void setError(String msg) { + setError(msg, true); + } + private void setError(String msg, boolean overrideMenu) { - if(curState == State.ERROR) return; // keep original message + if (curState == State.ERROR) return; // keep original message this.curState = State.ERROR; errorMessage = msg; } @@ -172,31 +182,31 @@ private void setError(String msg, boolean overrideMenu) { public void render(Screen screen) { screen.clear(0); - switch(curState) { + switch (curState) { case ENTERIP: Font.drawCentered("Logged in as: " + savedUsername, screen, 6, Color.get(1, 102, 255, 102)); - if(!online) - Font.drawCentered("Offline mode: local servers only", screen, Screen.h/2 - Font.textHeight()*6, Color.get(1, 153, 153, 255)); + if (!online) + Font.drawCentered("Offline mode: local servers only", screen, Screen.h / 2 - Font.textHeight() * 6, Color.get(1, 153, 153, 255)); - Font.drawCentered("Enter ip address to connect to:", screen, Screen.h/2-Font.textHeight()*2-2, Color.get(1, 255)); - Font.drawCentered(typing, screen, Screen.h/2-Font.textHeight(), Color.get(1, 255, 255, 102)); + Font.drawCentered("Enter ip address to connect to:", screen, Screen.h / 2 - Font.textHeight() * 2 - 2, Color.get(1, 255)); + Font.drawCentered(typing, screen, Screen.h / 2 - Font.textHeight(), Color.get(1, 255, 255, 102)); - Font.drawCentered("Press Shift-Escape to logout", screen, Screen.h-Font.textHeight()*7, Color.get(1, 204)); + Font.drawCentered("Press Shift-Escape to logout", screen, Screen.h - Font.textHeight() * 7, Color.get(1, 204)); break; case LOGIN: String msg = "Enter email:"; - if(!typingEmail) + if (!typingEmail) msg = "Enter password:"; Font.drawCentered(msg, screen, Screen.h / 2 - 6, Color.WHITE); msg = typing; - if(!typingEmail) + if (!typingEmail) //noinspection ReplaceAllDot msg = msg.replaceAll(".", "."); Font.drawCentered(msg, screen, Screen.h / 2 + 6, (inputIsValid ? Color.get(1, 204) : Color.RED)); - if(!inputIsValid) { + if (!inputIsValid) { Font.drawCentered("field is blank", screen, Screen.h / 2 + 20, Color.RED); } @@ -206,7 +216,7 @@ public void render(Screen screen) { break; case WAITING: - Font.drawCentered(waitingMessage+ ellipsis.updateAndGet(), screen, Screen.h/2, Color.WHITE); + Font.drawCentered(waitingMessage + ellipsis.updateAndGet(), screen, Screen.h / 2, Color.WHITE); break; case LOADING: @@ -216,15 +226,15 @@ public void render(Screen screen) { case ERROR: //if(Updater.tickCount % 10 == 0) System.out.println("error message: " + errorMessage); - Font.drawCentered("Could not connect to server:", screen, Screen.h/2-6, Color.RED); - FontStyle style = new FontStyle(Color.get(1, 255, 51, 51)).setYPos(Screen.h/2+6); + Font.drawCentered("Could not connect to server:", screen, Screen.h / 2 - 6, Color.RED); + FontStyle style = new FontStyle(Color.get(1, 255, 51, 51)).setYPos(Screen.h / 2 + 6); Font.drawParagraph(errorMessage, screen, style, 1); //Font.drawCentered(errorMessage, screen, Screen.h/2+6, Color.get(1, 255, 51, 51)); break; } - if(curState == State.ENTERIP || curState == State.ERROR) { - Font.drawCentered("Press "+Game.input.getMapping("exit")+" to return", screen, Screen.h-Font.textHeight()*2, Color.GRAY); + if (curState == State.ENTERIP || curState == State.ERROR) { + Font.drawCentered("Press " + Game.input.getMapping("exit") + " to return", screen, Screen.h - Font.textHeight() * 2, Color.GRAY); } } } diff --git a/src/client/java/minicraft/screen/OnScreenKeyboardMenu.java b/src/client/java/minicraft/screen/OnScreenKeyboardMenu.java index 82deee31c..6d6f285dc 100644 --- a/src/client/java/minicraft/screen/OnScreenKeyboardMenu.java +++ b/src/client/java/minicraft/screen/OnScreenKeyboardMenu.java @@ -2,13 +2,16 @@ import com.studiohartman.jamepad.ControllerButton; import minicraft.core.Game; +import minicraft.core.Renderer; import minicraft.core.io.InputHandler; import minicraft.core.io.Sound; import minicraft.gfx.Dimension; import minicraft.gfx.Font; +import minicraft.gfx.MinicraftImage; import minicraft.gfx.Point; import minicraft.gfx.Rectangle; import minicraft.gfx.Screen; +import minicraft.gfx.SpriteLinker; import org.jetbrains.annotations.Nullable; import java.awt.Label; @@ -191,7 +194,7 @@ public void tick(InputHandler input) throws OnScreenKeyboardMenuTickActionComple // This is only controllable by controller. if (visible) { - VirtualKey[][] keys = shiftPressed? keysB: keysF; + VirtualKey[][] keys = shiftPressed ? keysB : keysF; if (input.buttonPressed(ControllerButton.A)) { // Select keys[y][x].press(); Sound.play("select"); // Lack of sounds. @@ -245,12 +248,13 @@ public void tick(InputHandler input) throws OnScreenKeyboardMenuTickActionComple public void setVisible(boolean visible) { if (this.visible != visible) { Rectangle rec = getBounds(); - translate(0, visible? -rec.getHeight(): rec.getHeight()); + translate(0, visible ? -rec.getHeight() : rec.getHeight()); this.visible = visible; } keyPressed = 0; } + public boolean isVisible() { return visible; } @@ -259,115 +263,43 @@ public boolean isVisible() { public void render(Screen screen) { super.render(screen); - BiConsumer colorPixel = (pos, color) -> { - if (pos < screen.pixels.length && pos > 0) - screen.pixels[pos] = color; - }; - Rectangle bounds = getBounds(); int width = bounds.getWidth(); int height = bounds.getHeight(); - int renderingTop = bounds.getTop(); - for (int x = 0; x < width; x++) { // Rendering background. - for (int y = 0; y < height; y++) { - colorPixel.accept(x + (y + renderingTop) * Screen.w, 0x1CFCFCF); - } - } - - for (int x = 0; x < width; x++) { // Rendering upper edge. - for (int y = 0; y < 2; y++) { - colorPixel.accept(x + (y + renderingTop) * Screen.w, 0x1EFEFEF); - } - } + int top = bounds.getTop(); + // Rendering background. + screen.fillRect(0, top, width, height, 0x1CFCFCF); + // Rendering upper edge. + screen.fillRect(0, top, width, 2, 0x1EFEFEF); final int keyHeight = 14; - VirtualKey[][] keys = shiftPressed? keysB: keysF; + final int keyWidth = 16; + VirtualKey[][] keys = shiftPressed ? keysB : keysF; + MinicraftImage sheet = Renderer.spriteLinker.getSheet(SpriteLinker.SpriteType.Gui, "osk"); for (int r = 0; r < keys.length; r++) { - final int defaultKeyWidth = 16; - int keyWidth = defaultKeyWidth; int totalLength = (keys[r].length * keyWidth); totalLength += keyWidth * 2 * (int) Stream.of(keys[r]).filter(k -> k == spaceBar).count(); totalLength += keyWidth * (int) Stream.of(keys[r]).filter(k -> k == shiftKey).count(); int xOffset = (Screen.w - totalLength) / 2; - int y = renderingTop + 2 + r * keyHeight; + int y = top + 2 + r * keyHeight; int x = xOffset; for (int c = 0; c < keys[r].length; c++) { VirtualKey key = keys[r][c]; - if (key == spaceBar) - keyWidth = defaultKeyWidth * 3; - else if (key == shiftKey) - keyWidth = defaultKeyWidth * 2; - else - keyWidth = defaultKeyWidth; int color = keyPressed > 0 && r == this.y && c == this.x? 0x1EFEFF0: 0x1FDFDFD; - if (key == backspace) { // Rendering the backspace. - // Rendering the cross. - colorPixel.accept(x + 1 + keyWidth/2 + (y + keyHeight/2) * Screen.w, color); - colorPixel.accept(x + 1 + keyWidth/2 + 1 + (y + keyHeight/2 + 1) * Screen.w, color); - colorPixel.accept(x + 1 + keyWidth/2 - 1 + (y + keyHeight/2 - 1) * Screen.w, color); - colorPixel.accept(x + 1 + keyWidth/2 + 1 + (y + keyHeight/2 - 1) * Screen.w, color); - colorPixel.accept(x + 1 + keyWidth/2 - 1 + (y + keyHeight/2 + 1) * Screen.w, color); - - // Rendering the upper base. - colorPixel.accept(x + 1 + keyWidth/2 - 3 + (y + keyHeight/2 - 3) * Screen.w, color); - colorPixel.accept(x + 1 + keyWidth/2 - 2 + (y + keyHeight/2 - 3) * Screen.w, color); - colorPixel.accept(x + 1 + keyWidth/2 - 1 + (y + keyHeight/2 - 3) * Screen.w, color); - colorPixel.accept(x + 1 + keyWidth/2 + (y + keyHeight/2 - 3) * Screen.w, color); - colorPixel.accept(x + 1 + keyWidth/2 + 1 + (y + keyHeight/2 - 3) * Screen.w, color); - colorPixel.accept(x + 1 + keyWidth/2 + 2 + (y + keyHeight/2 - 3) * Screen.w, color); - colorPixel.accept(x + 1 + keyWidth/2 + 3 + (y + keyHeight/2 - 3) * Screen.w, color); - - // Rendering the lower base. - colorPixel.accept(x + 1 + keyWidth/2 - 3 + (y + keyHeight/2 + 3) * Screen.w, color); - colorPixel.accept(x + 1 + keyWidth/2 - 2 + (y + keyHeight/2 + 3) * Screen.w, color); - colorPixel.accept(x + 1 + keyWidth/2 - 1 + (y + keyHeight/2 + 3) * Screen.w, color); - colorPixel.accept(x + 1 + keyWidth/2 + (y + keyHeight/2 + 3) * Screen.w, color); - colorPixel.accept(x + 1 + keyWidth/2 + 1 + (y + keyHeight/2 + 3) * Screen.w, color); - colorPixel.accept(x + 1 + keyWidth/2 + 2 + (y + keyHeight/2 + 3) * Screen.w, color); - colorPixel.accept(x + 1 + keyWidth/2 + 3 + (y + keyHeight/2 + 3) * Screen.w, color); - - // Rendering the left angle. - colorPixel.accept(x + 1 + keyWidth/2 - 4 + (y + keyHeight/2 - 2) * Screen.w, color); - colorPixel.accept(x + 1 + keyWidth/2 - 5 + (y + keyHeight/2 - 1) * Screen.w, color); - colorPixel.accept(x + 1 + keyWidth/2 - 6 + (y + keyHeight/2) * Screen.w, color); - colorPixel.accept(x + 1 + keyWidth/2 - 5 + (y + keyHeight/2 + 1) * Screen.w, color); - colorPixel.accept(x + 1 + keyWidth/2 - 4 + (y + keyHeight/2 + 2) * Screen.w, color); - - colorPixel.accept(x + 1 + keyWidth/2 + 4 + (y + keyHeight/2 - 3) * Screen.w, color); - colorPixel.accept(x + 1 + keyWidth/2 + 4 + (y + keyHeight/2 - 2) * Screen.w, color); - colorPixel.accept(x + 1 + keyWidth/2 + 4 + (y + keyHeight/2 - 1) * Screen.w, color); - colorPixel.accept(x + 1 + keyWidth/2 + 4 + (y + keyHeight/2) * Screen.w, color); - colorPixel.accept(x + 1 + keyWidth/2 + 4 + (y + keyHeight/2 + 1) * Screen.w, color); - colorPixel.accept(x + 1 + keyWidth/2 + 4 + (y + keyHeight/2 + 2) * Screen.w, color); - colorPixel.accept(x + 1 + keyWidth/2 + 4 + (y + keyHeight/2 + 3) * Screen.w, color); - } else if (key == shiftKey) { // Rendering "SYM". - Font.draw("S", screen, x + keyWidth/2 - 3 - defaultKeyWidth/2, y + keyHeight/2 - 3, color); - Font.draw("Y", screen, x + keyWidth/2 - 3, y + keyHeight/2 - 3, color); - Font.draw("M", screen, x + keyWidth/2 - 3 + defaultKeyWidth/2, y + keyHeight/2 - 3, color); - } else if (key == spaceBar) { // Rendering "underscore". - for (int i = 1; i < 19; i++) { - colorPixel.accept(x + keyWidth/2 + i - 9 + (y + keyHeight/2 + 2) * Screen.w, color); - } + if (key == backspace) { + screen.render(x, y, 0, 0, keyWidth , keyHeight , sheet, color); + } else if (key == shiftKey) { + screen.render(x, y, keyWidth , 0, keyWidth , keyHeight , sheet, color); + } else if (key == spaceBar) { + screen.render(x, y, 0, keyHeight, keyWidth , keyHeight , sheet, color); } else - Font.draw(String.valueOf(key.output), screen, x + keyWidth/2 - 3, y + keyHeight/2 - 3, color); - - for (int i = 0; i <= keyHeight; i++) { // Rendering left and right border. - colorPixel.accept(x + (y + i) * Screen.w, 0x1BCBCBC); - colorPixel.accept(x + keyWidth + (y + i) * Screen.w, 0x1BCBCBC); - } for (int i = 0; i <= keyWidth; i++) { // Rendering top and bottom border. - colorPixel.accept(x + i + y * Screen.w, 0x1BCBCBC); - colorPixel.accept(x + i + (y + keyHeight) * Screen.w, 0x1BCBCBC); - } + Font.draw(String.valueOf(key.output), screen, x + keyWidth / 2 - 3, y + keyHeight / 2 - 3, color); + + screen.drawRect(x, y, keyWidth, keyHeight, 0x1BCBCBC); // border if (this.x == c && this.y == r) { - color = keyPressed > 0? 0x1EFEFF0: 0x1DFDFE0; - for (int i = 1; i < keyHeight; i++) { // Rendering left and right border. - colorPixel.accept(x + 1 + (y + i) * Screen.w, color); - colorPixel.accept(x - 1 + keyWidth + (y + i) * Screen.w, color); - } for (int i = 1; i < keyWidth; i++) { // Rendering top and bottom border. - colorPixel.accept(x + i + (y + 1) * Screen.w, color); - colorPixel.accept(x + i + (y - 1 + keyHeight) * Screen.w, color); - } + color = keyPressed > 0 ? 0x1EFEFF0 : 0x1DFDFE0; + screen.drawRect(x + 1, y + 1, keyWidth - 2, keyHeight - 2, color); // border } x += keyWidth; @@ -375,6 +307,9 @@ else if (key == shiftKey) } } - public static class OnScreenKeyboardMenuTickActionCompleted extends RuntimeException {} - public static class OnScreenKeyboardMenuBackspaceButtonActed extends RuntimeException {} + public static class OnScreenKeyboardMenuTickActionCompleted extends RuntimeException { + } + + public static class OnScreenKeyboardMenuBackspaceButtonActed extends RuntimeException { + } } diff --git a/src/client/java/minicraft/screen/OptionsMainMenuDisplay.java b/src/client/java/minicraft/screen/OptionsMainMenuDisplay.java index 6182bf3e0..f01b53ef3 100644 --- a/src/client/java/minicraft/screen/OptionsMainMenuDisplay.java +++ b/src/client/java/minicraft/screen/OptionsMainMenuDisplay.java @@ -1,30 +1,53 @@ package minicraft.screen; import minicraft.core.Game; +import minicraft.core.io.FileHandler; +import minicraft.core.io.InputHandler; import minicraft.core.io.Settings; import minicraft.saveload.Save; import minicraft.screen.entry.SelectEntry; +import java.util.ArrayList; + public class OptionsMainMenuDisplay extends Display { + private final boolean prevHwaValue = (boolean) Settings.get("hwa"); - public OptionsMainMenuDisplay() { - super(true, new Menu.Builder(false, 6, RelPos.LEFT, + public OptionsMainMenuDisplay() { + super(true, new Menu.Builder(false, 6, RelPos.LEFT, Settings.getEntry("fps"), Settings.getEntry("sound"), Settings.getEntry("showquests"), + Settings.getEntry("hwa"), new SelectEntry("minicraft.display.options_display.change_key_bindings", () -> Game.setDisplay(new KeyInputDisplay())), new SelectEntry("minicraft.displays.controls", () -> Game.setDisplay(new ControlsDisplay())), new SelectEntry("minicraft.display.options_display.language", () -> Game.setDisplay(new LanguageSettingsDisplay())), - Settings.getEntry("screenshot"), new SelectEntry("minicraft.display.options_display.resource_packs", () -> Game.setDisplay(new ResourcePackDisplay())) ) .setTitle("minicraft.displays.options_main_menu") .createMenu()); - } + } + + @Override + public void tick(InputHandler input) { + if (!prevHwaValue && (boolean) Settings.get("hwa") && FileHandler.OS.contains("windows") && input.inputPressed("EXIT")) { + ArrayList callbacks = new ArrayList<>(); + callbacks.add(new PopupDisplay.PopupActionCallback("SELECT", m -> { + Game.exitDisplay(2); + return true; + })); + Game.setDisplay(new PopupDisplay(new PopupDisplay.PopupConfig( + "minicraft.display.options_display.popup.hwa_warning.title", callbacks, 2), + "minicraft.display.options_display.popup.hwa_warning.content", + "minicraft.display.popup.escape_cancel", "minicraft.display.popup.enter_confirm")); + return; + } + + super.tick(input); + } - @Override - public void onExit() { - new Save(); - Game.MAX_FPS = (int) Settings.get("fps"); - } + @Override + public void onExit() { + new Save(); + Game.MAX_FPS = (int) Settings.get("fps"); + } } diff --git a/src/client/java/minicraft/screen/OptionsWorldDisplay.java b/src/client/java/minicraft/screen/OptionsWorldDisplay.java index 6a71e13d6..c297d1d52 100644 --- a/src/client/java/minicraft/screen/OptionsWorldDisplay.java +++ b/src/client/java/minicraft/screen/OptionsWorldDisplay.java @@ -1,6 +1,8 @@ package minicraft.screen; import minicraft.core.Game; +import minicraft.core.io.FileHandler; +import minicraft.core.io.InputHandler; import minicraft.core.io.Settings; import minicraft.gfx.Color; import minicraft.saveload.Save; @@ -15,6 +17,8 @@ import java.util.concurrent.Executors; public class OptionsWorldDisplay extends Display { + private final boolean prevHwaValue = (boolean) Settings.get("hwa"); + public OptionsWorldDisplay() { super(true); @@ -34,7 +38,8 @@ public OptionsWorldDisplay() { Game.exitDisplay(); try { Thread.sleep(50); - } catch (InterruptedException ignored) {} + } catch (InterruptedException ignored) { + } Game.exitDisplay(); }); return true; @@ -56,15 +61,33 @@ public OptionsWorldDisplay() { }; } + @Override + public void tick(InputHandler input) { + if (!prevHwaValue && (boolean) Settings.get("hwa") && FileHandler.OS.contains("windows") && input.inputPressed("EXIT")) { + ArrayList callbacks = new ArrayList<>(); + callbacks.add(new PopupDisplay.PopupActionCallback("SELECT", m -> { + Game.exitDisplay(2); + return true; + })); + Game.setDisplay(new PopupDisplay(new PopupDisplay.PopupConfig( + "minicraft.display.options_display.popup.hwa_warning.title", callbacks, 2), + "minicraft.display.options_display.popup.hwa_warning.content", + "minicraft.display.popup.escape_cancel", "minicraft.display.popup.enter_confirm")); + return; + } + + super.tick(input); + } + private List getEntries() { return new ArrayList<>(Arrays.asList(Settings.getEntry("diff"), Settings.getEntry("fps"), Settings.getEntry("sound"), Settings.getEntry("autosave"), + Settings.getEntry("hwa"), new SelectEntry("minicraft.display.options_display.change_key_bindings", () -> Game.setDisplay(new KeyInputDisplay())), new SelectEntry("minicraft.displays.controls", () -> Game.setDisplay(new ControlsDisplay())), new SelectEntry("minicraft.display.options_display.language", () -> Game.setDisplay(new LanguageSettingsDisplay())), - Settings.getEntry("screenshot"), new SelectEntry("minicraft.display.options_display.resource_packs", () -> Game.setDisplay(new ResourcePackDisplay())) )); } diff --git a/src/client/java/minicraft/screen/PauseDisplay.java b/src/client/java/minicraft/screen/PauseDisplay.java index 34a158d33..545f19b6a 100644 --- a/src/client/java/minicraft/screen/PauseDisplay.java +++ b/src/client/java/minicraft/screen/PauseDisplay.java @@ -21,10 +21,10 @@ public PauseDisplay() { String selectString = Localization.getLocalized("minicraft.displays.pause.display.help.choose", Game.input.getMapping("select")); ArrayList entries = new ArrayList<>(Arrays.asList( - new BlankEntry(), - new SelectEntry("minicraft.displays.pause.return", () -> Game.setDisplay(null)), - new SelectEntry("minicraft.display.options_display", () -> Game.setDisplay(new OptionsWorldDisplay())), - new SelectEntry("minicraft.displays.achievements", () -> Game.setDisplay(new AchievementsDisplay())) + new BlankEntry(), + new SelectEntry("minicraft.displays.pause.return", () -> Game.setDisplay(null)), + new SelectEntry("minicraft.display.options_display", () -> Game.setDisplay(new OptionsWorldDisplay())), + new SelectEntry("minicraft.displays.achievements", () -> Game.setDisplay(new AchievementsDisplay())) )); if (TutorialDisplayHandler.inQuests()) @@ -39,7 +39,7 @@ public PauseDisplay() { new SelectEntry("minicraft.displays.pause.menu", () -> { ArrayList items = new ArrayList<>(Arrays.asList(StringEntry.useLines("minicraft.displays.pause.display.exit_popup.0"))); - items.addAll(Arrays.asList(StringEntry.useLines(Color.RED, Localization.getLocalized("minicraft.displays.pause.display.exit_popup.1")))); + items.addAll(Arrays.asList(StringEntry.useLines(Color.RED, "minicraft.displays.pause.display.exit_popup.1"))); items.add(new BlankEntry()); items.add(new SelectEntry("minicraft.displays.pause.display.exit_popup.cancel", Game::exitDisplay)); items.add(new SelectEntry("minicraft.displays.pause.display.exit_popup.quit", () -> { @@ -52,8 +52,8 @@ public PauseDisplay() { new BlankEntry(), - new StringEntry(upString, Color.GRAY), - new StringEntry(selectString, Color.GRAY) + new StringEntry(upString, Color.GRAY, false), + new StringEntry(selectString, Color.GRAY, false) )); menus = new Menu[] { diff --git a/src/client/java/minicraft/screen/PlayDisplay.java b/src/client/java/minicraft/screen/PlayDisplay.java index c33e3ac0f..5b554151e 100644 --- a/src/client/java/minicraft/screen/PlayDisplay.java +++ b/src/client/java/minicraft/screen/PlayDisplay.java @@ -6,23 +6,25 @@ import minicraft.screen.entry.SelectEntry; import minicraft.screen.entry.StringEntry; -/** @deprecated This class is not used as this is replaced by an anonymous class in {@link TitleDisplay}. */ +/** + * @deprecated This class is not used as this is replaced by an anonymous class in {@link TitleDisplay}. + */ @Deprecated public class PlayDisplay extends Display { public PlayDisplay() { super(true, true, new Menu.Builder(false, 2, RelPos.CENTER, - new StringEntry("Game Mode", Color.YELLOW), - new BlankEntry(), - new BlankEntry(), - new SelectEntry("Singleplayer", () -> { - if (WorldSelectDisplay.getWorldNames().size() > 0) - Game.setDisplay(new Display(true, new Menu.Builder(false, 2, RelPos.CENTER, - new SelectEntry("Load World", () -> Game.setDisplay(new WorldSelectDisplay())), - new SelectEntry("New World", () -> Game.setDisplay(new WorldGenDisplay())) - ).createMenu())); - else Game.setDisplay(new WorldGenDisplay()); - }), - new SelectEntry("Multiplayer", () -> Game.setDisplay(new MultiplayerDisplay())) + new StringEntry("Game Mode", Color.YELLOW), + new BlankEntry(), + new BlankEntry(), + new SelectEntry("Singleplayer", () -> { + if (WorldSelectDisplay.getWorldNames().size() > 0) + Game.setDisplay(new Display(true, new Menu.Builder(false, 2, RelPos.CENTER, + new SelectEntry("Load World", () -> Game.setDisplay(new WorldSelectDisplay())), + new SelectEntry("New World", () -> Game.setDisplay(new WorldGenDisplay())) + ).createMenu())); + else Game.setDisplay(new WorldGenDisplay()); + }), + new SelectEntry("Multiplayer", () -> Game.setDisplay(new MultiplayerDisplay())) ).createMenu()); } } diff --git a/src/client/java/minicraft/screen/PlayerDeathDisplay.java b/src/client/java/minicraft/screen/PlayerDeathDisplay.java index c464334b2..1659592db 100644 --- a/src/client/java/minicraft/screen/PlayerDeathDisplay.java +++ b/src/client/java/minicraft/screen/PlayerDeathDisplay.java @@ -27,7 +27,7 @@ public PlayerDeathDisplay() { new BlankEntry() )); - if(!Game.isMode("minicraft.settings.mode.hardcore")) { + if (!Game.isMode("minicraft.settings.mode.hardcore")) { entries.add(new SelectEntry("minicraft.displays.player_death.respawn", () -> { World.resetGame(); Game.setDisplay(null); @@ -40,7 +40,7 @@ public PlayerDeathDisplay() { })); entries.add(new SelectEntry("minicraft.displays.player_death.quit", () -> Game.setDisplay(new TitleDisplay()))); - menus = new Menu[]{ + menus = new Menu[] { new Menu.Builder(true, 0, RelPos.LEFT, entries) .setPositioning(new Point(MinicraftImage.boxWidth, MinicraftImage.boxWidth * 3), RelPos.BOTTOM_RIGHT) .setTitle("minicraft.displays.player_death.title") diff --git a/src/client/java/minicraft/screen/PlayerInvDisplay.java b/src/client/java/minicraft/screen/PlayerInvDisplay.java index c152accc1..65373e58e 100644 --- a/src/client/java/minicraft/screen/PlayerInvDisplay.java +++ b/src/client/java/minicraft/screen/PlayerInvDisplay.java @@ -2,24 +2,31 @@ import com.studiohartman.jamepad.ControllerButton; import minicraft.core.Game; +import minicraft.core.Renderer; import minicraft.core.io.InputHandler; import minicraft.core.io.Localization; import minicraft.entity.mob.Player; import minicraft.gfx.Color; import minicraft.gfx.Font; +import minicraft.gfx.MinicraftImage; import minicraft.gfx.Point; +import minicraft.gfx.Rectangle; import minicraft.gfx.Screen; +import minicraft.gfx.SpriteLinker; import minicraft.item.Inventory; import minicraft.item.Item; import minicraft.item.Items; import minicraft.item.StackableItem; import minicraft.screen.entry.StringEntry; +import minicraft.util.Logging; public class PlayerInvDisplay extends Display { private static final int padding = 10; private final Player player; + private final MinicraftImage counterSheet = + Renderer.spriteLinker.getSheet(SpriteLinker.SpriteType.Gui, "inventory_counter"); private String itemDescription = ""; private Menu.Builder descriptionMenuBuilder; @@ -28,7 +35,7 @@ public class PlayerInvDisplay extends Display { private final Inventory creativeInv; public PlayerInvDisplay(Player player) { - super(new InventoryMenu(player, player.getInventory(), "minicraft.display.menus.inventory", RelPos.LEFT)); + menus = new Menu[] { new InventoryMenu(player, player.getInventory(), "minicraft.display.menus.inventory", RelPos.LEFT, this::update) }; this.player = player; descriptionMenuBuilder = new Menu.Builder(true, 3, RelPos.TOP_LEFT); creativeMode = Game.isMode("minicraft.settings.mode.creative"); @@ -41,16 +48,14 @@ public PlayerInvDisplay(Player player) { creativeInv = Items.getCreativeModeInventory(); menus = new Menu[] { menus[0], - new InventoryMenu(player, creativeInv, "minicraft.displays.player_inv.container_title.items", RelPos.RIGHT) {{ - creativeInv = true; - }}, + new InventoryMenu(player, creativeInv, "minicraft.displays.player_inv.container_title.items", RelPos.RIGHT, true), descriptionMenu }; menus[1].translate(menus[0].getBounds().getWidth() + padding, 0); update(); - if(menus[0].getNumOptions() == 0) onSelectionChange(0, 1); + if (menus[0].getNumOptions() == 0) onSelectionChange(0, 1); } else { creativeInv = null; menus = new Menu[] { menus[0], descriptionMenu }; @@ -93,14 +98,14 @@ public void tick(InputHandler input) { try { onScreenKeyboardMenu.tick(input); } catch (OnScreenKeyboardMenu.OnScreenKeyboardMenuTickActionCompleted | - OnScreenKeyboardMenu.OnScreenKeyboardMenuBackspaceButtonActed e) { + OnScreenKeyboardMenu.OnScreenKeyboardMenuBackspaceButtonActed e) { acted = true; } if (!acted) curMenu.tick(input); - if (input.getKey("menu").clicked) { // Should not listen button press. + if (input.getMappedKey("menu").isClicked()) { // Should not listen button press. Game.exitDisplay(); return; } @@ -129,22 +134,21 @@ public void tick(InputHandler input) { } from = player.getInventory(); - to = creativeInv; int fromSel = curMenu.getSelection(); Item fromItem = from.get(fromSel); boolean deleteAll; - if (input.getKey("SHIFT-D").clicked || input.buttonPressed(ControllerButton.Y)) { + if (input.getMappedKey("SHIFT-D").isClicked() || input.buttonPressed(ControllerButton.Y)) { deleteAll = true; - } else if (input.getKey("D").clicked || input.buttonPressed(ControllerButton.X)) { - deleteAll = !(fromItem instanceof StackableItem) || ((StackableItem)fromItem).count == 1; + } else if (input.getMappedKey("D").isClicked() || input.buttonPressed(ControllerButton.X)) { + deleteAll = !(fromItem instanceof StackableItem) || ((StackableItem) fromItem).count == 1; } else return; if (deleteAll) { from.remove(fromSel); } else { - ((StackableItem)fromItem).count--; // this is known to be valid. + ((StackableItem) fromItem).count--; // this is known to be valid. } update(); @@ -159,17 +163,19 @@ public void tick(InputHandler input) { Item fromItem = from.get(fromSel); boolean transferAll; - if (input.inputPressed("attack")) { // If stack limit is available, this can transfer whole stack - transferAll = !(fromItem instanceof StackableItem) || ((StackableItem)fromItem).count == 1; + if (input.getMappedKey("SHIFT-SELECT").isClicked()) { + transferAll = true; + } else if (input.inputPressed("SELECT")) { // If stack limit is available, this can transfer whole stack + transferAll = !(fromItem instanceof StackableItem); } else return; Item toItem = fromItem.copy(); + if (toItem instanceof StackableItem && transferAll) + ((StackableItem) toItem).count = ((StackableItem) toItem).maxCount; - if (!transferAll) { - ((StackableItem)toItem).count = 1; - } + if (to.add(toItem) != null) + Logging.PLAYER.trace("Item {} cannot be added to the player inventory because max slot reached.", toItem); - to.add(toSel, toItem); update(); } @@ -192,6 +198,64 @@ public void render(Screen screen) { super.render(screen); + if (selection == 0) { + // LHS is focused + Rectangle boundsLeft = menus[0].getBounds(); + int sizeLeft = player.getInventory().invSize(); + int capLeft = player.getInventory().getMaxSlots(); + // Expanded counter + if (sizeLeft < 10) { // At the moment at most just 2 digits and always 2 digits for capacity (no worry yet) + // Background + screen.render(boundsLeft.getRight() + 2 - (23 - 5), boundsLeft.getTop() - 3, + 12, 12, 3, 13, counterSheet); + // Skips the middle part as that is for more digits + screen.render(boundsLeft.getRight() + 2 - 15, boundsLeft.getTop() - 3, + 20, 12, 15, 13, counterSheet); + + // Digits + renderCounterNumber(screen, boundsLeft.getRight() + 2 - 16, boundsLeft.getTop() - 1, + 5, 5, 7, sizeLeft, colorByHeaviness(calculateHeaviness(sizeLeft, capLeft), true)); + renderCounterNumber(screen, boundsLeft.getRight() + 2 - 10, boundsLeft.getTop() + 3, + 0, 4, 5, capLeft, Color.GRAY); + } else { + // Background + screen.render(boundsLeft.getRight() + 2 - 23, boundsLeft.getTop() - 3, + 12, 12, 23, 13, counterSheet); + + // Digits + renderCounterNumber(screen, boundsLeft.getRight() + 2 - 21, boundsLeft.getTop() - 1, + 5, 5, 7, sizeLeft, colorByHeaviness(calculateHeaviness(sizeLeft, capLeft), true)); + renderCounterNumber(screen, boundsLeft.getRight() + 2 - 10, boundsLeft.getTop() + 3, + 0, 4, 5, capLeft, Color.GRAY); + } + } else if (creativeMode) { // assert selection == 1 + // LHS is not focused + Rectangle boundsLeft = menus[0].getBounds(); + int sizeLeft = player.getInventory().invSize(); + int capLeft = player.getInventory().getMaxSlots(); + // Minimized counter + if (sizeLeft < 10) { + // Background + screen.render(boundsLeft.getRight() - 4 - 8, boundsLeft.getTop() - 1, + 0, 12, 4, 9, counterSheet); + // Skips the middle part as that is for more digits + screen.render(boundsLeft.getRight() - 4 - 4, boundsLeft.getTop() - 1, + 8, 12, 4, 9, counterSheet); + + // Digits + renderCounterNumber(screen, boundsLeft.getRight() - 4 - 6, boundsLeft.getTop() + 1, + 0, 4, 5, sizeLeft, fadeColor(colorByHeaviness(calculateHeaviness(sizeLeft, capLeft), false))); + } else { + // Background + screen.render(boundsLeft.getRight() - 4 - 12, boundsLeft.getTop() - 1, + 0, 12, 12, 9, counterSheet); + + // Digits + renderCounterNumber(screen, boundsLeft.getRight() - 4 - 10, boundsLeft.getTop() + 1, + 0, 4, 5, sizeLeft, fadeColor(colorByHeaviness(calculateHeaviness(sizeLeft, capLeft), false))); + } + } + // Searcher help text String text = Localization.getLocalized("minicraft.displays.player_inv.display.help", Game.input.getMapping("SEARCHER-BAR")); Font.draw(text, screen, selection == 0 ? 12 : Screen.w - 12 - Font.textWidth(text), menus[creativeMode ? 2 : 1].getBounds().getBottom() + 8, Color.WHITE); @@ -200,6 +264,72 @@ public void render(Screen screen) { onScreenKeyboardMenu.render(screen); } + // xp, yp - x, y target pixel; ys - y source pixel; w, h - w, h of a digit sprite; n - number to render + private void renderCounterNumber(Screen screen, int xp, int yp, int ys, int w, int h, int n, int color) { + String display = String.valueOf(n); + for (int i = 0; i < display.length(); ++i) { + screen.render(xp + i * w, yp, w * (display.charAt(i) - '0'), ys, w, h, counterSheet, 0, color); + } + } + + // Gives a percentage of heaviness according to size and capacity. + // n <= cap && n >= 0 && cap > 0 + private float calculateHeaviness(int n, int cap) { + // Formula: -(x - 1)^2 + 1 # always positive as (co-)domain=[0,1] + float inner = (float) n / cap - 1; + return constrainDecimal(-(inner * inner) + 1); + } + + // Constrain any possible floating point calculation error causing potential issues + private float constrainDecimal(float val) { + if (val > 1) return 1; + if (val < 0) return 0; + return val; + } + + // Main color means more vibrant color, i.e. with greenness; else with whiteness instead + // Colors here are calculated as two phases as of the property of RGB space. + private int colorByHeaviness(float val, boolean main) { + if (main) { + if (val < .5) { + // From green (0) to yellow (.5) linearly + return ((int) (val / .5F * 255) << 16) | 0x100FF00; + } else { + // From yellow (.5) to red (1) linearly + return ((int) ((1 - val) / .5F * 255) << 8) | 0x1FF0000; + } + } else { + if (val < .3) { + // From white (0) to yellow (.3) linearly + return (int) (val / .3F * 255) | 0x1FFFF00; + } else { + // From yellow (.3) to red (1) linearly + return ((int) ((1 - val) / .7F * 255) << 8) | 0x1FF0000; + } + } + } + + /** + * Fading required color on counter background. Counter background here is hardcoded as #2A3299 while + * fading alpha (opacity) of the color is hardcoded as 35%. + */ + private int fadeColor(int color) { + /* + * Z = X + (Y - X) * P # Source: https://stackoverflow.com/a/12228643 + * where Z: new color value, X: background, Y: overlay color value, P: overlay opacity + */ + final float P = .35F; + int r = (color >> 16) & 0xFF; + int g = (color >> 8) & 0xFF; + int b = color & 0xFF; + + // New color values + int nr = 0x2A + (int) ((r - 0x2A) * P); + int ng = 0x32 + (int) ((g - 0x32) * P); + int nb = 0x99 + (int) ((b - 0x99) * P); + return 0x1000000 | (nr << 16) | (ng << 8) | nb; + } + @Override protected void onSelectionChange(int oldSel, int newSel) { super.onSelectionChange(oldSel, newSel); @@ -208,24 +338,27 @@ protected void onSelectionChange(int oldSel, int newSel) { if (selection == 0) menus[1].shouldRender = false; else menus[1].shouldRender = true; - if(oldSel == newSel) return; // this also serves as a protection against access to menus[0] when such may not exist. + if (oldSel == newSel) + return; // this also serves as a protection against access to menus[0] when such may not exist. int shift = 0; - if(newSel == 0) shift = padding - menus[0].getBounds().getLeft(); - if(newSel == 1) shift = (Screen.w - padding) - menus[1].getBounds().getRight(); + if (newSel == 0) shift = padding - menus[0].getBounds().getLeft(); + if (newSel == 1) shift = (Screen.w - padding) - menus[1].getBounds().getRight(); menus[0].translate(shift, 0); menus[1].translate(shift, 0); - if (newSel == 0) descriptionMenuBuilder.setPositioning(new Point(padding, menus[0].getBounds().getBottom() + 8), RelPos.BOTTOM_RIGHT); - if (newSel == 1) descriptionMenuBuilder.setPositioning(new Point(Screen.w - padding, menus[1].getBounds().getBottom() + 8), RelPos.BOTTOM_LEFT); + if (newSel == 0) + descriptionMenuBuilder.setPositioning(new Point(padding, menus[0].getBounds().getBottom() + 8), RelPos.BOTTOM_RIGHT); + if (newSel == 1) + descriptionMenuBuilder.setPositioning(new Point(Screen.w - padding, menus[1].getBounds().getBottom() + 8), RelPos.BOTTOM_LEFT); } } - private int getOtherIdx() { return (selection+1) % 2; } + private int getOtherIdx() { + return (selection + 1) % 2; + } private void update() { menus[0] = new InventoryMenu((InventoryMenu) menus[0]); - menus[1] = new InventoryMenu((InventoryMenu) menus[1]) {{ - creativeInv = true; - }}; + menus[1] = new InventoryMenu((InventoryMenu) menus[1]); menus[1].translate(menus[0].getBounds().getWidth() + padding, 0); onSelectionChange(0, selection); itemDescription = getDescription(); diff --git a/src/client/java/minicraft/screen/PopupDisplay.java b/src/client/java/minicraft/screen/PopupDisplay.java index 80142eeee..c156ca94f 100644 --- a/src/client/java/minicraft/screen/PopupDisplay.java +++ b/src/client/java/minicraft/screen/PopupDisplay.java @@ -12,17 +12,34 @@ import java.util.ArrayList; import java.util.stream.Stream; -/** Light-weighted exitable display with single menu. */ +/** + * Light-weighted exitable display with single menu. + */ public class PopupDisplay extends Display { // Using Color codes for coloring in title and plain text messages. private final ArrayList callbacks; - public PopupDisplay(@Nullable PopupConfig config, String... messages) { this(config, false, messages); } - public PopupDisplay(@Nullable PopupConfig config, boolean clearScreen, String... messages) { this(config, clearScreen, true, messages); } - public PopupDisplay(@Nullable PopupConfig config, boolean clearScreen, boolean menuFrame, String... messages) { this(config, clearScreen, menuFrame, StringEntry.useLines(messages)); } - public PopupDisplay(@Nullable PopupConfig config, ListEntry... entries) { this(config, false, entries); } - public PopupDisplay(@Nullable PopupConfig config, boolean clearScreen, ListEntry... entries) { this(config, clearScreen, true, entries); } + public PopupDisplay(@Nullable PopupConfig config, String... messages) { + this(config, false, messages); + } + + public PopupDisplay(@Nullable PopupConfig config, boolean clearScreen, String... messages) { + this(config, clearScreen, true, messages); + } + + public PopupDisplay(@Nullable PopupConfig config, boolean clearScreen, boolean menuFrame, String... messages) { + this(config, clearScreen, menuFrame, StringEntry.useLines(messages)); + } + + public PopupDisplay(@Nullable PopupConfig config, ListEntry... entries) { + this(config, false, entries); + } + + public PopupDisplay(@Nullable PopupConfig config, boolean clearScreen, ListEntry... entries) { + this(config, clearScreen, true, entries); + } + public PopupDisplay(@Nullable PopupConfig config, boolean clearScreen, boolean menuFrame, ListEntry... entries) { super(clearScreen, true); @@ -105,7 +122,7 @@ public void tick(InputHandler input) { private boolean tickCallbacks(InputHandler input) { if (callbacks != null) { for (PopupActionCallback callback : callbacks) { - if (callback.key == null || input.getKey(callback.key).clicked) { + if (callback.key == null || input.getMappedKey(callback.key).isClicked()) { if (callback.callback != null && callback.callback.acts(menus[0])) { // This overrides the original #tick check. return true; @@ -130,7 +147,7 @@ public static interface ActionCallback { * The callback acts when the key clicked. * @param key The key of the callback trigger. * @param callback The callback, when the return value is {@code true}, no more input check - * will be done. It continues if {@code false}. + * will be done. It continues if {@code false}. */ public PopupActionCallback(String key, ActionCallback callback) { this.key = key; diff --git a/src/client/java/minicraft/screen/QuestsDisplay.java b/src/client/java/minicraft/screen/QuestsDisplay.java index c871b79da..e185c58f7 100644 --- a/src/client/java/minicraft/screen/QuestsDisplay.java +++ b/src/client/java/minicraft/screen/QuestsDisplay.java @@ -1,5 +1,6 @@ package minicraft.screen; +import minicraft.core.CrashHandler; import minicraft.core.Game; import minicraft.core.Renderer; import minicraft.core.io.InputHandler; @@ -25,7 +26,10 @@ import org.json.JSONArray; import org.json.JSONObject; +import java.awt.image.BufferedImage; +import java.awt.image.DataBufferInt; import java.io.IOException; +import java.io.UncheckedIOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -37,7 +41,9 @@ import java.util.stream.Collectors; public class QuestsDisplay extends Display { - /** Unlocked but uncompleted. */ + /** + * Unlocked but uncompleted. + */ private final static HashSet displayableQuests = new HashSet<>(); // Temp set. Refreshed anytime. private final static HashSet series = new HashSet<>(); @@ -53,8 +59,6 @@ public class QuestsDisplay extends Display { e.printStackTrace(); Logging.QUEST.error("Failed to load quests."); } - - // TODO Localize this class } private static void loadQuestFile(@SuppressWarnings("SameParameterValue") String filename) throws IOException { @@ -256,20 +260,23 @@ public SeriesInformationDisplay(QuestSeries series) { super(false, true); ArrayList entries = new ArrayList<>(); - entries.add(series.isCompleted() ? new StringEntry("Status: Completed", Color.GREEN): - series.isUnlocked() ? new StringEntry("Status: Unlocked", Color.WHITE): - new StringEntry("Status: Locked", Color.GRAY) // Locked series would not been shown...? + entries.add(series.isCompleted() ? new StringEntry(Localization.getLocalized("minicraft.displays.quests.quest_info.display.status", + Localization.getLocalized("minicraft.displays.quests.quest_info.display.status.completed")), Color.GREEN, false) : + series.isUnlocked() ? new StringEntry(Localization.getLocalized("minicraft.displays.quests.quest_info.display.status", + Localization.getLocalized("minicraft.displays.quests.quest_info.display.status.unlocked")), Color.WHITE, false) : + new StringEntry(Localization.getLocalized("minicraft.displays.quests.quest_info.display.status", + Localization.getLocalized("minicraft.displays.quests.quest_info.display.status.locked")), Color.GRAY, false) // Locked series would not been shown...? ); - entries.add(new StringEntry("Quests completed: " + - series.getSeriesQuests().values().stream().filter(AdvancementElement::isCompleted).count())); - entries.addAll(Arrays.asList(StringEntry.useLines( - "Description: " + Localization.getLocalized(series.description)))); - entries.add(new StringEntry("Ongoing quests: " + - series.getSeriesQuests().values().stream().filter(AdvancementElement::isDisplayableAtStatus).count())); + entries.add(new StringEntry(Localization.getLocalized("minicraft.displays.quests.quest_info.display.quests_completed_count", + series.getSeriesQuests().values().stream().filter(AdvancementElement::isCompleted).count()), Color.WHITE, false)); + entries.addAll(Arrays.asList(StringEntry.useLines(Color.WHITE, false, + Localization.getLocalized("minicraft.displays.quests.quest_info.display.description", Localization.getLocalized(series.description))))); + entries.add(new StringEntry(Localization.getLocalized("minicraft.displays.quests.quest_info.display.ongoing_quests", + series.getSeriesQuests().values().stream().filter(AdvancementElement::isDisplayableAtStatus).count()), Color.WHITE, false)); entries.add(new BlankEntry()); - entries.add(new SelectEntry("View all quests of this series", () -> Game.setDisplay(new SeriesQuestViewerDisplay(series)))); + entries.add(new SelectEntry("minicraft.displays.quests.quest_info.view_quests", () -> Game.setDisplay(new SeriesQuestViewerDisplay(series)))); menus = new Menu[] { new Menu.Builder(true, 0, RelPos.CENTER) @@ -298,8 +305,9 @@ private static class SeriesQuestViewerDisplay extends Display { private final int rasterHeight; private final int rasterX; private final int rasterY; + private final MinicraftImage image; private final int[] rasterPixels; - private final Screen simulatedRasterScreen = new Screen() { + private final Screen simulatedRasterScreen = new Screen(new BufferedImage(Screen.w, Screen.h, BufferedImage.TYPE_INT_RGB)) { @Override public void render(int xp, int yp, int xt, int yt, int bits, MinicraftImage sheet, int whiteTint, boolean fullbright, int color) { if (sheet == null) return; // Verifying that sheet is not null. @@ -351,11 +359,11 @@ public void render(int xp, int yp, int xt, int yt, int bits, MinicraftImage shee public SeriesQuestViewerDisplay(QuestSeries series) { super(false, true); menus = new Menu[] { - new Menu.Builder(true, 0, RelPos.CENTER, StringEntry.useLines("minicrat.displays.quests", series.key)) - .setPositioning(new Point(Screen.w/2, 6), RelPos.BOTTOM) + new Menu.Builder(true, 0, RelPos.CENTER, StringEntry.useLines("minicraft.displays.quests", series.key)) + .setPositioning(new Point(Screen.w / 2, 6), RelPos.BOTTOM) .createMenu(), new Menu.Builder(true, 0, RelPos.CENTER) - .setPositioning(new Point(Screen.w/2, 40), RelPos.BOTTOM) + .setPositioning(new Point(Screen.w / 2, 40), RelPos.BOTTOM) .setSize(Screen.w - 16, Screen.h - 60) .createMenu() }; @@ -380,7 +388,7 @@ public SeriesQuestViewerDisplay(QuestSeries series) { }); while (childQuests.size() > 0) { - for (Iterator>> it = childQuests.entrySet().iterator(); it.hasNext();) { + for (Iterator>> it = childQuests.entrySet().iterator(); it.hasNext(); ) { Map.Entry> entry = it.next(); Quest parent = entry.getKey(); ArrayList questRow = questRowsList.stream().filter(quests1 -> quests1.contains(parent)).findAny().orElse(null); @@ -402,11 +410,11 @@ public SeriesQuestViewerDisplay(QuestSeries series) { int height = Font.textHeight(); for (int j = 0; j < questsTree[i].length; j++) { // x-axis int width = Font.textWidth(Localization.getLocalized(questsTree[i][j].key)); - treeDimensions[i][j] = new Rectangle(entryGap, entryGap, entryPadding*2 + width, entryPadding*2 + height, 0); + treeDimensions[i][j] = new Rectangle(entryGap, entryGap, entryPadding * 2 + width, entryPadding * 2 + height, 0); if (j > 0) - treeDimensions[i][j].translate(treeDimensions[i][j-1].getRight() + entryGap, 0); + treeDimensions[i][j].translate(treeDimensions[i][j - 1].getRight() + entryGap, 0); if (i > 0) - treeDimensions[i][j].translate(0, treeDimensions[i-1][0].getBottom() + entryGap*2); + treeDimensions[i][j].translate(0, treeDimensions[i - 1][0].getBottom() + entryGap * 2); } } } else { @@ -415,9 +423,10 @@ public SeriesQuestViewerDisplay(QuestSeries series) { } Rectangle menuBounds = menus[1].getBounds(); - rasterWidth = menuBounds.getWidth() - MinicraftImage.boxWidth*2; - rasterHeight = menuBounds.getHeight() - MinicraftImage.boxWidth*2; - rasterPixels = new int[rasterWidth * rasterHeight]; + rasterWidth = menuBounds.getWidth() - MinicraftImage.boxWidth * 2; + rasterHeight = menuBounds.getHeight() - MinicraftImage.boxWidth * 2; + image = new MinicraftImage(rasterWidth, rasterHeight); + rasterPixels = image.pixels; rasterX = menuBounds.getLeft() + MinicraftImage.boxWidth; rasterY = menuBounds.getTop() + MinicraftImage.boxWidth; } @@ -427,22 +436,22 @@ public void tick(InputHandler input) { super.tick(input); if (questsTree.length > 0) { - if (input.getKey("shift").down) { // Browsing mode. + if (input.getMappedKey("shift").isDown()) { // Browsing mode. inBrowsing = true; - if (input.getKey("shift-down").clicked) + if (input.getMappedKey("shift+cursor-down").isClicked()) yScroll += 3; - else if (input.getKey("shift-up").clicked) + else if (input.getMappedKey("shift+cursor-up").isClicked()) yScroll -= 3; - else if (input.getKey("shift-right").clicked) + else if (input.getMappedKey("shift+cursor-right").isClicked()) xScroll += 3; - else if (input.getKey("shift-left").clicked) + else if (input.getMappedKey("shift+cursor-left").isClicked()) xScroll -= 3; } else { if (inBrowsing) { scrollIfNeeded(); inBrowsing = false; } - if (input.getKey("cursor-down").clicked) { + if (input.getMappedKey("cursor-down").isClicked()) { if (cursorY < questsTree.length - 1) { cursorY++; if (cursorX >= questsTree[cursorY].length) @@ -450,7 +459,7 @@ else if (input.getKey("shift-left").clicked) Sound.play("select"); scrollIfNeeded(); } - } else if (input.getKey("cursor-up").clicked) { + } else if (input.getMappedKey("cursor-up").isClicked()) { if (cursorY > 0) { cursorY--; if (cursorX >= questsTree[cursorY].length) @@ -458,19 +467,19 @@ else if (input.getKey("shift-left").clicked) Sound.play("select"); scrollIfNeeded(); } - } else if (input.getKey("cursor-right").clicked) { + } else if (input.getMappedKey("cursor-right").isClicked()) { if (cursorX < questsTree[cursorY].length - 1) { cursorX++; Sound.play("select"); scrollIfNeeded(); } - } else if (input.getKey("cursor-left").clicked) { + } else if (input.getMappedKey("cursor-left").isClicked()) { if (cursorX > 0) { cursorX--; Sound.play("select"); scrollIfNeeded(); } - } else if (input.getKey("select").clicked) { + } else if (input.getMappedKey("select").isClicked()) { Sound.play("confirm"); Game.setDisplay(new QuestInformationDisplay(questsTree[cursorY][cursorX])); } @@ -497,27 +506,16 @@ public void render(Screen screen) { menu.render(screen); Arrays.fill(rasterPixels, Color.BLACK); renderRaster(); - final int xPadding = rasterX - 1; - final int yPadding = rasterY - 1; - for (int i = 0; i < rasterWidth + 2; i++) { - for (int j = 0; j < rasterHeight + 2; j++) { - final int pos = xPadding + i + (yPadding + j) * Screen.w; - if (i == 0 || i == rasterWidth + 1 || j == 0 || j == rasterHeight + 1) - screen.pixels[pos] = Color.WHITE; // Raster border. - else { - final int x = i - 1; // Also < rasterWidth. - final int y = j - 1; // Also < rasterHeight. - screen.pixels[pos] = rasterPixels[x + y * rasterWidth]; - } - } - } + // Border + screen.drawRect(rasterX - 1, rasterY - 1, rasterWidth + 2, rasterHeight + 2, Color.WHITE); + screen.render(rasterX, rasterY, 0, 0, rasterWidth, rasterHeight, image); } private void renderRaster() { if (questsTree.length == 0) { String text = Localization.getLocalized("minicraft.displays.quests.display.no_quest"); - Font.draw(text, simulatedRasterScreen, xScroll + rasterWidth/2 - Font.textWidth(text)/2, - yScroll + rasterHeight/2 - Font.textHeight()/2, Color.GRAY); + Font.draw(text, simulatedRasterScreen, xScroll + rasterWidth / 2 - Font.textWidth(text) / 2, + yScroll + rasterHeight / 2 - Font.textHeight() / 2, Color.GRAY); return; } @@ -586,6 +584,7 @@ private void renderRaster() { } } } + private void renderRasterPixel(int x, int y, int color) { x -= xScroll; y -= yScroll; @@ -611,9 +610,10 @@ void plotLineLow(int x0, int y0, int x1, int y1, IntPredicate yRange, int color) y = y + yi; D = D + (2 * (dy - dx)); } else - D = D + 2*dy; + D = D + 2 * dy; } } + void plotLineHigh(int x0, int y0, int x1, int y1, IntPredicate yRange, int color) { int dx = x1 - x0; int dy = y1 - y0; @@ -631,9 +631,10 @@ void plotLineHigh(int x0, int y0, int x1, int y1, IntPredicate yRange, int color x = x + xi; D = D + (2 * (dx - dy)); } else - D = D + 2*dx; + D = D + 2 * dx; } } + void plotLine(int x0, int y0, int x1, int y1, IntPredicate yRange, int color) { if (Math.abs(y1 - y0) < Math.abs(x1 - x0)) { if (x0 > x1) @@ -651,20 +652,23 @@ void plotLine(int x0, int y0, int x1, int y1, IntPredicate yRange, int color) { private static class QuestInformationDisplay extends Display { public QuestInformationDisplay(Quest quest) { super(false, true); - String state = quest.isCompleted() ? "Completed" : quest.isUnlocked() ? "Unlocked" : "Locked"; + String state = quest.isCompleted() ? "minicraft.displays.quests.quest_info.display.status.completed" : + quest.isUnlocked() ? "minicraft.displays.quests.quest_info.display.status.unlocked" : + "minicraft.displays.quests.quest_info.display.status.locked"; int color = quest.isCompleted() ? Color.GREEN : quest.isUnlocked() ? Color.WHITE : Color.GRAY; menus = new Menu[] { new Menu.Builder(true, 1, RelPos.CENTER) .setPositioning(new Point(Screen.w / 2, 5), RelPos.BOTTOM) - .setEntries(new StringEntry(Localization.getLocalized(quest.getSeries().key)), - new StringEntry(Localization.getLocalized(quest.key) + ": " + state, color), + .setEntries(new StringEntry(quest.getSeries().key), + new StringEntry(Localization.getLocalized(quest.key) + ": " + Localization.getLocalized(state), color, false), new StringEntry(quest.shouldAllCriteriaBeCompleted() ? - String.format("Progress: (%d/%d)", quest.getNumCriteriaCompleted(), quest.getTotalNumCriteria()) : - "Uncompleted")) + Localization.getLocalized("minicraft.displays.quests.quest_info.display.progress", + quest.getNumCriteriaCompleted(), quest.getTotalNumCriteria()) : + Localization.getLocalized("minicraft.displays.quests.quest_info.display.progress_uncompleted"), Color.WHITE, false)) .setSelectable(false) .createMenu(), new Menu.Builder(true, 2, RelPos.CENTER, - StringEntry.useLines(Localization.getLocalized(quest.description))) + StringEntry.useLines(quest.description)) .setPositioning(new Point(Screen.w / 2, 52), RelPos.BOTTOM) .setSelectable(false) .createMenu() @@ -678,7 +682,10 @@ public static HashSet getDisplayableQuests() { return new HashSet<>(displayableQuests); } - public static void resetGameQuests() { resetGameQuests(true); } + public static void resetGameQuests() { + resetGameQuests(true); + } + private static void resetGameQuests(boolean update) { series.forEach(AdvancementElement::reset); if (update) refreshDisplayableQuests(); @@ -701,7 +708,9 @@ public static void load(JSONObject json) { refreshDisplayableQuests(); } - /** Saving and writing all data into the given JSONObject. */ + /** + * Saving and writing all data into the given JSONObject. + */ public static void save(JSONObject json) { series.forEach(series1 -> { series1.save(json); @@ -724,9 +733,9 @@ public void tick(InputHandler input) { } if (menus[0].getCurEntry() != null) { - menus[3].setEntries(StringEntry.useLines(Localization.getLocalized(entrySeries[selectedEntry][menus[0].getSelection()].description))); + menus[3].setEntries(StringEntry.useLines(entrySeries[selectedEntry][menus[0].getSelection()].description)); } else { - menus[3].setEntries(StringEntry.useLines(Localization.getLocalized("minicraft.displays.quests.display.no_quest_desc"))); + menus[3].setEntries(StringEntry.useLines("minicraft.displays.quests.display.no_quest_desc")); } } @@ -734,11 +743,11 @@ private void updateEntries() { menus[0].setEntries(seriesEntries[selectedEntry]); String[] entryNames = new String[] { - "Unlocked", "Completed" + "minicraft.displays.quests.display.header.unlocked", "minicraft.displays.quests.display.header.completed" }; for (int i = 0; i < 2; i++) { - menus[i+1].updateEntry(0, new StringEntry(entryNames[i], (i == selectedEntry) ? Color.WHITE : Color.GRAY)); + menus[i + 1].updateEntry(0, new StringEntry(entryNames[i], (i == selectedEntry) ? Color.WHITE : Color.GRAY)); } int select = previousSelection; diff --git a/src/client/java/minicraft/screen/RecipeMenu.java b/src/client/java/minicraft/screen/RecipeMenu.java index 95420f532..8d18e32c3 100644 --- a/src/client/java/minicraft/screen/RecipeMenu.java +++ b/src/client/java/minicraft/screen/RecipeMenu.java @@ -12,10 +12,10 @@ private static RecipeEntry[] getAndSortRecipes(List recipes, Player play recipes.sort((r1, r2) -> { boolean craft1 = r1.checkCanCraft(player); boolean craft2 = r2.checkCanCraft(player); - if(craft1 == craft2) + if (craft1 == craft2) return 0; - if(craft1) return -1; - if(craft2) return 1; + if (craft1) return -1; + if (craft2) return 1; return 0; // should never actually be reached }); diff --git a/src/client/java/minicraft/screen/RelPos.java b/src/client/java/minicraft/screen/RelPos.java index 7c20c86b8..eb1f51021 100644 --- a/src/client/java/minicraft/screen/RelPos.java +++ b/src/client/java/minicraft/screen/RelPos.java @@ -15,7 +15,7 @@ public enum RelPos { // I think this way, the enums will all be constructed before this gets called, so there won't be any mishaps with number of values. static { - for(RelPos rp: RelPos.values()) { + for (RelPos rp : RelPos.values()) { int ord = rp.ordinal(); rp.xIndex = ord % 3; rp.yIndex = ord / 3; @@ -23,20 +23,23 @@ public enum RelPos { } public static RelPos getPos(int xIndex, int yIndex) { - return values()[MyUtils.clamp(xIndex, 0, 2) + MyUtils.clamp(yIndex, 0, 2)*3]; + return values()[MyUtils.clamp(xIndex, 0, 2) + MyUtils.clamp(yIndex, 0, 2) * 3]; } public RelPos getOpposite() { - int nx = -(xIndex-1) + 1; - int ny = -(yIndex-1) + 1; + int nx = -(xIndex - 1) + 1; + int ny = -(yIndex - 1) + 1; return getPos(nx, ny); } - /** positions the given rect around the given anchor. The double size is what aligns it to a point rather than a rect. */ + /** + * positions the given rect around the given anchor. The double size is what aligns it to a point rather than a rect. + */ public Point positionRect(Dimension rectSize, Point anchor) { - Rectangle bounds = new Rectangle(anchor.x, anchor.y, rectSize.width*2, rectSize.height*2, Rectangle.CENTER_DIMS); + Rectangle bounds = new Rectangle(anchor.x, anchor.y, rectSize.width * 2, rectSize.height * 2, Rectangle.CENTER_DIMS); return positionRect(rectSize, bounds); } + // the point is returned as a rectangle with the given dimension and the found location, within the provided dummy rectangle. public Rectangle positionRect(Dimension rectSize, Point anchor, Rectangle dummy) { Point pos = positionRect(rectSize, anchor); @@ -45,13 +48,15 @@ public Rectangle positionRect(Dimension rectSize, Point anchor, Rectangle dummy) return dummy; } - /** positions the given rect to a relative position in the container. */ + /** + * positions the given rect to a relative position in the container. + */ public Point positionRect(Dimension rectSize, Rectangle container) { Point tlcorner = container.getCenter(); // this moves the inner box correctly - tlcorner.x += ((xIndex -1) * container.getWidth() / 2) - (xIndex * rectSize.width / 2); - tlcorner.y += ((yIndex -1) * container.getHeight() / 2) - (yIndex * rectSize.height / 2); + tlcorner.x += ((xIndex - 1) * container.getWidth() / 2) - (xIndex * rectSize.width / 2); + tlcorner.y += ((yIndex - 1) * container.getHeight() / 2) - (yIndex * rectSize.height / 2); return tlcorner; } diff --git a/src/client/java/minicraft/screen/ResourcePackDisplay.java b/src/client/java/minicraft/screen/ResourcePackDisplay.java index e7fd1822a..6ca66a950 100644 --- a/src/client/java/minicraft/screen/ResourcePackDisplay.java +++ b/src/client/java/minicraft/screen/ResourcePackDisplay.java @@ -35,6 +35,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.io.UncheckedIOException; import java.net.MalformedURLException; import java.net.URISyntaxException; import java.net.URL; @@ -154,14 +155,20 @@ public class ResourcePackDisplay extends Display { defaultPack = Objects.requireNonNull(loadPackMetadata(defaultPackURL)); loadedPacks.add(defaultPack); try { - defaultLogo = new MinicraftImage(ImageIO.read(ResourcePackDisplay.class.getResourceAsStream("/resources/default_pack.png"))); + defaultLogo = MinicraftImage.createDefaultCompatible(ImageIO.read(Objects.requireNonNull(ResourcePackDisplay.class.getResourceAsStream("/resources/default_pack.png")))); } catch (IOException e) { CrashHandler.crashHandle(e); - throw new RuntimeException(); + throw new UncheckedIOException(e); + } catch (MinicraftImage.MinicraftImageDimensionIncompatibleException | NullPointerException e) { + CrashHandler.crashHandle(e); + //noinspection ProhibitedExceptionThrown + throw new RuntimeException(e); } } - /** Initializing the Display. */ + /** + * Initializing the Display. + */ public ResourcePackDisplay() { super(true, true); initPacks(); @@ -194,7 +201,8 @@ public ResourcePackDisplay() { @Override protected void onSelectionChange(int oldSel, int newSel) { super.onSelectionChange(oldSel, newSel); - if (oldSel == newSel) return; // this also serves as a protection against access to menus[0] when such may not exist. + if (oldSel == newSel) + return; // this also serves as a protection against access to menus[0] when such may not exist. menus[0].translate(-menus[0].getBounds().getLeft(), 0); menus[1].translate(Screen.w - menus[1].getBounds().getRight(), 0); if (newSel == 0) { @@ -206,7 +214,9 @@ protected void onSelectionChange(int oldSel, int newSel) { } } - /** Reloading the entries to refresh the current pack list. */ + /** + * Reloading the entries to refresh the current pack list. + */ private void reloadEntries() { entries0.clear(); // First list: unloaded. for (ResourcePack pack : resourcePacks) { // First list: all available resource packs. @@ -231,7 +241,9 @@ public int getColor(boolean isSelected) { } } - /** Applying the reloaded entries into the display. */ + /** + * Applying the reloaded entries into the display. + */ private void refreshEntries() { reloadEntries(); Menu[] newMenus = new Menu[] { @@ -247,11 +259,13 @@ private void refreshEntries() { menus = newMenus; - /* Translate position. */ - menus[selection ^ 1].translate(menus[selection].getBounds().getWidth() + padding, 0); + // Translate position. + onSelectionChange(selection ^ 1, selection); } - /** Watching the directory changes. Allowing hot-loading. */ + /** + * Watching the directory changes. Allowing hot-loading. + */ private class WatcherThread extends Thread implements Closeable { private WatchService watcher; private volatile Thread running = this; @@ -281,7 +295,7 @@ public void run() { @SuppressWarnings("unchecked") WatchEvent ev = (WatchEvent) event; - Path filename = ev.context(); + Path filename = ev.context(); try { urls.add(FOLDER_LOCATION.toPath().resolve(filename).toFile().toURI().toURL()); @@ -322,21 +336,7 @@ public void onExit() { @Override public void tick(InputHandler input) { // Overrides the default tick handler. - if (input.getKey("right").clicked) { // Move cursor to the second list. - if (selection == 0) { - Sound.play("select"); - onSelectionChange(0, 1); - } - - return; - } else if (input.getKey("left").clicked) { // Move cursor to the first list. - if (selection == 1) { - Sound.play("select"); - onSelectionChange(1, 0); - } - - return; - } else if (input.getKey("shift-right").clicked) { // Move the selected pack to the second list. + if (input.getMappedKey("shift+cursor-right").isClicked()) { // Move the selected pack to the second list. if (selection == 0 && resourcePacks.size() > 0) { loadedPacks.add(loadedPacks.indexOf(defaultPack), resourcePacks.remove(menus[0].getSelection())); changed = true; @@ -345,7 +345,7 @@ public void tick(InputHandler input) { } return; - } else if (input.getKey("shift-left").clicked) { // Move the selected pack to the first list. + } else if (input.getMappedKey("shift+cursor-left").isClicked()) { // Move the selected pack to the first list. if (selection == 1 && loadedPacks.get(menus[1].getSelection()) != defaultPack) { resourcePacks.add(loadedPacks.remove(menus[1].getSelection())); changed = true; @@ -354,7 +354,7 @@ public void tick(InputHandler input) { } return; - } else if (input.getKey("shift-up").clicked) { // Move up the selected pack in the second list. + } else if (input.getMappedKey("shift+cursor-up").isClicked()) { // Move up the selected pack in the second list. if (selection == 1 && menus[1].getSelection() > 0) { if (loadedPacks.get(menus[1].getSelection()) == defaultPack) return; // Default pack remains bottom. loadedPacks.add(menus[1].getSelection() - 1, loadedPacks.remove(menus[1].getSelection())); @@ -364,7 +364,7 @@ public void tick(InputHandler input) { } return; - } else if (input.getKey("shift-down").clicked) { // Move down the selected pack in the second list. + } else if (input.getMappedKey("shift+cursor-down").isClicked()) { // Move down the selected pack in the second list. if (selection == 1 && menus[1].getSelection() < loadedPacks.size() - 1) { if (loadedPacks.get(menus[1].getSelection() + 1) == defaultPack) return; // Default pack remains bottom. loadedPacks.add(menus[1].getSelection() + 1, loadedPacks.remove(menus[1].getSelection())); @@ -373,6 +373,20 @@ public void tick(InputHandler input) { Sound.play("select"); } + return; + } else if (input.getMappedKey("cursor-right").isClicked()) { // Move cursor to the second list. + if (selection == 0) { + Sound.play("select"); + onSelectionChange(0, 1); + } + + return; + } else if (input.getMappedKey("cursor-left").isClicked()) { // Move cursor to the first list. + if (selection == 1) { + Sound.play("select"); + onSelectionChange(1, 0); + } + return; } @@ -387,7 +401,8 @@ public void render(Screen screen) { Font.drawCentered(Localization.getLocalized("minicraft.displays.resource_packs.display.title"), screen, 6, Color.WHITE); // Info text at the bottom. - if (Game.input.anyControllerConnected()) Font.drawCentered(Localization.getLocalized("minicraft.displays.resource_packs.display.help.keyboard_needed"), screen, Screen.h - 33, Color.DARK_GRAY); + if (Game.input.anyControllerConnected()) + Font.drawCentered(Localization.getLocalized("minicraft.displays.resource_packs.display.help.keyboard_needed"), screen, Screen.h - 33, Color.DARK_GRAY); Font.drawCentered(Localization.getLocalized("minicraft.displays.resource_packs.display.help.move", Game.input.getMapping("cursor-down"), Game.input.getMapping("cursor-up")), screen, Screen.h - 25, Color.DARK_GRAY); Font.drawCentered(Localization.getLocalized("minicraft.displays.resource_packs.display.help.select", Game.input.getMapping("SELECT")), screen, Screen.h - 17, Color.DARK_GRAY); Font.drawCentered(Localization.getLocalized("minicraft.displays.resource_packs.display.help.position"), screen, Screen.h - 9, Color.DARK_GRAY); @@ -410,11 +425,15 @@ public void render(Screen screen) { } } - /** The object representation of resource pack. */ + /** + * The object representation of resource pack. + */ private static class ResourcePack implements Closeable { private URL packRoot; - /** 0 - before 2.2.0; 1 - 2.2.0-latest */ + /** + * 0 - before 2.2.0; 1 - 2.2.0-latest + */ @SuppressWarnings("unused") private final int packFormat; // The pack format of the pack. private final String name; // The name of the pack. @@ -432,14 +451,16 @@ private ResourcePack(URL packRoot, int packFormat, String name, String desc) { refreshPack(); } - /** This does not include metadata refresh. */ + /** + * This does not include metadata refresh. + */ public void refreshPack() { // Refresh pack logo.png. try { openStream(); InputStream in = getResourceAsStream("pack.png"); if (in != null) { - logo = new MinicraftImage(ImageIO.read(in)); + logo = MinicraftImage.createDefaultCompatible(ImageIO.read(in)); // Logo size verification. int h = logo.height; @@ -454,12 +475,12 @@ public void refreshPack() { } close(); - } catch (IOException | NullPointerException e) { + } catch (IOException | NullPointerException | MinicraftImage.MinicraftImageDimensionIncompatibleException e) { Logging.RESOURCEHANDLER_RESOURCEPACK.warn(e, "Unable to load logo in pack: {}, loading default logo instead.", name); if (this == defaultPack) { try { - logo = new MinicraftImage(ImageIO.read(getClass().getResourceAsStream("/resources/logo.png"))); - } catch (IOException e1) { + logo = new MinicraftImage(ImageIO.read(Objects.requireNonNull(getClass().getResourceAsStream("/resources/logo.png")))); + } catch (IOException | NullPointerException e1) { CrashHandler.crashHandle(e1); } } else logo = defaultLogo; @@ -480,7 +501,9 @@ private boolean openStream() { } } - /** Closing the stream of the zip file if opened. */ + /** + * Closing the stream of the zip file if opened. + */ @Override public void close() throws IOException { if (opened) { @@ -518,11 +541,11 @@ private static interface FilesFilter { // Literally functioned. @NotNull private ArrayList getFiles(String path, FilesFilter filter) { ArrayList paths = new ArrayList<>(); - for (Enumeration e = zipFile.entries(); e.hasMoreElements();) { + for (Enumeration e = zipFile.entries(); e.hasMoreElements(); ) { ZipEntry entry = e.nextElement(); Path parent; if ((parent = Paths.get(entry.getName()).getParent()) != null && parent.equals(Paths.get(path)) && - (filter == null || filter.check(Paths.get(entry.getName()), entry.isDirectory()))) { + (filter == null || filter.check(Paths.get(entry.getName()), entry.isDirectory()))) { paths.add(entry.getName()); } } @@ -564,7 +587,9 @@ public static ResourcePack loadPackMetadata(URL file) { return null; } - /** Intializing the packs from directory and loaded. */ + /** + * Intializing the packs from directory and loaded. + */ public static void initPacks() { // Generate resource packs folder if (FOLDER_LOCATION.mkdirs()) { @@ -573,7 +598,7 @@ public static void initPacks() { ArrayList urls = new ArrayList<>(); // Read and add the .zip file to the resource pack list. Only accept files ending with .zip or directory. - for (File file : Objects.requireNonNull(FOLDER_LOCATION.listFiles((dur, name) -> name.endsWith(".zip")))) { + for (File file : Objects.requireNonNull(FOLDER_LOCATION.listFiles((dur, name) -> name.endsWith(".zip")))) { try { urls.add(file.toPath().toUri().toURL()); } catch (MalformedURLException e) { @@ -650,7 +675,9 @@ private static void refreshResourcePacks(List urls) { resourcePacks.sort((p1, p2) -> p1.name.compareTo(p2.name)); } - /** Releasing the unloaded packs. */ + /** + * Releasing the unloaded packs. + */ public static void releaseUnloadedPacks() { resourcePacks.clear(); // Releases unloaded packs. } @@ -694,7 +721,9 @@ public static ArrayList getLoadedPacks() { return packs; } - /** Reloading all the resources with the currently packs to be loaded. */ + /** + * Reloading all the resources with the currently packs to be loaded. + */ @SuppressWarnings("unchecked") public static void reloadResources() { loadQuery.clear(); @@ -738,10 +767,18 @@ public static void reloadResources() { private static void loadTextures(ResourcePack pack) throws IOException { for (String t : pack.getFiles("assets/textures/", null)) { switch (t) { - case "assets/textures/entity/": loadTextures(pack, SpriteType.Entity); break; - case "assets/textures/gui/": loadTextures(pack, SpriteType.Gui); break; - case "assets/textures/item/": loadTextures(pack, SpriteType.Item); break; - case "assets/textures/tile/": loadTextures(pack, SpriteType.Tile); break; + case "assets/textures/entity/": + loadTextures(pack, SpriteType.Entity); + break; + case "assets/textures/gui/": + loadTextures(pack, SpriteType.Gui); + break; + case "assets/textures/item/": + loadTextures(pack, SpriteType.Item); + break; + case "assets/textures/tile/": + loadTextures(pack, SpriteType.Tile); + break; } } } @@ -755,10 +792,18 @@ private static void loadTextures(ResourcePack pack) throws IOException { private static void loadTextures(ResourcePack pack, SpriteType type) throws IOException { String path = "assets/textures/"; switch (type) { - case Entity: path += "entity/"; break; - case Gui: path += "gui/"; break; - case Item: path += "item/"; break; - case Tile: path += "tile/"; break; + case Entity: + path += "entity/"; + break; + case Gui: + path += "gui/"; + break; + case Item: + path += "item/"; + break; + case Tile: + path += "tile/"; + break; } ArrayList pngs = pack.getFiles(path, (p, isDir) -> p.toString().endsWith(".png") && !isDir); @@ -768,8 +813,9 @@ private static void loadTextures(ResourcePack pack, SpriteType type) throws IOEx try { JSONObject obj = new JSONObject(readStringFromInputStream(pack.getResourceAsStream(m))); SpriteLinker.SpriteMeta meta = new SpriteLinker.SpriteMeta(); - pngs.remove(m.substring(0, m.length() - 5)); - BufferedImage image = ImageIO.read(pack.getResourceAsStream(m.substring(0, m.length() - 5))); + String imgName = m.substring(0, m.length() - 5); + pngs.remove(imgName); + BufferedImage image = ImageIO.read(pack.getResourceAsStream(imgName)); // Applying animations. MinicraftImage sheet; @@ -779,9 +825,12 @@ private static void loadTextures(ResourcePack pack, SpriteType type) throws IOEx meta.frames = image.getHeight() / 16; if (meta.frames == 0) throw new IOException(new IllegalArgumentException(String.format( "Invalid frames 0 detected with {} in pack: {}", m, pack.name))); + validateImageAsset(pack, imgName, image, 16, 16 * meta.frames); sheet = new MinicraftImage(image, 16, 16 * meta.frames); - } else + } else { + validateImageAsset(pack, imgName, image, 16, 16); sheet = new MinicraftImage(image, 16, 16); + } Renderer.spriteLinker.setSprite(type, m.substring(path.length(), m.length() - 9), sheet); JSONObject borderObj = obj.optJSONObject("border"); @@ -792,7 +841,9 @@ private static void loadTextures(ResourcePack pack, SpriteType type) throws IOEx String borderK = path + meta.border + ".png"; pngs.remove(borderK); try { - Renderer.spriteLinker.setSprite(type, meta.border, new MinicraftImage(ImageIO.read(pack.getResourceAsStream(borderK)), 24, 24)); + BufferedImage img = ImageIO.read(pack.getResourceAsStream(borderK)); + validateImageAsset(pack, borderK, img, 24, 24); + Renderer.spriteLinker.setSprite(type, meta.border, new MinicraftImage(img, 24, 24)); } catch (IOException e) { Logging.RESOURCEHANDLER_RESOURCEPACK.warn(e, "Unable to read {} with {} in pack: {}", borderK, m, pack.name); meta.border = null; @@ -805,7 +856,9 @@ private static void loadTextures(ResourcePack pack, SpriteType type) throws IOEx String cornerK = path + meta.corner + ".png"; pngs.remove(cornerK); try { - Renderer.spriteLinker.setSprite(type, meta.corner, new MinicraftImage(ImageIO.read(pack.getResourceAsStream(cornerK)), 16, 16)); + BufferedImage img = ImageIO.read(pack.getResourceAsStream(cornerK)); + validateImageAsset(pack, cornerK, img, 16, 16); + Renderer.spriteLinker.setSprite(type, meta.corner, new MinicraftImage(img, 16, 16)); } catch (IOException e) { Logging.RESOURCEHANDLER_RESOURCEPACK.warn(e, "Unable to read {} with {} in pack: {}", cornerK, m, pack.name); meta.corner = null; @@ -827,10 +880,13 @@ private static void loadTextures(ResourcePack pack, SpriteType type) throws IOEx BufferedImage image = ImageIO.read(pack.getResourceAsStream(p)); MinicraftImage sheet; if (type == SpriteType.Item) { + validateImageAsset(pack, p, image, 8, 8); sheet = new MinicraftImage(image, 8, 8); // Set the minimum tile sprite size. } else if (type == SpriteType.Tile) { + validateImageAsset(pack, p, image, 16, 16); sheet = new MinicraftImage(image, 16, 16); // Set the minimum item sprite size. } else { + validateImageAsset(pack, p, image); sheet = new MinicraftImage(image); } @@ -841,6 +897,26 @@ private static void loadTextures(ResourcePack pack, SpriteType type) throws IOEx } } + private static void validateImageAsset(ResourcePack pack, String key, BufferedImage image) { + try { + MinicraftImage.validateImageDimension(image); + } catch (MinicraftImage.MinicraftImageDimensionIncompatibleException e) { + Logging.RESOURCEHANDLER_RESOURCEPACK.warn("Potentially incompatible image detected: {} in pack: {}: "+ + "image size ({}x{}) is not in multiple of 8.", key, pack.name, e.getWidth(), e.getHeight()); + } + } + + private static void validateImageAsset(ResourcePack pack, String key, BufferedImage image, int width, int height) { + validateImageAsset(pack, key, image); + try { + MinicraftImage.validateImageDimension(image, width, height); + } catch (MinicraftImage.MinicraftImageRequestOutOfBoundsException e) { + Logging.RESOURCEHANDLER_RESOURCEPACK.warn("Potentially incompatible image detected: {} in pack: {}: "+ + "image size ({}x{}) is smaller than the required ({}x{}).", key, pack.name, + e.getSourceWidth(), e.getSourceWidth(), e.getRequestedWidth(), e.getRequestedHeight()); + } + } + /** * Loading localization from the pack. * @param pack The pack to be loaded. @@ -889,15 +965,25 @@ private static void loadLocalization(ResourcePack pack) { * @param pack The pack to be loaded. */ private static void loadBooks(ResourcePack pack) { - for (String path : pack.getFiles("assets/books", (path, isDir) -> path.toString().endsWith(".txt") && !isDir)) { + for (String path : pack.getFiles("assets/books", (path, isDir) -> path.toString().endsWith(".txt") && !isDir)) { try { String book = BookData.loadBook(readStringFromInputStream(pack.getResourceAsStream(path))); switch (path) { - case "assets/books/about.txt": BookData.about = () -> book; break; - case "assets/books/credits.txt": BookData.credits = () -> book; break; - case "assets/books/instructions.txt": BookData.instructions = () -> book; break; - case "assets/books/antidous.txt": BookData.antVenomBook = () -> book; break; - case "assets/books/story_guide.txt": BookData.storylineGuide = () -> book; break; + case "assets/books/about.txt": + BookData.about = () -> book; + break; + case "assets/books/credits.txt": + BookData.credits = () -> book; + break; + case "assets/books/instructions.txt": + BookData.instructions = () -> book; + break; + case "assets/books/antidous.txt": + BookData.antVenomBook = () -> book; + break; + case "assets/books/game_guide.txt": + BookData.storylineGuide = () -> book; + break; } } catch (IOException e) { Logging.RESOURCEHANDLER_LOCALIZATION.debug(e, "Unable to load book: {} in pack : {}", path, pack.name); diff --git a/src/client/java/minicraft/screen/SignDisplay.java b/src/client/java/minicraft/screen/SignDisplay.java new file mode 100644 index 000000000..ce4459f11 --- /dev/null +++ b/src/client/java/minicraft/screen/SignDisplay.java @@ -0,0 +1,264 @@ +package minicraft.screen; + +import com.studiohartman.jamepad.ControllerButton; +import minicraft.core.Game; +import minicraft.core.io.ClipboardHandler; +import minicraft.core.io.InputHandler; +import minicraft.core.io.Localization; +import minicraft.gfx.Color; +import minicraft.gfx.Dimension; +import minicraft.gfx.Font; +import minicraft.gfx.MinicraftImage; +import minicraft.gfx.Point; +import minicraft.gfx.Rectangle; +import minicraft.gfx.Screen; +import minicraft.level.Level; +import minicraft.util.Logging; +import org.jetbrains.annotations.Nullable; + +import java.util.AbstractMap; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class SignDisplay extends Display { + public static final int MAX_TEXT_LENGTH = 20; + public static final int MAX_ROW_COUNT = 4; + + // TODO make this into an attached attribute of a sign tile. + private static final HashMap, List> signTexts = new HashMap<>(); // The lines of signs should be immutable when stored. + + public static void resetSignTexts() { + signTexts.clear(); + } + + public static void loadSignTexts(Map, List> signTexts) { + SignDisplay.signTexts.clear(); + signTexts.forEach((pt, texts) -> SignDisplay.signTexts.put(pt, Collections.unmodifiableList(new ArrayList<>(texts)))); + } + + public static Map, List> getSignTexts() { + return new HashMap<>(signTexts); + } + + public static void updateSign(int levelDepth, int x, int y, List lines) { + signTexts.put(new AbstractMap.SimpleImmutableEntry<>(levelDepth, new Point(x, y)), Collections.unmodifiableList(new ArrayList<>(lines))); + } + + public static void removeSign(int levelDepth, int x, int y) { + if (signTexts.remove(new AbstractMap.SimpleImmutableEntry<>(levelDepth, new Point(x, y))) == null) + Logging.WORLDNAMED.warn("Sign at ({}, {}) does not exist to be removed.", x, y); + } + + public static @Nullable List getSign(int levelDepth, int x, int y) { + return signTexts.get(new AbstractMap.SimpleImmutableEntry<>(levelDepth, new Point(x, y))); + } + + private final int levelDepth, x, y; + + private final SignEditor editor; + + public SignDisplay(Level level, int x, int y) { + super(false, new Menu.Builder(true, 3, RelPos.CENTER) + .setPositioning(new Point(Screen.w / 2, 6), RelPos.BOTTOM) + .setMenuSize(new Dimension(MinicraftImage.boxWidth * (MAX_TEXT_LENGTH + 2), MinicraftImage.boxWidth * (MAX_ROW_COUNT + 2))) + .setSelectable(false) + .createMenu()); + this.levelDepth = level.depth; + this.x = x; + this.y = y; + editor = new SignEditor(getSign(levelDepth, x, y)); + onScreenKeyboardMenu = OnScreenKeyboardMenu.checkAndCreateMenu(); + if (onScreenKeyboardMenu != null) + onScreenKeyboardMenu.setVisible(false); + } + + private class SignEditor { + private final ClipboardHandler clipboard = new ClipboardHandler(); + private final ArrayList rows = new ArrayList<>(); + private int cursorX = 0, cursorY = 0; + private int caretFrameCountDown = 60; + private boolean caretShown = true; + + public SignEditor(@Nullable List lines) { + if (lines != null) lines.forEach(l -> rows.add(new StringBuilder(l))); + while (rows.size() < MAX_ROW_COUNT) + rows.add(new StringBuilder()); + } + + public List getLines() { + return rows.stream().map(StringBuilder::toString).collect(Collectors.toList()); + } + + public void tick(InputHandler input) { + if (caretFrameCountDown-- == 0) { // Caret flashing animation + caretFrameCountDown = 30; + caretShown = !caretShown; + } + + insertChars(input.getKeysTyped(null)); + if (input.getMappedKey("PAGE-UP").isClicked()) { + cursorX = rows.get(cursorY = 0).length(); + updateCaretAnimation(); + } else if (input.getMappedKey("PAGE-DOWN").isClicked()) { + cursorX = rows.get(cursorY = rows.size() - 1).length(); + updateCaretAnimation(); + + } else if (input.getMappedKey("HOME").isClicked()) { + cursorX = 0; + updateCaretAnimation(); + } else if (input.getMappedKey("END").isClicked()) { + cursorX = rows.get(cursorY).length(); + updateCaretAnimation(); + + // Cursor navigating + // As lines are centered, the character above in rendering would not always be the one in indices. + // The position is set to the end of line when the cursor moved upward or downward. + } else if (input.inputPressed("CURSOR-UP")) { + cursorX = rows.get(cursorY == 0 ? cursorY = rows.size() - 1 : --cursorY).length(); + updateCaretAnimation(); + } else if (input.inputPressed("CURSOR-DOWN") || input.getMappedKey("ENTER").isClicked()) { + cursorX = rows.get(cursorY == rows.size() - 1 ? cursorY = 0 : ++cursorY).length(); + updateCaretAnimation(); + } else if (input.inputPressed("CURSOR-LEFT")) { + if (cursorX > 0) cursorX--; + updateCaretAnimation(); + } else if (input.inputPressed("CURSOR-RIGHT")) { + if (cursorX < rows.get(cursorY).length()) cursorX++; + updateCaretAnimation(); + + // Clipboard operations + } else if (input.getMappedKey("CTRL-X").isClicked()) { + cursorX = 0; + clipboard.setClipboardContents(rows.get(cursorY).toString()); + rows.set(cursorY, new StringBuilder()); + updateCaretAnimation(); + } else if (input.getMappedKey("CTRL-C").isClicked()) { + clipboard.setClipboardContents(rows.get(cursorY).toString()); + updateCaretAnimation(); + } else if (input.getMappedKey("CTRL-V").isClicked()) { + insertChars(clipboard.getClipboardContents()); + } + } + + public void render(Screen screen) { + Rectangle bounds = menus[0].getBounds(); + int yPos = bounds.getTop() + MinicraftImage.boxWidth; // Upper border + int centeredX = bounds.getLeft() + bounds.getWidth() / 2; + for (StringBuilder row : rows) { + Font.drawCentered(row.toString(), screen, yPos, Color.WHITE); + //noinspection SuspiciousNameCombination + yPos += MinicraftImage.boxWidth; + } + + // Cursor rendering + if (caretShown) { + int lineWidth = rows.get(cursorY).length() * MinicraftImage.boxWidth; + int displayX = cursorX * MinicraftImage.boxWidth; + int displayY = cursorY * MinicraftImage.boxWidth; + int lineBeginning = centeredX - lineWidth / 2; + int cursorX = lineBeginning + displayX; + int cursorY = bounds.getTop() + MinicraftImage.boxWidth + displayY; + if (this.cursorX == rows.get(this.cursorY).length()) { // Replace cursor + screen.drawLineSpecial(cursorX, cursorY + MinicraftImage.boxWidth - 1, 0, MinicraftImage.boxWidth); + } else { // Insert cursor + screen.drawLineSpecial(cursorX, cursorY, 1, MinicraftImage.boxWidth); + } + } + } + + private void updateCaretAnimation() { + caretShown = true; + caretFrameCountDown = 120; + } + + private void insertChars(String chars) { + chars = InputHandler.handleBackspaceChars(chars, true); // Reduce the number of unnecessary operations. + if (chars.isEmpty()) return; + updateCaretAnimation(); + for (int i = 0; i < chars.length(); i++) { + char c = chars.charAt(i); + if (!insertChar(c)) break; // Terminates the processing of characters if no more character can be proceeded. + } + } + + /** + * Inserts a character to be inserted at the current cursor position. Cursor position is handled when needed. + * This controls whether the procedure should be terminated depending on how the characters are handled. + * @param c A printable or line break (line feed) or backspace {@code \b} character to be inserted. Regex: {@code [\p{Print}\b\n]+} + * @return {@code true} if the char is handled and valid to be continuing processing the following chars; + * otherwise, the procedure of processing characters is terminated. + */ + private boolean insertChar(char c) { + if (c == '\b') { // Backspace + if (cursorX == 0) return true; // No effect; valid behaviour; handled + else { // cursorX > 0 + rows.get(cursorY).deleteCharAt(--cursorX); // Remove the char in front of the cursor. + } + + return true; // A backspace is always not limited by the line count limit, and it could reduce characters when appropriate. + } else if (c == '\n') { // Line break + return true; // No effect; the char is ignored; handled + } else { + // If the current line has spaces to expand, or else a new line would be required. + if (rows.get(cursorY).length() < MAX_TEXT_LENGTH) { + rows.get(cursorY).insert(cursorX++, c); + return true; + } else return false; // No more chars are accepted to expand at the current cursor position. + } + } + } + + OnScreenKeyboardMenu onScreenKeyboardMenu; + + @Override + public void render(Screen screen) { + super.render(screen); + Rectangle bounds = menus[0].getBounds(); + Font.drawCentered(Localization.getLocalized("Use SHIFT-ENTER to confirm input."), screen, bounds.getBottom() + 8, Color.GRAY); + editor.render(screen); + if (onScreenKeyboardMenu != null) + onScreenKeyboardMenu.render(screen); + } + + @Override + public void tick(InputHandler input) { + boolean acted = false; // Checks if typing action is needed to be handled. + boolean mainMethod = false; + if (onScreenKeyboardMenu == null || !onScreenKeyboardMenu.isVisible()) { + if (input.inputPressed("exit") || input.getMappedKey("SHIFT-ENTER").isClicked()) { + updateSign(levelDepth, x, y, editor.getLines()); + Game.exitDisplay(); + return; + } + + mainMethod = true; + } else { + try { + onScreenKeyboardMenu.tick(input); + } catch (OnScreenKeyboardMenu.OnScreenKeyboardMenuTickActionCompleted | + OnScreenKeyboardMenu.OnScreenKeyboardMenuBackspaceButtonActed e) { + acted = true; + } + + if (acted) + editor.tick(input); + + if (input.getMappedKey("exit").isClicked() || input.getMappedKey("SHIFT-ENTER").isClicked()) { // Should not listen button press + updateSign(levelDepth, x, y, editor.getLines()); + Game.exitDisplay(); + return; + } + + if (input.buttonPressed(ControllerButton.X)) { // Hide the keyboard. + onScreenKeyboardMenu.setVisible(!onScreenKeyboardMenu.isVisible()); + } + } + + if (mainMethod || !onScreenKeyboardMenu.isVisible()) + editor.tick(input); + } +} diff --git a/src/client/java/minicraft/screen/SignDisplayMenu.java b/src/client/java/minicraft/screen/SignDisplayMenu.java new file mode 100644 index 000000000..b5846b7ac --- /dev/null +++ b/src/client/java/minicraft/screen/SignDisplayMenu.java @@ -0,0 +1,50 @@ +package minicraft.screen; + +import minicraft.core.io.InputHandler; +import minicraft.gfx.Dimension; +import minicraft.gfx.MinicraftImage; +import minicraft.gfx.Point; +import minicraft.gfx.Screen; +import minicraft.level.Level; +import minicraft.screen.entry.StringEntry; +import minicraft.util.Logging; + +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +public class SignDisplayMenu extends Menu { + private final int levelDepth, x, y; + + public SignDisplayMenu(Level level, int x, int y) { + super(new Menu.Builder(true, 0, RelPos.CENTER) + .setPositioning(new Point(Screen.w / 2, 6), RelPos.BOTTOM) + .setMenuSize(new Dimension(MinicraftImage.boxWidth * (SignDisplay.MAX_TEXT_LENGTH + 2), MinicraftImage.boxWidth * (SignDisplay.MAX_ROW_COUNT + 2))) + .setDisplayLength(4) + .setSelectable(false) + .createMenu()); + this.levelDepth = level.depth; + this.x = x; + this.y = y; + List lines; + if ((lines = SignDisplay.getSign(levelDepth, x, y)) == null) { + lines = Collections.emptyList(); + Logging.WORLDNAMED.warn("Sign at ({}, {}) does not exist or has not initialized, but a display menu is invoked.", x, y); + } + setEntries(lines.stream().map(r -> new StringEntry(r, false)).collect(Collectors.toList())); + } + + /** Checks if this sign's coordinates differ from the given ones. */ + public boolean differsFrom(int levelDepth, int x, int y) { + return this.levelDepth != levelDepth || this.x != x || this.y != y; + } + + /** Checks if this sign's coordinates match the given ones. */ + public boolean matches(int levelDepth, int x, int y) { + return this.levelDepth == levelDepth && this.x == x && this.y == y; + } + + @Deprecated + @Override + public void tick(InputHandler input) {} // Render only +} diff --git a/src/client/java/minicraft/screen/SkinDisplay.java b/src/client/java/minicraft/screen/SkinDisplay.java index 40896cd5d..e19a80616 100644 --- a/src/client/java/minicraft/screen/SkinDisplay.java +++ b/src/client/java/minicraft/screen/SkinDisplay.java @@ -22,14 +22,11 @@ import javax.imageio.ImageIO; import javax.security.auth.DestroyFailedException; +import java.awt.image.BufferedImage; import java.io.File; import java.io.FileInputStream; import java.io.IOException; -import java.nio.file.FileSystems; -import java.nio.file.Path; -import java.nio.file.StandardWatchEventKinds; -import java.nio.file.WatchEvent; -import java.nio.file.WatchService; +import java.nio.file.*; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; @@ -69,7 +66,7 @@ public SkinDisplay() { new Menu.Builder(false, 2, RelPos.CENTER) .setDisplayLength(8) .setSelectable(true) - .setPositioning(new Point(Screen.w/2, Screen.h*3/5), RelPos.CENTER) + .setPositioning(new Point(Screen.w / 2, Screen.h * 3 / 5), RelPos.CENTER) .createMenu() ); @@ -137,7 +134,9 @@ public static void releaseSkins() { } } - /** Watching the directory changes. Allowing hot-loading. */ + /** + * Watching the directory changes. Allowing hot-loading. + */ private class WatcherThread extends Thread { private WatchService watcher; private volatile Thread running = this; @@ -195,13 +194,24 @@ private synchronized static void refreshSkinFiles(List files) { String skinPath = file.getName(); String name = skinPath.substring(0, skinPath.length() - 4); if (file.exists()) try { - MinicraftImage sheet = new MinicraftImage(ImageIO.read(new FileInputStream(file)), 64, 32); + BufferedImage img = ImageIO.read(Files.newInputStream(file.toPath())); + MinicraftImage.validateImageDimension(img); + MinicraftImage.validateImageDimension(img, 64, 32); + MinicraftImage sheet = new MinicraftImage(img, 64, 32); Renderer.spriteLinker.setSkin("skin." + name, sheet); skins.put(name, Mob.compileMobSpriteAnimations(0, 0, "skin." + name)); } catch (IOException e) { Logging.RESOURCEHANDLER_SKIN.error("Could not read image at path {}. The file is probably missing or formatted wrong.", skinPath); } catch (SecurityException e) { Logging.RESOURCEHANDLER_SKIN.error("Access to file located at {} was denied. Check if game is given permission.", skinPath); + } + catch (MinicraftImage.MinicraftImageRequestOutOfBoundsException e) { + Logging.RESOURCEHANDLER_SKIN.warn("Potentially incompatible image at {}:\n" + + "Source: width {}; height {}\nRequested: width {}; height {}", skinPath, + e.getSourceWidth(), e.getSourceHeight(), e.getRequestedWidth(), e.getRequestedHeight()); + } catch (MinicraftImage.MinicraftImageDimensionIncompatibleException e) { + Logging.RESOURCEHANDLER_SKIN.warn("Potentially incompatible image at {}:\n" + + "Source: width {}; height {}", skinPath, e.getWidth(), e.getHeight()); } else { Renderer.spriteLinker.setSkin("skin." + name, null); if (skins.containsKey(name)) for (LinkedSprite[] a : skins.remove(name)) { diff --git a/src/client/java/minicraft/screen/TempDisplay.java b/src/client/java/minicraft/screen/TempDisplay.java index 544177f82..acbc82517 100644 --- a/src/client/java/minicraft/screen/TempDisplay.java +++ b/src/client/java/minicraft/screen/TempDisplay.java @@ -4,45 +4,45 @@ import minicraft.util.MyUtils; public class TempDisplay extends Display { - + private int milliDelay; - + public TempDisplay(int milliDelay) { this.milliDelay = milliDelay; } - + public TempDisplay(int milliDelay, Menu... menus) { super(menus); this.milliDelay = milliDelay; } - + public TempDisplay(int milliDelay, boolean clearScreen) { super(clearScreen); this.milliDelay = milliDelay; } - + public TempDisplay(int milliDelay, boolean clearScreen, Menu... menus) { super(clearScreen, menus); this.milliDelay = milliDelay; } - + public TempDisplay(int milliDelay, boolean clearScreen, boolean canExit) { super(clearScreen, canExit); this.milliDelay = milliDelay; } - + public TempDisplay(int milliDelay, boolean clearScreen, boolean canExit, Menu... menus) { super(clearScreen, canExit, menus); this.milliDelay = milliDelay; } - + @Override public void init(Display parent) { super.init(parent); - + new Thread(() -> { MyUtils.sleep(milliDelay); - if(Game.getDisplay() == TempDisplay.this) + if (Game.getDisplay() == TempDisplay.this) Game.exitDisplay(); }).start(); } diff --git a/src/client/java/minicraft/screen/TitleDisplay.java b/src/client/java/minicraft/screen/TitleDisplay.java index 4fc688322..de083b95f 100644 --- a/src/client/java/minicraft/screen/TitleDisplay.java +++ b/src/client/java/minicraft/screen/TitleDisplay.java @@ -34,32 +34,32 @@ public class TitleDisplay extends Display { public TitleDisplay() { super(true, false, new Menu.Builder(false, 2, RelPos.CENTER, - new StringEntry("minicraft.displays.title.display.checking", Color.BLUE), - new BlankEntry(), - new SelectEntry("minicraft.displays.title.play", () -> { - if (WorldSelectDisplay.getWorldNames().size() > 0) - Game.setDisplay(new Display(true, new Menu.Builder(false, 2, RelPos.CENTER, - new SelectEntry("minicraft.displays.title.play.load_world", () -> Game.setDisplay(new WorldSelectDisplay())), - new SelectEntry("minicraft.displays.title.play.new_world", () -> Game.setDisplay(new WorldGenDisplay())) - ).createMenu())); - else Game.setDisplay(new WorldGenDisplay()); - }), - new SelectEntry("minicraft.display.options_display", () -> Game.setDisplay(new OptionsMainMenuDisplay())), - new SelectEntry("minicraft.displays.skin", () -> Game.setDisplay(new SkinDisplay())), - new SelectEntry("minicraft.displays.achievements", () -> Game.setDisplay(new AchievementsDisplay())), - new SelectEntry("minicraft.displays.title.help", () -> - Game.setDisplay(new Display(true, new Menu.Builder(false, 1, RelPos.CENTER, - new BlankEntry(), - new SelectEntry("minicraft.displays.title.help.instructions", () -> Game.setDisplay(new BookDisplay(BookData.instructions.collect()))), - new SelectEntry("minicraft.displays.title.help.storyline_guide", () -> Game.setDisplay(new BookDisplay(BookData.storylineGuide.collect()))), - new SelectEntry("minicraft.displays.title.help.about", () -> Game.setDisplay(new BookDisplay(BookData.about.collect()))), - new SelectEntry("minicraft.displays.title.help.credits", () -> Game.setDisplay(new BookDisplay(BookData.credits.collect()))) - ).setTitle("minicraft.displays.title.help").createMenu())) - ), - new SelectEntry("minicraft.displays.title.quit", Game::quit) + new StringEntry("minicraft.displays.title.display.checking", Color.BLUE), + new BlankEntry(), + new SelectEntry("minicraft.displays.title.play", () -> { + if (WorldSelectDisplay.getWorldNames().size() > 0) + Game.setDisplay(new Display(true, new Menu.Builder(false, 2, RelPos.CENTER, + new SelectEntry("minicraft.displays.title.play.load_world", () -> Game.setDisplay(new WorldSelectDisplay())), + new SelectEntry("minicraft.displays.title.play.new_world", () -> Game.setDisplay(new WorldGenDisplay())) + ).createMenu())); + else Game.setDisplay(new WorldGenDisplay()); + }), + new SelectEntry("minicraft.display.options_display", () -> Game.setDisplay(new OptionsMainMenuDisplay())), + new SelectEntry("minicraft.displays.skin", () -> Game.setDisplay(new SkinDisplay())), + new SelectEntry("minicraft.displays.achievements", () -> Game.setDisplay(new AchievementsDisplay())), + new SelectEntry("minicraft.displays.title.help", () -> + Game.setDisplay(new Display(true, new Menu.Builder(false, 1, RelPos.CENTER, + new BlankEntry(), + new SelectEntry("minicraft.displays.title.help.instructions", () -> Game.setDisplay(new BookDisplay(BookData.instructions.collect()))), + new SelectEntry("minicraft.displays.title.help.storyline_guide", () -> Game.setDisplay(new BookDisplay(BookData.storylineGuide.collect()))), + new SelectEntry("minicraft.displays.title.help.about", () -> Game.setDisplay(new BookDisplay(BookData.about.collect()))), + new SelectEntry("minicraft.displays.title.help.credits", () -> Game.setDisplay(new BookDisplay(BookData.credits.collect()))) + ).setTitle("minicraft.displays.title.help").createMenu())) + ), + new SelectEntry("minicraft.displays.title.quit", Game::quit) ) - .setPositioning(new Point(Screen.w/2, Screen.h*3/5), RelPos.CENTER) - .createMenu() + .setPositioning(new Point(Screen.w / 2, Screen.h * 3 / 5), RelPos.CENTER) + .createMenu() ); } @@ -81,17 +81,16 @@ public void init(Display parent) { World.levels = new Level[World.levels.length]; - if(Game.player == null) + if (Game.player == null) // Was online, need to reset player World.resetGame(false); } private void checkVersion() { VersionInfo latestVersion = Network.getLatestVersion(); - if(latestVersion == null) { + if (latestVersion == null) { Network.findLatestVersion(this::checkVersion); - } - else { + } else { if (latestVersion.version.compareTo(Game.VERSION, true) > 0) { menus[0].updateEntry(0, new StringEntry(Localization.getLocalized("minicraft.displays.title.display.new_version", latestVersion.releaseName), Color.GREEN)); menus[0].updateEntry(1, new LinkEntry(Color.CYAN, Localization.getLocalized("minicraft.displays.title.select_to_download"), latestVersion.releaseUrl, Localization.getLocalized("minicraft.displays.title.link_to_version", latestVersion.releaseUrl))); @@ -105,7 +104,7 @@ private void checkVersion() { @Override public void tick(InputHandler input) { - if (input.getKey("F3-r").clicked) rand = random.nextInt(splashes.length - 3) + 3; + if (input.getMappedKey("F3-r").isClicked()) rand = random.nextInt(splashes.length - 3) + 3; super.tick(input); } @@ -140,7 +139,7 @@ public void render(Screen screen) { /// This isn't as complicated as it looks. It just gets a color based off of count, which oscilates between 0 and 25. int bcol = 5 - count / 5; // This number ends up being between 1 and 5, inclusive. - int splashColor = isblue ? Color.BLUE : isRed ? Color.RED : isGreen ? Color.GREEN : Color.get(1, bcol*51, bcol*51, bcol*25); + int splashColor = isblue ? Color.BLUE : isRed ? Color.RED : isGreen ? Color.GREEN : Color.get(1, bcol * 51, bcol * 51, bcol * 25); Font.drawCentered(splashes[rand], screen, (Screen.h / 2) - 44, splashColor); diff --git a/src/client/java/minicraft/screen/TutorialDisplayHandler.java b/src/client/java/minicraft/screen/TutorialDisplayHandler.java index 06be9c594..84b9b3235 100644 --- a/src/client/java/minicraft/screen/TutorialDisplayHandler.java +++ b/src/client/java/minicraft/screen/TutorialDisplayHandler.java @@ -62,7 +62,7 @@ private static void loadTutorialElement(String criterionName, JSONObject json) { private static ControlGuide currentGuide = null; static { - controlGuides.add(new ControlGuide(120, "move-up|move-down|move-left|move-right", + controlGuides.add(new ControlGuide(300, "move-up|move-down|move-left|move-right", () -> Localization.getLocalized("minicraft.control_guide.move", String.format("%s|%s|%s|%s", Game.input.getMapping("move-up"), Game.input.getMapping("move-left"), Game.input.getMapping("move-down"), @@ -90,21 +90,18 @@ private ControlGuide(int duration, String key, Supplier display) { } private void tick() { - if (this.key.contains("|")) { - InputHandler.Key key = new InputHandler.Key(); - for (String keyposs: this.key.split("\\|")) { - InputHandler.Key aKey = Game.input.getKey(keyposs); - key.down = key.down || aKey.down; - key.clicked = key.clicked || aKey.clicked; + if (key.contains("|")) { + for (String k : key.split("\\|")) { + if (Game.input.inputDown(k)) interactedDuration++; } - - if (key.down) interactedDuration++; - } else if (Game.input.getKey(key).down) + } else if (Game.input.inputDown(key)) interactedDuration++; } } - /** Updating all data by the newly completed element. */ + /** + * Updating all data by the newly completed element. + */ public static void updateCompletedElement(TutorialElement element) { if (!element.isCompleted()) return; if (!(boolean) Settings.get("tutorials")) return; @@ -157,7 +154,7 @@ public static void turnOffTutorials() { currentOngoingElement = null; Settings.set("tutorials", false); Logging.TUTORIAL.debug("Tutorial completed."); - Game.notifications.add(Localization.getLocalized("minicraft.notification.tutorial_completed")); + Game.notifications.add(Localization.getLocalized("minicraft.notification.tutorials_completed")); } private static void turnOffGuides() { @@ -171,7 +168,7 @@ private static void turnOffGuides() { public static void tick(InputHandler input) { if (currentGuide != null) { if (ControlGuide.animation > 0) ControlGuide.animation--; - if (input.getKey("expandQuestDisplay").clicked) { + if (input.getMappedKey("expandQuestDisplay").isClicked()) { Logging.TUTORIAL.debug("Force-completed the guides."); turnOffGuides(); return; @@ -188,34 +185,35 @@ public static void tick(InputHandler input) { return; } - currentGuide.tick(); + if (Game.getDisplay() == null) + currentGuide.tick(); } if (currentOngoingElement != null) { - if (input.getKey("expandQuestDisplay").clicked && Game.getDisplay() == null) { + if (input.getMappedKey("expandQuestDisplay").isClicked() && Game.getDisplay() == null) { Game.setDisplay(new PopupDisplay(new PopupDisplay.PopupConfig(currentOngoingElement.key, null, 4), currentOngoingElement.description)); } } } - /** Rendering directly on the GUI/HUD. */ + /** + * Rendering directly on the GUI/HUD. + */ public static void render(Screen screen) { if (currentGuide != null) { // Is ongoing. - String[] lines = Font.getLines(Localization.getLocalized(currentGuide.display.get()), Screen.w, Screen.h, 0); + String[] lines = Font.getLines(currentGuide.display.get(), Screen.w, Screen.h, 0); if (ControlGuide.animation > 0) { int textWidth = Font.textWidth(lines); - int xPadding = Screen.w/2 - (textWidth + 8)/2; - int yPadding = Screen.h/2 - (lines.length * 8 + 8)/2; - int yPad = Screen.h/2 - (lines.length * 8)/2; - for (int i = 0; i < lines.length * 8 + 8; i++) { // Background. - for (int j = 0; j < textWidth + 8; j++) { - screen.pixels[xPadding + j + (yPadding + i) * Screen.w] = - i == 0 || i == lines.length * 8 + 7 || - j == 0 || j == textWidth + 7 ? Color.WHITE : Color.BLUE; - } - } + int xPadding = Screen.w / 2 - (textWidth + 8) / 2; + int yPadding = Screen.h / 2 - (lines.length * 8 + 8) / 2; + screen.fillRect(xPadding + 1, yPadding + 1, textWidth + 6, lines.length * 8 + 6, Color.BLUE); + screen.drawAxisLine(xPadding, yPadding, 0, textWidth + 8, Color.WHITE); // left border + screen.drawAxisLine(xPadding, yPadding + lines.length * 8 + 7, 0, textWidth + 8, Color.WHITE); // right border + screen.drawAxisLine(xPadding, yPadding, 1, lines.length * 8 + 8, Color.WHITE); // top border + screen.drawAxisLine(xPadding + lines.length * 8 + 7, yPadding, 1, lines.length * 8 + 8, Color.WHITE); // bottom border + int yPad = Screen.h/2 - (lines.length * 8)/2; for (int i = 0; i < lines.length; i++) { Font.drawCentered(lines[i], screen, yPad + 8 * i, Color.WHITE); } @@ -230,10 +228,8 @@ public static void render(Screen screen) { int length = bounds.getWidth() - 4; int bottom = bounds.getBottom() - 2; int left = bounds.getLeft() + 2; - for (int i = 0; i < length * currentGuide.interactedDuration / currentGuide.duration; i++) { - screen.pixels[left + i + bottom * Screen.w] = Color.WHITE; - screen.pixels[left + i + (bottom - 1) * Screen.w] = Color.WHITE; - } + screen.drawAxisLine(left, bottom, 0, length * currentGuide.interactedDuration / currentGuide.duration, Color.WHITE); + screen.drawAxisLine(left, bottom - 1, 0, length * currentGuide.interactedDuration / currentGuide.duration, Color.WHITE); } } else if (currentOngoingElement != null) { // Is ongoing. Menu menu = new Menu.Builder(true, 0, RelPos.RIGHT) @@ -245,9 +241,9 @@ public static void render(Screen screen) { Rectangle bounds = menu.getBounds(); String text = Localization.getLocalized("minicraft.displays.tutorial_display_handler.display.element_examine_help", Game.input.getMapping("expandQuestDisplay")); - String[] lines = Font.getLines(text, Screen.w*2/3, Screen.h, 0); + String[] lines = Font.getLines(text, Screen.w * 2 / 3, Screen.h, 0); for (int i = 0; i < lines.length; i++) - Font.draw(lines[i], screen, bounds.getRight() - Font.textWidth(lines[i]), bounds.getBottom() + 8 * (1+i), Color.GRAY); + Font.draw(lines[i], screen, bounds.getRight() - Font.textWidth(lines[i]), bounds.getBottom() + 8 * (1 + i), Color.GRAY); } } @@ -276,7 +272,9 @@ public static void load(JSONObject json) { if (currentOngoingElement != null) currentOngoingElement.update(); } - /** Saving and writing all data into the given JSONObject. */ + /** + * Saving and writing all data into the given JSONObject. + */ public static void save(JSONObject json) { if (currentOngoingElement != null) json.put("CurrentOngoingTutorial", currentOngoingElement.key); tutorialElements.forEach(element -> element.save(json)); diff --git a/src/client/java/minicraft/screen/WorldGenDisplay.java b/src/client/java/minicraft/screen/WorldGenDisplay.java index 660bccafb..63ca2735f 100644 --- a/src/client/java/minicraft/screen/WorldGenDisplay.java +++ b/src/client/java/minicraft/screen/WorldGenDisplay.java @@ -25,25 +25,26 @@ public class WorldGenDisplay extends Display { private static final Pattern detailedFilenamePattern; private static final String worldNameRegex; + static { if (FileHandler.OS.contains("windows")) { // Reference: https://stackoverflow.com/a/6804755 worldNameRegex = "[^<>:\"/\\\\|?*\\x00-\\x1F]+"; detailedFilenamePattern = Pattern.compile( - "# Match a valid Windows filename (unspecified file system). \n" + - "^ # Anchor to start of string. \n" + - "(?! # Assert filename is not: CON, PRN, \n" + - " (?: # AUX, NUL, COM1, COM2, COM3, COM4, \n" + - " CON|PRN|AUX|NUL| # COM5, COM6, COM7, COM8, COM9, \n" + - " COM[1-9]|LPT[1-9] # LPT1, LPT2, LPT3, LPT4, LPT5, \n" + - " ) # LPT6, LPT7, LPT8, and LPT9... \n" + - " (?:\\.[^.]*)? # followed by optional extension \n" + - " $ # and end of string \n" + - ") # End negative lookahead assertion. \n" + - "[^<>:\"/\\\\|?*\\x00-\\x1F]* # Zero or more valid filename chars.\n" + - "[^<>:\"/\\\\|?*\\x00-\\x1F\\ .] # Last char is not a space or dot. \n" + - "$ # Anchor to end of string. ", - Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE | Pattern.COMMENTS); + "# Match a valid Windows filename (unspecified file system). \n" + + "^ # Anchor to start of string. \n" + + "(?! # Assert filename is not: CON, PRN, \n" + + " (?: # AUX, NUL, COM1, COM2, COM3, COM4, \n" + + " CON|PRN|AUX|NUL| # COM5, COM6, COM7, COM8, COM9, \n" + + " COM[1-9]|LPT[1-9] # LPT1, LPT2, LPT3, LPT4, LPT5, \n" + + " ) # LPT6, LPT7, LPT8, and LPT9... \n" + + " (?:\\.[^.]*)? # followed by optional extension \n" + + " $ # and end of string \n" + + ") # End negative lookahead assertion. \n" + + "[^<>:\"/\\\\|?*\\x00-\\x1F]* # Zero or more valid filename chars.\n" + + "[^<>:\"/\\\\|?*\\x00-\\x1F\\ .] # Last char is not a space or dot. \n" + + "$ # Anchor to end of string. ", + Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE | Pattern.COMMENTS); } else if (FileHandler.OS.contains("mac")) { worldNameRegex = "[^/:]+"; detailedFilenamePattern = null; @@ -59,7 +60,7 @@ public static OptionalLong getSeed() { String seedStr = worldSeed.getUserInput(); // If there is no input seed, generate random number - if(seedStr.length() == 0) + if (seedStr.length() == 0) return OptionalLong.empty(); // If the seed is only numbers, just use numbers @@ -72,7 +73,7 @@ public static OptionalLong getSeed() { int len = seedStr.length(); for (int i = 0; i < len; i++) { - seed = 31*seed + seedStr.charAt(i); + seed = 31 * seed + seedStr.charAt(i); } return OptionalLong.of(seed); @@ -84,10 +85,10 @@ public static InputEntry makeWorldNameInput(String prompt, List takenNam @Override public boolean isValid() { - if(!super.isValid()) return false; + if (!super.isValid()) return false; String name = getUserInput(); - for(String other: takenNames) - if(other.equalsIgnoreCase(name)) { + for (String other : takenNames) + if (other.equalsIgnoreCase(name)) { if (!name.equals(lastName)) { Logging.WORLD.debug("Duplicated or existed world name \"{}\".", name); lastName = name; @@ -97,7 +98,7 @@ public boolean isValid() { } try { // Checking if the folder name is valid; - Paths.get(Game.gameDir+"/saves/"+name+"/"); + Paths.get(Game.gameDir + "/saves/" + name + "/"); } catch (InvalidPathException e) { if (!name.equals(lastName)) { Logging.WORLD.debug("Invalid world name (InvalidPathException) \"{}\": {}", name, e.getMessage()); @@ -129,8 +130,8 @@ public String getUserInput() { @Override public void render(Screen screen, int x, int y, boolean isSelected) { - super.render(screen, isGen? - (getUserInput().length() > 11? x - (getUserInput().length()-11) * 8: x): + super.render(screen, isGen ? + (getUserInput().length() > 11 ? x - (getUserInput().length() - 11) * 8 : x) : x, y, isSelected); } }; @@ -153,8 +154,8 @@ public int getColor(boolean isSelected) { HashSet controls = new HashSet<>(); controls.addAll(Arrays.asList(Game.input.getMapping("cursor-up").split("/"))); controls.addAll(Arrays.asList(Game.input.getMapping("cursor-down").split("/"))); - for (String key: controls) { - if(key.matches("^\\w$")) { + for (String key : controls) { + if (key.matches("^\\w$")) { nameHelp.setVisible(true); break; } @@ -162,7 +163,9 @@ public int getColor(boolean isSelected) { worldSeed = new InputEntry("minicraft.displays.world_gen.world_seed", "[-!\"#%/()=+,a-zA-Z0-9]+", 20) { @Override - public boolean isValid() { return true; } + public boolean isValid() { + return true; + } }; Menu mainMenu = @@ -173,7 +176,7 @@ public int getColor(boolean isSelected) { Settings.getEntry("scoretime"), new SelectEntry("minicraft.displays.world_gen.create_world", () -> { - if(!nameField.isValid()) return; + if (!nameField.isValid()) return; WorldSelectDisplay.setWorldName(nameField.getUserInput(), false); Game.setDisplay(new LoadingDisplay()); }) { diff --git a/src/client/java/minicraft/screen/WorldSelectDisplay.java b/src/client/java/minicraft/screen/WorldSelectDisplay.java index 82f47f654..83286a4f8 100644 --- a/src/client/java/minicraft/screen/WorldSelectDisplay.java +++ b/src/client/java/minicraft/screen/WorldSelectDisplay.java @@ -80,7 +80,7 @@ private void updateEntries() { public void tick(InputHandler input) { super.tick(input); - if (input.getKey("SHIFT-C").clicked || input.buttonPressed(ControllerButton.LEFTBUMPER)) { + if (input.getMappedKey("SHIFT-C").isClicked() || input.buttonPressed(ControllerButton.LEFTBUMPER)) { ArrayList entries = new ArrayList<>(); ArrayList names = WorldSelectDisplay.getWorldNames(); entries.add(new StringEntry("minicraft.displays.world_select.popups.display.change", Color.BLUE)); @@ -127,7 +127,7 @@ public void tick(InputHandler input) { })); Game.setDisplay(new PopupDisplay(new PopupDisplay.PopupConfig(null, callbacks, 0), entries.toArray(new ListEntry[0]))); - } else if (input.getKey("SHIFT-R").clicked || input.buttonPressed(ControllerButton.RIGHTBUMPER)) { + } else if (input.getMappedKey("SHIFT-R").isClicked() || input.buttonPressed(ControllerButton.RIGHTBUMPER)) { ArrayList entries = new ArrayList<>(); ArrayList names = WorldSelectDisplay.getWorldNames(); names.remove(worldName); @@ -173,7 +173,7 @@ public void tick(InputHandler input) { })); Game.setDisplay(new PopupDisplay(new PopupDisplay.PopupConfig(null, callbacks, 0), entries.toArray(new ListEntry[0]))); - } else if (input.getKey("SHIFT-D").clicked || input.leftTriggerPressed() && input.rightTriggerPressed()) { + } else if (input.getMappedKey("SHIFT-D").isClicked() || input.leftTriggerPressed() && input.rightTriggerPressed()) { ArrayList entries = new ArrayList<>(); entries.addAll(Arrays.asList(StringEntry.useLines(Color.RED, Localization.getLocalized("minicraft.displays.world_select.popups.display.delete", Color.toStringCode(Color.tint(Color.RED, 1, true)), worldNames.get(menus[0].getSelection()), @@ -230,7 +230,7 @@ public void render(Screen screen) { col = Color.RED; Font.drawCentered(Localization.getLocalized("minicraft.displays.world_select.display.world_too_new"), screen, Font.textHeight() * 5, col); } - Font.drawCentered(Localization.getLocalized("minicraft.displays.world_select.display.world_version", (version.compareTo(new Version("1.9.2")) <= 0 ? "~" : "") + version), screen, Font.textHeight() * 7/2, col); + Font.drawCentered(Localization.getLocalized("minicraft.displays.world_select.display.world_version", (version.compareTo(new Version("1.9.2")) <= 0 ? "~" : "") + version), screen, Font.textHeight() * 7 / 2, col); } Font.drawCentered(Localization.getLocalized("minicraft.displays.world_select.display.help.0", Game.input.getMapping("select")), screen, Screen.h - 60, Color.GRAY); @@ -287,13 +287,20 @@ public static void updateWorlds() { } } - public static String getWorldName() { return worldName; } + public static String getWorldName() { + return worldName; + } + public static void setWorldName(String world, boolean loaded) { worldName = world; loadedWorld = loaded; } - public static boolean hasLoadedWorld() { return loadedWorld; } + public static boolean hasLoadedWorld() { + return loadedWorld; + } - public static ArrayList getWorldNames() { return worldNames; } + public static ArrayList getWorldNames() { + return worldNames; + } } diff --git a/src/client/java/minicraft/screen/entry/ArrayEntry.java b/src/client/java/minicraft/screen/entry/ArrayEntry.java index e1b33dae2..1c540869a 100644 --- a/src/client/java/minicraft/screen/entry/ArrayEntry.java +++ b/src/client/java/minicraft/screen/entry/ArrayEntry.java @@ -20,10 +20,14 @@ public class ArrayEntry extends ListEntry { private ChangeListener changeAction; @SafeVarargs - public ArrayEntry(String label, T... options) { this(label, true, true, options); } + public ArrayEntry(String label, T... options) { + this(label, true, true, options); + } @SafeVarargs - public ArrayEntry(String label, boolean wrap, T... options) { this(label, wrap, true, options); } + public ArrayEntry(String label, boolean wrap, T... options) { + this(label, wrap, true, options); + } @SafeVarargs public ArrayEntry(String label, boolean wrap, boolean localize, T... options) { @@ -49,15 +53,25 @@ public void setValue(Object value) { setSelection(getIndex(value)); // if it is -1, setSelection simply won't set the value. } - protected String getLabel() { return label; } - protected String getLocalizationOption(T option) { return option.toString(); } + protected String getLabel() { + return label; + } + + protected String getLocalizationOption(T option) { + return option.toString(); + } + + public int getSelection() { + return selection; + } - public int getSelection() { return selection; } - public T getValue() { return options[selection]; } + public T getValue() { + return options[selection]; + } public boolean valueIs(Object value) { if (value instanceof String && options instanceof String[]) - return ((String)value).equalsIgnoreCase((String)getValue()); + return ((String) value).equalsIgnoreCase((String) getValue()); else return getValue().equals(value); } @@ -65,7 +79,7 @@ public boolean valueIs(Object value) { private int getIndex(Object value) { boolean areStrings = value instanceof String && options instanceof String[]; for (int i = 0; i < options.length; i++) { - if (areStrings && ((String)value).equalsIgnoreCase((String)options[i]) || options[i].equals(value)) { + if (areStrings && ((String) value).equalsIgnoreCase((String) options[i]) || options[i].equals(value)) { return i; } } @@ -85,7 +99,7 @@ public void setValueVisibility(Object value, boolean visible) { public boolean getValueVisibility(Object value) { int idx = getIndex(value); - if(idx < 0) return false; + if (idx < 0) return false; return optionVis[idx]; } @@ -96,14 +110,14 @@ public void tick(InputHandler input) { int selection = this.selection; if (this instanceof RangeEntry) { - if (input.inputPressed("cursor-left")) selection -= input.getKey("ALT").down ? 10 : 1; - if (input.inputPressed("cursor-right")) selection += input.getKey("ALT").down ? 10 : 1; + if (input.inputPressed("cursor-left")) selection -= input.getMappedKey("ALT").isDown() ? 10 : 1; + if (input.inputPressed("cursor-right")) selection += input.getMappedKey("ALT").isDown() ? 10 : 1; } else { if (input.inputPressed("cursor-left")) selection--; if (input.inputPressed("cursor-right")) selection++; } - if(prevSel != selection) { + if (prevSel != selection) { Sound.play("select"); moveSelection(selection - prevSel); } @@ -116,14 +130,14 @@ private void moveSelection(int dir) { do { selection += dir; - if(wrap) { + if (wrap) { selection = selection % options.length; - if(selection < 0) selection = options.length - 1; + if (selection < 0) selection = options.length - 1; } else { - selection = Math.min(selection, options.length-1); + selection = Math.min(selection, options.length - 1); selection = Math.max(0, selection); } - } while(!optionVis[selection] && selection != prevSel); + } while (!optionVis[selection] && selection != prevSel); setSelection(selection); } @@ -145,7 +159,7 @@ public String toString() { public void setChangeAction(ChangeListener l) { this.changeAction = l; - if(l != null) + if (l != null) l.onChange(getValue()); } } diff --git a/src/client/java/minicraft/screen/entry/BlankEntry.java b/src/client/java/minicraft/screen/entry/BlankEntry.java index 9f42b58ef..fcad07afc 100644 --- a/src/client/java/minicraft/screen/entry/BlankEntry.java +++ b/src/client/java/minicraft/screen/entry/BlankEntry.java @@ -11,10 +11,12 @@ public BlankEntry() { } @Override - public void tick(InputHandler input) {} + public void tick(InputHandler input) { + } @Override - public void render(Screen screen, int x, int y, boolean isSelected) {} + public void render(Screen screen, int x, int y, boolean isSelected) { + } @Override public int getWidth() { @@ -22,5 +24,7 @@ public int getWidth() { } @Override - public String toString() { return " "; } + public String toString() { + return " "; + } } diff --git a/src/client/java/minicraft/screen/entry/BooleanEntry.java b/src/client/java/minicraft/screen/entry/BooleanEntry.java index 0829bcd4a..ecafe488c 100644 --- a/src/client/java/minicraft/screen/entry/BooleanEntry.java +++ b/src/client/java/minicraft/screen/entry/BooleanEntry.java @@ -5,7 +5,7 @@ public class BooleanEntry extends ArrayEntry { public BooleanEntry(String label, boolean initial) { - super(label, true, new Boolean[] {true, false}); + super(label, true, new Boolean[] { true, false }); setSelection(initial ? 0 : 1); } diff --git a/src/client/java/minicraft/screen/entry/InputEntry.java b/src/client/java/minicraft/screen/entry/InputEntry.java index 0ca8aab3c..5dceb61e4 100644 --- a/src/client/java/minicraft/screen/entry/InputEntry.java +++ b/src/client/java/minicraft/screen/entry/InputEntry.java @@ -22,9 +22,11 @@ public class InputEntry extends ListEntry { public InputEntry(String prompt) { this(prompt, null, 0); } + public InputEntry(String prompt, String regex, int maxLen) { this(prompt, regex, maxLen, ""); } + public InputEntry(String prompt, String regex, int maxLen, String initValue) { this.prompt = prompt; this.regex = regex; @@ -42,21 +44,23 @@ public void tick(InputHandler input) { if (maxLength > 0 && userInput.length() > maxLength) userInput = userInput.substring(0, maxLength); // truncates extra - if (input.getKey("CTRL-V").clicked) { + if (input.getMappedKey("CTRL-V").isClicked()) { userInput = userInput + clipboardHandler.getClipboardContents(); } if (!userInput.equals("")) { - if (input.getKey("CTRL-C").clicked) { + if (input.getMappedKey("CTRL-C").isClicked()) { clipboardHandler.setClipboardContents(userInput); } - if (input.getKey("CTRL-X").clicked) { + if (input.getMappedKey("CTRL-X").isClicked()) { clipboardHandler.setClipboardContents(userInput); userInput = ""; } } } - public String getUserInput() { return userInput; } + public String getUserInput() { + return userInput; + } public String toString() { return Localization.getLocalized(prompt) + (prompt.length() == 0 ? "" : ": ") + userInput; diff --git a/src/client/java/minicraft/screen/entry/ItemEntry.java b/src/client/java/minicraft/screen/entry/ItemEntry.java index 4da6d2a48..cfc17d1c3 100644 --- a/src/client/java/minicraft/screen/entry/ItemEntry.java +++ b/src/client/java/minicraft/screen/entry/ItemEntry.java @@ -17,12 +17,17 @@ public static ItemEntry[] useItems(List items) { private Item item; - public ItemEntry(Item i) { this.item = i; } + public ItemEntry(Item i) { + this.item = i; + } - public Item getItem() { return item; } + public Item getItem() { + return item; + } @Override - public void tick(InputHandler input) {} + public void tick(InputHandler input) { + } @Override public void render(Screen screen, int x, int y, boolean isSelected) { diff --git a/src/client/java/minicraft/screen/entry/ItemListing.java b/src/client/java/minicraft/screen/entry/ItemListing.java index c123f849c..9150366c1 100644 --- a/src/client/java/minicraft/screen/entry/ItemListing.java +++ b/src/client/java/minicraft/screen/entry/ItemListing.java @@ -3,17 +3,19 @@ import minicraft.item.Item; public class ItemListing extends ItemEntry { - + private String info; - + public ItemListing(Item i, String text) { super(i); setSelectable(false); this.info = text; } - - public void setText(String text) { info = text; } - + + public void setText(String text) { + info = text; + } + @Override public String toString() { return " " + info; diff --git a/src/client/java/minicraft/screen/entry/KeyInputEntry.java b/src/client/java/minicraft/screen/entry/KeyInputEntry.java index c75fec687..2d362fe88 100644 --- a/src/client/java/minicraft/screen/entry/KeyInputEntry.java +++ b/src/client/java/minicraft/screen/entry/KeyInputEntry.java @@ -23,7 +23,7 @@ private void setMapping(String mapping, Set duplicated) { this.mapping = mapping; StringBuilder buffer = new StringBuilder(); - for (int spaces = 0; spaces < Screen.w/Font.textWidth(" ") - action.length() - mapping.length(); spaces++) + for (int spaces = 0; spaces < Screen.w / Font.textWidth(" ") - action.length() - mapping.length(); spaces++) buffer.append(" "); String newMapping = ""; @@ -39,9 +39,9 @@ private void setMapping(String mapping, Set duplicated) { @Override public void tick(InputHandler input) { - if (input.getKey("c").clicked || input.getKey("enter").clicked) + if (input.getMappedKey("c").isClicked() || input.getMappedKey("enter").isClicked()) input.changeKeyBinding(action); - else if (input.getKey("a").clicked) + else if (input.getMappedKey("a").isClicked()) // Add a binding, don't remove previous. input.addKeyBinding(action); } diff --git a/src/client/java/minicraft/screen/entry/LinkEntry.java b/src/client/java/minicraft/screen/entry/LinkEntry.java index 574bc6422..ab994555f 100644 --- a/src/client/java/minicraft/screen/entry/LinkEntry.java +++ b/src/client/java/minicraft/screen/entry/LinkEntry.java @@ -25,11 +25,22 @@ public class LinkEntry extends SelectEntry { // note that if the failMsg should be localized, such must be done before passing them as parameters, for this class will not do it since, by default, the failMsg contains a url. - public LinkEntry(int color, String urlText) { this(color, urlText, urlText, false); } - public LinkEntry(int color, String text, String url) { this(color, text, url, true); } - public LinkEntry(int color, String text, String url, String failMsg) { this(color, text, url, failMsg, true); } + public LinkEntry(int color, String urlText) { + this(color, urlText, urlText, false); + } + + public LinkEntry(int color, String text, String url) { + this(color, text, url, true); + } + + public LinkEntry(int color, String text, String url, String failMsg) { + this(color, text, url, failMsg, true); + } + + public LinkEntry(int color, String text, String url, boolean localize) { + this(color, text, url, Localization.getLocalized("Go to") + ": " + url, localize); + } - public LinkEntry(int color, String text, String url, boolean localize) { this(color, text, url, Localization.getLocalized("Go to") + ": " + url, localize); } public LinkEntry(int color, String text, String url, String failMsg, boolean localize) { super(text, () -> { if (!checkedDesktop) { @@ -40,7 +51,7 @@ public LinkEntry(int color, String text, String url, String failMsg, boolean loc } } - if(canBrowse) { + if (canBrowse) { // try to open the download link directly from the browser. try { URI uri = URI.create(url); @@ -63,5 +74,7 @@ public LinkEntry(int color, String text, String url, String failMsg, boolean loc } @Override - public int getColor(boolean isSelected) { return color; } + public int getColor(boolean isSelected) { + return color; + } } diff --git a/src/client/java/minicraft/screen/entry/ListEntry.java b/src/client/java/minicraft/screen/entry/ListEntry.java index 9b60eda8d..6b00e17a8 100644 --- a/src/client/java/minicraft/screen/entry/ListEntry.java +++ b/src/client/java/minicraft/screen/entry/ListEntry.java @@ -5,8 +5,6 @@ import minicraft.gfx.Font; import minicraft.gfx.Screen; -import java.util.Locale; - public abstract class ListEntry { public static final int COL_UNSLCT = Color.GRAY; @@ -30,8 +28,7 @@ public void render(Screen screen, int x, int y, boolean isSelected, String conta return; } - String string = toString().toLowerCase(Locale.ENGLISH); - contain = contain.toLowerCase(Locale.ENGLISH); + String string = toString(); Font.drawColor(string.replace(contain, Color.toStringCode(containColor) + contain + Color.WHITE_CODE), screen, x, y); } @@ -59,7 +56,9 @@ public void render(Screen screen, int x, int y, boolean isSelected) { * @param isSelected true if the entry is selected, false otherwise * @return the current entry color */ - public int getColor(boolean isSelected) { return isSelected ? COL_SLCT : COL_UNSLCT; } + public int getColor(boolean isSelected) { + return isSelected ? COL_SLCT : COL_UNSLCT; + } /** * Calculates the width of the entry. @@ -81,25 +80,33 @@ public static int getHeight() { * Determines if this entry can be selected. * @return true if it is visible and can be selected, false otherwise. */ - public final boolean isSelectable() { return selectable && visible; } + public final boolean isSelectable() { + return selectable && visible; + } /** * Returns whether the entry is visible or not. * @return true if the entry is visible, false otherwise */ - public final boolean isVisible() { return visible; } + public final boolean isVisible() { + return visible; + } /** * Changes if the entry can be selected or not. * @param selectable true if the entry can be selected, false if not */ - public final void setSelectable(boolean selectable) { this.selectable = selectable; } + public final void setSelectable(boolean selectable) { + this.selectable = selectable; + } /** * Changes if the entry is visible or not. * @param visible true if the entry should be visible, false if not */ - public final void setVisible(boolean visible) { this.visible = visible; } + public final void setVisible(boolean visible) { + this.visible = visible; + } @Override public abstract String toString(); diff --git a/src/client/java/minicraft/screen/entry/RangeEntry.java b/src/client/java/minicraft/screen/entry/RangeEntry.java index d6356ca9c..a4a8c5311 100644 --- a/src/client/java/minicraft/screen/entry/RangeEntry.java +++ b/src/client/java/minicraft/screen/entry/RangeEntry.java @@ -1,31 +1,31 @@ package minicraft.screen.entry; public class RangeEntry extends ArrayEntry { - + private static Integer[] getIntegerArray(int min, int max) { Integer[] ints = new Integer[max - min + 1]; - + for (int i = 0; i < ints.length; i++) - ints[i] = min+i; - + ints[i] = min + i; + return ints; } - + private int min, max; - + public RangeEntry(String label, int min, int max, int initial) { super(label, false, getIntegerArray(min, max)); - + this.min = min; this.max = max; - + setValue(initial); } - + @Override public void setValue(Object o) { if (!(o instanceof Integer)) return; - - setSelection(((Integer)o)-min); + + setSelection(((Integer) o) - min); } } diff --git a/src/client/java/minicraft/screen/entry/RecipeEntry.java b/src/client/java/minicraft/screen/entry/RecipeEntry.java index 85faa2d46..41fe3fc75 100644 --- a/src/client/java/minicraft/screen/entry/RecipeEntry.java +++ b/src/client/java/minicraft/screen/entry/RecipeEntry.java @@ -24,7 +24,8 @@ public RecipeEntry(Recipe r) { } @Override - public void tick(InputHandler input) {} + public void tick(InputHandler input) { + } @Override public void render(Screen screen, int x, int y, boolean isSelected) { diff --git a/src/client/java/minicraft/screen/entry/SelectEntry.java b/src/client/java/minicraft/screen/entry/SelectEntry.java index c558a0d9e..071efc9fa 100644 --- a/src/client/java/minicraft/screen/entry/SelectEntry.java +++ b/src/client/java/minicraft/screen/entry/SelectEntry.java @@ -19,7 +19,10 @@ public class SelectEntry extends ListEntry { * @param text Text displayed on this entry * @param onSelect Action which happens when the entry is selected */ - public SelectEntry(String text, Action onSelect) { this(text, onSelect, true); } + public SelectEntry(String text, Action onSelect) { + this(text, onSelect, true); + } + public SelectEntry(String text, Action onSelect, boolean localize) { this.onSelect = onSelect; this.text = text; @@ -30,9 +33,13 @@ public SelectEntry(String text, Action onSelect, boolean localize) { * Changes the text of the entry. * @param text new text */ - void setText(String text) { this.text = text; } + void setText(String text) { + this.text = text; + } - public String getText() { return text; } + public String getText() { + return text; + } @Override public void tick(InputHandler input) { @@ -43,8 +50,12 @@ public void tick(InputHandler input) { } @Override - public int getWidth() { return Font.textWidth(toString()); } + public int getWidth() { + return Font.textWidth(toString()); + } @Override - public String toString() { return localize ? Localization.getLocalized(text) : text; } + public String toString() { + return localize ? Localization.getLocalized(text) : text; + } } diff --git a/src/client/java/minicraft/screen/entry/StringEntry.java b/src/client/java/minicraft/screen/entry/StringEntry.java index de22241aa..ec866f594 100644 --- a/src/client/java/minicraft/screen/entry/StringEntry.java +++ b/src/client/java/minicraft/screen/entry/StringEntry.java @@ -7,6 +7,7 @@ import minicraft.gfx.Screen; import java.util.ArrayList; +import java.util.Arrays; // an unselectable line. public class StringEntry extends ListEntry { @@ -23,15 +24,19 @@ public class StringEntry extends ListEntry { public static StringEntry[] useLines(String... lines) { return useLines(DEFAULT_COLOR, lines); } - public static StringEntry[] useLines(int color, String... lines) { return useLines(color, true, lines); } + + public static StringEntry[] useLines(int color, String... lines) { + return useLines(color, true, lines); + } + public static StringEntry[] useLines(int color, boolean localize, String... lines) { ArrayList lns = new ArrayList<>(); for (String l : lines) { - for (String ll : Font.getLines(localize? Localization.getLocalized(l): l, Screen.w-20, Screen.h*2, 0)) lns.add(ll); + lns.addAll(Arrays.asList(Font.getLines(localize ? Localization.getLocalized(l) : l, Screen.w - 20, Screen.h * 2, 0))); } StringEntry[] entries = new StringEntry[lns.size()]; for (int i = 0; i < lns.size(); i++) - entries[i] = new StringEntry(lns.get(i), color); + entries[i] = new StringEntry(lns.get(i), color, false); return entries; } @@ -39,8 +44,15 @@ public static StringEntry[] useLines(int color, boolean localize, String... line public StringEntry(String text) { this(text, DEFAULT_COLOR); } - public StringEntry(String text, boolean localize) { this(text, DEFAULT_COLOR, localize); } // This might be false as the text might have been localized already. - public StringEntry(String text, int color) { this(text, color, true); } // This should be always true with the new localization IDs. + + public StringEntry(String text, boolean localize) { + this(text, DEFAULT_COLOR, localize); + } // This might be false as the text might have been localized already. + + public StringEntry(String text, int color) { + this(text, color, true); + } // This should be always true with the new localization IDs. + public StringEntry(String text, int color, boolean localize) { setSelectable(false); this.text = text; @@ -53,11 +65,16 @@ public void setText(String text) { } @Override - public void tick(InputHandler input) {} + public void tick(InputHandler input) { + } @Override - public int getColor(boolean isSelected) { return color; } + public int getColor(boolean isSelected) { + return color; + } @Override - public String toString() { return localize? Localization.getLocalized(text): text; } + public String toString() { + return localize ? Localization.getLocalized(text) : text; + } } diff --git a/src/client/java/minicraft/util/AdvancementElement.java b/src/client/java/minicraft/util/AdvancementElement.java index a0c25c5d5..5006577fc 100644 --- a/src/client/java/minicraft/util/AdvancementElement.java +++ b/src/client/java/minicraft/util/AdvancementElement.java @@ -32,7 +32,9 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -/** World-wide. */ +/** + * World-wide. + */ public class AdvancementElement { private static final HashSet recipeUnlockingElements; @@ -100,7 +102,7 @@ public static void loadAdvancementElement(Collection element ElementRewards rewards = loadRewards(json.optJSONObject("rewards")); elements.add(new AdvancementElement(criterionName, - displayable ? json.getString("description"): null, criteria, + displayable ? json.getString("description") : null, criteria, rewards, requirements, unlockingCriteria, unlockingRequirements)); } @@ -144,7 +146,9 @@ public static void loadRecipeUnlockingElements(JSONObject json) { } } - /** Saving and writing all data into the given JSONObject. */ + /** + * Saving and writing all data into the given JSONObject. + */ public static void saveRecipeUnlockingElements(JSONObject json) { recipeUnlockingElements.forEach(element -> element.save(json)); } @@ -162,9 +166,9 @@ public static void saveRecipeUnlockingElements(JSONObject json) { protected boolean unlocked = false; public AdvancementElement(String key, String description, Map criteria, - @Nullable ElementRewards rewards, @NotNull Set> requirements, - @NotNull Map unlockingCriteria, - @NotNull Set> unlockingRequirements) { + @Nullable ElementRewards rewards, @NotNull Set> requirements, + @NotNull Map unlockingCriteria, + @NotNull Set> unlockingRequirements) { this.key = key; this.description = description; this.criteria.putAll(criteria); @@ -230,8 +234,13 @@ public ElementRewards(ArrayList items, ArrayList recipes) { this.recipes = recipes; } - public ArrayList getItems() { return new ArrayList<>(items); } - public ArrayList getRecipe() { return new ArrayList<>(recipes); } + public ArrayList getItems() { + return new ArrayList<>(items); + } + + public ArrayList getRecipe() { + return new ArrayList<>(recipes); + } } @SuppressWarnings("unused") @@ -266,8 +275,10 @@ protected void registerCriteria() { }); } - /** Warning: This method should be used carefully as this could impact - * the gaming experience deeply on the progress. */ + /** + * Warning: This method should be used carefully as this could impact + * the gaming experience deeply on the progress. + */ public void deregisterCriteria() { criteria.values().forEach(criterion -> { criterion.trigger.registeredCriteria.remove(criterion); @@ -282,7 +293,9 @@ public boolean isUnlocked() { return unlocked; } - /** Is unlocked but not completed. */ + /** + * Is unlocked but not completed. + */ public boolean isDisplayableAtStatus() { return unlocked && !completed; } @@ -290,9 +303,11 @@ public boolean isDisplayableAtStatus() { public int getNumCriteriaCompleted() { return (int) criteria.values().stream().filter(ElementCriterion::isCompleted).count(); } + public int getTotalNumCriteria() { return criteria.size(); } + public boolean shouldAllCriteriaBeCompleted() { return requirements.isEmpty(); } @@ -314,7 +329,9 @@ protected boolean checkIsCompleted() { })); } - /** Updating and refreshing by the data in this element. */ + /** + * Updating and refreshing by the data in this element. + */ public void update() { registerUnlockingCriteria(); @@ -349,7 +366,10 @@ protected void sendRewards() { } } - public void reset() { reset(true); } + public void reset() { + reset(true); + } + protected void reset(boolean update) { completed = false; unlocked = false; @@ -357,7 +377,9 @@ protected void reset(boolean update) { if (update) update(); } - /** Loading from a JSONObject of an element. */ + /** + * Loading from a JSONObject of an element. + */ public void load(JSONObject json) { reset(false); completed = json.optBoolean("done"); @@ -385,7 +407,9 @@ public void load(JSONObject json) { update(); } - /** Saving and writing data to the root JSONObject */ + /** + * Saving and writing data to the root JSONObject + */ public void save(JSONObject json) { JSONObject elementJson = new JSONObject(); JSONObject criteriaJson = new JSONObject(); @@ -417,7 +441,7 @@ public static abstract class AdvancementTrigger { private static final Set pendingCompletedCriteria = ConcurrentHashMap.newKeySet(); public static void tick() { - for (Iterator it = pendingCompletedCriteria.iterator(); it.hasNext();) { + for (Iterator it = pendingCompletedCriteria.iterator(); it.hasNext(); ) { ElementCriterion criterion = it.next(); criterion.markAsCompleted(false, null); it.remove(); // Action done. @@ -453,18 +477,24 @@ public void register(ElementCriterion criterion) { registeredCriteria.add(criterion); } - /** This should be called by another thread if method {@link #singleThreadNeeded()} is not + /** + * This should be called by another thread if method {@link #singleThreadNeeded()} is not * implemented to return true. If false, this should use {@link #pendingCompletedCriteria} * to mark completed criteria instead of calling it directly as this method should be called - * by the global game tick updater to ensure the synchronization. */ + * by the global game tick updater to ensure the synchronization. + */ protected abstract void trigger0(AdvancementTriggerConditionHandler.AdvancementTriggerConditions conditions); - /** @return {@code true} if this trigger implementation requires single thread as the global game tick updater. */ + /** + * @return {@code true} if this trigger implementation requires single thread as the global game tick updater. + */ protected boolean singleThreadNeeded() { return true; } - /** Triggering and checking passes by another thread. */ + /** + * Triggering and checking passes by another thread. + */ public void trigger(AdvancementTriggerConditionHandler.AdvancementTriggerConditions conditions) { if (!singleThreadNeeded()) executorService.submit(() -> trigger0(conditions)); else trigger0(conditions); @@ -477,20 +507,26 @@ public AdvancementElement.AdvancementTrigger.AdvancementTriggerConditionHandler } public abstract static class AdvancementTriggerConditionHandler { - protected AdvancementTriggerConditionHandler() {} + protected AdvancementTriggerConditionHandler() { + } @NotNull public abstract AdvancementCriterionConditions createCriterionConditions(JSONObject json) throws JSONException; - /** A condition carrier for the corresponding trigger. */ - public abstract static class AdvancementTriggerConditions {} + /** + * A condition carrier for the corresponding trigger. + */ + public abstract static class AdvancementTriggerConditions { + } public abstract static class AdvancementCriterionConditions { - protected AdvancementCriterionConditions() {} + protected AdvancementCriterionConditions() { + } public static class Rangeable> { public final @Nullable T min; public final @Nullable T max; + public Rangeable(@Nullable T min, @Nullable T max) { this.min = min; this.max = max; @@ -514,8 +550,8 @@ private boolean inRange(T value) { public String toString() { return isAbsent(this) ? "" : min == null ? "max: " + max : - max == null ? "min: " + min : - String.format("min: %s;max: %s", min, max); + max == null ? "min: " + min : + String.format("min: %s;max: %s", min, max); } } @@ -523,6 +559,7 @@ public static class ItemConditions { private final HashSet items = new HashSet<>(); private final @Nullable Rangeable count; private final @Nullable Rangeable durability; + private ItemConditions(Set items, @Nullable Rangeable count, @Nullable Rangeable durability) { this.items.addAll(items); this.count = count; @@ -576,7 +613,9 @@ private boolean matches(Item item) { } } - /** Tile location. */ + /** + * Tile location. + */ public static class LocationConditions { private final HashSet tiles = new HashSet<>(); private final @Nullable Integer level; @@ -585,7 +624,7 @@ public static class LocationConditions { private final @Nullable Rangeable y; private LocationConditions(Set tiles, @Nullable Integer level, @Nullable Integer data, - @Nullable Rangeable x, @Nullable Rangeable y) { + @Nullable Rangeable x, @Nullable Rangeable y) { this.tiles.addAll(tiles); this.level = level; this.data = data; @@ -609,12 +648,14 @@ private static LocationConditions getFromJson(JSONObject json) { try { data = tileJson.getInt("data"); - } catch (JSONException ignored) {} + } catch (JSONException ignored) { + } } try { level = json.getInt("level"); - } catch (JSONException ignored) {} + } catch (JSONException ignored) { + } JSONObject positionJson = json.optJSONObject("position"); if (json.has("x")) try { @@ -664,16 +705,19 @@ protected ImpossibleTrigger() { } @Override - public void register(ElementCriterion criterion) {} // No action. + public void register(ElementCriterion criterion) { + } // No action. @Override - protected void trigger0(AdvancementTriggerConditionHandler.AdvancementTriggerConditions conditions) {} // No action. + protected void trigger0(AdvancementTriggerConditionHandler.AdvancementTriggerConditions conditions) { + } // No action. public static class ImpossibleTriggerConditionHandler extends AdvancementTriggerConditionHandler { @Override public @NotNull AdvancementElement.AdvancementTrigger.AdvancementTriggerConditionHandler.AdvancementCriterionConditions createCriterionConditions(JSONObject json) { - return new AdvancementCriterionConditions() {}; // Empty. + return new AdvancementCriterionConditions() { + }; // Empty. } } } @@ -718,9 +762,11 @@ protected void trigger0(AdvancementTriggerConditionHandler.AdvancementTriggerCon } } - /** Modified from {@link #test(List, List)}. */ + /** + * Modified from {@link #test(List, List)}. + */ private static boolean isConditionalMatched(ArrayList items, - HashSet itemConditions) { + HashSet itemConditions) { Set> combinations = new HashSet<>(); List> combinationsOutput = new ArrayList<>(); List conditionsList = new ArrayList<>(); @@ -751,17 +797,21 @@ private static boolean isConditionalMatched(ArrayList items, } } - /** Used by {@link #allMatch(Collection, Collection, HashMap)} for conditional check for each element. */ + /** + * Used by {@link #allMatch(Collection, Collection, HashMap)} for conditional check for each element. + */ private static boolean isMatched(Item item, InventoryChangedTriggerConditionHandler.InventoryChangedCriterionConditions.ItemConditions itemConditions, - @Nullable String selectedItem) { + @Nullable String selectedItem) { if (!itemConditions.matches(item)) return false; return selectedItem == null || item.getName().equalsIgnoreCase(selectedItem); } - /** Modified from {@link #containsAll(List, List)}. */ + /** + * Modified from {@link #containsAll(List, List)}. + */ private static boolean allMatch(Collection source, Collection target, - HashMap selectedItems) { + HashMap selectedItems) { for (Item e : source) { target.removeIf(conditions1 -> isMatched(e, conditions1, selectedItems.get(conditions1))); if (target.isEmpty()) { @@ -772,7 +822,9 @@ private static boolean allMatch(Collection source, Collection boolean test(List list, List> matcher) { List> combinations = new ArrayList<>(); @@ -784,7 +836,9 @@ private static boolean test(List list, List> matcher) { return false; } - /** Original archive of array elements matching. */ + /** + * Original archive of array elements matching. + */ private static boolean containsAll(List source, List target) { for (T e : source) { target.remove(e); @@ -884,8 +938,9 @@ public static class InventoryChangedCriterionConditions extends AdvancementCrite private final @Nullable Rangeable slotsEmpty; private final @Nullable Rangeable slotsFull; private final @Nullable Rangeable slotsOccupied; + private InventoryChangedCriterionConditions(Set items, @Nullable Rangeable slotsEmpty, - @Nullable Rangeable slotsFull, @Nullable Rangeable slotsOccupied) { + @Nullable Rangeable slotsFull, @Nullable Rangeable slotsOccupied) { this.items.addAll(items); this.slotsEmpty = slotsEmpty; this.slotsFull = slotsFull; @@ -940,7 +995,8 @@ public static class PlacedTileTriggerConditionHandler extends AdvancementTrigger Integer data = null; try { data = json.getInt("data"); - } catch (JSONException ignored) {} + } catch (JSONException ignored) { + } return new PlacedTileCriterionConditions(tile, item, location, data); } @@ -969,7 +1025,7 @@ public static class PlacedTileCriterionConditions extends AdvancementCriterionCo private final @Nullable Integer data; private PlacedTileCriterionConditions(@Nullable String tile, @Nullable ItemConditions item, - @Nullable LocationConditions location, @Nullable Integer data) { + @Nullable LocationConditions location, @Nullable Integer data) { this.tile = tile; this.item = item; this.location = location; diff --git a/src/client/java/minicraft/util/Logging.java b/src/client/java/minicraft/util/Logging.java index 0296d48ee..903acaaeb 100644 --- a/src/client/java/minicraft/util/Logging.java +++ b/src/client/java/minicraft/util/Logging.java @@ -6,7 +6,9 @@ public final class Logging { public static boolean logTime = false; public static boolean logThread = false; - /** Applied only when debug mode is enabled */ + /** + * Applied only when debug mode is enabled + */ public static boolean logTrace = false; public static boolean logLevel = false; public static boolean fileLogFull = false; @@ -34,6 +36,8 @@ public final class Logging { public static final TaggedLogger CONTROLLER = Logger.tag("Controller"); public static final TaggedLogger PLAYER = Logger.tag("Player"); - /** This is defined dynamically. */ + /** + * This is defined dynamically. + */ public static TaggedLogger WORLDNAMED = Logger.tag(null); } diff --git a/src/client/java/minicraft/util/MyUtils.java b/src/client/java/minicraft/util/MyUtils.java index d6416da27..6a0f78614 100644 --- a/src/client/java/minicraft/util/MyUtils.java +++ b/src/client/java/minicraft/util/MyUtils.java @@ -2,7 +2,8 @@ public final class MyUtils { - private MyUtils() {} + private MyUtils() { + } public static int clamp(int val, int min, int max) { if (val > max) return max; @@ -10,7 +11,10 @@ public static int clamp(int val, int min, int max) { return val; } - public static int randInt(int max) { return randInt(0, max); } + public static int randInt(int max) { + return randInt(0, max); + } + public static int randInt(int min, int max) { return (int) (Math.random() * (max - min + 1)) + min; } @@ -23,7 +27,7 @@ public static String plural(int num, String word) { public static void sleep(int millis) { try { Thread.sleep(millis); - } catch(InterruptedException ignored) { + } catch (InterruptedException ignored) { } } diff --git a/src/client/java/minicraft/util/Quest.java b/src/client/java/minicraft/util/Quest.java index 3ab17214a..aadf4fd73 100644 --- a/src/client/java/minicraft/util/Quest.java +++ b/src/client/java/minicraft/util/Quest.java @@ -14,13 +14,16 @@ public class Quest extends AdvancementElement { private final @Nullable String parent; public Quest(String key, String description, Map criteria, @Nullable AdvancementElement.ElementRewards rewards, - @NotNull Set> requirements, @Nullable String parent, - @NotNull HashMap unlockingCriteria, @NotNull Set> unlockingRequirements) { + @NotNull Set> requirements, @Nullable String parent, + @NotNull HashMap unlockingCriteria, @NotNull Set> unlockingRequirements) { super(key, description, criteria, rewards, requirements, unlockingCriteria, unlockingRequirements); this.parent = parent; } - public QuestSeries getSeries() { return series; } + public QuestSeries getSeries() { + return series; + } + public @Nullable Quest getParent() { if (parent != null && series != null) { return series.quests.get(parent); @@ -53,15 +56,17 @@ public static class QuestSeries extends AdvancementElement { private final HashMap quests = new HashMap<>(); public QuestSeries(String key, String description, Map criteria, - @Nullable AdvancementElement.ElementRewards rewards, @NotNull Set> requirements, - @NotNull Map quests, @NotNull HashMap unlockingCriteria, - @NotNull Set> unlockingRequirements) { + @Nullable AdvancementElement.ElementRewards rewards, @NotNull Set> requirements, + @NotNull Map quests, @NotNull HashMap unlockingCriteria, + @NotNull Set> unlockingRequirements) { super(key, description, criteria, rewards, requirements, unlockingCriteria, unlockingRequirements); this.quests.putAll(quests); quests.values().forEach(q -> q.series = this); } - public HashMap getSeriesQuests() { return new HashMap<>(quests); } + public HashMap getSeriesQuests() { + return new HashMap<>(quests); + } @Override protected boolean checkIsCompleted() { diff --git a/src/client/java/minicraft/util/TinylogLoggingConfiguration.java b/src/client/java/minicraft/util/TinylogLoggingConfiguration.java index 2d6af6ea9..506f55057 100644 --- a/src/client/java/minicraft/util/TinylogLoggingConfiguration.java +++ b/src/client/java/minicraft/util/TinylogLoggingConfiguration.java @@ -40,7 +40,10 @@ public static class TagList { private Set tags = null; private final boolean all; - public TagList(boolean all) { this.all = all; } + public TagList(boolean all) { + this.all = all; + } + public TagList(Set tags) { this.tags = tags; all = false; @@ -119,12 +122,14 @@ public Set computeLevelsFromMinimum(Level minimum) { return levels; } - /** Generate all possible instances of console writer (writer1) with the configuration. */ + /** + * Generate all possible instances of console writer (writer1) with the configuration. + */ public HashMap generateConsoleWriters() { HashMap map = new HashMap<>(); - for (final boolean i : new boolean[] { false, true}) { - for (final boolean j : new boolean[] { false, true}) { - for (final boolean k : new boolean[] { false, true}) { + for (final boolean i : new boolean[] { false, true }) { + for (final boolean j : new boolean[] { false, true }) { + for (final boolean k : new boolean[] { false, true }) { map.putAll(createConsoleWriter(i, j, k)); } } @@ -132,7 +137,10 @@ public HashMap generateConsoleWriters() { return map; } - /** Generate a console writer with the configuration. */ + + /** + * Generate a console writer with the configuration. + */ public Map createConsoleWriter(boolean logTime, boolean logThread, boolean logTrace) { HashMap properties = new HashMap<>(); String ID = String.format("writer1%s%s%s", logTime ? "T" : "F", logThread ? "T" : "F", logTrace ? "T" : "F"); @@ -148,33 +156,23 @@ public Map createConsoleWriter(boolean logTime, boo return Collections.singletonMap(new ConsoleWriter(properties), new WriterConfig(ID, computeLevelsFromMinimum(level), new TagList(true))); } - /** + /** * Creates a new log entry. - * - * @param stackTraceElement - * Optional stack trace element of caller - * @param tag - * Tag name if issued from a tagged logger - * @param level - * Severity level - * @param exception - * Caught exception or throwable to log - * @param formatter - * Formatter for text message - * @param obj - * Message to log - * @param arguments - * Arguments for message - * @param required - * The required log entry value array slice of the tag index of the used tag - * @param contextProvider - * The context provider + * @param stackTraceElement Optional stack trace element of caller + * @param tag Tag name if issued from a tagged logger + * @param level Severity level + * @param exception Caught exception or throwable to log + * @param formatter Formatter for text message + * @param obj Message to log + * @param arguments Arguments for message + * @param required The required log entry value array slice of the tag index of the used tag + * @param contextProvider The context provider * @return Filled log entry */ public static LogEntry createLogEntry(final StackTraceElement stackTraceElement, final String tag, - final Level level, final Throwable exception, final MessageFormatter formatter, final Object obj, - final Object[] arguments, final Collection required, - final TinylogContextProvider contextProvider) { + final Level level, final Throwable exception, final MessageFormatter formatter, final Object obj, + final Object[] arguments, final Collection required, + final TinylogContextProvider contextProvider) { Timestamp timestamp = RuntimeProvider.createTimestamp(); Thread thread = required.contains(LogEntryValue.THREAD) ? Thread.currentThread() : null; diff --git a/src/client/java/minicraft/util/TinylogLoggingProvider.java b/src/client/java/minicraft/util/TinylogLoggingProvider.java index cd465be0e..b7bafbb6c 100644 --- a/src/client/java/minicraft/util/TinylogLoggingProvider.java +++ b/src/client/java/minicraft/util/TinylogLoggingProvider.java @@ -24,7 +24,9 @@ import java.util.HashMap; import java.util.function.Consumer; -/** Originally copied from {@link org.tinylog.core.TinylogLoggingProvider} */ +/** + * Originally copied from {@link org.tinylog.core.TinylogLoggingProvider} + */ public class TinylogLoggingProvider implements LoggingProvider { private final TinylogContextProvider context; @@ -39,7 +41,9 @@ public class TinylogLoggingProvider implements LoggingProvider { private ConsoleWriter currentConsoleWriter; private FileWriter currentFileWriter; - /** */ + /** + * + */ public TinylogLoggingProvider() { TinylogLoggingConfiguration config = new TinylogLoggingConfiguration(); context = new TinylogContextProvider(); @@ -73,7 +77,7 @@ public TinylogLoggingProvider() { ctr.setAccessible(true); writingThread = ctr.newInstance(writers.keySet()); } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException - | NoSuchMethodException | SecurityException | ClassNotFoundException e) { + | NoSuchMethodException | SecurityException | ClassNotFoundException e) { throw new RuntimeException(e); } @@ -90,7 +94,9 @@ public TinylogLoggingProvider() { } } - /** Applying the configuration in {@link Logging} */ + /** + * Applying the configuration in {@link Logging} + */ public void init() { currentConsoleWriter = consoleWriters.get(String.format("writer1%s%s%s", Logging.logTime ? "T" : "F", Logging.logThread ? "T" : "F", Logging.logTrace ? "T" : "F")); currentFileWriter = fileWriters.get("writer2" + (Logging.fileLogFull ? "Full" : "")); @@ -118,7 +124,7 @@ public boolean isEnabled(final int depth, final String tag, final Level level) { @Override public void log(final int depth, final String tag, final Level level, final Throwable exception, final MessageFormatter formatter, - final Object obj, final Object... arguments) { + final Object obj, final Object... arguments) { StackTraceElement stackTraceElement; if (fullStackTraceRequired.get(currentConsoleWriter) || tag.equals("LOC")) { stackTraceElement = RuntimeProvider.getCallerStackTraceElement(depth + 1); @@ -135,7 +141,7 @@ public void log(final int depth, final String tag, final Level level, final Thro @Override public void log(final String loggerClassName, final String tag, final Level level, final Throwable exception, - final MessageFormatter formatter, final Object obj, final Object... arguments) { + final MessageFormatter formatter, final Object obj, final Object... arguments) { StackTraceElement stackTraceElement; if (fullStackTraceRequired.get(currentConsoleWriter) || tag.equals("LOC")) { stackTraceElement = RuntimeProvider.getCallerStackTraceElement(loggerClassName); @@ -170,11 +176,11 @@ public void shutdown() throws InterruptedException { * Outputs a log entry to all passed writers. */ private void output(final StackTraceElement stackTraceElement, final String tag, - final Level level, final Throwable exception, final MessageFormatter formatter, final Object obj, - final Object[] arguments) { + final Level level, final Throwable exception, final MessageFormatter formatter, final Object obj, + final Object[] arguments) { LogEntry logEntry = TinylogLoggingConfiguration.createLogEntry(stackTraceElement, tag, level, exception, formatter, - obj, arguments, requiredLogEntryValues, context); + obj, arguments, requiredLogEntryValues, context); Consumer addToThread = writer -> { WriterConfig cfg = writers.get(writer); @@ -190,7 +196,6 @@ private void output(final StackTraceElement stackTraceElement, final String tag, /** * Gets all writers of the provider. - * * @return All writers */ public Collection getWriters() { diff --git a/src/client/java/minicraft/util/TutorialElement.java b/src/client/java/minicraft/util/TutorialElement.java index 9c60f5790..a21558cff 100644 --- a/src/client/java/minicraft/util/TutorialElement.java +++ b/src/client/java/minicraft/util/TutorialElement.java @@ -11,7 +11,9 @@ public TutorialElement(String key, String description, Map(), new HashMap<>(), new HashSet<>()); } - /** Updating and refreshing by the data in this element. */ + /** + * Updating and refreshing by the data in this element. + */ public void update() { super.update(); TutorialDisplayHandler.updateCompletedElement(this); diff --git a/src/client/java/minicraft/util/Vector2.java b/src/client/java/minicraft/util/Vector2.java index 04598c2d8..703c67352 100644 --- a/src/client/java/minicraft/util/Vector2.java +++ b/src/client/java/minicraft/util/Vector2.java @@ -10,15 +10,15 @@ public Vector2(double x, double y) { public Vector2 normalized() { double max = Math.max(x, y); - return new Vector2(x/max, y/max); + return new Vector2(x / max, y / max); } public static Vector2 normalize(Vector2 vec) { double max = Math.max(vec.x, vec.y); - return new Vector2(vec.x/max, vec.y/max); + return new Vector2(vec.x / max, vec.y / max); } public static double distance(double x, double y) { - return Math.sqrt(x*x + y*y); + return Math.sqrt(x * x + y * y); } } diff --git a/src/client/resources/assets/books/credits.txt b/src/client/resources/assets/books/credits.txt index 0ee238123..ba10cae95 100644 --- a/src/client/resources/assets/books/credits.txt +++ b/src/client/resources/assets/books/credits.txt @@ -1,7 +1,7 @@ Original game by Markus Persson. Project Maintainers: -David.b, Dillyg10, Chris J, afyber, and Makkkkus. +David.b, Dillyg10, Chris J, afyber, Makkkkus, and Litorom1. Special contributors: A.L.I.C.E, Christoffer Holmesland, El-Virus, Litorom1, TheBigEye, PelletsstarPL and Ben Forge. diff --git a/src/client/resources/assets/books/story_guide.txt b/src/client/resources/assets/books/game_guide.txt similarity index 72% rename from src/client/resources/assets/books/story_guide.txt rename to src/client/resources/assets/books/game_guide.txt index 05327e7b4..4378bac31 100644 --- a/src/client/resources/assets/books/story_guide.txt +++ b/src/client/resources/assets/books/game_guide.txt @@ -8,16 +8,16 @@ If you manage to accomplish that, and craft a gem pickaxe, then you can break th When the air wizard is defeated, a message appears on screen, saying the dungeon is opened. That refers to a certain staircase on the third underground level going down, surrounded by purple obsidian bricks and walls. Only after defeating the air wizard can you destroy the obsidian and go down the stairs. The dungeon level you'll find is entirely composed of various obsidian tiles, with occasional small pockets of lava scattered about. There are no ores. -The enemies there are mostly of two types: snakes, and knights. Snakes drop scales, which can be used to craft green snake armor, and knights drop shards, which are needed to craft claymores, upgraded powerful swords. Additionally, there are a variety of rooms through the dungeon: spawn rooms, dungeon gardens, fancy lava pools, and rooms filled with grayed-out chests. These chests are dungeon chests and require keys to open and said keys drop from the enemies of the floor. Within these chests are fancy powerful items to help fight the next boss. +The enemies there are mostly of two types: snakes, and knights. Snakes drop scales, which can be used to craft green snake armor, and knights drop shards, which are needed to craft claymores, upgraded powerful swords. Additionally, there are a variety of rooms through the dungeon: spawner rooms, dungeon gardens, fancy lava pools, and rooms filled with grayed-out chests. These chests are dungeon chests and require keys to open and said keys drop from the enemies of the floor. Within these chests are fancy powerful items to help fight the next boss. There are a certain amount of dungeon chests that you will have to open if you want to survive from the next boss. The amount is dependent on the map size and some random chance. If you press F3 while on the dungeon level, it will display how many locked chests remain. Upon unlocking the final chest out of all the chest on the map, you will receive 5 golden apples. -You will eventually come across a room with a strange curious statue and can walk through its walls. This is the boss room, if you tap the statue inside three times, the obsidian knight will spawn. Soon you will notice the walls are solid and unbreakable until either the boss is defeated or the player dies. This boss has 3 attack patterns and 2 phases: fire spray and normal walk for phase 1 and additionally dash for phase 2. +You will eventually come across a room with a strange curious statue. This is the boss room, if you tap the statue inside three times, the obsidian knight will spawn. Soon you will notice the room's doors are locked solid and unbreakable until either the boss is defeated or the player dies. This boss has 3 attack patterns and 2 phases: fire spray and normal walk for phase 1 and additionally dash for phase 2. -If you came prepared and/or was lucky and manage to defeat the obsidian knight, it will drop a big amount of shards and a new curious item. This item, the obsidian heart, when used will increase your health by 5 per use, with a maximum of 30 in total (4 obsidian hearts are needed). The boss only drops one, so for maximum hp you will need to respawn the boss with an obsidian poppet, which is craftable in the enchanter. +If you came prepared and/or was lucky and manage to defeat the obsidian knight, it will drop a big amount of shards and a new curious item. This item, the obsidian heart, when used will increase your max health by 5 per use, with a maximum of 30 in total (4 obsidian hearts are needed). The boss only drops one, so for maximum hp you will need to respawn the boss with an obsidian poppet, which is craftable in the enchanter. @@@ -Back in the sky world are white ores called cloud ore, which you can mine. You can craft a Totem of Air from such ores, which will respawn the air wizard when used. +Back in the sky world are white ores called cloud ore, which you can mine. You can craft a Totem of Air from such ores, which will respawn the air wizard when used. There is also a house which belonged to the Air Wizard. It contains a free enchanter to craft potions and boss respawn items. And of course, you may continue to play your world as usual afterwards. diff --git a/src/client/resources/assets/books/instructions.txt b/src/client/resources/assets/books/instructions.txt index 0d6472725..188c76632 100644 --- a/src/client/resources/assets/books/instructions.txt +++ b/src/client/resources/assets/books/instructions.txt @@ -1,5 +1,8 @@ With the default controls... -Move your character with arrow keys or WSAD. Press C to attack and X to open the inventory, and to use items. Pickup furniture and torches with V. Select an item in the inventory to equip it. +Move your character with arrow keys or WSAD. Press C to attack and X to open the inventory, and to use items. Pickup furniture and torches with V. Select an item in the inventory to equip it. Q to drop an item or Shift + Q to drop a stack. Escape key for pause menu. -The Goal: Defeat the air wizard! \ No newline at end of file +Similarly on controller move your character or with dpad or left joystick, A button to attack or select, B button to exit menus, X button for inventory, Y button for craft menu, start menu for pause menu or search in a list of items, Left Bumper to pick up furniture, Right Bumper to drop an item or use Right Joystick Button to drop a stack. + +The main Goal: Defeat the air wizard and Obsidian Knight! +Prevail, get stronger, survive! diff --git a/src/client/resources/assets/localization/de-de.json b/src/client/resources/assets/localization/de-de.json new file mode 100644 index 000000000..6f97fc899 --- /dev/null +++ b/src/client/resources/assets/localization/de-de.json @@ -0,0 +1,408 @@ +{ + "Acorn": "Eichel", + "AirWizard Spawner": "Luftmagier-Monsterspawner", + "Antidious": "Gefährlich", + "Anvil": "Amboss", + "Apple": "Apfel", + "Axe": "Axt", + "Baked Potato": "Gebackene Kartoffeln", + "Bed": "Bett", + "Black Clothes": "Schwarze Kleidung", + "Black Wool": "Schwarze Wolle", + "Blue Clothes": "Blaue Kleidung", + "Blue Wool": "Blaue Wolle", + "Bone": "Knochen", + "Book": "Buch", + "Bow": "Bogen", + "Bread": "Brot", + "Cactus": "Kaktus", + "Cactus Sapling": "Kaktussetzling", + "Chest": "Kiste", + "Claymore": "Sprengmiene", + "Cloud": "Wolke", + "Cloud Cactus": "Wolken Kaktus", + "Cloud Ore": "Wolkenerz", + "Coal": "Kohle", + "Cooked Fish": "Gebratener Fisch", + "Cooked Pork": "Gebratenes Schweinerfleisch", + "Cow Spawner": "Kuh-Monsterspawner", + "Creeper Spawner": "Creeper-Monsterspawner", + "Cyan Clothes": "Cyan Kleidung", + "Death Chest": "Todesschatztruhe", + "Dirt": "Erde", + "Empty Bucket": "Leerer Eimer", + "Enchanter": "Verzauberungstisch", + "Energy Potion": "Energietrank", + "Escape Potion": "Fluchttrank", + "Explode": "Explodieren", + "Farmland": "Ackerland", + "Flower": "Blume", + "Furnace": "Ofen", + "Gem": "Edelstein", + "Gem Armor": "Edelsteinrüstung", + "Gem Fishing Rod": "Edelsteinrute", + "Gem Ore": "Edelsteinerz", + "Gold": "Gold", + "Gold Apple": "Goldener Apfel", + "Gold Armor": "Goldrüstung", + "Gold Fishing Rod": "Goldrute", + "Gold Lantern": "Gold-Laterne", + "Gold Ore": "Golderz", + "Grass": "Gras", + "Grass Seeds": "Grasssamen", + "Green Clothes": "Grüne Kleidung", + "Green Wool": "Grüne Wolle", + "Gunpowder": "Schießpulver", + "Hard Rock": "Hartgestein", + "Haste Potion": "Eiltrank", + "Health Potion": "Gesundheitstrank", + "Hoe": "Feldhacke", + "Hole": "Loch", + "Infinite Fall": "Unendlicher Fall", + "Iron": "Eisen", + "Iron Armor": "Eisenrüstung", + "Iron Fishing Rod": "Steinrute", + "Iron Lantern": "Eisen-Laterne", + "Iron Ore": "Eisenerz", + "Key": "Schlüssel", + "Knight Spawner": "Ritter-Monsterspawner", + "Lantern": "Laterne", + "Lapis": "Lapis", + "Lava": "Lava", + "Lava Brick": "Lavaziegel", + "Lava Bucket": "Lavaeimer", + "Lava Potion": "Lavatrank", + "Leather": "Leder", + "Leather Armor": "Lederrüstung", + "Light Potion": "Lichttrank", + "Loom": "Webstuhl", + "Natural Rock": "Naturgestein", + "None Potion": "Kein Trank", + "Obsidian": "Obsidian", + "Obsidian Brick": "Obsidianziegel", + "Obsidian Door": "Obsidiantür", + "Obsidian Wall": "Obsidianwand", + "Orange Clothes": "Orange Kleidung", + "Ornate Obsidian": "Verzierter Obsidian", + "Ornate Stone": "Verzierter Stein", + "Oven": "Backofen", + "Pickaxe": "Spitzhacke", + "Pig Spawner": "Schweine-Monsterspawner", + "Plank": "Planke", + "Plank Wall": "Bretterwand", + "Player": "Spieler", + "Pork Chop": "Schweinekotelett", + "Potato": "Kartoffel", + "Potion": "Trank", + "Power Glove": "Krafthanschuh", + "Purple Clothes": "Lilane Kleidung", + "Raw Beef": "Rohes Rindfleisch", + "Raw Fish": "Roher Fisch", + "Raw Obsidian": "Roher Obsidian", + "Raw Pork": "Rohes Schweinefleisch", + "Red Clothes": "Rote Kleidung", + "Red Wool": "Rote Wolle", + "Reg Clothes": "Reg Kleidung", + "Regen Potion": "Regenerationstrank", + "Rock": "Stein", + "Rose": "Rose", + "Sand": "Sand", + "Scale": "Schuppe", + "Seeds": "Samen", + "Shard": "Scherbe", + "Shears": "Schere", + "Sheep Spawner": "Schaf-Monsterspawner", + "Shield Potion": "Schildtrank", + "Shovel": "Schaufel", + "Skeleton Spawner": "Skellett-Monsterspawner", + "Slime": "Schleim", + "Slime Spawner": "Schleim-Monsterspawner", + "Snake Armor": "Schlangerüstung", + "Snake Spawner": "Schlangen-Monsterspawner", + "Speed Potion": "Geschwindigkeitstrank", + "Stairs Down": "Treppen runter", + "Stairs Up": "Treppen rauf", + "Steak": "Gebratenens Rindfleisch", + "Stone": "Stein", + "Stone Brick": "Steinziegel", + "Stone Bricks": "Steinziegel", + "Stone Door": "Steintür", + "Stone Wall": "Steinwand", + "Swim Potion": "Schwimmtrank", + "Sword": "Schwert", + "Time Potion": "Zeittrank", + "Tnt": "TNT", + "Torch": "Fackel", + "Totem of Air": "Totem der Luft", + "Tree": "Baum", + "Tree Sapling": "Baumsetzling", + "Water": "Wasser", + "Water Bucket": "Wassereimer", + "Wheat": "Weizen", + "Wheat Seeds": "Weizensamen", + "Wood": "Holz", + "Wood Door": "Holztür", + "Wood Fishing Rod": "Holzrute", + "Wood Planks": "Holzplanken", + "Wood Wall": "Holzwand", + "Wool": "Wolle", + "Workbench": "Werkbank", + "Yellow Clothes": "Gelbe Kleidung", + "Yellow Wool": "Gelbe Wolle", + "Zombie Spawner": "Zombie-Monsterspawner", + "minicraft.achievement.airwizard": "Besiege... die Luft?", + "minicraft.achievement.airwizard.desc": "Besiege den ersten Luftzauberer!", + "minicraft.achievement.benchmarking": "Handwerker", + "minicraft.achievement.benchmarking.desc": "Baue eine Werkbank.", + "minicraft.achievement.bow.desc": "Schieße einen Pfeil mit einem Bogen ab.", + "minicraft.achievement.clothes": "Hab einen Farbenfrohen Tag!", + "minicraft.achievement.clothes.desc": "Stelle Kleidung in einer Farbe her", + "minicraft.achievement.demolition": "Abriss-Vorschau", + "minicraft.achievement.demolition.desc": "Benutze TNT.", + "minicraft.achievement.doors": "Schutz durch die Tür", + "minicraft.achievement.doors.desc": "Baue eine Holztür.", + "minicraft.achievement.find_gem": "Sehr glänzend!", + "minicraft.achievement.find_gem.desc": "Finde Edelsteinerz und baue es ab.", + "minicraft.achievement.fish": "Geh Angeln!", + "minicraft.achievement.fish.desc": "Fische einen Fisch!", + "minicraft.achievement.lava": "Heiße Angelegenheiten", + "minicraft.achievement.lava.desc": "Trinke einen Lava Trank und versuche in Lava zu schwimmen.", + "minicraft.achievement.lowest_caves": "Dunkelheit hinter dem Licht", + "minicraft.achievement.lowest_caves.desc": "Erreiche die untersten Höhlen.", + "minicraft.achievement.obsidian_dungeon": "Von Rittern und Männern", + "minicraft.achievement.obsidian_dungeon.desc": "Erreiche den Obsidian-Dungeon.", + "minicraft.achievement.planks": "Du bist auf dem Holzweg!", + "minicraft.achievement.planks.desc": "Baue Holzplanken.", + "minicraft.achievement.plant_seed": "Ein zwielichtiger Ort", + "minicraft.achievement.plant_seed.desc": "Pflanze einen Samen und schaue zu wie er wächst", + "minicraft.achievement.skin": "Modenschau", + "minicraft.achievement.skin.desc": "Verändere dein Aussehen.", + "minicraft.achievement.survive_darkness": "Wer hat Angst vor der Dunkelheit?", + "minicraft.achievement.survive_darkness.desc": "Überlebe 5 Minuten in der absoluten Dunkelheit.", + "minicraft.achievement.upgrade": "Fortschritt!", + "minicraft.achievement.upgrade.desc": "Baue ein beliebiges Steinwerkzeug.", + "minicraft.achievement.woodcutter": "Holzfäller", + "minicraft.achievement.woodcutter.desc": "Sammle Holz.", + "minicraft.control_guide.attack": "Benutze %s, um Mobs anzugreifen oder Kacheln zu zerstören.", + "minicraft.control_guide.craft": "Benutze %s, um dein Handwerksmenü zu öffnen.", + "minicraft.control_guide.menu": "Verwenden Sie %s, um Ihr Inventarmenü zu öffnen.", + "minicraft.control_guide.move": "Verwende%sum dich zu bewegen.", + "minicraft.display.entries.boolean.false": "Aus", + "minicraft.display.entries.boolean.true": "An", + "minicraft.display.gui.link_opening": "Im Browser öffnen", + "minicraft.display.gui.perm_status.saving": "Speichern... %s%%", + "minicraft.display.gui.perm_status.sleep_cancel": "Drücke %s zum Abbrechen", + "minicraft.display.gui.perm_status.sleeping": "Schlafen...", + "minicraft.display.gui.potion_effects.hide_hint": "(%s zum Verstecken!)", + "minicraft.display.gui.potion_effects.potion_dur": "%s(%d:%02d)", + "minicraft.display.gui.score.current_score": "Aktuelle Punktzahl: %s", + "minicraft.display.gui.score.time_left": "Zeit übrig %s%sm %ss", + "minicraft.display.menus.inventory": "Inventar", + "minicraft.display.options_display": "Einstellungen", + "minicraft.display.options_display.change_key_bindings": "Tastenbelegung ändern", + "minicraft.display.options_display.language": "Sprache", + "minicraft.display.options_display.resource_packs": "Ressourcenpakete", + "minicraft.display.popup.enter_confirm": "Eingabe zum bestätigen", + "minicraft.display.popup.escape_cancel": "Esc zum abbrechen", + "minicraft.display.popup.title_confirm": "Bestätigen", + "minicraft.displays.achievements": "Errungenschaften", + "minicraft.displays.achievements.display.achieved": "Erreicht!", + "minicraft.displays.achievements.display.help": "Benutze %s und %s um dich zu bewegen.", + "minicraft.displays.achievements.display.not_achieved": "Nicht erreicht", + "minicraft.displays.achievements.display.score": "Errungenschaftspunkte: %s", + "minicraft.displays.book.default_book": "Dieses Buch hat keinen Inhalt.", + "minicraft.displays.controls": "Steuerung", + "minicraft.displays.controls.display.controller": "Controller", + "minicraft.displays.controls.display.controller.00": "Bewegen des Spielers erfolgt durch das DPAD", + "minicraft.displays.controls.display.controller.01": "Bewegen des Cursors durch das DPAD", + "minicraft.displays.controls.display.controller.02": "Die Auswahl der Einträge erfolgt mit A", + "minicraft.displays.controls.display.controller.03": "Das Verlassen der Seiten erfolgt mit B", + "minicraft.displays.controls.display.controller.04": "Angreifen, Zerstören und Interagieren mit Kacheln erfolgt mit A", + "minicraft.displays.controls.display.controller.05": "Das Öffnen von Menüs im Spiel erfolgt mit X", + "minicraft.displays.controls.display.controller.06": "Das Öffnen von Handwerk-Menüs erfolgt mit Y", + "minicraft.displays.controls.display.controller.07": "Das Aufheben von Möbel erfolgt mit der linken Schultertaste", + "minicraft.displays.controls.display.controller.08": "Das Fallenlassen von Gegenständen erfolgt mit der rechten Schultertaste", + "minicraft.displays.controls.display.controller.09": "Das Fallenlassen eines ganzen Stapels erfolgt mit dem rechten Stick", + "minicraft.displays.controls.display.controller.10": "Das Umschalten der Suchleiste im Inventar verwendet START", + "minicraft.displays.controls.display.controller.11": "Das Pausieren des Spiels erfolgt mit START", + "minicraft.displays.controls.display.controller.desc.0": "Auf Debug-Zuordnungen kann nicht zugegriffen werden", + "minicraft.displays.controls.display.controller.desc.1": "Detaillierte Zuordnungen sind unbrauchbar", + "minicraft.displays.controls.display.help.0": "%s/%s um weitere Steuerelemente zu sehen", + "minicraft.displays.controls.display.keyboard": "Tastatur", + "minicraft.displays.controls.display.keyboard.03": "Das Verlassen von Seiten erfolgt mit EXIT", + "minicraft.displays.controls.display.keyboard.04": "Zum schnellen Speichern wird QUICKSAVE verwendet", + "minicraft.displays.crafting": "Bauen", + "minicraft.displays.crafting.container_title.cost": "Kosten:", + "minicraft.displays.crafting.container_title.have": "Du hast:", + "minicraft.displays.end_game.display.bonuses": "", + "minicraft.displays.end_game.display.final_score": "Punktzahl: %s", + "minicraft.displays.end_game.display.player_score": "Spielerpunktzahl: %s", + "minicraft.displays.end_game.display.unlocked": "Freigeschaltet in %s Sekunden", + "minicraft.displays.end_game.exit": "Zurück zum Menü", + "minicraft.displays.info.display.exit_help": "%s/%s:Verlassen", + "minicraft.displays.info.display.score": "Aktuelle Punktzahl: %s", + "minicraft.displays.info.display.time": "Zeit gespielt: %s Sekunden", + "minicraft.displays.info.title": "Spieler Status", + "minicraft.displays.key_input.display.help.0": "Drücke C/Eingabe um die Tastenbelegung zu ändern", + "minicraft.displays.key_input.display.help.1": "Drücke A, um eine Tastenbelegung hinzuzufügen", + "minicraft.displays.key_input.display.help.2": "Shift-D setzt alle Tastenbelegungen auf den Standard", + "minicraft.displays.key_input.display.help.3": "%s um zum Menü zurückzukommen", + "minicraft.displays.key_input.popup_display.confirm_reset": "Bist du sicher, dass du alle Tastenbelegungen auf Werkseinstellungen zurücksetzen willst?", + "minicraft.displays.key_input.popup_display.press_key_sequence": "Drücke die gewünschte Tastenkombination", + "minicraft.displays.key_input.title": "Steuerung", + "minicraft.displays.language_settings.title": "Sprache …", + "minicraft.displays.loading.message.dungeon_regeneration": "Regenerierung von B4", + "minicraft.displays.loading.message.entities": "Entitäten", + "minicraft.displays.loading.message.generating": "Generierung", + "minicraft.displays.loading.message.level": "Level %s", + "minicraft.displays.loading.message.levels": "Level", + "minicraft.displays.loading.message.loading": "Laden", + "minicraft.displays.loading.message.quests": "Quests", + "minicraft.displays.loading.message.saving": "Speichern", + "minicraft.displays.loading.message.world": "Welt", + "minicraft.displays.loading.regeneration_cancellation_popup.display": "Laden der Welt wurde abgebrochen", + "minicraft.displays.loading.regeneration_popup.display.0": "Der Dungeon der alten Version (B4-Etage) wurde erkannt.", + "minicraft.displays.loading.regeneration_popup.display.1": "Regeneration ist notwendig", + "minicraft.displays.loading.regeneration_popup.display.2": "Die alten Daten auf dieser Etage werden gelöscht:", + "minicraft.displays.loading.regeneration_popup.display.3": "%s zum Fortfahren", + "minicraft.displays.loading.regeneration_popup.display.4": "%s um das Laden der Welt abzubrechen", + "minicraft.displays.options_main_menu": "Hautpmenü-Optionen", + "minicraft.displays.options_main_menu.resource_packs": "Ressourcen-Pakete", + "minicraft.displays.options_world": "Weltoptionen", + "minicraft.displays.options_world.off_tutorials_confirm_popup": "Bist du dir sicher das du die Tutorials für immer deaktivieren möchtest?", + "minicraft.displays.options_world.turn_off_tutorials": "Tutorials deaktivieren", + "minicraft.displays.pause": "Pausiert", + "minicraft.displays.pause.display.exit_popup.0": "Bist du sicher, dass du das Spiel verlassen möchtest?", + "minicraft.displays.pause.display.exit_popup.1": "Dein ungesicherter Fortschritt wird verloren gehen", + "minicraft.displays.pause.display.exit_popup.cancel": "Abbrechen", + "minicraft.displays.pause.display.exit_popup.quit": "Verlassen ohne zu speichern", + "minicraft.displays.pause.display.help.choose": "%s: Wähle", + "minicraft.displays.pause.display.help.scroll": "%s und %s zum Scrollen", + "minicraft.displays.pause.menu": "Hauptmenü", + "minicraft.displays.pause.return": "Zurück zum Spiel", + "minicraft.displays.pause.save": "Spiel speichern", + "minicraft.displays.player_death.display.score": "Punktzahl: %s", + "minicraft.displays.player_death.display.time": "Zeit: %s", + "minicraft.displays.player_death.quit": "Verlassen", + "minicraft.displays.player_death.respawn": "Wiederbeleben", + "minicraft.displays.player_death.save_quit": "Speichern und verlassen", + "minicraft.displays.player_death.title": "Du bist gestorben! Aww!", + "minicraft.displays.player_inv.container_title.items": "Gegenstände", + "minicraft.displays.player_inv.display.help": "(%s) zum Suchen.", + "minicraft.displays.quests": "Aufgaben", + "minicraft.displays.quests.display.header.completed": "Erfüllt", + "minicraft.displays.quests.display.header.unlocked": "Freigeschaltet", + "minicraft.displays.quests.display.no_quest": "Keine Quest freigeschaltet", + "minicraft.displays.quests.display.no_quest_desc": "Keine Aufgaben", + "minicraft.displays.resource_packs.display.help.keyboard_needed": "Es werden nur Tastatureingaben akzeptiert.", + "minicraft.displays.resource_packs.display.help.move": "Benutze %s und %s um dich zu bewegen.", + "minicraft.displays.resource_packs.display.help.position": "UMSCHALT-[LINKS|RECHTS|OBEN|UNTEN], um Pakete zu verschieben.␣", + "minicraft.displays.resource_packs.display.help.select": "%s zum Prüfen.", + "minicraft.displays.resource_packs.display.title": "Ressourcen-Pakete", + "minicraft.displays.skin": "Skins", + "minicraft.displays.skin.display.help.move": "Benutze %s und %s um dich zu bewegen.", + "minicraft.displays.skin.display.help.select": "%s zum Auswählen und %s zum Abbrechen.", + "minicraft.displays.title.display.cannot_check": "Es konnte nicht nach Updates gesucht werden.", + "minicraft.displays.title.display.checking": "Suche nach Updates …", + "minicraft.displays.title.display.help.0": "(%s, %s zur Auswahl)", + "minicraft.displays.title.display.help.1": "(%s to accept)", + "minicraft.displays.title.display.help.2": "(%s um zurückzukehren)", + "minicraft.displays.title.display.latest_already": "Du hast die aktuelle Version.", + "minicraft.displays.title.display.new_version": "Neu: %s", + "minicraft.displays.title.display.version": "Version %s", + "minicraft.displays.title.help": "Hilfe", + "minicraft.displays.title.help.about": "Über", + "minicraft.displays.title.help.credits": "Credits", + "minicraft.displays.title.help.instructions": "Anweisungen", + "minicraft.displays.title.help.storyline_guide": "Storyline-Leitfaden", + "minicraft.displays.title.link_to_version": "Direkter Link zur neuesten Version: %s", + "minicraft.displays.title.play": "Spielen", + "minicraft.displays.title.play.load_world": "Welt laden", + "minicraft.displays.title.play.new_world": "Neue Welt", + "minicraft.displays.title.quit": "Verlassen", + "minicraft.displays.title.select_to_download": "--Hier zum Herunterladen auswählen--", + "minicraft.displays.tutorial_display_handler.display.element_examine_help": "Drücken Sie %s, um die Details des aktuellen Tutorials zu prüfen.", + "minicraft.displays.world_gen.create_world": "Welt erschaffen", + "minicraft.displays.world_gen.enter_world": "Gib einen Weltnamen ein", + "minicraft.displays.world_gen.title": "Welt generierungsoptionen", + "minicraft.displays.world_gen.troublesome_input": "Probleme mit dem Weltnamen?", + "minicraft.displays.world_gen.troublesome_input.msg": "Es scheint, dass Sie Buchstaben als Steuerelemente für die Bewegung des Cursors nach oben und unten festgelegt haben, was wahrscheinlich störend ist. Dies kann im Tastenbelegungsmenü als \"Cursor-XXX\"-Tasten geändert werden. Um den Buchstaben einzugeben, anstatt den Cursor zu bewegen, halten Sie die Umschalttaste während der Eingabe gedrückt.", + "minicraft.displays.world_gen.world_seed": "Welt Seed", + "minicraft.displays.world_select.display.help.0": "%s zum bestätigen", + "minicraft.displays.world_select.display.help.1": "%s um zurückzukehren", + "minicraft.displays.world_select.display.help.2": "SHIFT-C zum kopieren", + "minicraft.displays.world_select.display.help.3": "%s zum Umbenennen", + "minicraft.displays.world_select.display.help.4": "SHIFT-D zum löschen", + "minicraft.displays.world_select.display.world_too_new": "Neuere version, laden der Welt nicht möglich!", + "minicraft.displays.world_select.display.world_version": "Welt version: %s", + "minicraft.displays.world_select.popups.display.cancel": "%s um abzubrechen", + "minicraft.displays.world_select.popups.display.change": "Neuer Weltname:", + "minicraft.displays.world_select.popups.display.confirm": "%s zum bestätigen", + "minicraft.displays.world_select.popups.display.delete": "Bist du sicher das du folgende Welt löschen möchtest?\n%s\"%s\"%s\nEs gibt kein zurück!", + "minicraft.displays.world_select.select_world": "Welt auswählen", + "minicraft.notification.achievement_unlocked": "Errungenschaft freigeschaltet: %s", + "minicraft.notification.air_wizard_defeated": "Luftzauberer besiegt!", + "minicraft.notification.boss_limit": "Es können keine Bosse mehr gespawnt werden", + "minicraft.notification.cannot_sleep": "Kann nicht schlafen! %smin %s s übrig!", + "minicraft.notification.death_chest_retrieved": "Todestruhe wiedergefunden!", + "minicraft.notification.defeat_air_wizard_first": "Der Luftzauberer muss zuerst besiegt werden.", + "minicraft.notification.dig_hole": "Erst ein Loch graben!", + "minicraft.notification.dungeon_opened": "Der Dungeon ist jetzt geöffnet!", + "minicraft.notification.gem_pickaxe_required": "Edelstein-Spitzhacke erforderlich.", + "minicraft.notification.invalid_placement": "Kann nur auf %s platziert werden!", + "minicraft.notification.knight_statue_exists": "Eine Ritterstatue existiert", + "minicraft.notification.obsidian_knight_awoken": "Der Obsidian-Ritter ist erwacht!", + "minicraft.notification.obsidian_knight_defeated": "Obsidianritter: wurde Besiegt!", + "minicraft.notification.quest_completed": "Aufgabe abgeschlossen", + "minicraft.notification.quest_unlocked": "Aufgabe freigeschaltet", + "minicraft.notification.spawn_on_boss_tile": "Kann nur im Bossraum gespawnt werden", + "minicraft.notification.world_saved": "Welt gespeichert!", + "minicraft.notification.wrong_level_dungeon": "Kann nur auf der Dungeonebene gespawnt werden", + "minicraft.notification.wrong_level_sky": "Kann nur in der Himmelsebene beschworen werden", + "minicraft.notifications.statue_tapped": "Du hörst widerhallendes Geflüster...", + "minicraft.quest.farming": "arbeitender Landwirt", + "minicraft.quest.farming.crafting_hoe": "Eine Hacke craften", + "minicraft.quest.farming.getting_wheat": "Ein Weizen anbauen", + "minicraft.quest.farming.making_farmland": "Ein Ackerland schaffen", + "minicraft.quest.farming.planting_potato": "Eine Kartoffel pflanzen", + "minicraft.quest.farming.planting_wheat": "Ein Weizenkorn pflanzen", + "minicraft.quest.gems": "Straße aus Gems", + "minicraft.quest.gems.gem_armor": "Meister des Schutzes", + "minicraft.quest.iron_equipments.getting_more_iron": "Reich an Eisen", + "minicraft.quest.iron_equipments.iron_tools": "Alle Tools upgraden", + "minicraft.quest.potions.powerful_potions": "Mächtige Tränke", + "minicraft.settings.autosave": "Automatisches Speichern", + "minicraft.settings.difficulty": "Schwierigkeit", + "minicraft.settings.difficulty.easy": "Einfach", + "minicraft.settings.difficulty.hard": "Schwer", + "minicraft.settings.difficulty.normal": "Normal", + "minicraft.settings.fps": "Maximale FPS", + "minicraft.settings.mode": "Spielmodus", + "minicraft.settings.mode.creative": "Kreativmodus", + "minicraft.settings.mode.hardcore": "Hardcoremodus", + "minicraft.settings.mode.score": "Punktzahl", + "minicraft.settings.mode.survival": "Überlebensmodus", + "minicraft.settings.scoretime": "Zeit (Punktzahlmodus)", + "minicraft.settings.screenshot_scale": "Schnappschuss-Auflösung", + "minicraft.settings.size": "Weltgröße", + "minicraft.settings.sound": "Soundeinstellungen", + "minicraft.settings.theme": "Thema der Welt", + "minicraft.settings.theme.desert": "Wüste", + "minicraft.settings.theme.forest": "Wald", + "minicraft.settings.theme.hell": "Hölle", + "minicraft.settings.theme.normal": "Normal", + "minicraft.settings.theme.plain": "Grasland", + "minicraft.settings.type": "Oberflächen-Typ", + "minicraft.settings.type.box": "Box", + "minicraft.settings.type.irregular": "Uneben", + "minicraft.settings.type.island": "Insel", + "minicraft.settings.type.mountain": "Berg", + "minicraft.skin.minecraft_alex": "Bekanntes Mädchen", + "minicraft.skin.minecraft_steve": "Bekannte Junge", + "minicraft.skin.paul": "Paul", + "minicraft.skin.paul_cape": "Paul mit Umhang", + "minicraft.text_particales.key_consumed": "-1 Schlüssel", + "minicraft.tutorial.getting_wood": "Mehr Holz bekommen", + "minicraft.tutorial.getting_wooden_pickaxe": "Eine Holzspitzhacke bekommen", + "minicraft.tutorial.getting_workbench": "Eine Werkbank bekommen" +} diff --git a/src/client/resources/assets/localization/en-gb.json b/src/client/resources/assets/localization/en-gb.json new file mode 100644 index 000000000..57193ebc7 --- /dev/null +++ b/src/client/resources/assets/localization/en-gb.json @@ -0,0 +1,466 @@ +{ + "Acorn": "Acorn", + "AirWizard Spawner": "AirWizard Spawner", + "Antidious": "Antidious", + "Anvil": "Anvil", + "Apple": "Apple", + "Axe": "Axe", + "Baked Potato": "Baked Potato", + "Bed": "Bed", + "Black Clothes": "Black Clothes", + "Black Wool": "Black Wool", + "Blue Clothes": "Blue Clothes", + "Blue Wool": "Blue Wool", + "Bone": "Bone", + "Book": "Book", + "Bow": "Bow", + "Bread": "Bread", + "Cactus": "Cactus", + "Cactus Sapling": "Cactus Sapling", + "Chest": "Chest", + "Claymore": "Claymore", + "Cloud": "Cloud", + "Cloud Cactus": "Cloud Cactus", + "Cloud Ore": "Cloud Ore", + "Coal": "Coal", + "Cooked Fish": "Cooked Fish", + "Cooked Pork": "Cooked Pork", + "Cow Spawner": "Cow Spawner", + "Creeper Spawner": "Creeper Spawner", + "Cyan Clothes": "Cyan Clothes", + "Death Chest": "Death Chest", + "Dirt": "Dirt", + "Empty Bucket": "Empty Bucket", + "Enchanter": "Enchanter", + "Energy Potion": "Energy Potion", + "Escape Potion": "Escape Potion", + "Explode": "Explode", + "Farmland": "Farmland", + "Flower": "Flower", + "Furnace": "Furnace", + "Gem": "Gem", + "Gem Armor": "Gem Armor", + "Gem Fishing Rod": "Gem Fishing Rod", + "Gem Ore": "Gem Ore", + "Gold": "Gold", + "Gold Apple": "Gold Apple", + "Gold Armor": "Gold Armor", + "Gold Fishing Rod": "Gold Fishing Rod", + "Gold Lantern": "Gold Lantern", + "Gold Ore": "Gold Ore", + "Grass": "Grass", + "Grass Seeds": "Grass Seeds", + "Green Clothes": "Green Clothes", + "Green Wool": "Green Wool", + "Gunpowder": "Gunpowder", + "Hard Rock": "Hard Rock", + "Haste Potion": "Haste Potion", + "Health Potion": "Health Potion", + "Hoe": "Hoe", + "Hole": "Hole", + "Infinite Fall": "Infinite Fall", + "Iron": "Iron", + "Iron Armor": "Iron Armor", + "Iron Fishing Rod": "Iron Fishing Rod", + "Iron Lantern": "Iron Lantern", + "Iron Ore": "Iron Ore", + "Key": "Key", + "Knight Spawner": "Knight Spawner", + "Lantern": "Lantern", + "Lapis": "Lapis", + "Lava": "Lava", + "Lava Brick": "Lava Brick", + "Lava Bucket": "Lava Bucket", + "Lava Potion": "Lava Potion", + "Leather": "Leather", + "Leather Armor": "Leather Armor", + "Light Potion": "Light Potion", + "Loom": "Loom", + "Natural Rock": "Natural Rock", + "None Potion": "None Potion", + "Obsidian": "Obsidian", + "Obsidian Brick": "Obsidian Brick", + "Obsidian Door": "Obsidian Door", + "Obsidian Wall": "Obsidian Wall", + "Orange Clothes": "Orange Clothes", + "Ornate Obsidian": "Ornate Obsidian", + "Ornate Stone": "Ornate Stone", + "Oven": "Oven", + "Pickaxe": "Pickaxe", + "Pig Spawner": "Pig Spawner", + "Plank": "Plank", + "Plank Wall": "Plank Wall", + "Player": "Player", + "Pork Chop": "Pork Chop", + "Potato": "Potato", + "Potion": "Potion", + "Power Glove": "Power Glove", + "Purple Clothes": "Purple Clothes", + "Raw Beef": "Raw Beef", + "Raw Fish": "Raw Fish", + "Raw Obsidian": "Raw Obsidian", + "Raw Pork": "Raw Pork", + "Red Clothes": "Red Clothes", + "Red Wool": "Red Wool", + "Reg Clothes": "Reg Clothes", + "Regen Potion": "Regen Potion", + "Rock": "Rock", + "Rose": "Rose", + "Sand": "Sand", + "Scale": "Scale", + "Seeds": "Seeds", + "Shard": "Shard", + "Shears": "Shears", + "Sheep Spawner": "Sheep Spawner", + "Shield Potion": "Shield Potion", + "Shovel": "Shovel", + "Skeleton Spawner": "Skeleton Spawner", + "Slime": "Slime", + "Slime Spawner": "Slime Spawner", + "Snake Armor": "Snake Armor", + "Snake Spawner": "Snake Spawner", + "Speed Potion": "Speed Potion", + "Stairs Down": "Stairs Down", + "Stairs Up": "Stairs Up", + "Steak": "Steak", + "Stone": "Stone", + "Stone Brick": "Stone Brick", + "Stone Bricks": "Stone Brisk", + "Stone Door": "Stone Door", + "Stone Wall": "Stone Wall", + "Swim Potion": "Swim Potion", + "Sword": "Sword", + "Time Potion": "Time Potion", + "Tnt": "Tnt", + "Torch": "Torch", + "Totem of Air": "Totem of Air", + "Tree": "Tre", + "Tree Sapling": "Tree Sapling", + "Water": "Water", + "Water Bucket": "Water Bucket", + "Wheat": "Wheat", + "Wheat Seeds": "Wheat Seeds", + "Wood": "Wood", + "Wood Door": "Wood Door", + "Wood Fishing Rod": "Wood Fishing Rod", + "Wood Planks": "Wood Planks", + "Wood Wall": "Wood Wall", + "Wool": "Wool", + "Workbench": "Workbench", + "Yellow Clothes": "Yellow Clothes", + "Yellow Wool": "Yellow Wool", + "Zombie Spawner": "Zombie Spawner", + "minicraft.achievement.airwizard": "Defeat... the air?", + "minicraft.achievement.airwizard.desc": "Defeat the first Air Wizard!", + "minicraft.achievement.benchmarking": "Benchmarking", + "minicraft.achievement.benchmarking.desc": "Make a workbench.", + "minicraft.achievement.bow": "Bow down to me!", + "minicraft.achievement.bow.desc": "Fire an arrow with a bow.", + "minicraft.achievement.clothes": "Have a colourful day!", + "minicraft.achievement.clothes.desc": "Craft any color of clothes", + "minicraft.achievement.demolition": "Demolition Demo", + "minicraft.achievement.demolition.desc": "Use TNT.", + "minicraft.achievement.doors": "Adooring Protection", + "minicraft.achievement.doors.desc": "Craft a wood door.", + "minicraft.achievement.find_gem": "Oooh Shiny!", + "minicraft.achievement.find_gem.desc": "Find Gem Ore and mine it.", + "minicraft.achievement.fish": "Go Fish!", + "minicraft.achievement.fish.desc": "Fish up a Fish!", + "minicraft.achievement.lava": "Hot Affairs", + "minicraft.achievement.lava.desc": "Use a lava potion to swim in lava.", + "minicraft.achievement.lowest_caves": "What the light hides behind", + "minicraft.achievement.lowest_caves.desc": "Reach the lowest caves.", + "minicraft.achievement.obsidian_dungeon": "Of Knights and Men", + "minicraft.achievement.obsidian_dungeon.desc": "Reach the obsidian dungeon.", + "minicraft.achievement.planks": "Walk the Planks!", + "minicraft.achievement.planks.desc": "Craft wood planks.", + "minicraft.achievement.skin": "Glamour Show", + "minicraft.achievement.skin.desc": "Change your look.", + "minicraft.achievement.survive_darkness": "Afraid of the Dark?", + "minicraft.achievement.survive_darkness.desc": "Survive 5 minutes in total darkness.", + "minicraft.achievement.upgrade": "Upgrade!", + "minicraft.achievement.upgrade.desc": "Craft any Stone tool.", + "minicraft.achievement.woodcutter": "Woodcutter", + "minicraft.achievement.woodcutter.desc": "Get wood.", + "minicraft.control_guide.attack": "Use %s to attack mobs or destroy tiles.", + "minicraft.control_guide.craft": "Use %s to open your crafting menu.", + "minicraft.control_guide.menu": "Use %s to open your inventory menu.", + "minicraft.control_guide.move": "Use %s to move.", + "minicraft.display.entries.boolean.false": "Off", + "minicraft.display.entries.boolean.true": "On", + "minicraft.display.gui.link_opening": "Opening with browser...", + "minicraft.display.gui.perm_status.saving": "Saving... %s%%", + "minicraft.display.gui.perm_status.sleep_cancel": "Press %s to cancel", + "minicraft.display.gui.perm_status.sleeping": "Taking a Nap...", + "minicraft.display.gui.potion_effects.hide_hint": "(%s to hide!)", + "minicraft.display.gui.potion_effects.potion_dur": "%s (%d:%02d)", + "minicraft.display.gui.score.current_score": "Current score: %s", + "minicraft.display.gui.score.time_left": "Time left %s%sm %ss", + "minicraft.display.menus.inventory": "Inventory", + "minicraft.display.options_display": "Settings", + "minicraft.display.options_display.change_key_bindings": "Key bindings", + "minicraft.display.options_display.language": "Language", + "minicraft.display.options_display.resource_packs": "Resource packs", + "minicraft.display.popup.enter_confirm": "enter to confirm", + "minicraft.display.popup.escape_cancel": "escape to cancel", + "minicraft.display.popup.title_confirm": "Confirm Action", + "minicraft.displays.achievements": "Achievements", + "minicraft.displays.achievements.display.achieved": "Completed!", + "minicraft.displays.achievements.display.help": "Use %s and %s to move.", + "minicraft.displays.achievements.display.not_achieved": "Uncompleted", + "minicraft.displays.achievements.display.score": "Achievement Score: %s", + "minicraft.displays.book.default_book": "The book has no text.", + "minicraft.displays.controls": "Controls", + "minicraft.displays.controls.display.controller": "Controller", + "minicraft.displays.controls.display.controller.00": "Moving player uses DPAD", + "minicraft.displays.controls.display.controller.01": "Moving cursor uses DPAD", + "minicraft.displays.controls.display.controller.02": "Selecting entries uses A", + "minicraft.displays.controls.display.controller.03": "Exiting pages uses B", + "minicraft.displays.controls.display.controller.04": "Attacking entities, destroying and interacting tiles use A", + "minicraft.displays.controls.display.controller.05": "Opening menus in-game uses X", + "minicraft.displays.controls.display.controller.06": "Opening crafting menus uses Y", + "minicraft.displays.controls.display.controller.07": "Picking up furniture uses LEFTBUMPER", + "minicraft.displays.controls.display.controller.08": "Dropping 1 item uses RIGHTBUMPER", + "minicraft.displays.controls.display.controller.09": "Dropping whole stack of item uses RIGHTSTICK", + "minicraft.displays.controls.display.controller.10": "Toggling search bar in item menus uses START", + "minicraft.displays.controls.display.controller.11": "Pausing game uses START", + "minicraft.displays.controls.display.controller.12": "Use X to toggle on-screen keyboard on input", + "minicraft.displays.controls.display.controller.13": "Use B as shortcut for backspace on on-screen keyboard", + "minicraft.displays.controls.display.controller.14": "Use X to remove an selected item in inventory on creative mode", + "minicraft.displays.controls.display.controller.15": "Use Y to remove whole stack of item in inventory on creative mode", + "minicraft.displays.controls.display.controller.desc.0": "Debugging mappings are inaccessible", + "minicraft.displays.controls.display.controller.desc.1": "Detailed mappings are unusable", + "minicraft.displays.controls.display.help.0": "%s/%s to see another controls.", + "minicraft.displays.controls.display.keyboard": "Keyboard", + "minicraft.displays.controls.display.keyboard.00": "Moving player uses MOVE-(DIRECTION)", + "minicraft.displays.controls.display.keyboard.01": "Moving cursor uses CURSOR-(DIRECTION)", + "minicraft.displays.controls.display.keyboard.02": "Selecting entries uses SELECT", + "minicraft.displays.controls.display.keyboard.03": "Exiting pags uses EXIT", + "minicraft.displays.controls.display.keyboard.04": "Quick saving uses QUICKSAVE", + "minicraft.displays.controls.display.keyboard.05": "Attacking entities, destroying and interacting tiles use ATTACK", + "minicraft.displays.controls.display.keyboard.06": "Opening menus in-game uses MENU", + "minicraft.displays.controls.display.keyboard.07": "Opening crafting menus uses CRAFT", + "minicraft.displays.controls.display.keyboard.08": "Picking up furniture uses PICKUP", + "minicraft.displays.controls.display.keyboard.09": "Dropping 1 item uses DROP-ONE", + "minicraft.displays.controls.display.keyboard.10": "Dropping whole stack of item uses DROP-STACK", + "minicraft.displays.controls.display.keyboard.11": "Toggling search bar in item menus uses SEARCHER-BAR", + "minicraft.displays.controls.display.keyboard.12": "Browsing searched results uses PAGE-UP/DOWN", + "minicraft.displays.controls.display.keyboard.13": "Pausing game uses PAUSE", + "minicraft.displays.controls.display.keyboard.14": "Toggling potion effect display uses POTIONEFFECTS", + "minicraft.displays.controls.display.keyboard.15": "Toggling simplified potion display uses SIMPPOTIONEFFECTS", + "minicraft.displays.controls.display.keyboard.16": "Temperately expanding quest display in-game uses EXPANDQUESTDISPLAY", + "minicraft.displays.controls.display.keyboard.17": "Toggling HUD uses TOGGLEHUD", + "minicraft.displays.controls.display.keyboard.18": "Taking screenshot uses SCREENSHOT", + "minicraft.displays.controls.display.keyboard.19": "Showing in-game info uses INFO", + "minicraft.displays.controls.display.keyboard.20": "Toggling fullscreen uses FULLSCREEN", + "minicraft.displays.controls.display.keyboard.21": "Use D to remove an selected item in inventory on creative mode", + "minicraft.displays.controls.display.keyboard.22": "Use SHIFT-D to remove whole stack of item in inventory on creative mode", + "minicraft.displays.controls.display.keyboard.desc": "Debug mappings are not explained", + "minicraft.displays.crafting": "Crafting", + "minicraft.displays.crafting.container_title.cost": "Cost:", + "minicraft.displays.crafting.container_title.have": "Have:", + "minicraft.displays.end_game.display.bonuses": "", + "minicraft.displays.end_game.display.final_score": "Final Score: %s", + "minicraft.displays.end_game.display.player_score": "Player Score: %s", + "minicraft.displays.end_game.display.unlocked": "Unlocked! %s Score Time", + "minicraft.displays.end_game.exit": "Exit to Menu", + "minicraft.displays.info.display.exit_help": "%s/%s:Exit", + "minicraft.displays.info.display.score": "Current Score: %s", + "minicraft.displays.info.display.time": "Time Played: %s", + "minicraft.displays.info.title": "Player Statistics", + "minicraft.displays.key_input.display.help.0": "Press C/Enter to change key binding", + "minicraft.displays.key_input.display.help.1": "Press A to add key binding", + "minicraft.displays.key_input.display.help.2": "Shift-D to reset all keys to default", + "minicraft.displays.key_input.display.help.3": "%s to Return to menu", + "minicraft.displays.key_input.popup_display.confirm_reset": "Are you sure you want to reset all key bindings to the default keys?", + "minicraft.displays.key_input.popup_display.press_key_sequence": "Press the desired key sequence", + "minicraft.displays.key_input.title": "Controls", + "minicraft.displays.language_settings.title": "Language...", + "minicraft.displays.loading.message.dungeon_regeneration": "Regenerating B4", + "minicraft.displays.loading.message.entities": "Entities", + "minicraft.displays.loading.message.generating": "Generating", + "minicraft.displays.loading.message.level": "Level %s", + "minicraft.displays.loading.message.levels": "Levels", + "minicraft.displays.loading.message.loading": "Loading", + "minicraft.displays.loading.message.quests": "Quests", + "minicraft.displays.loading.message.saving": "Saving", + "minicraft.displays.loading.message.world": "World", + "minicraft.displays.loading.regeneration_cancellation_popup.display": "World loading cancelled", + "minicraft.displays.loading.regeneration_popup.display.0": "Old version dungeon (B4 floor) is detected.", + "minicraft.displays.loading.regeneration_popup.display.1": "Regeneration is needed.", + "minicraft.displays.loading.regeneration_popup.display.2": "Old data on that floor are going to be erased:", + "minicraft.displays.loading.regeneration_popup.display.3": "%s to continue", + "minicraft.displays.loading.regeneration_popup.display.4": "%s to cancel world loading", + "minicraft.displays.options_main_menu": "Main Menu Options", + "minicraft.displays.options_main_menu.resource_packs": "Resource packs", + "minicraft.displays.options_world": "World Options", + "minicraft.displays.options_world.off_tutorials_confirm_popup": "Are you sure you want to turn off the tutorials forever?", + "minicraft.displays.options_world.turn_off_tutorials": "Turn off tutorials", + "minicraft.displays.pause": "Paused", + "minicraft.displays.pause.display.exit_popup.0": "Are you sure you want to exit the game?", + "minicraft.displays.pause.display.exit_popup.1": "All unsaved progress will be lost", + "minicraft.displays.pause.display.exit_popup.cancel": "Cancel", + "minicraft.displays.pause.display.exit_popup.quit": "Quit without saving", + "minicraft.displays.pause.display.help.choose": "%s: Choose", + "minicraft.displays.pause.display.help.scroll": "%s and %s to Scroll", + "minicraft.displays.pause.menu": "Main Menu", + "minicraft.displays.pause.return": "Return to Game", + "minicraft.displays.pause.save": "Save Game", + "minicraft.displays.player_death.display.score": "Score: %s", + "minicraft.displays.player_death.display.time": "Time: %s", + "minicraft.displays.player_death.quit": "Quit", + "minicraft.displays.player_death.respawn": "Respawn", + "minicraft.displays.player_death.save_quit": "Save and Quit", + "minicraft.displays.player_death.title": "You Died! Yikes!", + "minicraft.displays.player_inv.container_title.items": "Items", + "minicraft.displays.player_inv.display.help": "(%s) to search.", + "minicraft.displays.quests": "Quests", + "minicraft.displays.quests.display.header.completed": "Completed", + "minicraft.displays.quests.display.header.unlocked": "Unlocked", + "minicraft.displays.quests.display.no_quest": "No quest unlocked", + "minicraft.displays.quests.display.no_quest_desc": "No quest", + "minicraft.displays.resource_packs.display.help.keyboard_needed": "Only keyboard input is accepted.", + "minicraft.displays.resource_packs.display.help.move": "Use %s and %s to move.", + "minicraft.displays.resource_packs.display.help.position": "SHIFT-[ARROW KEYS] to move packs. ", + "minicraft.displays.resource_packs.display.help.select": "%s to examine", + "minicraft.displays.resource_packs.display.title": "Resource Packs", + "minicraft.displays.skin": "Skins", + "minicraft.displays.skin.display.help.move": "Use %s and %s to move.", + "minicraft.displays.skin.display.help.select": "%s to select, and %s to cancel.", + "minicraft.displays.title.display.cannot_check": "Couldn't check for updates.", + "minicraft.displays.title.display.checking": "Checking for updates...", + "minicraft.displays.title.display.help.0": "(%s, %s to select)", + "minicraft.displays.title.display.help.1": "(%s to accept)", + "minicraft.displays.title.display.help.2": "(%s to return)", + "minicraft.displays.title.display.latest_already": "You have the latest version.", + "minicraft.displays.title.display.new_version": "New: %s", + "minicraft.displays.title.display.version": "Version %s", + "minicraft.displays.title.help": "Help", + "minicraft.displays.title.help.about": "About", + "minicraft.displays.title.help.credits": "Credits", + "minicraft.displays.title.help.instructions": "Instructions", + "minicraft.displays.title.help.storyline_guide": "Storyline", + "minicraft.displays.title.link_to_version": "Direct link to latest version: %s", + "minicraft.displays.title.play": "Play", + "minicraft.displays.title.play.load_world": "Load World", + "minicraft.displays.title.play.new_world": "New World", + "minicraft.displays.title.quit": "Quit", + "minicraft.displays.title.select_to_download": "--Select here to Download--", + "minicraft.displays.tutorial_display_handler.display.element_examine_help": "Press %s to examine the details of the current tutorial.", + "minicraft.displays.world_gen.create_world": "Create World", + "minicraft.displays.world_gen.enter_world": "Enter World Name", + "minicraft.displays.world_gen.title": "World Gen Options", + "minicraft.displays.world_gen.troublesome_input": "Trouble typing world name?", + "minicraft.displays.world_gen.troublesome_input.msg": "it seems you've set letters as the controls to move the cursor up and down, which is probably annoying. This can be changed in the key binding menu as the \"cursor-XXX\" keys. For now, to type the letter instead of using the cursor, hold the shift key while typing.", + "minicraft.displays.world_gen.world_seed": "World Seed", + "minicraft.displays.world_select.display.help.0": "%s to confirm", + "minicraft.displays.world_select.display.help.1": "%s to return", + "minicraft.displays.world_select.display.help.2": "SHIFT-C to copy", + "minicraft.displays.world_select.display.help.3": "SHIFT-R to rename", + "minicraft.displays.world_select.display.help.4": "SHIFT-D to delete", + "minicraft.displays.world_select.display.world_too_new": "Higher version, cannot load world!", + "minicraft.displays.world_select.display.world_version": "World Version: %s", + "minicraft.displays.world_select.popups.display.cancel": "%s to cancel", + "minicraft.displays.world_select.popups.display.change": "New World Name:", + "minicraft.displays.world_select.popups.display.confirm": "%s to confirm", + "minicraft.displays.world_select.popups.display.delete": "Are you sure you want to delete\n%s\"%s\"%s?\nThis cannot be undone!", + "minicraft.displays.world_select.select_world": "Select World", + "minicraft.notification.achievement_unlocked": "Achivement unlocked: %s", + "minicraft.notification.air_wizard_defeated": "Air Wizard Defeated!", + "minicraft.notification.boss_limit": "No more bosses can be spawned", + "minicraft.notification.cannot_sleep": "Can't sleep! %sMin %s Sec left!", + "minicraft.notification.death_chest_retrieved": "Death chest retrieved!", + "minicraft.notification.defeat_air_wizard_first": "The Air Wizard must be defeated first.", + "minicraft.notification.defeat_obsidian_knight_first": "The Obsidian Knight must be defeated first.", + "minicraft.notification.dig_hole": "Dig a hole first!", + "minicraft.notification.dungeon_opened": "The Dungeon is now open!", + "minicraft.notification.gem_pickaxe_required": "Gem Pickaxe Required.", + "minicraft.notification.invalid_placement": "Can only be placed on %s!", + "minicraft.notification.obsidian_knight_awoken": "The Obsidian Knight has awoken!", + "minicraft.notification.obsidian_knight_defeated": "Obsidian Knight: Defeated!", + "minicraft.notification.quest_completed": "Quest Completed", + "minicraft.notification.quest_unlocked": "Quest unlocked", + "minicraft.notification.spawn_on_boss_tile": "Can only be summoned in the Boss Room", + "minicraft.notification.world_saved": "World Saved!", + "minicraft.notification.wrong_level_dungeon": "Can only be summoned on the dungeon level", + "minicraft.notification.wrong_level_sky": "Can only be summoned on the sky level", + "minicraft.notifications.statue_tapped": "You hear echoed whispers...", + "minicraft.notifications.statue_touched": "You hear the statue vibrating...", + "minicraft.quest.farming": "Farming Farmer", + "minicraft.quest.farming.crafting_hoe": "Crafting a hoe", + "minicraft.quest.farming.crafting_hoe.description": "Crafting any hoe from the workbench", + "minicraft.quest.farming.description": "The basics as being a farmer.", + "minicraft.quest.farming.getting_wheat": "Harvesting a wheat", + "minicraft.quest.farming.getting_wheat.description": "Harvesting a wheat by breaking a grown wheat crop.", + "minicraft.quest.farming.making_farmland": "Making a farmland", + "minicraft.quest.farming.making_farmland.description": "Making a farmland with a hoe by interacting a dirt tile.", + "minicraft.quest.farming.planting_potato": "Planting a potato", + "minicraft.quest.farming.planting_potato.description": "Planting a potato by putting a potato on a farmland", + "minicraft.quest.farming.planting_wheat": "Planting a wheat", + "minicraft.quest.farming.planting_wheat.description": "Planting a wheat by putting a wheat seeds on a farmland.", + "minicraft.quest.gems": "Road of Gem", + "minicraft.quest.gems.description": "Getting gem equipments prepared.", + "minicraft.quest.gems.gem_armor": "Master of Protection", + "minicraft.quest.gems.gem_armor.description": "Getting a gem armor.", + "minicraft.quest.gems.gem_claymore": "Master of Weapon", + "minicraft.quest.gems.gem_claymore.description": "Getting a gem claymore.", + "minicraft.quest.iron_equipments": "Master Of Iron", + "minicraft.quest.iron_equipments.description": "Getting all of the iron equipments.", + "minicraft.quest.iron_equipments.getting_more_iron": "Rich of Iron", + "minicraft.quest.iron_equipments.getting_more_iron.description": "Getting more of iron.", + "minicraft.quest.iron_equipments.iron_armor": "Upgrading armor", + "minicraft.quest.iron_equipments.iron_armor.description": "Upgrading your armor to iron.", + "minicraft.quest.iron_equipments.iron_tools": "Upgrading all tools", + "minicraft.quest.iron_equipments.iron_tools.description": "Upgrading your tools to iron.", + "minicraft.quest.iron_equipments.upgrading_pickaxe": "Advanced pickaxe", + "minicraft.quest.iron_equipments.upgrading_pickaxe.description": "Upgrading your pickaxe.", + "minicraft.quest.potions": "Master of Potions", + "minicraft.quest.potions.all_potions_prepared": "Studier of Potions", + "minicraft.quest.potions.all_potions_prepared.description": "Getting all the potions at the same time.", + "minicraft.quest.potions.awkward_potions": "Awkward Potion", + "minicraft.quest.potions.awkward_potions.description": "Getting a awkward potion.", + "minicraft.quest.potions.description": "Getting the potions.", + "minicraft.quest.potions.powerful_potions": "Powerful Potions", + "minicraft.quest.potions.powerful_potions.description": "Getting the useful and powerful potions.", + "minicraft.settings.autosave": "Autosave", + "minicraft.settings.difficulty": "Difficulty", + "minicraft.settings.difficulty.easy": "Easy", + "minicraft.settings.difficulty.hard": "Hard", + "minicraft.settings.difficulty.normal": "Normal", + "minicraft.settings.fps": "Max FPS", + "minicraft.settings.mode": "Gamemode", + "minicraft.settings.mode.creative": "Creative", + "minicraft.settings.mode.hardcore": "Hardcore", + "minicraft.settings.mode.score": "Score", + "minicraft.settings.mode.survival": "Survival", + "minicraft.settings.scoretime": "Time (Score Mode)", + "minicraft.settings.screenshot_scale": "Screenshot Scale", + "minicraft.settings.size": "World Size", + "minicraft.settings.sound": "Sound", + "minicraft.settings.theme": "World Theme", + "minicraft.settings.theme.desert": "Desert", + "minicraft.settings.theme.forest": "Forest", + "minicraft.settings.theme.hell": "Hell", + "minicraft.settings.theme.normal": "Normal", + "minicraft.settings.theme.plain": "Plain", + "minicraft.settings.type": "Terrain Type", + "minicraft.settings.type.box": "Box", + "minicraft.settings.type.irregular": "Irregular", + "minicraft.settings.type.island": "Island", + "minicraft.settings.type.mountain": "Mountain", + "minicraft.skin.minecraft_alex": "Familiar Girl", + "minicraft.skin.minecraft_steve": "Familiar Boy", + "minicraft.skin.paul": "Paul", + "minicraft.skin.paul_cape": "Paul with Cape", + "minicraft.text_particales.key_consumed": "-1 Key", + "minicraft.tutorial.getting_rocks": "Getting stones and coals", + "minicraft.tutorial.getting_rocks.description": "Getting at least 5 stone and 5 coal items by destroying rocks with the pickaxe crafted.", + "minicraft.tutorial.getting_wood": "Getting more wood", + "minicraft.tutorial.getting_wood.description": "Getting at least 10 wood items from trees.", + "minicraft.tutorial.getting_wooden_pickaxe": "Getting a wooden pickaxe", + "minicraft.tutorial.getting_wooden_pickaxe.description": "Crafting a wooden pickaxe in the crafting menu from the workbench.", + "minicraft.tutorial.getting_workbench": "Getting a workbench", + "minicraft.tutorial.getting_workbench.description": "Crafting a workbench in the crafting menu. Placing it after that.", + "minicraft.tutorial.start_getting_wood": "Beginning of All", + "minicraft.tutorial.start_getting_wood.description": "Continuously attacking trees to get wood." +} diff --git a/src/client/resources/assets/localization/en-us.json b/src/client/resources/assets/localization/en-us.json index 5104b46ff..60c374467 100644 --- a/src/client/resources/assets/localization/en-us.json +++ b/src/client/resources/assets/localization/en-us.json @@ -1,36 +1,206 @@ { - "minicraft.achievement.woodcutter": "Woodcutter", - "minicraft.achievement.woodcutter.desc": "Get wood.", + "Acorn": "Acorn", + "AirWizard Spawner": "AirWizard Spawner", + "Antidious": "Antidious", + "Anvil": "Anvil", + "Apple": "Apple", + "Arrow": "Arrow", + "Awkward Potion": "Awkward Potion", + "Axe": "Axe", + "Baked Potato": "Baked Potato", + "Bed": "Bed", + "Black Clothes": "Black Clothes", + "Black Wool": "Black Wool", + "Blue Clothes": "Blue Clothes", + "Blue Wool": "Blue Wool", + "Bone": "Bone", + "Book": "Book", + "Bow": "Bow", + "Bread": "Bread", + "Cactus": "Cactus", + "Cactus Sapling": "Cactus Sapling", + "Chest": "Chest", + "Claymore": "Claymore", + "Cloth": "Cloth", + "Cloud": "Cloud", + "Cloud Cactus": "Cloud Cactus", + "Cloud Ore": "Cloud Ore", + "Coal": "Coal", + "Cooked Fish": "Cooked Fish", + "Cooked Pork": "Cooked Pork", + "Cow Spawner": "Cow Spawner", + "Creeper Spawner": "Creeper Spawner", + "Cyan Clothes": "Cyan Clothes", + "Death Chest": "Death Chest", + "Dirt": "Dirt", + "Dungeon Chest": "Dungeon Chest", + "Empty Bucket": "Empty Bucket", + "Enchanter": "Enchanter", + "Energy Potion": "Energy Potion", + "Escape Potion": "Escape Potion", + "Explode": "Explode", + "Farmland": "Farmland", + "Flower": "Flower", + "Furnace": "Furnace", + "Gem": "Gem", + "Gem Armor": "Gem Armor", + "Gem Fishing Rod": "Gem Fishing Rod", + "Gem Ore": "Gem Ore", + "Glass": "Glass", + "Glass Bottle": "Glass Bottle", + "Gold": "Gold", + "Gold Apple": "Gold Apple", + "Gold Armor": "Gold Armor", + "Gold Fishing Rod": "Gold Fishing Rod", + "Gold Lantern": "Gold Lantern", + "Gold Ore": "Gold Ore", + "Grass": "Grass", + "Grass Seeds": "Grass Seeds", + "Green Clothes": "Green Clothes", + "Green Wool": "Green Wool", + "Gunpowder": "Gunpowder", + "Hard Rock": "Hard Rock", + "Haste Potion": "Haste Potion", + "Health Potion": "Health Potion", + "Hoe": "Hoe", + "Hole": "Hole", + "Infinite Fall": "Infinite Fall", + "Iron": "Iron", + "Iron Armor": "Iron Armor", + "Iron Fishing Rod": "Iron Fishing Rod", + "Iron Lantern": "Iron Lantern", + "Iron Ore": "Iron Ore", + "Key": "Key", + "Knight Spawner": "Knight Spawner", + "Lantern": "Lantern", + "Lapis": "Lapis", + "Lava": "Lava", + "Lava Brick": "Lava Brick", + "Lava Bucket": "Lava Bucket", + "Lava Potion": "Lava Potion", + "Leather": "Leather", + "Leather Armor": "Leather Armor", + "Light Potion": "Light Potion", + "Loom": "Loom", + "Natural Rock": "Natural Rock", + "None Potion": "None Potion", + "Obsidian": "Obsidian", + "Obsidian Brick": "Obsidian Brick", + "Obsidian Door": "Obsidian Door", + "Obsidian Fence": "Obsidian Fence", + "Obsidian Heart": "Obsidian Heart", + "Obsidian Poppet": "Obsidian Poppet", + "Obsidian Wall": "Obsidian Wall", + "Orange Clothes": "Orange Clothes", + "Ornate Obsidian": "Ornate Obsidian", + "Ornate Stone": "Ornate Stone", + "Oven": "Oven", + "Path": "Path", + "Pickaxe": "Pickaxe", + "Pig Spawner": "Pig Spawner", + "Plank": "Plank", + "Plank Wall": "Plank Wall", + "Player": "Player", + "Pork Chop": "Pork Chop", + "Potato": "Potato", + "Potion": "Potion", + "Power Glove": "Power Glove", + "Purple Clothes": "Purple Clothes", + "Raw Beef": "Raw Beef", + "Raw Fish": "Raw Fish", + "Raw Obsidian": "Raw Obsidian", + "Raw Pork": "Raw Pork", + "Red Clothes": "Red Clothes", + "Red Wool": "Red Wool", + "Reg Clothes": "Reg Clothes", + "Regen Potion": "Regen Potion", + "Rock": "Rock", + "Rose": "Rose", + "Sand": "Sand", + "Scale": "Scale", + "Seeds": "Seeds", + "Shard": "Shard", + "Shears": "Shears", + "Sheep Spawner": "Sheep Spawner", + "Shield Potion": "Shield Potion", + "Shovel": "Shovel", + "Skeleton Spawner": "Skeleton Spawner", + "Slime": "Slime", + "Slime Spawner": "Slime Spawner", + "Snake Armor": "Snake Armor", + "Snake Spawner": "Snake Spawner", + "Speed Potion": "Speed Potion", + "Stairs Down": "Stairs Down", + "Stairs Up": "Stairs Up", + "Steak": "Steak", + "Stone": "Stone", + "Stone Brick": "Stone Brick", + "Stone Bricks": "Stone Bricks", + "Stone Door": "Stone Door", + "Stone Fence": "Stone Fence", + "Stone Wall": "Stone Wall", + "String": "String", + "Swim Potion": "Swim Potion", + "Sword": "Sword", + "Time Potion": "Time Potion", + "Tnt": "Tnt", + "Torch": "Torch", + "Totem of Air": "Totem of Air", + "Tree": "Tree", + "Tree Sapling": "Tree Sapling", + "Water": "Water", + "Water Bucket": "Water Bucket", + "Wheat": "Wheat", + "Wheat Seeds": "Wheat Seeds", + "Wood": "Wood", + "Wood Door": "Wood Door", + "Wood Fence": "Wood Fence", + "Wood Fishing Rod": "Wood Fishing Rod", + "Wood Planks": "Wood Planks", + "Wood Wall": "Wood Wall", + "Wool": "Wool", + "Workbench": "Workbench", + "Yellow Clothes": "Yellow Clothes", + "Yellow Wool": "Yellow Wool", + "Zombie Spawner": "Zombie Spawner", + "minicraft.achievement.airwizard": "Defeat... the air?", + "minicraft.achievement.airwizard.desc": "Defeat the Air Wizard!", "minicraft.achievement.benchmarking": "Benchmarking", "minicraft.achievement.benchmarking.desc": "Make a workbench.", - "minicraft.achievement.upgrade": "Upgrade!", - "minicraft.achievement.upgrade.desc": "Craft any Stone tool.", + "minicraft.achievement.boat": "Boating license", + "minicraft.achievement.boat.desc": "Craft a boat.", "minicraft.achievement.bow": "Bow down to me!", "minicraft.achievement.bow.desc": "Fire an arrow with a bow.", - "minicraft.achievement.fish": "Go Fish!", - "minicraft.achievement.fish.desc": "Fish up a Fish!", - "minicraft.achievement.doors": "Adooring Protection", - "minicraft.achievement.doors.desc": "Craft a wood door.", - "minicraft.achievement.planks": "Walk the Planks!", - "minicraft.achievement.planks.desc": "Craft wood planks.", "minicraft.achievement.clothes": "Have a colourful day!", - "minicraft.achievement.clothes.desc": "Craft any color of clothes", + "minicraft.achievement.clothes.desc": "Craft any color of clothes.", "minicraft.achievement.demolition": "Demolition Demo", "minicraft.achievement.demolition.desc": "Use TNT.", - "minicraft.achievement.survive_darkness": "Afraid of the Dark?", - "minicraft.achievement.survive_darkness.desc": "Survive 5 minutes in total darkness.", - "minicraft.achievement.lava": "Hot Affairs", - "minicraft.achievement.lava.desc": "Use a lava potion to swim in lava.", + "minicraft.achievement.doors": "Adooring Protection", + "minicraft.achievement.doors.desc": "Craft a wood door.", "minicraft.achievement.find_gem": "Oooh Shiny!", "minicraft.achievement.find_gem.desc": "Find Gem Ore and mine it.", + "minicraft.achievement.fish": "Go Fish!", + "minicraft.achievement.fish.desc": "Fish up a Fish!", + "minicraft.achievement.lava": "Hot Affairs", + "minicraft.achievement.lava.desc": "Use a lava potion to swim in lava.", "minicraft.achievement.lowest_caves": "Darkness behind light", "minicraft.achievement.lowest_caves.desc": "Reach the lowest caves.", "minicraft.achievement.obsidian_dungeon": "Of Knights and Men", "minicraft.achievement.obsidian_dungeon.desc": "Reach the obsidian dungeon.", - "minicraft.achievement.airwizard": "Defeat... the air?", - "minicraft.achievement.airwizard.desc": "Defeat the first Air Wizard!", + "minicraft.achievement.obsidianknight": "Shattered Burning Heart", + "minicraft.achievement.obsidianknight.desc": "Defeat the Obsidian Knight and obtain its heart!", + "minicraft.achievement.planks": "Walk the Planks!", + "minicraft.achievement.planks.desc": "Craft wood planks.", + "minicraft.achievement.plant_seed": "A Seedy Place", + "minicraft.achievement.plant_seed.desc": "Plant a seed and watch it grow.", "minicraft.achievement.skin": "Fashion Show", "minicraft.achievement.skin.desc": "Change your skin.", + "minicraft.achievement.survive_darkness": "Afraid of the Dark?", + "minicraft.achievement.survive_darkness.desc": "Survive 5 minutes in total darkness.", + "minicraft.achievement.upgrade": "Upgrade!", + "minicraft.achievement.upgrade.desc": "Craft any Stone tool.", + "minicraft.achievement.woodcutter": "Woodcutter", + "minicraft.achievement.woodcutter.desc": "Get wood.", "minicraft.control_guide.attack": "Use %s to attack mobs or destroy tiles.", "minicraft.control_guide.craft": "Use %s to open your crafting menu.", "minicraft.control_guide.menu": "Use %s to open your inventory menu.", @@ -49,9 +219,11 @@ "minicraft.display.options_display": "Options", "minicraft.display.options_display.change_key_bindings": "Change Key Bindings", "minicraft.display.options_display.language": "Language", + "minicraft.display.options_display.popup.hwa_warning.content": "Possible visual problems might occur if OpenGL Hardware Acceleration is enabled. Please confirm if you want to proceed.", + "minicraft.display.options_display.popup.hwa_warning.title": "Warning", "minicraft.display.options_display.resource_packs": "Resource packs", - "minicraft.display.popup.enter_confirm": "enter to confirm", - "minicraft.display.popup.escape_cancel": "escape to cancel", + "minicraft.display.popup.enter_confirm": "Enter to confirm", + "minicraft.display.popup.escape_cancel": "Escape to cancel", "minicraft.display.popup.title_confirm": "Confirm Action", "minicraft.displays.achievements": "Achievements", "minicraft.displays.achievements.display.achieved": "Achieved!", @@ -134,16 +306,17 @@ "minicraft.displays.loading.message.quests": "Quests", "minicraft.displays.loading.message.saving": "Saving", "minicraft.displays.loading.message.world": "World", + "minicraft.displays.loading.regeneration_cancellation_popup.display": "World loading cancelled", "minicraft.displays.loading.regeneration_popup.display.0": "Old version dungeon (B4 floor) is detected.", "minicraft.displays.loading.regeneration_popup.display.1": "Regeneration is needed.", "minicraft.displays.loading.regeneration_popup.display.2": "Old data on that floor are going to be erased:", "minicraft.displays.loading.regeneration_popup.display.3": "%s to continue", "minicraft.displays.loading.regeneration_popup.display.4": "%s to cancel world loading", - "minicraft.displays.loading.regeneration_cancellation_popup.display": "World loading cancelled", "minicraft.displays.options_main_menu": "Main Menu Options", "minicraft.displays.options_main_menu.resource_packs": "Resource packs", "minicraft.displays.options_world": "World Options", "minicraft.displays.options_world.off_tutorials_confirm_popup": "Are you sure you want to turn off the tutorials forever?", + "minicraft.displays.options_world.skip_current_tutorial": "Skip current tutorial", "minicraft.displays.options_world.turn_off_tutorials": "Turn off tutorials", "minicraft.displays.pause": "Paused", "minicraft.displays.pause.display.exit_popup.0": "Are you sure you want to exit the game?", @@ -168,6 +341,16 @@ "minicraft.displays.quests.display.header.unlocked": "Unlocked", "minicraft.displays.quests.display.no_quest": "No quest unlocked", "minicraft.displays.quests.display.no_quest_desc": "No quest", + "minicraft.displays.quests.quest_info.display.description": "Description: %s", + "minicraft.displays.quests.quest_info.display.ongoing_quests": "Ongoing quests: %s", + "minicraft.displays.quests.quest_info.display.progress": "Progress: (%d/%d)", + "minicraft.displays.quests.quest_info.display.progress_uncompleted": "Uncompleted", + "minicraft.displays.quests.quest_info.display.quests_completed_count": "Quests completed: %d", + "minicraft.displays.quests.quest_info.display.status": "Status: %s", + "minicraft.displays.quests.quest_info.display.status.completed": "Completed", + "minicraft.displays.quests.quest_info.display.status.locked": "Locked", + "minicraft.displays.quests.quest_info.display.status.unlocked": "Unlocked", + "minicraft.displays.quests.quest_info.view_quests": "View all quests of this series", "minicraft.displays.resource_packs.display.help.keyboard_needed": "Only keyboard input is accepted.", "minicraft.displays.resource_packs.display.help.move": "Use %s and %s to move.", "minicraft.displays.resource_packs.display.help.position": "SHIFT-[LEFT|RIGHT|UP|DOWN] to move packs. ", @@ -200,7 +383,7 @@ "minicraft.displays.world_gen.enter_world": "Enter World Name", "minicraft.displays.world_gen.title": "World Gen Options", "minicraft.displays.world_gen.troublesome_input": "Trouble with world name?", - "minicraft.displays.world_gen.troublesome_input.msg": "it seems you've set letters as the controls to move the cursor up and down, which is probably annoying. This can be changed in the key binding menu as the \"cursor-XXX\" keys. For now, to type the letter instead of moving the cursor, hold the shift key while typing.", + "minicraft.displays.world_gen.troublesome_input.msg": "It seems you've set letters as the controls to move the cursor up and down, which is probably annoying. This can be changed in the key binding menu as the \"cursor-XXX\" keys. For now, to type the letter instead of moving the cursor, hold the shift key while typing.", "minicraft.displays.world_gen.world_seed": "World Seed", "minicraft.displays.world_select.display.help.0": "%s to confirm", "minicraft.displays.world_select.display.help.1": "%s to return", @@ -216,8 +399,7 @@ "minicraft.displays.world_select.select_world": "Select World", "minicraft.notification.achievement_unlocked": "Achivement unlocked: %s", "minicraft.notification.air_wizard_defeated": "Air Wizard Defeated!", - "minicraft.notification.obsidian_knight_defeated": "Obsidian Knight: Defeated!", - "minicraft.notification.obsidian_knight_awoken": "The Obsidian Knight has awoken!", + "minicraft.notification.boss_limit": "No more bosses can be spawned", "minicraft.notification.cannot_sleep": "Can't sleep! %sMin %s Sec left!", "minicraft.notification.death_chest_retrieved": "Death chest retrieved!", "minicraft.notification.defeat_air_wizard_first": "The Air Wizard must be defeated first.", @@ -226,13 +408,16 @@ "minicraft.notification.dungeon_opened": "The Dungeon is now open!", "minicraft.notification.gem_pickaxe_required": "Gem Pickaxe Required.", "minicraft.notification.invalid_placement": "Can only be placed on %s!", + "minicraft.notification.knight_statue_exists": "A knight statue exists", + "minicraft.notification.obsidian_knight_awoken": "The Obsidian Knight has awoken!", + "minicraft.notification.obsidian_knight_defeated": "Obsidian Knight: Defeated!", "minicraft.notification.quest_completed": "Quest completed", "minicraft.notification.quest_unlocked": "Quest unlocked", + "minicraft.notification.spawn_on_boss_tile": "Can only be summoned in the Boss Room", + "minicraft.notification.tutorials_completed": "Tutorials are completed.", "minicraft.notification.world_saved": "World Saved!", - "minicraft.notification.wrong_level_sky": "Can only be summoned on the sky level", "minicraft.notification.wrong_level_dungeon": "Can only be summoned on the dungeon level", - "minicraft.notification.boss_limit": "No more bosses can be spawned", - "minicraft.notification.spawn_on_boss_tile": "Can only be summoned in the Boss Room", + "minicraft.notification.wrong_level_sky": "Can only be summoned on the sky level", "minicraft.notifications.statue_tapped": "You hear echoed whispers...", "minicraft.notifications.statue_touched": "You hear the statue vibrating...", "minicraft.quest.farming": "Farming Farmer", @@ -271,36 +456,40 @@ "minicraft.quest.potions.description": "Getting the potions.", "minicraft.quest.potions.powerful_potions": "Powerful Potions", "minicraft.quest.potions.powerful_potions.description": "Getting the useful and powerful potions.", - "minicraft.settings.fps": "Max FPS", + "minicraft.settings.autosave": "Autosave", "minicraft.settings.difficulty": "Difficulty", "minicraft.settings.difficulty.easy": "Easy", - "minicraft.settings.difficulty.normal": "Normal", "minicraft.settings.difficulty.hard": "Hard", + "minicraft.settings.difficulty.normal": "Normal", + "minicraft.settings.fps": "Max FPS", "minicraft.settings.mode": "Game Mode", - "minicraft.settings.mode.survival": "Survival", "minicraft.settings.mode.creative": "Creative", "minicraft.settings.mode.hardcore": "Hardcore", "minicraft.settings.mode.score": "Score", + "minicraft.settings.mode.survival": "Survival", + "minicraft.settings.opengl_hwa": "OpenGL Hardware Acceleration", + "minicraft.settings.quests": "Quests", "minicraft.settings.scoretime": "Time (Score Mode)", "minicraft.settings.screenshot_scale": "Screenshot Scale", - "minicraft.settings.sound": "Sound", - "minicraft.settings.autosave": "Autosave", + "minicraft.settings.show_quests": "Quest Panel", "minicraft.settings.size": "World Size", + "minicraft.settings.sound": "Sound", "minicraft.settings.theme": "World Theme", - "minicraft.settings.theme.normal": "Normal", - "minicraft.settings.theme.forest": "Forest", "minicraft.settings.theme.desert": "Desert", - "minicraft.settings.theme.plain": "Plain", + "minicraft.settings.theme.forest": "Forest", "minicraft.settings.theme.hell": "Hell", + "minicraft.settings.theme.normal": "Normal", + "minicraft.settings.theme.plain": "Plain", + "minicraft.settings.tutorials": "Tutorials", "minicraft.settings.type": "Terrain Type", - "minicraft.settings.type.island": "Island", "minicraft.settings.type.box": "Box", - "minicraft.settings.type.mountain": "Mountain", "minicraft.settings.type.irregular": "Irregular", + "minicraft.settings.type.island": "Island", + "minicraft.settings.type.mountain": "Mountain", + "minicraft.skin.minecraft_alex": "Familiar girl", + "minicraft.skin.minecraft_steve": "Familiar boy", "minicraft.skin.paul": "Paul", "minicraft.skin.paul_cape": "Paul with cape", - "minicraft.skin.minecraft_steve": "Familiar boy", - "minicraft.skin.minecraft_alex": "Familiar girl", "minicraft.text_particales.key_consumed": "-1 key", "minicraft.tutorial.getting_rocks": "Getting stones and coals", "minicraft.tutorial.getting_rocks.description": "Getting at least 5 stone and 5 coal items by destroying rocks with the pickaxe crafted.", @@ -311,161 +500,5 @@ "minicraft.tutorial.getting_workbench": "Getting a workbench", "minicraft.tutorial.getting_workbench.description": "Crafting a workbench in the crafting menu. Placing it after that.", "minicraft.tutorial.start_getting_wood": "Beginning of All", - "minicraft.tutorial.start_getting_wood.description": "Continuously Attacking trees to get wood.", - "Death Chest": "Death Chest", - "Player": "Player", - "Leather Armor": "Leather Armor", - "Snake Armor": "Snake Armor", - "Iron Armor": "Iron Armor", - "Gold Armor": "Gold Armor", - "Gem Armor": "Gem Armor", - "Book": "Book", - "Antidious": "Antidious", - "Empty Bucket": "Empty Bucket", - "Water Bucket": "Water Bucket", - "Lava Bucket": "Lava Bucket", - "Red Clothes": "Red Clothes", - "Blue Clothes": "Blue Clothes", - "Green Clothes": "Green Clothes", - "Yellow Clothes": "Yellow Clothes", - "Black Clothes": "Black Clothes", - "Orange Clothes": "Orange Clothes", - "Purple Clothes": "Purple Clothes", - "Cyan Clothes": "Cyan Clothes", - "Reg Clothes": "Reg Clothes", - "Bread": "Bread", - "Apple": "Apple", - "Raw Pork": "Raw Pork", - "Raw Fish": "Raw Fish", - "Raw Beef": "Raw Beef", - "Pork Chop": "Pork Chop", - "Cooked Fish": "Cooked Fish", - "Cooked Pork": "Cooked Pork", - "Steak": "Steak", - "Gold Apple": "Gold Apple", - "Baked Potato": "Baked Potato", - "Cow Spawner": "Cow Spawner", - "Pig Spawner": "Pig Spawner", - "Sheep Spawner": "Sheep Spawner", - "Slime Spawner": "Slime Spawner", - "Zombie Spawner": "Zombie Spawner", - "Creeper Spawner": "Creeper Spawner", - "Skeleton Spawner": "Skeleton Spawner", - "Snake Spawner": "Snake Spawner", - "Knight Spawner": "Knight Spawner", - "AirWizard Spawner": "AirWizard Spawner", - "Workbench": "Workbench", - "Oven": "Oven", - "Furnace": "Furnace", - "Anvil": "Anvil", - "Enchanter": "Enchanter", - "Loom": "Loom", - "Lantern": "Lantern", - "Iron Lantern": "Iron Lantern", - "Gold Lantern": "Gold Lantern", - "Tnt": "Tnt", - "Bed": "Bed", - "Chest": "Chest", - "None Potion": "None Potion", - "Speed Potion": "Speed Potion", - "Light Potion": "Light Potion", - "Swim Potion": "Swim Potion", - "Energy Potion": "Energy Potion", - "Regen Potion": "Regen Potion", - "Health Potion": "Health Potion", - "Time Potion": "Time Potion", - "Lava Potion": "Lava Potion", - "Shield Potion": "Shield Potion", - "Haste Potion": "Haste Potion", - "Escape Potion": "Escape Potion", - "Potion": "Potion", - "Power Glove": "Power Glove", - "Wood": "Wood", - "Stone": "Stone", - "Leather": "Leather", - "Wheat": "Wheat", - "Key": "Key", - "arrow": "arrow", - "string": "string", - "Coal": "Coal", - "Iron Ore": "Iron Ore", - "Gold Ore": "Gold Ore", - "Gem Ore": "Gem Ore", - "Cloud Ore": "Cloud Ore", - "Iron": "Iron", - "Gold": "Gold", - "Lapis": "Lapis", - "Rose": "Rose", - "GunPowder": "GunPowder", - "Slime": "Slime", - "glass": "glass", - "cloth": "cloth", - "gem": "gem", - "Scale": "Scale", - "Shard": "Shard", - "Flower": "Flower", - "Acorn": "Acorn", - "Dirt": "Dirt", - "Natural Rock": "Natural Rock", - "Plank": "Plank", - "Plank Wall": "Plank Wall", - "Wood Door": "Wood Door", - "Stone Brick": "Stone Brick", - "Ornate Stone": "Ornate Stone", - "Stone Wall": "Stone Wall", - "Stone Door": "Stone Door", - "Obsidian Brick": "Obsidian Brick", - "Ornate Obsidian": "Ornate Obsidian", - "Obsidian Wall": "Obsidian Wall", - "Obsidian Door": "Obsidian Door", - "Wool": "Wool", - "Red Wool": "Red Wool", - "Blue Wool": "Blue Wool", - "Green Wool": "Green Wool", - "Yellow Wool": "Yellow Wool", - "Black Wool": "Black Wool", - "Sand": "Sand", - "Cactus": "Cactus", - "Seeds": "Seeds", - "Wheat Seeds": "Wheat Seeds", - "Grass Seeds": "Grass Seeds", - "Bone": "Bone", - "Cloud": "Cloud", - "Rock": "Rock", - "Gem": "Gem", - "Potato": "Potato", - "Wood Fishing Rod": "Wood Fishing Rod", - "Iron Fishing Rod": "Iron Fishing Rod", - "Gold Fishing Rod": "Gold Fishing Rod", - "Gem Fishing Rod": "Gem Fishing Rod", - "Shovel": "Shovel", - "Hoe": "Hoe", - "Sword": "Sword", - "Pickaxe": "Pickaxe", - "Axe": "Axe", - "Bow": "Bow", - "Claymore": "Claymore", - "Shears": "Shears", - "Torch": "Torch", - "Wood Planks": "Wood Planks", - "Stone Bricks": "Stone Bricks", - "Obsidian": "Obsidian", - "Wood Wall": "Wood Wall", - "Grass": "Grass", - "Hole": "Hole", - "Stairs Up": "Stairs Up", - "Stairs Down": "Stairs Down", - "Water": "Water", - "Tree": "Tree", - "Tree Sapling": "Tree Sapling", - "Cactus Sapling": "Cactus Sapling", - "Lava": "Lava", - "Lava Brick": "Lava Brick", - "Explode": "Explode", - "Farmland": "Farmland", - "Hard Rock": "Hard Rock", - "Infinite Fall": "Infinite Fall", - "Cloud Cactus": "Cloud Cactus", - "Raw Obsidian": "Raw Obsidian", - "Totem of Air": "Totem of Air" + "minicraft.tutorial.start_getting_wood.description": "Continuously Attacking trees to get wood." } diff --git a/src/client/resources/assets/localization/es-es.json b/src/client/resources/assets/localization/es-es.json index e29d00a66..77e13150a 100644 --- a/src/client/resources/assets/localization/es-es.json +++ b/src/client/resources/assets/localization/es-es.json @@ -1,351 +1,504 @@ { - "minicraft.achievement.woodcutter": "Talador", - "minicraft.achievement.woodcutter.desc": "Conseguir madera", - "minicraft.achievement.benchmarking": "¡Hora de trabajar!", - "minicraft.achievement.benchmarking.desc": "Hacer un mesa de trabajo.", - "minicraft.achievement.upgrade": "Actualización!", - "minicraft.achievement.upgrade.desc": "Consigue una herramienta con un material más resistente que la madera.", - "minicraft.achievement.bow": "¡Inclínate ante mí!", - "minicraft.achievement.bow.desc": "Mata a un Mob con un arco.", - "minicraft.achievement.fish": "¡Arriba los peces!", - "minicraft.achievement.fish.desc": "¡Pescar un pez!", - "minicraft.achievement.doors": "Protección de puertas", - "minicraft.achievement.doors.desc": "Coloque todas las puertas.", - "minicraft.achievement.planks": "¡Camina por las tablas!", - "minicraft.achievement.planks.desc": "Coloca todos los tipos de tablas.", - "minicraft.achievement.clothes": "¡Que tengas un día lleno de color!", - "minicraft.achievement.clothes.desc": "Consigue ropa de todos los colores.", - "minicraft.achievement.demolition": "Demostración de demolición", - "minicraft.achievement.demolition.desc": "Usa dinamita.", - "minicraft.achievement.survive_darkness": "¿Miedo a la oscuridad?", - "minicraft.achievement.survive_darkness.desc": "Sobrevive 5 minutos en total oscuridad.", - "minicraft.achievement.lava": "Asuntos candentes", - "minicraft.achievement.lava.desc": "Usa una poción de lava para nadar en lava.", - "minicraft.achievement.find_gem": "¡Oooh Brillante!", - "minicraft.achievement.find_gem.desc": "Encuentra el mineral de gema y minalo.", - "minicraft.achievement.lowest_caves": "La oscuridad detrás de la luz", - "minicraft.achievement.lowest_caves.desc": "Llega a las cuevas más bajas.", - "minicraft.achievement.obsidian_dungeon": "De caballeros y hombres", - "minicraft.achievement.obsidian_dungeon.desc": "Llega a la mazmorra de obsidiana.", - "minicraft.achievement.airwizard": "Derrota... ¿el aire?", - "minicraft.achievement.airwizard.desc": "¡Derrota al primer Mago del Aire!", - "minicraft.achievement.skin": "Desfile de moda", - "minicraft.achievement.skin.desc": "Cambia de personaje.", - "minicraft.display.achievement": "Logros", - "minicraft.display.achievement.achieved": "¡Conseguido!", - "minicraft.display.achievement.not_achieved": "No se ha conseguido", - "minicraft.display.achievement.score": "Puntuación del logro:", - "minicraft.notification.achievement_unlocked": "Logro desbloqueado:", - "Entities": "Entidades", - "Air Wizard: Defeated!": "Mago de Aire: Derrotado!", - "The Dungeon is now open!": "El calabozo está abierto ahora", - "A costume lies on the ground...": "Un disfraz descansa en el suelo...", - "Can't sleep!": "¡No puedes dormir!", - "Min ": "Min ", - " Sec left!": " Segundo restante!", - "You hear a noise from the surface!": "Escuchas un ruido de la superficie!", - "Death Chest": "Cofre de la Muerte", - "Player": "Jugador", - "Crafting": "Elaborando", - "Set your home!": "Establece tu casa!", - "Can't set home here!": "No puedes establecer la casa aquí!", - "Home Sweet Home!": "Hogar Dulce Hogar!", - "Mode penalty: -2 health": "Modo de penalización: -2 de salud", - "You don't have a home!": "No tienes una casa!", - "You can't go home from here!": "No puedes ir a casa desde aquí!", - "Leather Armor": "Armadura de Cuero", - "Snake Armor": "Armadura de Serpiente", - "Iron Armor": "Armadura de Hierro", - "Gold Armor": "Armadura de Oro", - "Gem Armor": "Armadura de Gema", - "Book": "Libro", - "Antidious": "Antídoto", - "Empty Bucket": "Cubo vacío", - "Water Bucket": "Cubo de Agua", - "Lava Bucket": "Cubo de Lava", - " Bucket": " Cubo", - "Red Clothes": "Ropa Roja", - "Blue Clothes": "Ropa Azul", - "Green Clothes": "Ropa Verde", - "Yellow Clothes": "Ropa Amarilla", + "Acorn": "Bellota", + "AirWizard Spawner": "Generador de Mago Aéreo", + "Antidious": "Antidious", + "Anvil": "Yunque", + "Apple": "Manzana", + "Arrow": "Flecha", + "Awkward Potion": "Poción Extraña", + "Axe": "Hacha", + "Baked Potato": "Patata Cocida", + "Bed": "Cama", "Black Clothes": "Ropa Negra", - "Orange Clothes": "Ropa Anaranjada", - "Purple Clothes": "Ropa Morado", - "Cyan Clothes": "Ropa Turquesa", - "Reg Clothes": "Ropa Reg", + "Black Wool": "Lana Negra", + "Blue Clothes": "Ropa Azul", + "Blue Wool": "Lana Azul", + "Bone": "Hueso", + "Book": "Libro", + "Bow": "Arco", "Bread": "Pan", - "Apple": "Manzana", - "Raw Pork": "Cerdo crudo", - "Raw Fish": "Pescado crudo", - "Raw Beef": "Bistec crudo", - "Pork Chop": "Chuleta de Cerdo", - "Cooked Fish": "Pescado cocido", - "Cooked Pork": "Cerdo cocido", - "Steak": "Bistec", - "Gold Apple": "Manzana Dorada", - "Baked Potato": "Patata al Horno", + "Cactus": "Cactus", + "Cactus Sapling": "Brote de Cactus", + "Chest": "Cofre", + "Claymore": "Claymore", + "Cloth": "Paño", + "Cloud": "Nube", + "Cloud Cactus": "Cactus Nuboso", + "Cloud Ore": "Mena Nubosa", + "Coal": "Carbón", + "Cooked Fish": "Pescado Cocido", + "Cooked Pork": "Cerdo Cocido", "Cow Spawner": "Generador de Vaca", - "Pig Spawner": "Generador de Cerdo", - "Sheep Spawner": "Generador de Oveja", - "Slime Spawner": "Generador de Slime", - "Zombie Spawner": "Generador de Zombie", "Creeper Spawner": "Generador de Creeper", - "Skeleton Spawner": "Generador de Esqueleto", - "Snake Spawner": "Generador de Serpiente", - "Knight Spawner": "Generador de Caballero", - "AirWizard Spawner": "Generador de MagoAire", - "Workbench": "Mesa de trabajo", - "Oven": "Horno", - "Furnace": "Horno", - "Anvil": "Yunque", + "Cyan Clothes": "Ropa Cian", + "Death Chest": "Cofre de Recuperación", + "Dirt": "Tierra", + "Dungeon Chest": "Cofre de Mazmorra", + "Empty Bucket": "Cubo vacío", "Enchanter": "Encantador", - "Loom": "Telar", - "Lantern": "Linterna", - "Iron Lantern": "Linterna de Hierro", - "Gold Lantern": "Linterna de Oro", - "Tnt": "Dinamita", - "Bed": "Cama", - "Chest": "Cofre", - "None Potion": "Ninguna Poción", - "Speed Potion": "Poción de Velocidad", - "Light Potion": "Poción de Luz", - "Swim Potion": "Poción de Nadar", - "Energy Potion": "Poción de Energía", - "Regen Potion": "Poción de Reneg", - "Health Potion": "Poción de Vida", - "Time Potion": "Poción de Tiempo", - "Lava Potion": "Poción de Lava", - "Shield Potion": "Poción de Escudo", + "Energy Potion": "Poción Energética", + "Escape Potion": "Poción de Escape", + "Explode": "Explosión", + "Farmland": "Tierra Fértil", + "Flower": "Flor", + "Furnace": "Horno", + "Gem": "Gema", + "Gem Armor": "Armadura de Gema", + "Gem Fishing Rod": "Estrobo de gema", + "Gem Ore": "Mena de Gema", + "Glass": "Cristal", + "Glass Bottle": "Botella de Cristal", + "Gold": "Oro", + "Gold Apple": "Manzana Dorada", + "Gold Armor": "Armadura de Oro", + "Gold Fishing Rod": "Estrobo de oro", + "Gold Lantern": "Farol de Oro", + "Gold Ore": "Mena de Oro", + "Grass": "Pasto", + "Grass Seeds": "Semillas de Pasto", + "Green Clothes": "Ropa Verde", + "Green Wool": "Lana Verde", + "Gunpowder": "Pólvora", + "Hard Rock": "Roca Dura", "Haste Potion": "Poción de Prisa", - "Escape Potion": "Poción de Escapar", - "Potion": "Poción", - "Power Glove": "Poder de Guante", - "Wood": "Madera", - "Stone": "Piedra", - "Leather": "Cuero", - "Wheat": "Trigo", - "Key": "Llave", - "arrow": "flecha", - "string": "cuerda", - "Coal": "Carbón", + "Health Potion": "Poción de Vida", + "Hoe": "Azada", + "Hole": "Hoyo", + "Infinite Fall": "Caída Infinita", + "Iron": "Hierro", + "Iron Armor": "Armadura de Hierro", + "Iron Fishing Rod": "Estrobo de hierro", + "Iron Lantern": "Farol de Hierro", "Iron Ore": "Mena de Hierro", + "Key": "Llave", + "Knight Spawner": "Generador de Caballero", + "Lantern": "Farol", "Lapis": "Lapis", - "Gold Ore": "Mena de Oro", - "Iron": "Hierro", - "Gold": "Oro", - "Rose": "Rosa", - "GunPowder": "Pólvora", - "Slime": "Slime", - "glass": "cristal", - "cloth": "paño", - "gem": "gema", - "Scale": "Escala", - "Shard": "Élitro", - "Flower": "Flor", - "Acorn": "Bellota", - "Dirt": "Tierra", + "Lava": "Lava", + "Lava Brick": "Ladrillo de Lava", + "Lava Bucket": "Cubo de Lava", + "Lava Potion": "Poción Ignífuga", + "Leather": "Cuero", + "Leather Armor": "Armadura de Cuero", + "Light Potion": "Poción Lumínica", + "Loom": "Telar", "Natural Rock": "Roca natural", - "Plank": "Tablón", - "Plank Wall": "Muro de Tablón", - "Wood Door": "Puerta de Madera", - "Stone Brick": "Ladrillo de Piedra", - "Ornate Stone": "Piedra Ornamentada", - "Stone Wall": "Muro de Piedra", - "Stone Door": "Puerta de Piedra", + "None Potion": "Poción Vacía", + "Obsidian": "Obsidiana", "Obsidian Brick": "Ladrillo de Obsidiana", - "Ornate Obsidian": "Obsidiana Ornamentada", - "Obsidian Wall": "Muro de Obsidiana", "Obsidian Door": "Puerta de Obsidiana", - "Wool": "Lana", + "Obsidian Fence": "Valla de Obsidiana", + "Obsidian Heart": "Corazón de Obsidiana", + "Obsidian Poppet": "Figura de Obsidiana", + "Obsidian Wall": "Muro de Obsidiana", + "Orange Clothes": "Ropa Naranja", + "Ornate Obsidian": "Patrón de Obsidiana", + "Ornate Stone": "Patrón de Piedra", + "Oven": "Cocina", + "Path": "Camino", + "Pickaxe": "Pico", + "Pig Spawner": "Generador de Cerdo", + "Plank": "Tabla", + "Plank Wall": "Muro de Tablas", + "Player": "Jugador", + "Pork Chop": "Chuleta de Cerdo", + "Potato": "Patata", + "Potion": "Poción", + "Power Glove": "Guante Fuerte", + "Purple Clothes": "Ropa Morada", + "Raw Beef": "Bistec Crudo", + "Raw Fish": "Pescado Crudo", + "Raw Obsidian": "Obsidiana Cruda", + "Raw Pork": "Cerdo Crudo", + "Red Clothes": "Ropa Roja", "Red Wool": "Lana Roja", - "Blue Wool": "Lana Azul", - "Green Wool": "Lana Verde", - "Yellow Wool": "Lana Amarilla", - "Black Wool": "Lana Negra", + "Reg Clothes": "Ropa Común", + "Regen Potion": "Poción de Regen.", + "Rock": "Roca", + "Rose": "Rosa", "Sand": "Arena", - "Cactus": "Cactus", + "Scale": "Escama", "Seeds": "Semillas", - "Wheat Seeds": "Semilla de Trigo", - "Grass Seeds": "Semillas de Pasto", - "Bone": "Hueso", - "Cloud": "Nube", - "Rock": "Roca", - "Gem": "Gema", - "Potato": "Patata", - "Wood Fishing Rod": "Caña de pescar de madera", - "Iron Fishing Rod": "Caña de pescar de hierro", - "Gold Fishing Rod": "Caña de pescar de oro", - "Gem Fishing Rod": "Caña de pescar de gema", + "Shard": "Pieza", + "Shears": "Tijeras", + "Sheep Spawner": "Generador de Oveja", + "Shield Potion": "Poción de Escudo", "Shovel": "Pala", - "Hoe": "Azada", + "Skeleton Spawner": "Generador de Esqueleto", + "Slime": "Slime", + "Slime Spawner": "Generador de Slime", + "Snake Armor": "Armadura de Víbora", + "Snake Spawner": "Generador de Víbora", + "Speed Potion": "Poción de Velocidad", + "Stairs Down": "Escaleras Abajo", + "Stairs Up": "Escaleras Arriba", + "Steak": "Bistec", + "Stone": "Piedra", + "Stone Brick": "Ladrillo de Piedra", + "Stone Bricks": "Ladrillo de piedra", + "Stone Door": "Puerta de Piedra", + "Stone Fence": "Valla de Piedra", + "Stone Wall": "Muro de Piedra", + "String": "Cuerda", + "Swim Potion": "Poción de Natación", "Sword": "Espada", - "Pickaxe": "Pico", - "Axe": "Hacha", - "Bow": "Arco", - "Claymore": "Claymore", - "Shears": "Tijeras", + "Time Potion": "Poción Contrarreloj", + "Tnt": "Dinamita", "Torch": "Antorcha", - "Gem Ore": "Mena de Gema", - "Wood Planks": "Tablón de Madera", - "Stone Bricks": "Ladrillo de piedra", - "Obsidian": "Obsidiana", - "Wood Wall": "Muro de Madera", - "Grass": "Pasto", - "Hole": "Hoyo", - "Stairs Up": "Escaleras Arriba", - "Stairs Down": "Escaleras Abajo", - "Water": "Agua", + "Totem of Air": "Tótem Aéreo", "Tree": "Árbol", "Tree Sapling": "Brote de Árbol", - "Cactus Sapling": "Cactus Joven", - "Lava": "Lava", - "Lava Brick": "Ladrillo de Lava", - "Explode": "Explotar", - "Farmland": "Tierras de cultivo", - "Hard Rock": "Roca Dura", - "Infinite Fall": "Caída Infinita", - "Cloud Cactus": "Nubes de Cactus", - "Ore": "Mena", - "host not found": "alojamiento no encontrado", - "unable to get localhost address": "incapaz de obtener la dirección localhost", - "World Saved!": "¡Mundo Guardado!", - "On": "On", - "Off": "Off", - "There is nothing of use here.": "No hay nada de uso aquí.", - "Still nothing... :P": "Todavía nada... :P", - "Have:": "Tienes:", - "Cost:": "Costo:", - "Time: ": "Tiempo: ", - "Score: ": "Puntos: ", - "Quit": "Salir", - "Respawn": "Reaparecer", - "You died! Aww!": "Moriste! Aww!", - "Player Score: ": "Puntos del Jugador: ", - "": "", - "Final Score: ": "Puntos final: ", - "Exit to Menu": "Salir al Menu", - "Time Played: ": "Tiempo Jugado: ", - "Current Score: ": "Puntuación Actual: ", - "Exit": "Salir", - "Player Stats": "Estadisticas del Jugador", - "Controls": "Controles", - "Press the desired": "Presione el deseado", - "key sequence": "secuencia de tecla", - "minicraft.display.key_input.confirm_popup": "Estás seguro que quieres reiniciar todos los atajos de teclado a las teclas predeterminadas?", - "minicraft.display.popup.enter_confirm": "enter para confirmar", + "Water": "Agua", + "Water Bucket": "Cubo de Agua", + "Wheat": "Trigo", + "Wheat Seeds": "Semillas de Trigo", + "Wood": "Madera", + "Wood Door": "Puerta de Madera", + "Wood Fence": "Valla de Madera", + "Wood Fishing Rod": "Estrobo de madera", + "Wood Planks": "Tablas de Madera", + "Wood Wall": "Muro de Madera", + "Wool": "Lana", + "Workbench": "Mesa de trabajo", + "Yellow Clothes": "Ropa Amarilla", + "Yellow Wool": "Lana Amarilla", + "Zombie Spawner": "Generador de Zombi", + "minicraft.achievement.airwizard": "Desvanecido cual aire", + "minicraft.achievement.airwizard.desc": "¡Derrota al Mago aéreo!", + "minicraft.achievement.benchmarking": "¡A fabricar!", + "minicraft.achievement.benchmarking.desc": "Haz una Mesa de trabajo.", + "minicraft.achievement.boat": "Rema a Roma", + "minicraft.achievement.boat.desc": "Fabrica un bote.", + "minicraft.achievement.bow": "¡Tiro al blanco!", + "minicraft.achievement.bow.desc": "Dispara una flecha con un arco.", + "minicraft.achievement.clothes": "¡Ten un día colorido!", + "minicraft.achievement.clothes.desc": "Fabrica ropa de cualquier color.", + "minicraft.achievement.demolition": "¡La cosa está que explota!", + "minicraft.achievement.demolition.desc": "Explota una dinamita.", + "minicraft.achievement.doors": "Vistazo al Portazo", + "minicraft.achievement.doors.desc": "Fabrica una puerta de madera.", + "minicraft.achievement.find_gem": "¡Qué brillante!", + "minicraft.achievement.find_gem.desc": "Encuentra una mena de gema y mínala.", + "minicraft.achievement.fish": "Pesca marina", + "minicraft.achievement.fish.desc": "¡Pesca un pez con un estrobo!", + "minicraft.achievement.lava": "Asuntos ignífugos", + "minicraft.achievement.lava.desc": "Usa una poción ignífuga y date un baño calentito.", + "minicraft.achievement.lowest_caves": "La oscuridad tras la luz", + "minicraft.achievement.lowest_caves.desc": "Llega al nivel de cuevas más bajo.", + "minicraft.achievement.obsidian_dungeon": "Los nobles y el hombre", + "minicraft.achievement.obsidian_dungeon.desc": "Entra a la mazmorra de obsidiana.", + "minicraft.achievement.obsidianknight": "Rompiste su corazón", + "minicraft.achievement.obsidianknight.desc": "¡Derrota al Caballero Obsidiano y obtén su corazón!", + "minicraft.achievement.planks": "¡Anda sobre las tablas!", + "minicraft.achievement.planks.desc": "Fabrica tablas de madera.", + "minicraft.achievement.plant_seed": "¡Crece, pequeña!", + "minicraft.achievement.plant_seed.desc": "Planta una semilla de cualquier tipo y espera a que crezca.", + "minicraft.achievement.skin": "La nueva moda", + "minicraft.achievement.skin.desc": "Cambia de aspecto.", + "minicraft.achievement.survive_darkness": "¿Tienes nictofobia?", + "minicraft.achievement.survive_darkness.desc": "Sobrevive 5 minutos en total oscuridad.", + "minicraft.achievement.upgrade": "Edad de piedra", + "minicraft.achievement.upgrade.desc": "Fabrica una herramienta de Piedra.", + "minicraft.achievement.woodcutter": "Cortaleña", + "minicraft.achievement.woodcutter.desc": "Obtén madera.", + "minicraft.control_guide.attack": "%s: Atacar enemigos o destruir cosas", + "minicraft.control_guide.craft": "%s: Abrir menú de fabricación", + "minicraft.control_guide.menu": "%s: Abrir menú de inventario", + "minicraft.control_guide.move": "%s: Moverse", + "minicraft.display.entries.boolean.false": "No", + "minicraft.display.entries.boolean.true": "Sí", + "minicraft.display.gui.link_opening": "Abriendo en navegador...", + "minicraft.display.gui.perm_status.saving": "Guardando... %s%%", + "minicraft.display.gui.perm_status.sleep_cancel": "%s: Cancelar", + "minicraft.display.gui.perm_status.sleeping": "Durmiendo...", + "minicraft.display.gui.potion_effects.hide_hint": "(%s: Ocultar)", + "minicraft.display.gui.potion_effects.potion_dur": "%s (%d:%02d)", + "minicraft.display.gui.score.current_score": "Puntaje actual: %s", + "minicraft.display.gui.score.time_left": "Tiempo restante %s%sm %ss", + "minicraft.display.menus.inventory": "Inventario", + "minicraft.display.options_display": "Ajustes", + "minicraft.display.options_display.change_key_bindings": "Atajos de teclado", + "minicraft.display.options_display.language": "Idioma", + "minicraft.display.options_display.popup.hwa_warning.content": "Al habilitar Aceleración de Hardware OpenGL eres susceptible a experimentar errores visuales. Confirma si quieres habilitarla.", + "minicraft.display.options_display.popup.hwa_warning.title": "Advertencia", + "minicraft.display.options_display.resource_packs": "Lotes de recursos", + "minicraft.display.popup.enter_confirm": "ENTER para confirmar", "minicraft.display.popup.escape_cancel": "ESC para cancelar", - "Confirm Action": "Confirmar Acción", - "Press C/Enter to change key binding": "Presiona C/Enter para cambiar el atajo de teclado", - "Press A to add key binding": "Presiona A para añadir atajo de teclado", - "Shift-D to reset all keys to default": "Shift-D para restablecer todas las teclas a sus valores predeterminados", - "ESCAPE to Return to menu": "ESC para Regresar al menú", - "Loading": "Cargando", - "Generating": "Generando", - "World": "Mundo", - "waiting": "esperando", - "nothing": "nada", - "attempting log in": "intentando iniciar sesión", - "no internet connection, but no login data saved; cannot enter offline mode.": "no hay conexión a Internet, pero no se guardaron datos de inicio de sesión; no puede ingresar al modo fuera de línea.", - "connecting to server": "conectando al servidor", - "logging in": "iniciando sesión", - "saving credentials": "guardando credenciales", - "login failed.": "error de inicio de sesion.", - "problem with saved login data; please exit and login again.": "problema con los datos de inicio de sesión guardados; por favor salga y vuelva a iniciar sesión.", - "Internal server error: Couldn't fetch username from uuid": "Error interno del servidor: no se pudo obtener el nombre de usuario de uuid", - "logged in as: ": "conectado como: ", - "offline mode: local servers only": "modo fuera de línea: solo servidores locales", - "Enter ip address to connect to:": "Ingrese la dirección de IP para conectarse:", - "Press Shift-Escape to logout": "Presione Shift-ESC para cerrar la sesión", - "Enter email:": "Ingrese correo electronico:", - "Enter password:": "Ingrese contraseña:", - "field is blank": "el campo esta en blanco", - "get an account at:": "obtener una cuenta en:", - "Loading ": "Cargando ", - " from server": " desde el servidor", - "Could not connect to server:": "no pudo conectar al servidor:", - "Press ": "Presione ", - " to return": " para regresar", - "Change Key Bindings": "Cambiar Atajos de Teclado", - "Options": "Opciones", - "Change language": "Cambiar idioma", - "Return to Game": "Regresar al Juego", - "Make World Multiplayer": "Hacer Mundo Multijugador", - "Save Game": "Guardar Juego", - " and ": " y ", - " to Scroll": " para desplazarse", - ": Choose": ": Escoge", - "Paused": "Pausado", - "Main Menu": "Menú Principal", - "Yes": "Sí", - "No": "No", - "Inventory": "Inventario", - "to search.": "para buscar.", - "Play": "Jugar", - "Load World": "Cargar Mundo", - "New World": "Nuevo Mundo", - "Singleplayer": "Un jugador", - "Multiplayer": "Entrar en Mundo en línea", - "Help": "Ayuda", - "Instructions": "Instrucciones", - "Storyline Guide": "Guía de historias", - "About": "Acerca de", - "Credits": "Creditos", - " to select": " para seleccionar", - " to accept": " para aceptar", - "New World Name:": "Nuevo Nombre del Mundo:", - "Are you sure you want to delete": "Estás seguro que quieres eliminarlo", - "This can not be undone!": "¡Esto no se puede deshacer!", - " to confirm": " para confirmar", - " to cancel": " para cancelar", - "World Seed": "Semilla del Mundo", - "Enter World Name": "Ingrese Nombre del Mundo", - "Trouble with world name?": "¿Problema con el nombre?", - "by default, w and s move the cursor up and down. This can be changed in the key binding menu. To type the letter instead of moving the cursor, hold the shift key while typing the world name.": "de forma predeterminada, w y s mueven el cursor hacia arriba y hacia abajo. Esto se puede cambiar en el menú de enlace de teclas. Para escribir la letra en lugar de mover el cursor, mantenga presionada la tecla Mayús mientras escribe el nombre del mundo.", - "Create World": "Crear Mundo", - "World Gen Options": "Opciones de Generador de Mundo", - " to Copy": " para Copiar", - " to Rename": " para Renombrar", - " to Delete": " para Eliminar", - "Select World": "Seleccionar Mundo", - "Select a World to Delete": "Selecciona un Mundo para Eliminar", - "Select a World to Rename": "Selecciona un Mundo para Renombrar", - "Select a World to Copy": "Selecciona un Mundo para Copiar", - "Higher version, cannot load world!": "Version más nueva, ¡no se puede cargar el mundo!", - "World Version:": "Version del Mundo:", - "Languages": "Idiomas", - "Language": "Idioma", - "Select": "Selecionar", - "Max FPS": "Max FPS", - "Difficulty": "Dificultad", - "Easy": "Facíl", - "Normal": "Normal", - "Hard": "Difícil", - "Game Mode": "Modo de Juego", - "Survival": "Supervivencia", - "Creative": "Creativo", - "Hardcore": "Hardcore", - "Score": "Puntos", - "Time (Score Mode)": "Tiempo (Modo Puntos)", - "Sound": "Sonido", - "Autosave": "Autoguardado", - "World Size": "Tamaño del Mundo", - "World Theme": "Tema del Mundo", - "Forest": "Bosque", - "Desert": "Desierto", - "Plain": "Plano", - "Hell": "Infierno", - "Terrain Type": "Tipo de Terreno", - "Island": "Isla", - "Box": "Caja", - "Mountain": "Montaña", - "Irregular": "Inrregular", - "Wear Suit": "Usar traje", - "You have the latest version.": "Tienes la última version.", - "minicraft.display.skin": "Personajes", + "minicraft.display.popup.title_confirm": "Confirmar acción", + "minicraft.displays.achievements": "Logros", + "minicraft.displays.achievements.display.achieved": "¡Logrado!", + "minicraft.displays.achievements.display.help": "%s, %s: Moverse", + "minicraft.displays.achievements.display.not_achieved": "No Logrado", + "minicraft.displays.achievements.display.score": "Puntaje de logros: %s", + "minicraft.displays.book.default_book": "Este libro no tiene texto.", + "minicraft.displays.controls": "Controles", + "minicraft.displays.controls.display.controller": "Mando", + "minicraft.displays.controls.display.controller.00": "Mueve al jugador con el DPAD", + "minicraft.displays.controls.display.controller.01": "Mueve el cursor con el DPAD", + "minicraft.displays.controls.display.controller.02": "Selecciona opciones con A", + "minicraft.displays.controls.display.controller.03": "Sal de páginas con B", + "minicraft.displays.controls.display.controller.04": "Ataca enemigos, destruye e interactúa con objetos con A", + "minicraft.displays.controls.display.controller.05": "Abre menús en-juego con X", + "minicraft.displays.controls.display.controller.06": "Abre menús de fabricación con Y", + "minicraft.displays.controls.display.controller.07": "Coge muebles con LB", + "minicraft.displays.controls.display.controller.08": "Tira 1 objeto con RB", + "minicraft.displays.controls.display.controller.09": "Tira un montón entero de objetos con el STICK DERECHO", + "minicraft.displays.controls.display.controller.10": "Alterna la barra de búsqueda en menús de objetos con START", + "minicraft.displays.controls.display.controller.11": "Pausa el juego con START", + "minicraft.displays.controls.display.controller.12": "Usa X para alternar el teclado en pantalla", + "minicraft.displays.controls.display.controller.13": "Usa B como atajo de retroceso en teclado en pantalla", + "minicraft.displays.controls.display.controller.14": "Usa X para eliminar un objeto seleccionado en el inventario del modo creativo", + "minicraft.displays.controls.display.controller.15": "Usa Y para eliminar un montón entero de objetos en el inventario del modo creativo", + "minicraft.displays.controls.display.controller.desc.0": "Mapeos depuración inaccesibles", + "minicraft.displays.controls.display.controller.desc.1": "Mapeos detallados no usables", + "minicraft.displays.controls.display.help.0": "%s/%s: Ver controles de mando", + "minicraft.displays.controls.display.keyboard": "Teclado", + "minicraft.displays.controls.display.keyboard.00": "Mueve al jugador con MOVE-(DIRECCIÓN)", + "minicraft.displays.controls.display.keyboard.01": "Mueve el cursor con CURSOR-(DIRECCIÓN)", + "minicraft.displays.controls.display.keyboard.02": "Selecciona opciones con SELECT", + "minicraft.displays.controls.display.keyboard.03": "Sal de páginas con EXIT", + "minicraft.displays.controls.display.keyboard.04": "Haz un guardado rápido con QUICKSAVE", + "minicraft.displays.controls.display.keyboard.05": "Ataca enemigos, destruye e interactúa con objetos con ATTACK", + "minicraft.displays.controls.display.keyboard.06": "Abre menús en-juego con MENU", + "minicraft.displays.controls.display.keyboard.07": "Abre menús de fabricación con CRAFT", + "minicraft.displays.controls.display.keyboard.08": "Coge muebles con PICKUP", + "minicraft.displays.controls.display.keyboard.09": "Tira 1 objeto con DROP-ONE", + "minicraft.displays.controls.display.keyboard.10": "Tira un montón entero de objetos con DROP-STACK", + "minicraft.displays.controls.display.keyboard.11": "Alterna la barra de búsqueda en menús de objetos con SEARCHER-BAR", + "minicraft.displays.controls.display.keyboard.12": "Navega entre resultados de búsqueda con PAGE-UP/DOWN", + "minicraft.displays.controls.display.keyboard.13": "Pausa el juego con PAUSE", + "minicraft.displays.controls.display.keyboard.14": "Alterna notificaciones de efectos de poción con POTIONEFFECTS", + "minicraft.displays.controls.display.keyboard.15": "Alterna notificaciones de pociones simplificadas con SIMPPOTIONEFFECTS", + "minicraft.displays.controls.display.keyboard.16": "Expande notificaciones de misiones en-juego con EXPANDQUESTDISPLAY", + "minicraft.displays.controls.display.keyboard.17": "Alterna la HUD con TOGGLEHUD", + "minicraft.displays.controls.display.keyboard.18": "Toma capturas de pantalla con SCREENSHOT", + "minicraft.displays.controls.display.keyboard.19": "Muestra información de la partida con INFO", + "minicraft.displays.controls.display.keyboard.20": "Alterna pantalla completa con FULLSCREEN", + "minicraft.displays.controls.display.keyboard.21": "Usa D para eliminar un objeto seleccionado en el inventario del modo creativo", + "minicraft.displays.controls.display.keyboard.22": "Usa SHIFT-D para eliminar un montón entero de objetos en el inventario del modo creativo", + "minicraft.displays.controls.display.keyboard.desc": "Mapeos depuración no explicados", + "minicraft.displays.crafting": "Fabricando", + "minicraft.displays.crafting.container_title.cost": "Vale:", + "minicraft.displays.crafting.container_title.have": "Tengo:", + "minicraft.displays.end_game.display.bonuses": "", + "minicraft.displays.end_game.display.final_score": "Puntaje final: %s", + "minicraft.displays.end_game.display.player_score": "Puntaje del jugador: %s", + "minicraft.displays.end_game.display.unlocked": "¡Desbloqueado! %s Tiempo Cronometro", + "minicraft.displays.end_game.exit": "Salir al Menú principal", + "minicraft.displays.info.display.exit_help": "%s/%s: Salir", + "minicraft.displays.info.display.score": "Puntaje actual: %s", + "minicraft.displays.info.display.time": "Tiempo jugado: %s", + "minicraft.displays.info.title": "Datos de Jugador", + "minicraft.displays.key_input.display.help.0": "C/ENTER: Cambiar atajo de teclado", + "minicraft.displays.key_input.display.help.1": "A: Añadir atajo de teclado", + "minicraft.displays.key_input.display.help.2": "SHIFT-D: Reiniciar atajos de teclado", + "minicraft.displays.key_input.display.help.3": "%s: Volver al menú principal", + "minicraft.displays.key_input.popup_display.confirm_reset": "¿Estás seguro de reiniciar atajos de teclado a los predeterminados?", + "minicraft.displays.key_input.popup_display.press_key_sequence": "Presiona la tecla que desees", + "minicraft.displays.key_input.title": "Controles", + "minicraft.displays.language_settings.title": "Idioma...", + "minicraft.displays.loading.message.dungeon_regeneration": "Regenerando B4", + "minicraft.displays.loading.message.entities": "Entidades", + "minicraft.displays.loading.message.generating": "Generando", + "minicraft.displays.loading.message.level": "Nivel %s", + "minicraft.displays.loading.message.levels": "Niveles", + "minicraft.displays.loading.message.loading": "Cargando", + "minicraft.displays.loading.message.quests": "Misiones", + "minicraft.displays.loading.message.saving": "Guardando", + "minicraft.displays.loading.message.world": "Mundo", + "minicraft.displays.loading.regeneration_cancellation_popup.display": "La carga del mundo fue cancelada", + "minicraft.displays.loading.regeneration_popup.display.0": "La mazmorra de una versión antigua (Piso B4) fue detectada.", + "minicraft.displays.loading.regeneration_popup.display.1": "Se necesita una regeneración.", + "minicraft.displays.loading.regeneration_popup.display.2": "Los datos antiguos en ese piso serán eliminados:", + "minicraft.displays.loading.regeneration_popup.display.3": "%s: Continuar", + "minicraft.displays.loading.regeneration_popup.display.4": "%s: Cancelar carga del mundo", + "minicraft.displays.options_main_menu": "Opciones Principales", + "minicraft.displays.options_main_menu.resource_packs": "Lotes de recursos", + "minicraft.displays.options_world": "Opciones de Mundo", + "minicraft.displays.options_world.off_tutorials_confirm_popup": "¿Estás seguro de desactivar los tutoriales para siempre?", + "minicraft.displays.options_world.skip_current_tutorial": "Saltar tutorial actual", + "minicraft.displays.options_world.turn_off_tutorials": "Desactivar tutoriales", + "minicraft.displays.pause": "Pausado", + "minicraft.displays.pause.display.exit_popup.0": "¿Estás seguro de salir de la partida?", + "minicraft.displays.pause.display.exit_popup.1": "Todo el progreso no guardado se perderá", + "minicraft.displays.pause.display.exit_popup.cancel": "Cancelar", + "minicraft.displays.pause.display.exit_popup.quit": "Salir de todas formas", + "minicraft.displays.pause.display.help.choose": "%s: Elegir", + "minicraft.displays.pause.display.help.scroll": "%s, %s: Desplazarse", + "minicraft.displays.pause.menu": "Menú principal", + "minicraft.displays.pause.return": "Reanudar", + "minicraft.displays.pause.save": "Guardar partida", + "minicraft.displays.player_death.display.score": "Puntaje: %s", + "minicraft.displays.player_death.display.time": "Tiempo: %s", + "minicraft.displays.player_death.quit": "Salir", + "minicraft.displays.player_death.respawn": "Reaparecer", + "minicraft.displays.player_death.save_quit": "Salir y guardar", + "minicraft.displays.player_death.title": "¡Has muerto! ¡Auch!", + "minicraft.displays.player_inv.container_title.items": "Objetos", + "minicraft.displays.player_inv.display.help": "(%s: Buscar)", + "minicraft.displays.quests": "Misiones", + "minicraft.displays.quests.display.header.completed": "Completas", + "minicraft.displays.quests.display.header.unlocked": "Desbloqueadas", + "minicraft.displays.quests.display.no_quest": "No se han desbloqueado misiones", + "minicraft.displays.quests.display.no_quest_desc": "Sin misión", + "minicraft.displays.quests.quest_info.display.description": "Descripción: %s", + "minicraft.displays.quests.quest_info.display.ongoing_quests": "Misiones Empezadas: %s", + "minicraft.displays.quests.quest_info.display.progress": "Progreso: (%d/%d)", + "minicraft.displays.quests.quest_info.display.progress_uncompleted": "Sin completar", + "minicraft.displays.quests.quest_info.display.quests_completed_count": "Misiones completas: %d", + "minicraft.displays.quests.quest_info.display.status": "Estado: %s", + "minicraft.displays.quests.quest_info.display.status.completed": "Completado", + "minicraft.displays.quests.quest_info.display.status.locked": "Bloqueado", + "minicraft.displays.quests.quest_info.display.status.unlocked": "Desbloqueado", + "minicraft.displays.quests.quest_info.view_quests": "Ver misiones de esta serie", + "minicraft.displays.resource_packs.display.help.keyboard_needed": "Solo se acepta teclado.", + "minicraft.displays.resource_packs.display.help.move": "%s, %s: Moverse", + "minicraft.displays.resource_packs.display.help.position": "SHIFT-[FLECHAS]: Mover lotes", + "minicraft.displays.resource_packs.display.help.select": "%s: Examinar", + "minicraft.displays.resource_packs.display.title": "Lotes de recursos", + "minicraft.displays.skin": "Aspectos", + "minicraft.displays.skin.display.help.move": "%s, %s: Moverse", + "minicraft.displays.skin.display.help.select": "%s: Seleccionar, %s: Cancelar", + "minicraft.displays.title.display.cannot_check": "No pudo buscar actualizaciones.", + "minicraft.displays.title.display.checking": "Buscando actualizaciones...", + "minicraft.displays.title.display.help.0": "(%s, %s: Seleccionar)", + "minicraft.displays.title.display.help.1": "(%s: Aceptar)", + "minicraft.displays.title.display.help.2": "(%s: Volver)", + "minicraft.displays.title.display.latest_already": "Tienes la última versión.", + "minicraft.displays.title.display.new_version": "Nueva: %s", + "minicraft.displays.title.display.version": "Versión %s", + "minicraft.displays.title.help": "Ayuda", + "minicraft.displays.title.help.about": "Acerca de", + "minicraft.displays.title.help.credits": "Créditos", + "minicraft.displays.title.help.instructions": "Instrucciones", + "minicraft.displays.title.help.storyline_guide": "Guía de la historia", + "minicraft.displays.title.link_to_version": "Enlace a la última versión: %s", + "minicraft.displays.title.play": "Jugar", + "minicraft.displays.title.play.load_world": "Cargar Mundo", + "minicraft.displays.title.play.new_world": "Crear Mundo", + "minicraft.displays.title.quit": "Salir", + "minicraft.displays.title.select_to_download": "--Descárgala aquí--", + "minicraft.displays.tutorial_display_handler.display.element_examine_help": "Examina los detalles del tutorial actual con %s.", + "minicraft.displays.world_gen.create_world": "Crear Mundo", + "minicraft.displays.world_gen.enter_world": "Nombre del Mundo", + "minicraft.displays.world_gen.title": "Opciones de Mundo", + "minicraft.displays.world_gen.troublesome_input": "¿Problemas con el nombre?", + "minicraft.displays.world_gen.troublesome_input.msg": "Parece que has puesto letras como atajos de mover el cursor en vertical, lo cual puede molestar. Esto se puede cambiar en el menú atajos de teclado como las teclas \"cursor-XXX\". Por ahora, para escribir una letra en vez de mover el cursor, mantén SHIFT apretado al escribir.", + "minicraft.displays.world_gen.world_seed": "Semilla", + "minicraft.displays.world_select.display.help.0": "%s: Confirmar", + "minicraft.displays.world_select.display.help.1": "%s: Volver", + "minicraft.displays.world_select.display.help.2": "%s: Copiar mundo", + "minicraft.displays.world_select.display.help.3": "%s: Renombrar mundo", + "minicraft.displays.world_select.display.help.4": "%s: Eliminar mundo", + "minicraft.displays.world_select.display.world_too_new": "¡No se puede cargar el mundo, versión mayor!", + "minicraft.displays.world_select.display.world_version": "Versión del Mundo: %s", + "minicraft.displays.world_select.popups.display.cancel": "%s: Cancelar", + "minicraft.displays.world_select.popups.display.change": "Nuevo Nombre:", + "minicraft.displays.world_select.popups.display.confirm": "%s: Confirmar", + "minicraft.displays.world_select.popups.display.delete": "¿Estás seguro de querer eliminar \n%s\"%s\"%s?\n¡Esto no se puede deshacer!", + "minicraft.displays.world_select.select_world": "Seleccionar Mundo", + "minicraft.notification.achievement_unlocked": "Logro desbloqueado: %s", + "minicraft.notification.air_wizard_defeated": "Mago Aéreo: ¡Derrotado!", + "minicraft.notification.boss_limit": "Ya no se pueden invocar más jefes", + "minicraft.notification.cannot_sleep": "¡No puedes dormir! ¡Espera %s :%s !", + "minicraft.notification.death_chest_retrieved": "¡Cofre de recuperación obtenido!", + "minicraft.notification.defeat_air_wizard_first": "El mago aéreo debe ser derrotado primero.", + "minicraft.notification.defeat_obsidian_knight_first": "El Caballero Obsidiano debe ser derrotado primero.", + "minicraft.notification.dig_hole": "¡Cava un hoyo primero!", + "minicraft.notification.dungeon_opened": "¡La mazmorra se abrió!", + "minicraft.notification.gem_pickaxe_required": "Pico de gema requerido.", + "minicraft.notification.invalid_placement": "¡Solo puede colocarse en %s!", + "minicraft.notification.knight_statue_exists": "Ya existe una estatua", + "minicraft.notification.obsidian_knight_awoken": "¡El Caballero Obsidiano ha despertado!", + "minicraft.notification.obsidian_knight_defeated": "Caballero Obsidiano: ¡Derrotado!", + "minicraft.notification.quest_completed": "Misión completada", + "minicraft.notification.quest_unlocked": "Misión desbloqueada", + "minicraft.notification.spawn_on_boss_tile": "Solo se puede invocar en la Sala de Combate", + "minicraft.notification.tutorials_completed": "Has completado los tutoriales.", + "minicraft.notification.world_saved": "¡Mundo guardado!", + "minicraft.notification.wrong_level_dungeon": "Solo se puede invocar en la mazmorra", + "minicraft.notification.wrong_level_sky": "Solo se puede invocar en el cielo", + "minicraft.notifications.statue_tapped": "Los susurros hacen eco...", + "minicraft.notifications.statue_touched": "La estatua oyes vibrar...", + "minicraft.quest.farming": "Agricultor", + "minicraft.quest.farming.crafting_hoe": "Fabrica una azada", + "minicraft.quest.farming.crafting_hoe.description": "Fabrica cualquier azada en una mesa de trabajo", + "minicraft.quest.farming.description": "Lo básico de un agricultor.", + "minicraft.quest.farming.getting_wheat": "Sembradío de trigo", + "minicraft.quest.farming.getting_wheat.description": "Recoge trigo rompiendo una siembra de trigo ya crecida.", + "minicraft.quest.farming.making_farmland": "Cultivo activo", + "minicraft.quest.farming.making_farmland.description": "Haz tierra fértil interactuando con una azada a un trozo de tierra.", + "minicraft.quest.farming.planting_potato": "Plantando patatas", + "minicraft.quest.farming.planting_potato.description": "Planta una patata poniendo una patata en tierra fértil", + "minicraft.quest.farming.planting_wheat": "Plantando trigo", + "minicraft.quest.farming.planting_wheat.description": "Planta trigo poniendo semillas de trigo en tierra fértil.", + "minicraft.quest.gems": "Llévame a la Gema", + "minicraft.quest.gems.description": "Preparando equipamiento de gema.", + "minicraft.quest.gems.gem_armor": "Listo para Luchar", + "minicraft.quest.gems.gem_armor.description": "Obtén armadura de gema.", + "minicraft.quest.gems.gem_claymore": "As de la Espada", + "minicraft.quest.gems.gem_claymore.description": "Obtén claymore de gema.", + "minicraft.quest.iron_equipments": "Herrero Nuevo", + "minicraft.quest.iron_equipments.description": "Obtén todo el equipamiento de hierro.", + "minicraft.quest.iron_equipments.getting_more_iron": "Me sobra el hierro", + "minicraft.quest.iron_equipments.getting_more_iron.description": "Obtén aún más hierro.", + "minicraft.quest.iron_equipments.iron_armor": "Mejora de armadura", + "minicraft.quest.iron_equipments.iron_armor.description": "Mejora tu armadura a hierro.", + "minicraft.quest.iron_equipments.iron_tools": "Mejora toda herramienta", + "minicraft.quest.iron_equipments.iron_tools.description": "Mejora tus herramientas a hierro.", + "minicraft.quest.iron_equipments.upgrading_pickaxe": "Pico Mejorado", + "minicraft.quest.iron_equipments.upgrading_pickaxe.description": "Mejora tu pico.", + "minicraft.quest.potions": "Mago Destilador", + "minicraft.quest.potions.all_potions_prepared": "Alquimia Mixta", + "minicraft.quest.potions.all_potions_prepared.description": "Obtén todos los efectos de poción al mismo tiempo.", + "minicraft.quest.potions.awkward_potions": "Poción Extraña", + "minicraft.quest.potions.awkward_potions.description": "Obtén una poción extraña.", + "minicraft.quest.potions.description": "Obteniendo Pociones.", + "minicraft.quest.potions.powerful_potions": "Pociones Poderosas", + "minicraft.quest.potions.powerful_potions.description": "Obtén las pociones útiles y poderosas.", + "minicraft.settings.autosave": "Autoguardado", + "minicraft.settings.difficulty": "Dificultad", + "minicraft.settings.difficulty.easy": "Fácil", + "minicraft.settings.difficulty.hard": "Difícil", + "minicraft.settings.difficulty.normal": "Normal", + "minicraft.settings.fps": "FPS Máx.", + "minicraft.settings.mode": "Modo de Juego", + "minicraft.settings.mode.creative": "Creativo", + "minicraft.settings.mode.hardcore": "Extremo", + "minicraft.settings.mode.score": "Puntaje", + "minicraft.settings.mode.survival": "Supervivencia", + "minicraft.settings.opengl_hwa": "Acelerac. de Hardware OpenGL", + "minicraft.settings.quests": "Misiones", + "minicraft.settings.scoretime": "Cronometro (Modo Puntaje)", + "minicraft.settings.screenshot_scale": "Gama de Capturas", + "minicraft.settings.show_quests": "Panel de Misiones", + "minicraft.settings.size": "Tamaño del Mundo", + "minicraft.settings.sound": "Sonido", + "minicraft.settings.theme": "Tema del Mundo", + "minicraft.settings.theme.desert": "Desierto", + "minicraft.settings.theme.forest": "Arboleda", + "minicraft.settings.theme.hell": "Magma", + "minicraft.settings.theme.normal": "Normal", + "minicraft.settings.theme.plain": "Plano", + "minicraft.settings.tutorials": "Tutoriales", + "minicraft.settings.type": "Tipo de Terreno", + "minicraft.settings.type.box": "Caja", + "minicraft.settings.type.irregular": "Irregular", + "minicraft.settings.type.island": "Isla", + "minicraft.settings.type.mountain": "Montaña", + "minicraft.skin.minecraft_alex": "Chica conocida", + "minicraft.skin.minecraft_steve": "Chico conocido", "minicraft.skin.paul": "Paul", "minicraft.skin.paul_cape": "Paul con capa", - "minicraft.skin.minecraft_steve": "Hombre conocido", - "minicraft.skin.minecraft_alex": "Mujer conocida", - "minicraft.notification.invalid_placement": "Sólo puede colocarse en", - "minicraft.notification.dig_hole": "¡Cava un agujero primero!" + "minicraft.text_particales.key_consumed": "-1 Llave", + "minicraft.tutorial.getting_rocks": "Rocas y carbón", + "minicraft.tutorial.getting_rocks.description": "Obtén al menos 5 de piedra y 5 de carbón destruyendo rocas con el pico fabricado.", + "minicraft.tutorial.getting_wood": "Mucha más madera", + "minicraft.tutorial.getting_wood.description": "Obtén al menos 10 de madera de los árboles.", + "minicraft.tutorial.getting_wooden_pickaxe": "El Pico de madera", + "minicraft.tutorial.getting_wooden_pickaxe.description": "Fabrica un pico de madera en el menú de fabricación de la mesa de trabajo.", + "minicraft.tutorial.getting_workbench": "La útil mesa de trabajo", + "minicraft.tutorial.getting_workbench.description": "Fabrica una mesa de trabajo en el menú de fabricación. Luego colócala.", + "minicraft.tutorial.start_getting_wood": "Donde todo comienza", + "minicraft.tutorial.start_getting_wood.description": "Ataca árboles continuamente para obtener madera." } diff --git a/src/client/resources/assets/localization/fr-fr.json b/src/client/resources/assets/localization/fr-fr.json index 4f8069960..864269241 100644 --- a/src/client/resources/assets/localization/fr-fr.json +++ b/src/client/resources/assets/localization/fr-fr.json @@ -1,344 +1,470 @@ { - "minicraft.achievement.woodcutter": "Bûcheron", - "minicraft.achievement.woodcutter.desc": "Obtenir du bois.", - "minicraft.achievement.benchmarking": "Artisanat", - "minicraft.achievement.benchmarking.desc": "Fabriquez un établi.", - "minicraft.achievement.upgrade": "Mise à niveau!", - "minicraft.achievement.upgrade.desc": "Fabriquer n'importe quel outil à partir de la pierre.", - "minicraft.achievement.bow": "Prosternez-vous devant moi !", - "minicraft.achievement.bow.desc": "Tirez une flèche avec un arc.", - "minicraft.achievement.fish": "Allez les poissons!", - "minicraft.achievement.fish.desc": "attraper un poisson!", - "minicraft.achievement.doors": "Protection des adorateurs", - "minicraft.achievement.doors.desc": "Fabrication d'une porte en bois.", - "minicraft.achievement.planks": "Marche sur les planches!", - "minicraft.achievement.planks.desc": "Planches de bois artisanales.", - "minicraft.achievement.clothes": "Passez une journée haute en couleurs!", - "minicraft.achievement.clothes.desc": "Créez des vêtements de n'importe quelle couleur", - "minicraft.achievement.demolition": "Démonstration de démolition", - "minicraft.achievement.demolition.desc": "Utilisez du TNT.", - "minicraft.achievement.survive_darkness": "Peur de l'obscurité?", - "minicraft.achievement.survive_darkness.desc": "Survivre 5 minutes dans l'obscurité totale.", - "minicraft.achievement.lava": "Affaires chaudes", - "minicraft.achievement.lava.desc": "Utilisez une potion de lave pour nager dans la lave..", - "minicraft.achievement.find_gem": "Oooh Brillant!", - "minicraft.achievement.find_gem.desc": "Trouvez le minerai de gemme et exploitez-le.", - "minicraft.achievement.lowest_caves": "L'obscurité derrière la lumière", - "minicraft.achievement.lowest_caves.desc": "Atteindre les grottes les plus basses.", - "minicraft.achievement.obsidian_dungeon": "Des chevaliers et des hommes", - "minicraft.achievement.obsidian_dungeon.desc": "Atteindre le donjon d'obsidienne.", - "minicraft.achievement.airwizard": "Vaincre... l'air?", - "minicraft.achievement.airwizard.desc": "Battez le premier magicien de l'air!", - "minicraft.achievement.skin": "Défilé de mode", - "minicraft.achievement.skin.desc": "Changez votre peau.", - "minicraft.display.achievement": "Réalisations", - "minicraft.display.achievement.achieved": "Atteint!", - "minicraft.display.achievement.not_achieved": "Non atteint", - "minicraft.display.achievement.score": "Score de réussite:", - "Entities": "Entités", - "Air Wizard: Defeated!": "Sorcier Des Airs: Vaincu!", - "The Dungeon is now open!": "Le donjon est ouvert !", - "A costume lies on the ground...": "Un costume git sur le sol...", - "Can't sleep! ": "Tu peux pas dormir!", - "Min ": "Min ", - " Sec left!": " Sec left!", - "You hear a noise from the surface!": "Tu entend du bruit venant de la surface!", - "Death Chest": "Coffre Morbide", - "Player": "Joueur", - "Crafting": "Crafting", - "Set your home!": "Place ta maison!", - "Can't set home here!": "Tu ne peux pas placer de maison ici!", - "Home Sweet Home!": "Home Sweet Home!", - "Mode penalty: -2 health": "Mode penalty: -2 vies", - "You don't have a home!": "Tu n'as pas de maison!", - "You can't go home from here!": "Tu ne peux pas rentrez chez toi depuis ici!", - "Leather Armor": "Armure en Cuir", - "Snake Armor": "Armure en Serpent", - "Iron Armor": "Armure en Fer", - "Gold Armor": "Armure en Or", - "Gem Armor": "Armure en Gemme", - "Book": "Livre", + "Acorn": "Gland", + "AirWizard Spawner": "Générateur de sorciers de l'Air ", "Antidious": "Antidious", - "Empty Bucket": "Seau Vide", - "Water Bucket": "Seau d'Eau", - "Lava Bucket": "Seau de Lave", - " Bucket": " Seau", - "Red Clothes": "Vetements Rouge", - "Blue Clothes": "Vetements Bleu", - "Green Clothes": "Vetements Vert", - "Yellow Clothes": "Vetements Jaune", - "Black Clothes": "Vetements Noir", - "Orange Clothes": "Vetements Orange", - "Purple Clothes": "Vetements Violet", - "Cyan Clothes": "Vetements Cyan", - "Reg Clothes": "Vetements de Chifons", - "Bread": "Pain", - "Apple": "Pomme", - "Raw Pork": "Cochon Cru", - "Raw Fish": "Poisson Cru", - "Raw Beef": "Beuf Cru", - "Pork Chop": "Cotelette", - "Cooked Fish": "Poisson Fume", - "Cooked Pork": "Cochon Cuit", - "Steak": "Steak", - "Gold Apple": "Pomme d'Or", - "Cow Spawner": "Generateur a Vaches", - "Pig Spawner": "Generateur a Cochons", - "Sheep Spawner": "Generateur a Moutons", - "Slime Spawner": "Generateur a Slime", - "Zombie Spawner": "Generateur a Zombie", - "Creeper Spawner": "Generateur a Creeper", - "Skeleton Spawner": "Generateur a Squelettes", - "Snake Spawner": "Generateur a Serpents", - "Knight Spawner": "Generateur a Chevalier", - "AirWizard Spawner": "Generateur a Sorciers des Airs ", - "Workbench": "Atelier", - "Oven": "Four", - "Furnace": "Fourneau", "Anvil": "Enclume", - "Enchanter": "Enchanteur", - "Loom": "Metier a Tisser", - "Lantern": "Lanterne", - "Iron Lantern": "Lanterne en Fer", - "Gold Lantern": "Lanterne en Or", - "Tnt": "Tnt", + "Apple": "Pomme", + "Arrow": "Fleche", + "Axe": "Hache", + "Baked Potato": "Patate cuite", "Bed": "Lit", + "Black Clothes": "Vêtements noirs", + "Black Wool": "Laine noire", + "Blue Clothes": "Vêtements bleus", + "Blue Wool": "Laine bleue", + "Bone": "Os", + "Book": "Livre", + "Bow": "Arc", + "Bread": "Pain", + "Cactus": "Cactus", + "Cactus Sapling": "Pousse de cactus", "Chest": "Coffre", - "None Potion": "Potion Nulle", - "Speed Potion": "Potion de Vitesse", - "Light Potion": "Potion de Phosphorescence", - "Swim Potion": "Potion de Nage", - "Energy Potion": "Potion Energetique", - "Regen Potion": "Potion de Regeneration", - "Health Potion": "Potion de Vitalite.", - "Time Potion": "Potion de Temps", - "Lava Potion": "Potion de Lave", - "Shield Potion": "Potion de Bouclier", - "Haste Potion": "Potion de Hate", - "Potion": "Potion", - "Power Glove": "Gant de Force", - "Wood": "Bois", - "Stone": "Pierre", - "Leather": "Cuir", - "Wheat": "Ble", - "Key": "Cle", - "arrow": "fleche", - "string": "fil", + "Claymore": "Claymore", + "Cloth": "Chiffon", + "Cloud": "Nuage", + "Cloud Cactus": "Cactus des nuages", + "Cloud Ore": "Minerai de nuage", "Coal": "Charbon", - "Iron Ore": "Minerai de Fer", - "Lapis": "Lapis", - "Gold Ore": "Minerai d'Or", - "Iron": "Fer", - "Gold": "Or", - "Rose": "Rose", - "GunPowder": "PoudreACanon", - "Slime": "Slime", - "glass": "verre", - "cloth": "chiffon", - "gem": "gemme", - "Scale": "Echelle", - "Shard": "Tesson", - "Flower": "Fleur", - "Acorn": "Gland", + "Cooked Fish": "Poisson cuit", + "Cooked Pork": "Côtelette de porc cuite", + "Cow Spawner": "Générateur de vaches", + "Creeper Spawner": "Générateur de creepers", + "Cyan Clothes": "Vêtements cyans", + "Death Chest": "Coffre de la Mort", "Dirt": "Terre", - "Natural Rock": "Roche naturelle", - "Plank": "Planche", - "Plank Wall": "Mur De Planches", - "Wood Door": "Porte en Bois", - "Stone Brick": "Brique de Pierre", - "Ornate Stone": "Pierre ornée", - "Stone Wall": "Mur de Pierre", - "Stone Door": "Porte de Pierre", - "Obsidian Brick": "Brique d'Obsidienne", - "Ornate Obsidian": "Obsidienne ornée", - "Obsidian Wall": "Mur d'Obsidienne", - "Obsidian Door": "Porte d'Obsidienne", - "Wool": "Laine", - "Red Wool": "Laine Rouge", - "Blue Wool": "Laine Bleue", - "Green Wool": "Laine Verte", - "Yellow Wool": "Laine Jaune", - "Black Wool": "Laine Noire", - "Sand": "Sable", - "Cactus": "Cactus", - "Wheat Seeds": "Graines de blé", - "Seeds": "Graines", - "Grass Seeds": "Graines d'Herbe", - "Bone": "Os", - "Cloud": "Nuage", - "Rock": "Roche", + "Empty Bucket": "Seau vide", + "Enchanter": "Enchanteur", + "Energy Potion": "Potion d'énergie", + "Escape Potion": "Potion d'échappement", + "Explode": "Exploser", + "Farmland": "Terre labourée", + "Flower": "Fleur", + "Furnace": "Fourneau", "Gem": "Gemme", - "Wood Fishing Rod": "Canne à pêche en bois", - "Iron Fishing Rod": "Canne à pêche en fer", + "Gem Armor": "Armure en Gemme", + "Gem Fishing Rod": "Canne à pêche en gemme", + "Gem Ore": "Minerai de gemme", + "Glass": "Verre", + "Gold": "Or", + "Gold Apple": "Pomme d'Or", + "Gold Armor": "Armure en Or", "Gold Fishing Rod": "Canne à pêche en or", - "Gem Fishing Rod": "Canne à pêche Gem", - "Shovel": "Pelle", + "Gold Lantern": "Lanterne en or", + "Gold Ore": "Minerai d'or", + "Grass": "Herbe", + "Grass Seeds": "Graines d'herbe", + "Green Clothes": "Vêtements verts", + "Green Wool": "Laine verte", + "Gunpowder": "Poudre noire", + "Hard Rock": "Roche dure", + "Haste Potion": "Potion de hâte", + "Health Potion": "Potion de soin", "Hoe": "Houe", - "Sword": "Epee", + "Hole": "Trou", + "Infinite Fall": "Chute infinie", + "Iron": "Fer", + "Iron Armor": "Armure en Fer", + "Iron Fishing Rod": "Canne à pêche en fer", + "Iron Lantern": "Lanterne en fer", + "Iron Ore": "Minerai de fer", + "Key": "Clé", + "Knight Spawner": "Générateur de chevaliers", + "Lantern": "Lanterne", + "Lapis": "Lapis", + "Lava": "Lave", + "Lava Brick": "Brique de lave", + "Lava Bucket": "Seau de lave", + "Lava Potion": "Potion de résistance à la lave", + "Leather": "Cuir", + "Leather Armor": "Armure en Cuir", + "Light Potion": "Potion de lumière", + "Loom": "Métier à tisser", + "Natural Rock": "Roche naturelle", + "None Potion": "Potion nulle", + "Obsidian": "Obsidienne", + "Obsidian Brick": "Brique d'obsidienne", + "Obsidian Door": "Porte en obsidienne", + "Obsidian Wall": "Mur d'obsidienne", + "Orange Clothes": "Vêtements oranges", + "Ornate Obsidian": "Obsidienne ornée", + "Ornate Stone": "Pierre ornée", + "Oven": "Four", "Pickaxe": "Pioche", - "Axe": "Hache", - "Bow": "Arc", - "Claymore": "Argile", + "Pig Spawner": "Générateur de cochons", + "Plank": "Planche", + "Plank Wall": "Mur de planches", + "Player": "Joueur", + "Pork Chop": "Côtelette de porc", + "Potato": "Patate", + "Potion": "Potion", + "Power Glove": "Gant de force", + "Purple Clothes": "Vêtements violets", + "Raw Beef": "Bœuf cru", + "Raw Fish": "Poisson cru", + "Raw Obsidian": "Obsidienne brute", + "Raw Pork": "Porc cru", + "Red Clothes": "Vêtements rouges", + "Red Wool": "Laine rouge", + "Reg Clothes": "Guenilles", + "Regen Potion": "Potion de régénération", + "Rock": "Roche", + "Rose": "Rose", + "Sand": "Sable", + "Scale": "Écaille", + "Seeds": "Graines", + "Shard": "Tesson", "Shears": "Ciseaux", + "Sheep Spawner": "Générateur de moutons", + "Shield Potion": "Potion de bouclier", + "Shovel": "Pelle", + "Skeleton Spawner": "Générateur de squelettes", + "Slime": "Slime", + "Slime Spawner": "Générateur de slimes", + "Snake Armor": "Armure de Serpent", + "Snake Spawner": "Générateur de serpents", + "Speed Potion": "Potion de vitesse", + "Stairs Down": "Descendre l'escalier", + "Stairs Up": "Monter l'escalier", + "Steak": "Steak", + "Stone": "Pierre", + "Stone Brick": "Brique de pierre", + "Stone Bricks": "Briques de pierre", + "Stone Door": "Porte en pierre", + "Stone Wall": "Mur de pierre", + "String": "Fil", + "Swim Potion": "Potion de nage", + "Sword": "Épée", + "Time Potion": "Potion de temps", + "Tnt": "TNT", "Torch": "Torche", - "Gem Ore": "Minerai de Gemme", - "Wood Planks": "Planches de Bois", - "Stone Bricks": "Briques de Pierre", - "Obsidian": "Obsidienne", - "Wood Wall": "Mur de Bois", - "Grass": "Herbe", - "Hole": "Trou", - "Stairs Up": "Escaliers Montants", - "Stairs Down": "Escaliers Descendants", - "Water": "Eau", + "Totem of Air": "Totem de l'Air", "Tree": "Arbre", - "Tree Sapling": "Arbrisseau", - "Cactus Sapling": "Pousse de Cactus", - "Lava": "Lave", - "Lava Brick": "Brique de Lave", - "Explode": "Exploser", - "Farmland": "Terre Agricole", - "Hard Rock": "Roche Dure", - "Infinite Fall": "Chute Infinie", - "Cloud Cactus": "Cactus Nuage", - "Ore": "Minerai", - "host not found": "hote non trouve", - "unable to get localhost address": "incapable d'avoir l'adresse locale", - "World Saved!": "Monde sauvé!", - "On": "Marche", - "Off": "Arret", - "There is nothing of use here.": "Il n'y a rien d'utile ici.", - "Still nothing... :P": "Toujours rien... :P", - "Have:": "A:", - "Cost:": "Coute:", - "Time: ": "Temps:", - "Score: ": "Score: ", - "Quit": "Quitter", - "Respawn": "Reapparaitre", - "You died! Aww!": "Tu es mort! Aww!", - "With the default controls...\\n\\nMove your character with arrow keys or WSAD. Press C to attack and X to open the inventory, and to use items. Select an item in the inventory to equip it.\\n\\nKill the air wizard to win the game!": "Avec les controles par defaut...\\n\\nBougez votre avatar avec les fleches ou WSAD. Appuyez sur C pour attaquer et X pour ouvrir l'inventaire, et utiliser des objets. Choisissez un objet de l'inventaire pour l'equiper.\\n\\nTuez le sorcier des airs pour gagner!", - "Player Score: ": "Score du Joueur: ", - "": "", - "Final Score: ": "Score Final: ", - "Exit to Menu": "Retour au Menu", - "Time Played: ": "Temps Joue: ", - "Current Score: ": "Score Actuel: ", - "Exit": "Retour", - "Player Stats": "Stats du Joueur", - "Controls": "Controles", - "Press the desired": "Appuiez sur la", - "key sequence": "suite de touches desire", - "minicraft.display.key_input.confirm_popup": "Etes vous sur que vous voulez remettre toute les touches par defaut?", - "minicraft.display.popup.enter_confirm": "Entree pour confirmer", - "minicraft.display.popup.escape_cancel": "Echap pour annuler", - "Confirm Action": "Confirmer l'Action", - "Press C/Enter to change key binding": "Appuyez sur C/Entree pour changer la touche", - "Press A to add key binding": "Appuyez sur A pour ajouter un touche", - "Shift-D to reset all keys to default": "Maj-D pour remettre les touches par defaut.", - "ESCAPE to Return to menu": "Echap pour retourner au menu", - "Loading": "Chargement", - "waiting": "attente", - "nothing": "rien", - "attempting log in": "tentative de connection", - "no internet connection, but no login data saved; cannot enter offline mode.": "pas de connection internet, mais pas de d'identifiant enregiste; on ne peut entre en mode hors-ligne.", - "connecting to server": "connection au serveur", - "logging in": "identification", - "saving credentials": "enregistrement de l'identite", - "login failed.": "indentification rate", - "problem with saved login data; please exit and login again.": "probleme avec l'identifiant enregistre", - "Internal server error: Couldn't fetch username from uuid": "Erreur du serveur interne: Ne peut recuperer le pseudo depuis l'uuid", - "logged in as: ": "connecte en tant que:", - "offline mode: local servers only": "mode hors-ligne: serveurs locaux seulement", - "Enter ip address to connect to:": "Entrez l'adresse ip a qui se connecter:", - "Press Shift-Escape to logout": "Appuyez sur Maj-Echap pour vous deconnecter", - "Enter email:": "Entrez votre email", - "Enter password:": "Entrez votre mot de passe", - "field is blank": "champ de texte vide", - "get an account at:": "obtenez un compte sur:", - "Loading ": "Chargement ", - " from server": " depuis le serveur", - "Could not connect to server:": "N'a pas pu se connecter au serveur:", - "Press ": "Appuyez", - " to return": " pour revenir", - "Change Key Bindings": "Modifier les Touches", - "Options": "Options", - "Change language": "Changer de langue", - "Return to Game": "Retourner au Jeu", - "Make World Multiplayer": "Rendre le Monde Jouable en Multijoueur", - "Save Game": "Sauvegarder", - " and ": " et", - " to Scroll": " pour Defiler", - ": Choose": ": Choisissez", - "Paused": "Pause", - "Main Menu": "Menu Principal", - "Inventory": "Inventaire", - "to search.": "à rechercher.", - "Play": "Jouer", - "Load World": "Charger un Monde", - "New World": "Creer un Monde", - "Multiplayer": "Joindre un Monde en Ligne", - "Singleplayer": "Jeu solo", - "Help": "Aide", - "Instructions": "Instructions", - "Storyline Guide": "Guide d'Histoire", - "About": "A Propos", - "Credits": "Crédits", - " to select": " pour choisir", - " to accept": " pour accepter", - "New World Name:": "Nom du Monde:", - "Are you sure you want to delete": "Etes vous sur de vouloir effacer", - "This can not be undone!": "Ceci ne peut etre annule!", - " to confirm": " pour confirmer", - " to cancel": " pour annuler", - "World Seed": "Graine du Monde", - "Enter World Name": "Entrez le Nom du Monde", - "Trouble with world name?": "Un probleme avec le nom du monde?", - "by default, w and s move the cursor up and down. This can be changed in the key binding menu. To type the letter instead of moving the cursor, hold the shift key while typing the world name.": "par defaut, w et s bougent le curseur de haut en bas. Ceci peut etre change dans le menu de changement des touches. Pour taper la lette au lieu de bouger le curseur, maintenez le bouton Maj pendant que vous tapez le nom du monde.", - "Create World": "Creer le Monde", - "World Gen Options": "Options de Generation", - " to Copy": " à Copier", - " to Rename": " à Renommer", - " to Delete": " à Effacer", - "Select World": "Choisir un Monde", - "Select a World to Delete": "Choisissez un Monde pour Effacer", - "Select a World to Rename": "Choisissez un Monde pour Renommer", - "Select a World to Copy": "Choisissez un Monde pour Copier", - "Higher version, cannot load world!": "Version supérieure, ne peut pas charger le monde!", - "World Version:": "Version monde:", - "Languages": "Languages", - "Language": "Language", - "Select": "Selectionner", - "Max FPS": "FPS Max", - "Difficulty": "Difficulte", - "Easy": "Facile", - "Normal": "Normal", - "Hard": "Difficile", - "Game Mode": "Mode de Jeu", - "Survival": "Survie", - "Creative": "Creatif", - "Hardcore": "Hardcore", - "Score": "Score", - "Time (Score Mode)": "Temps (Mode Score)", - "Sound": "Son", - "Autosave": "Sauvegarde Auto", - "World Size": "Taille du Monde", - "World Theme": "Theme du Monde", - "Forest": "Foret", - "Desert": "Desert", - "Plain": "Plaines", - "Hell": "Enfer", - "Terrain Type": "Type de Terrain", - "Island": "Ile", - "Box": "Boite", - "Mountain": "Montagne", - "Irregular": "Irregulier", - "Wear Suit": "Porter Combinaison", - "You have the latest version.": "Vous avez la dernière version.", - "minicraft.display.skin": "Skins", + "Tree Sapling": "Pousse d'arbre", + "Water": "Eau", + "Water Bucket": "Seau d'eau", + "Wheat": "Blé", + "Wheat Seeds": "Graines de blé", + "Wood": "Bois", + "Wood Door": "Porte en bois", + "Wood Fishing Rod": "Canne à pêche en bois", + "Wood Planks": "Planches de bois", + "Wood Wall": "Mur de bois", + "Wool": "Laine", + "Workbench": "Établi", + "Yellow Clothes": "Vêtements jaunes", + "Yellow Wool": "Laine jaune", + "Zombie Spawner": "Générateur de zombies", + "minicraft.achievement.airwizard": "Vainqueur de... l'air?", + "minicraft.achievement.airwizard.desc": "Tuez votre premier magicien de l'air!", + "minicraft.achievement.benchmarking": "Artisanat", + "minicraft.achievement.benchmarking.desc": "Fabriquez un établi.", + "minicraft.achievement.bow": "Prosternez-vous devant moi !", + "minicraft.achievement.bow.desc": "Tirez une flèche avec un arc.", + "minicraft.achievement.clothes": "Passez une journée haute en couleurs!", + "minicraft.achievement.clothes.desc": "Créez des vêtements de n'importe quelle couleur", + "minicraft.achievement.demolition": "Démonstration de démolition", + "minicraft.achievement.demolition.desc": "Utilisez de la TNT.", + "minicraft.achievement.doors": "Protection des adorateurs", + "minicraft.achievement.doors.desc": "Fabriquez une porte en bois.", + "minicraft.achievement.find_gem": "Oooh Brillant!", + "minicraft.achievement.find_gem.desc": "Trouvez un minerai de gemmes et minez-le.", + "minicraft.achievement.fish": "Allez pêcher!", + "minicraft.achievement.fish.desc": "Pêcher un poisson!", + "minicraft.achievement.lava": "Affaires chaudes", + "minicraft.achievement.lava.desc": "Utilisez une potion de résistance à la lave pour nager dedans", + "minicraft.achievement.lowest_caves": "L'obscurité derrière la lumière", + "minicraft.achievement.lowest_caves.desc": "Atteignez les grottes les plus profondes.", + "minicraft.achievement.obsidian_dungeon": "Des chevaliers et des hommes", + "minicraft.achievement.obsidian_dungeon.desc": "Atteignez le donjon d'obsidienne.", + "minicraft.achievement.planks": "Marche sur les planches!", + "minicraft.achievement.planks.desc": "Fabriquez des planches en bois.", + "minicraft.achievement.skin": "Défilé de mode", + "minicraft.achievement.skin.desc": "Changez votre skin.", + "minicraft.achievement.survive_darkness": "Appeuré(e) par la nuit ?", + "minicraft.achievement.survive_darkness.desc": "Survivre 5 minutes dans l'obscurité totale.", + "minicraft.achievement.upgrade": "Amélioration !", + "minicraft.achievement.upgrade.desc": "Fabriquez n'importe quel outil en pierre.", + "minicraft.achievement.woodcutter": "Bûcheron", + "minicraft.achievement.woodcutter.desc": "Obtenir du bois.", + "minicraft.control_guide.attack": "Utilisez %s pour attaquer les mobs ou détruire les entités", + "minicraft.control_guide.craft": "Utilisez %s pour ouvrir votre menu de fabrication", + "minicraft.control_guide.menu": "Utilisez %s pour ouvrir votre inventaire", + "minicraft.control_guide.move": "Utilisez %s pour bouger", + "minicraft.display.entries.boolean.false": "Éteint", + "minicraft.display.entries.boolean.true": "Allumé", + "minicraft.display.gui.link_opening": "ouverture avec votre navigateur web", + "minicraft.display.gui.perm_status.saving": "Sauvegarde... %s%%", + "minicraft.display.gui.perm_status.sleep_cancel": "Appuyer sur %s pour annuler", + "minicraft.display.gui.perm_status.sleeping": "Vous êtes en train de dormir", + "minicraft.display.gui.potion_effects.hide_hint": "(%s pour cacher l'interface!)", + "minicraft.display.gui.potion_effects.potion_dur": "%s (%d:%02d)", + "minicraft.display.gui.score.current_score": "Score actuel : %s", + "minicraft.display.gui.score.time_left": "Temps restant %s%sm %ss", + "minicraft.display.menus.inventory": "Inventaire", + "minicraft.display.options_display": "Options", + "minicraft.display.options_display.change_key_bindings": "Changer la configuration des touches", + "minicraft.display.options_display.language": "Langue", + "minicraft.display.options_display.resource_packs": "Packs de ressources", + "minicraft.display.popup.enter_confirm": "Appuyez sur entrée pour confirmer", + "minicraft.display.popup.escape_cancel": "Appuyez sur Echap pour annuler", + "minicraft.display.popup.title_confirm": "Confirmer l'action", + "minicraft.displays.achievements": "Succès", + "minicraft.displays.achievements.display.achieved": "Réussi !", + "minicraft.displays.achievements.display.help": "Utilisez %s et %s pour vous déplacer.", + "minicraft.displays.achievements.display.not_achieved": "Pas encore réussi", + "minicraft.displays.achievements.display.score": "Atteignez le score : %s", + "minicraft.displays.book.default_book": "Ce livre n'a pas de texte", + "minicraft.displays.controls": "Contrôles", + "minicraft.displays.controls.display.controller": "Manette", + "minicraft.displays.controls.display.controller.00": "Bouger le joueur en utilisant de le DPAD", + "minicraft.displays.controls.display.controller.01": "Bouger le curseur en utilisant le DPAD", + "minicraft.displays.controls.display.controller.02": "Pour sélectionner, appuyez sur le bouton A", + "minicraft.displays.controls.display.controller.03": "Pour annuler, appuyez sur le bouton B", + "minicraft.displays.controls.display.controller.04": "Pour attaquer des entités, détruire et interagir avec les tuiles, appuyez sur le bouton A", + "minicraft.displays.controls.display.controller.05": "Pour ouvrir les menus en jeu, appuyez sur le bouton X", + "minicraft.displays.controls.display.controller.06": "Pour ouvrir le menu de fabrication, appuyez sur le bouton Y", + "minicraft.displays.controls.display.controller.07": "Pour récupérer des meubles, appuyez sur le bouton LB", + "minicraft.displays.controls.display.controller.08": "Pour jeter un objet, appuyez sur le bouton RB", + "minicraft.displays.controls.display.controller.09": "Pour jeter un tas entier, appuyez sur le stick directionnel droit", + "minicraft.displays.controls.display.controller.10": "Pour activer/désactiver la barre de recherche dans les menus, appuyez sur START", + "minicraft.displays.controls.display.controller.11": "Pour mettre le jeu en pause, appuyez sur START", + "minicraft.displays.controls.display.controller.12": "Pour activer/désactiver le clavier virtuel, appuyez sur X", + "minicraft.displays.controls.display.controller.13": "Pour effacer un caractère sur le clavier virtuel, appuyez sur B", + "minicraft.displays.controls.display.controller.14": "Pour retirer un objet sélectionné de l'inventaire créatif, appuyez sur X", + "minicraft.displays.controls.display.controller.15": "Pour retirer un tas entier de l'inventaire créatif, appuyez sur Y", + "minicraft.displays.controls.display.controller.desc.0": "Les mappings de débogage sont inaccessibles", + "minicraft.displays.controls.display.controller.desc.1": "Les mappings détaillés sont inusables", + "minicraft.displays.controls.display.help.0": "%s/%s pour voir d'autres contrôles.", + "minicraft.displays.controls.display.keyboard": "Clavier", + "minicraft.displays.controls.display.keyboard.00": "Pour déplacer le joueur, utilisez MOVE-(DIRECTION)", + "minicraft.displays.controls.display.keyboard.01": "Pour déplacer le cursor, utilisez CURSOR-(DIRECTION)", + "minicraft.displays.controls.display.keyboard.02": "Pour sélectionner des entrées, appuyez sur SELECT", + "minicraft.displays.controls.display.keyboard.03": "Pour sortir des pages, appuyez sur EXIT", + "minicraft.displays.controls.display.keyboard.04": "Pour la sauvegarde rapide, appuyez sur QUICKSAVE", + "minicraft.displays.controls.display.keyboard.05": "Attaquer des entités, détruire et interagir avec des tuiles utiliser ATTACK", + "minicraft.displays.controls.display.keyboard.06": "L'ouverture du Menu dans le jeu utiliser MENU", + "minicraft.displays.controls.display.keyboard.07": "L'ouverture des menus d'artisanat utiliser CRAFT", + "minicraft.displays.controls.display.keyboard.08": "Ramasser des meubles utiliser PICKUP", + "minicraft.displays.controls.display.keyboard.09": "Dropper 1 article utiliser DROP-ONE", + "minicraft.displays.controls.display.keyboard.10": "Dropper une pile entière d'éléments utiliser DROP-STACK", + "minicraft.displays.controls.display.keyboard.11": "Basculer la barre de recherche dans les menus d'éléments utilise SEARCHER-BAR", + "minicraft.displays.controls.display.keyboard.12": "Pour parcourir les résultats de la recherche, utilisez PAGE-UP/DOWN", + "minicraft.displays.controls.display.keyboard.13": "Pour mettre en pause le jeu, appuyez sur PAUSE", + "minicraft.displays.controls.display.keyboard.14": "Pour activer/désactiver l'interface des effets de potions, appuyez sur POTIONEFFECTS", + "minicraft.displays.controls.display.keyboard.15": "Pour activer/désactiver l'interface simplifiée de potions, appuyez sur SIMPPOTIONEFFECTS", + "minicraft.displays.controls.display.keyboard.16": "L'affichage des quêtes en expansion temporaire dans le jeu utilise EXPANDQUESTDISPLAY", + "minicraft.displays.controls.display.keyboard.17": "Pour activer/désactiver le HUD, appuyez sur TOGGLEHUD", + "minicraft.displays.controls.display.keyboard.18": "Pour prendre une capture d'écran, appuyez sur SCREENSHOT", + "minicraft.displays.controls.display.keyboard.19": "Pour des informations sur la partie, appuyez sur INFO", + "minicraft.displays.controls.display.keyboard.20": "Pour le mode plein écran, appuyez sur FULLSCREEN", + "minicraft.displays.controls.display.keyboard.21": "Pour retirer un objet sélectionné de l'inventaire créatif, appuyez sur D", + "minicraft.displays.controls.display.keyboard.22": "Utilisez MAJ-D pour jeter un stack entier d'un item dans votre inventaire en créatif", + "minicraft.displays.controls.display.keyboard.desc": "Le Debug Mappings n'est pas expliqué", + "minicraft.displays.crafting": "Fabrication", + "minicraft.displays.crafting.container_title.cost": "Coût :", + "minicraft.displays.crafting.container_title.have": "Vous avez:", + "minicraft.displays.end_game.display.bonuses": "", + "minicraft.displays.end_game.display.final_score": "Score final : %s", + "minicraft.displays.end_game.display.player_score": "Score du joueur: %s", + "minicraft.displays.end_game.display.unlocked": "Vous débloquez! %s Temps de Score", + "minicraft.displays.end_game.exit": "Allez au Menu", + "minicraft.displays.info.display.exit_help": "%s/%s:Sortie", + "minicraft.displays.info.display.score": "Score Actuel : %s", + "minicraft.displays.info.display.time": "Temps de jeu : %s", + "minicraft.displays.info.title": "Statistiques du joueur", + "minicraft.displays.key_input.display.help.0": "Appuyez sur C ou Entrée pour changer la configuration de touche", + "minicraft.displays.key_input.display.help.1": "Appuyez sur A pour ajouter une configuration de touche", + "minicraft.displays.key_input.display.help.2": "Appuyez sur MAJ-S pour réinitialiser toutes les touches", + "minicraft.displays.key_input.display.help.3": "%s Pour retourner au menu", + "minicraft.displays.key_input.popup_display.confirm_reset": "Êtes-vous sûr(e) de vouloir réinitialiser la configuration des touches ?", + "minicraft.displays.key_input.popup_display.press_key_sequence": "Pressez la combinaison de touches désirée", + "minicraft.displays.key_input.title": "Contrôles", + "minicraft.displays.language_settings.title": "Langue...", + "minicraft.displays.loading.message.dungeon_regeneration": "Régénération du B4", + "minicraft.displays.loading.message.entities": "Entités", + "minicraft.displays.loading.message.generating": "Génération en cours", + "minicraft.displays.loading.message.level": "Niveau %s", + "minicraft.displays.loading.message.levels": "Niveaux", + "minicraft.displays.loading.message.loading": "Chargement", + "minicraft.displays.loading.message.quests": "Quêtes", + "minicraft.displays.loading.message.saving": "Sauvegarde", + "minicraft.displays.loading.message.world": "Monde", + "minicraft.displays.loading.regeneration_cancellation_popup.display": "Chargement du monde annulé", + "minicraft.displays.loading.regeneration_popup.display.0": "L'ancienne version du donjon (étage B4) a été détecté.", + "minicraft.displays.loading.regeneration_popup.display.1": "Une régénération est nécessaire.", + "minicraft.displays.loading.regeneration_popup.display.2": "Les anciennes données de cet étage vont être effacer.", + "minicraft.displays.loading.regeneration_popup.display.3": "%s pour continuer", + "minicraft.displays.loading.regeneration_popup.display.4": "%s pour annuler le chargement du monde", + "minicraft.displays.options_main_menu": "Options du menu principal", + "minicraft.displays.options_main_menu.resource_packs": "Pack de ressources", + "minicraft.displays.options_world": "Option du monde", + "minicraft.displays.options_world.off_tutorials_confirm_popup": "Êtes-vous sûr(e) de vouloir désactiver le tutoriel pour toujours ?", + "minicraft.displays.options_world.turn_off_tutorials": "Désactivation du tutoriel", + "minicraft.displays.pause": "En pause", + "minicraft.displays.pause.display.exit_popup.0": "Êtes-vous sûr(e) de vouloir quitter le jeu ?", + "minicraft.displays.pause.display.exit_popup.1": "Toutes les données non sauvegardées seront perdues", + "minicraft.displays.pause.display.exit_popup.cancel": "Annuler", + "minicraft.displays.pause.display.exit_popup.quit": "Quitter sans sauvegarder", + "minicraft.displays.pause.display.help.choose": "%s: Choisir", + "minicraft.displays.pause.display.help.scroll": "%s et %s pour faire défiler", + "minicraft.displays.pause.menu": "Menu principal", + "minicraft.displays.pause.return": "Retour en jeu", + "minicraft.displays.pause.save": "Sauvegarder la partie", + "minicraft.displays.player_death.display.score": "Score : %s", + "minicraft.displays.player_death.display.time": "Temps: %s", + "minicraft.displays.player_death.quit": "Quitter", + "minicraft.displays.player_death.respawn": "Réapparaître", + "minicraft.displays.player_death.save_quit": "Sauvegarder et quitter", + "minicraft.displays.player_death.title": "Vous êtes mort! Ohhh!", + "minicraft.displays.player_inv.container_title.items": "Objets", + "minicraft.displays.player_inv.display.help": "(%s) pour chercher.", + "minicraft.displays.quests": "Quêtes", + "minicraft.displays.quests.display.header.completed": "Complétée", + "minicraft.displays.quests.display.header.unlocked": "Débloquer", + "minicraft.displays.quests.display.no_quest": "Aucune quête débloquée", + "minicraft.displays.quests.display.no_quest_desc": "Pas de quête", + "minicraft.displays.resource_packs.display.help.keyboard_needed": "Seul les entrées par clavier sont acceptées", + "minicraft.displays.resource_packs.display.help.move": "Utilisez %s et %s pour bouger", + "minicraft.displays.resource_packs.display.help.position": "MAJ-[GAUCHE|DROITE|HAUT|BAS] pour bouger des paquets. ␣", + "minicraft.displays.resource_packs.display.help.select": "%s pour examiner", + "minicraft.displays.resource_packs.display.title": "Pack de Ressource", + "minicraft.displays.skin": "Skins", + "minicraft.displays.skin.display.help.move": "Utilisez %s et %s pour bouger", + "minicraft.displays.skin.display.help.select": "%s pour sélectionner, et %s pour annuler", + "minicraft.displays.title.display.cannot_check": "N'a pas pu chercher de mises à jour.", + "minicraft.displays.title.display.checking": "Cherche des mises à jour...", + "minicraft.displays.title.display.help.0": "(%s, %s pour sélectionner)", + "minicraft.displays.title.display.help.1": "(%s pour accepter)", + "minicraft.displays.title.display.help.2": "(%s pour retourner en arrière)", + "minicraft.displays.title.display.latest_already": "Vous avez la dernière version", + "minicraft.displays.title.display.new_version": "Nouveau: %s", + "minicraft.displays.title.display.version": "Version %s", + "minicraft.displays.title.help": "Aide", + "minicraft.displays.title.help.about": "À propos", + "minicraft.displays.title.help.credits": "Crédits", + "minicraft.displays.title.help.instructions": "Instructions", + "minicraft.displays.title.help.storyline_guide": "Guide du déroulement de l'histoire", + "minicraft.displays.title.link_to_version": "Lien directe à la dernière version", + "minicraft.displays.title.play": "Jouer", + "minicraft.displays.title.play.load_world": "Charger un monde", + "minicraft.displays.title.play.new_world": "Nouveau monde", + "minicraft.displays.title.quit": "Quitter", + "minicraft.displays.title.select_to_download": "--Sélectionner ici pour télécharger--", + "minicraft.displays.tutorial_display_handler.display.element_examine_help": "Appuyez sur %s pour examiner les détails du tuto actuel.", + "minicraft.displays.world_gen.create_world": "Créer un Monde", + "minicraft.displays.world_gen.enter_world": "Entrer le nom du monde", + "minicraft.displays.world_gen.title": "Options de génération du monde", + "minicraft.displays.world_gen.troublesome_input": "Un soucis avec le nom de votre monde ?", + "minicraft.displays.world_gen.troublesome_input.msg": "Il semblerait que vous ayez mis les lettres comme contrôles pour bouger le curseur de haut en bas, ce qui parait embêtant. Ceci peut être changer dans le menu de configuration de touche en tant que touche \"curseur-XXX\". Pour l'instant, pour taper des lettres et ne pas bouger, rester appuyer sur MAJ pendant que vous tapez.", + "minicraft.displays.world_gen.world_seed": "Seed du monde", + "minicraft.displays.world_select.display.help.0": "%s pour confirmer", + "minicraft.displays.world_select.display.help.1": "%s pour revenir en arrière", + "minicraft.displays.world_select.display.help.2": "MAJ-C pour copier", + "minicraft.displays.world_select.display.help.3": "MAJ-R pour renommer", + "minicraft.displays.world_select.display.help.4": "MAJ-D pour supprimer", + "minicraft.displays.world_select.display.world_too_new": "Version supérieure nécessaire pour charger le monde !", + "minicraft.displays.world_select.display.world_version": "Version du Monde: %s", + "minicraft.displays.world_select.popups.display.cancel": "%s pour annuler", + "minicraft.displays.world_select.popups.display.change": "Nom du Nouveau Monde: ", + "minicraft.displays.world_select.popups.display.confirm": "%s pour confirmer", + "minicraft.displays.world_select.popups.display.delete": "Êtes-vous certain(e) de vouloir supprimer\n%s\"%s\"%s?\nCela ne peut pas être annulé!", + "minicraft.displays.world_select.select_world": "Sélection du monde", + "minicraft.notification.achievement_unlocked": "Succès atteint: %s", + "minicraft.notification.air_wizard_defeated": "Sorcier de l'Air Battu!", + "minicraft.notification.boss_limit": "Plus aucun boss ne peut apparaître", + "minicraft.notification.cannot_sleep": "Vous ne pouvez pas encore dormir! %sMin %s Sec restant!", + "minicraft.notification.death_chest_retrieved": "Coffre de la Mort récupéré!", + "minicraft.notification.defeat_air_wizard_first": "Le Sorcier de l'Air doit être vaincu d'abord.", + "minicraft.notification.defeat_obsidian_knight_first": "Le Chevalier d'Obsidienne doit être battu avant.", + "minicraft.notification.dig_hole": "Vous devez creuser un trou avant!", + "minicraft.notification.dungeon_opened": "Le Donjon est maintenant ouvert!", + "minicraft.notification.gem_pickaxe_required": "Pioche en Gemme requise", + "minicraft.notification.invalid_placement": "Ceci ne peut être placé que sur %s!", + "minicraft.notification.obsidian_knight_awoken": "Le Chevalier d'Obsidienne est réveillé!", + "minicraft.notification.obsidian_knight_defeated": "Chevalier d'Obsidienne: Battu!", + "minicraft.notification.quest_completed": "Quête complétée", + "minicraft.notification.quest_unlocked": "Quête débloquée", + "minicraft.notification.spawn_on_boss_tile": "Peut seulement être invoqué dans la sale du boss", + "minicraft.notification.world_saved": "Monde Sauvegardé!", + "minicraft.notification.wrong_level_dungeon": "Peut seulement être invoqué dans le donjon", + "minicraft.notification.wrong_level_sky": "Ne peut être invoqué qu'au niveau du Ciel", + "minicraft.notifications.statue_tapped": "Vous entendez des murmures en échos... ", + "minicraft.notifications.statue_touched": "Vous entendez la statue vibrer...", + "minicraft.quest.farming": "Fermier qui farm", + "minicraft.quest.farming.crafting_hoe": "Créez une Houe", + "minicraft.quest.farming.crafting_hoe.description": "Créez n'importe quelle houe depuis l'établi", + "minicraft.quest.farming.description": "Les bases pour être fermier.", + "minicraft.quest.farming.getting_wheat": "Récoltez du blé", + "minicraft.quest.farming.getting_wheat.description": "Récoltez du blé en cassant un plant de blé mûr.", + "minicraft.quest.farming.making_farmland": "Labourez la terre", + "minicraft.quest.farming.making_farmland.description": "Labourez la terre avec une houe.", + "minicraft.quest.farming.planting_potato": "Plantez une patate", + "minicraft.quest.farming.planting_potato.description": "Plantez une patate dans la terre labourée", + "minicraft.quest.farming.planting_wheat": "Plantez du blé", + "minicraft.quest.farming.planting_wheat.description": "Plantez du blé dans la terre labourée.", + "minicraft.quest.gems": "Route des gemmes", + "minicraft.quest.gems.description": "Obtenez de l'équipement en gemme.", + "minicraft.quest.gems.gem_armor": "Maître de la protection", + "minicraft.quest.gems.gem_armor.description": "Obtenez une armure en gemme.", + "minicraft.quest.gems.gem_claymore": "Maître d'armes", + "minicraft.quest.gems.gem_claymore.description": "Obtenez une claymore en gemme.", + "minicraft.quest.iron_equipments": "Maître du fer", + "minicraft.quest.iron_equipments.description": "Obtenez l'entièreté de l'équipement en fer.", + "minicraft.quest.iron_equipments.getting_more_iron": "Riche en fer", + "minicraft.quest.iron_equipments.getting_more_iron.description": "Obtenez encore plus de fer.", + "minicraft.quest.iron_equipments.iron_armor": "Amélioration d'armure", + "minicraft.quest.iron_equipments.iron_armor.description": "Faites-vous une armure en fer.", + "minicraft.quest.iron_equipments.iron_tools": "Améliorer tous les outils", + "minicraft.quest.iron_equipments.iron_tools.description": "Faites-vous tous les outils en fer.", + "minicraft.quest.iron_equipments.upgrading_pickaxe": "Meilleure pioche", + "minicraft.quest.iron_equipments.upgrading_pickaxe.description": "Améliorez votre pioche.", + "minicraft.quest.potions": "Maître des potions", + "minicraft.quest.potions.all_potions_prepared": "Chercheur en potions", + "minicraft.quest.potions.all_potions_prepared.description": "Buvez toutes les potions en même temps", + "minicraft.quest.potions.awkward_potions": "Potion étrange", + "minicraft.quest.potions.awkward_potions.description": "Obtenez une potion étrange.", + "minicraft.quest.potions.description": "Obtenez toutes les potions.", + "minicraft.quest.potions.powerful_potions": "Potions puissantes", + "minicraft.quest.potions.powerful_potions.description": "Obtenez les potions puissantes et utiles.", + "minicraft.settings.autosave": "Sauvegarde automatique", + "minicraft.settings.difficulty": "Difficulté", + "minicraft.settings.difficulty.easy": "Facile", + "minicraft.settings.difficulty.hard": "Difficile", + "minicraft.settings.difficulty.normal": "Normal", + "minicraft.settings.fps": "FPS Max", + "minicraft.settings.mode": "Mode de Jeu", + "minicraft.settings.mode.creative": "Créatif", + "minicraft.settings.mode.hardcore": "Hardcore", + "minicraft.settings.mode.score": "Score", + "minicraft.settings.mode.survival": "Survie", + "minicraft.settings.scoretime": "Temps (Mode Score)", + "minicraft.settings.screenshot_scale": "Échelle du Screenshot", + "minicraft.settings.size": "Taille du monde", + "minicraft.settings.sound": "Son", + "minicraft.settings.theme": "Thème du monde", + "minicraft.settings.theme.desert": "Désert", + "minicraft.settings.theme.forest": "Forêt", + "minicraft.settings.theme.hell": "Enfer", + "minicraft.settings.theme.normal": "Normal", + "minicraft.settings.theme.plain": "Plaine", + "minicraft.settings.type": "Type de Terrain", + "minicraft.settings.type.box": "Boîte", + "minicraft.settings.type.irregular": "Irrégulier", + "minicraft.settings.type.island": "Îles", + "minicraft.settings.type.mountain": "Montagne", + "minicraft.skin.minecraft_alex": "Fille familière", + "minicraft.skin.minecraft_steve": "Garçon familier", "minicraft.skin.paul": "Paul", "minicraft.skin.paul_cape": "Paul avec cape", - "minicraft.skin.minecraft_steve": "Garçon familier", - "minicraft.skin.minecraft_alex": "Fille familière", - "minicraft.notification.invalid_placement": "Ne peut être placé que sur", - "minicraft.notification.dig_hole": "Creusez d'abord un trou!" + "minicraft.text_particales.key_consumed": "-1 clé", + "minicraft.tutorial.getting_rocks": "Récupérez de la pierre et du charbon", + "minicraft.tutorial.getting_rocks.description": "Avoir récupéré au moins 5 pierres et 5 charbons en cassant des roches avec la pioche.", + "minicraft.tutorial.getting_wood": "Prendre plus de bois", + "minicraft.tutorial.getting_wood.description": "Avoir récupéré au moins 10 bois en coupant des arbres.", + "minicraft.tutorial.getting_wooden_pickaxe": "Obtenez une pioche en bois", + "minicraft.tutorial.getting_wooden_pickaxe.description": "Fabriquez une pioche en bois dans un établi.", + "minicraft.tutorial.getting_workbench": "Obtenir un établi", + "minicraft.tutorial.getting_workbench.description": "Construisez un établi depuis le menu de fabrication. Placez-le juste après.", + "minicraft.tutorial.start_getting_wood": "Le commencement", + "minicraft.tutorial.start_getting_wood.description": "Frapper des arbres en continu pour avoir du bois." } diff --git a/src/client/resources/assets/localization/hu-hu.json b/src/client/resources/assets/localization/hu-hu.json index e879b0b90..e29b7f8f4 100644 --- a/src/client/resources/assets/localization/hu-hu.json +++ b/src/client/resources/assets/localization/hu-hu.json @@ -1,351 +1,195 @@ { - "minicraft.achievement.woodcutter": "Favágó", - "minicraft.achievement.woodcutter.desc": "Szerezd meg a fát", - "minicraft.achievement.benchmarking": "Ideje munkához látni!", - "minicraft.achievement.benchmarking.desc": "Készítsen egy munkapadot.", - "minicraft.achievement.upgrade": "Frissítés!", - "minicraft.achievement.upgrade.desc": "Készítsen bármilyen kőszerszámot.", - "minicraft.achievement.bow": "Hajoljatok meg előttem!", - "minicraft.achievement.bow.desc": "Lőj ki egy nyilat egy íjjal.", - "minicraft.achievement.fish": "Menjetek horgászni!", - "minicraft.achievement.fish.desc": "Szerezz egy halat", - "minicraft.achievement.doors": "Adooring védelem", - "minicraft.achievement.doors.desc": "Készítsen egy faajtót.", - "minicraft.achievement.planks": "Sétálj a deszkákon!", - "minicraft.achievement.planks.desc": "Fadeszkák készítése.", - "minicraft.achievement.clothes": "Legyen színes a napod!", - "minicraft.achievement.clothes.desc": "Készíts bármilyen színű ruhát", - "minicraft.achievement.demolition": "Dinamitát", - "minicraft.achievement.demolition.desc": "Használj Dinamitát.", - "minicraft.achievement.survive_darkness": "Félsz a sötétségtől?", - "minicraft.achievement.survive_darkness.desc": "Túlélni 5 percet teljes sötétségben.", - "minicraft.achievement.lava": "Forró ügyek", - "minicraft.achievement.lava.desc": "Használj lávaitalt a lávában való úszáshoz", - "minicraft.achievement.find_gem": "Oooh Shiny!", - "minicraft.achievement.find_gem.desc": "Találd meg a Gem Ore-t és bányászd ki.", - "minicraft.achievement.lowest_caves": "Sötétség a fény mögött", - "minicraft.achievement.lowest_caves.desc": "Elérni a legalacsonyabb barlangokat.", - "minicraft.achievement.obsidian_dungeon": "Of Knights and Men", - "minicraft.achievement.obsidian_dungeon.desc": "Érje el az obszidiánbörtönt.", - "minicraft.achievement.airwizard": "Győzd le... a levegőt?", - "minicraft.achievement.airwizard.desc": "Győzd le az első légvarázslót!", - "minicraft.achievement.skin": "Divatbemutató", - "minicraft.achievement.skin.desc": "Változtassa meg a bőrét.", - "minicraft.display.achievement": "Eredmények", - "minicraft.display.achievement.achieved": "Elérve!", - "minicraft.display.achievement.not_achieved": "Nem teljesült", - "minicraft.display.achievement.score": "Teljesítmény pontszám:", - "minicraft.notification.achievement_unlocked": "Elérés feloldva:", - "Entities": "Jogalanyok", - "Air Wizard: Defeated!": "Megölted a levegővarázslót!", - "The Dungeon is now open!": "A Dungeon ki van nyitva!", - "A costume lies on the ground...": "Egy jelmez van a földön...", - "Can't sleep!": "Nem tudsz aludni!", - "Min ": "Perc ", - " Sec left!": " Másodperc van hátra!", - "You hear a noise from the surface!": "Hallasz egy zajot felülről...", - "Death Chest": "Halálláda", - "Player": "Játékos", - "Crafting": "Barkácsolás", - "Set your home!": "Megjelölted az otthonodat!", - "Can't set home here!": "Nem tudsz otthont jelölni itt!", - "Home Sweet Home!": "Otthon, édes otthon!", - "Mode penalty: -2 health": "Mód büntetés: -2 élet", - "You don't have a home!": "Nincs otthonod!", - "You can't go home from here!": "Nem tudsz innen haza menni!", - "Leather Armor": "Bőrpáncél", - "Snake Armor": "Kígyópáncél", - "Iron Armor": "Vaspáncél", - "Gold Armor": "Aranypáncél", - "Gem Armor": "Kristálypáncél", - "Book": "Könyv", + "Acorn": "Makk", + "AirWizard Spawner": "Levegővarázsló idéző", "Antidious": "Antidious", - "Empty Bucket": "Üres vödör", - "Water Bucket": "Vizesvödör", - "Lava Bucket": "Lávásvödör", - " Bucket": " Vödör", - "Red Clothes": "Piros ruha", - "Blue Clothes": "Kék ruha", - "Green Clothes": "Zöld ruha", - "Yellow Clothes": "Sárga ruha", + "Anvil": "Üllő", + "Apple": "Alma", + "Arrow": "Nyíl", + "Axe": "Balta", + "Baked Potato": "Sült burgonya", + "Bed": "Ágy", "Black Clothes": "Fekete ruha", - "Orange Clothes": "Narancssárga ruha", - "Purple Clothes": "Lila ruha", - "Cyan Clothes": "Cián ruha", - "Reg Clothes": "Reg ruha", + "Black Wool": "Fekete gyapjú", + "Blue Clothes": "Kék ruha", + "Blue Wool": "Kék gyapjú", + "Bone": "Csont", + "Book": "Könyv", + "Bow": "Íj", "Bread": "Kenyér", - "Apple": "Alma", - "Raw Pork": "Nyers disznóhús", - "Raw Fish": "Nyers hal", - "Raw Beef": "Nyers marhahús", - "Pork Chop": "Sült disznóhús", + "Cactus": "Kaktusz", + "Cactus Sapling": "Kaktuszcsemete", + "Chest": "Láda", + "Claymore": "Nagykard", + "Cloth": "Szövet", + "Cloud": "Felhő", + "Cloud Cactus": "Felhőkaktusz", + "Coal": "Szén", "Cooked Fish": "Sült hal", "Cooked Pork": "Sült marhahús", - "Steak": "Steak", - "Gold Apple": "Aranyalma", - "Baked Potato": "Sült burgonya", "Cow Spawner": "Tehén idéző", - "Pig Spawner": "Malac idéző", - "Sheep Spawner": "Bárány idéző", - "Slime Spawner": "Nyálka idéző", - "Zombie Spawner": "Zombi idéző", "Creeper Spawner": "Creeper idéző", - "Skeleton Spawner": "Csontváz idéző", - "Snake Spawner": "Kígyó idéző", - "Knight Spawner": "Lovag idéző", - "AirWizard Spawner": "Levegővarázsló idéző", - "Workbench": "Barkácsaztal", - "Oven": "Sütő", - "Furnace": "Kemence", - "Anvil": "Üllő", + "Cyan Clothes": "Cián ruha", + "Death Chest": "Halálláda", + "Dirt": "Föld", + "Empty Bucket": "Üres vödör", "Enchanter": "Varázsoló", - "Loom": "Szövőszék", - "Lantern": "Lámpa", - "Iron Lantern": "Vaslámpa", - "Gold Lantern": "Aranylámpa", - "Tnt": "TNT", - "Bed": "Ágy", - "Chest": "Láda", - "None Potion": "Haszontalan bájital", - "Speed Potion": "Gyorsaság bájital", - "Light Potion": "Fény bájital", - "Swim Potion": "Úszás bájital", "Energy Potion": "Energia bájital", - "Regen Potion": "Regenálódás bájital", - "Health Potion": "Élet bájital", - "Time Potion": "Idő bájital", - "Lava Potion": "Tűz bájital", - "Shield Potion": "Pajzs bájital", - "Haste Potion": "Sietség bájital", "Escape Potion": "Kijutás bájital", - "Potion": "Bájital", - "Power Glove": "Érőkesztyű", - "Wood": "Fa", - "Stone": "Kő", - "Leather": "Bőr", - "Wheat": "Búza", - "Key": "Kulcs", - "arrow": "Nyíl", - "string": "Fonál", - "Coal": "Szén", - "Iron Ore": "Vasérc", - "Lapis": "Lazurit", + "Explode": "Felrobban", + "Farmland": "Termőföld", + "Flower": "Virág", + "Furnace": "Kemence", + "Gem": "Kristály", + "Gem Armor": "Kristálypáncél", + "Gem Fishing Rod": "Kristály horgászbot", + "Gem Ore": "Kristályérc", + "Glass": "Üveg", + "Gold": "Arany", + "Gold Apple": "Aranyalma", + "Gold Armor": "Aranypáncél", + "Gold Fishing Rod": "Arany horgászbot", + "Gold Lantern": "Aranylámpa", "Gold Ore": "Aranyérc", + "Grass": "Fű", + "Grass Seeds": "Fűmag", + "Green Clothes": "Zöld ruha", + "Green Wool": "Zöld gyapjú", + "Gunpowder": "Puskapor", + "Hard Rock": "Nehéz kő", + "Haste Potion": "Sietség bájital", + "Health Potion": "Élet bájital", + "Hoe": "Kapa", + "Hole": "Lyuk", + "Infinite Fall": "Végtelen esés", "Iron": "Vas", - "Gold": "Arany", - "Rose": "Rózsa", - "GunPowder": "Puskapor", - "Slime": "Nyálka", - "glass": "Üveg", - "cloth": "Szövet", - "gem": "Kristály", - "Scale": "Pikkely", - "Shard": "Szilánk", - "Flower": "Virág", - "Acorn": "Makk", - "Dirt": "Föld", + "Iron Armor": "Vaspáncél", + "Iron Fishing Rod": "Vas horgászbot", + "Iron Lantern": "Vaslámpa", + "Iron Ore": "Vasérc", + "Key": "Kulcs", + "Knight Spawner": "Lovag idéző", + "Lantern": "Lámpa", + "Lapis": "Lazurit", + "Lava": "Láva", + "Lava Brick": "Lávatégla", + "Lava Bucket": "Lávásvödör", + "Lava Potion": "Tűz bájital", + "Leather": "Bőr", + "Leather Armor": "Bőrpáncél", + "Light Potion": "Fény bájital", + "Loom": "Szövőszék", "Natural Rock": "természetes kőzet", - "Plank": "Deszka", - "Plank Wall": "Deszkafal", - "Wood Door": "Faajtó", - "Stone Brick": "Kőtégla", - "Ornate Stone": "Díszes kő", - "Stone Wall": "Kőfal", - "Stone Door": "Kő ajtó", + "None Potion": "Haszontalan bájital", + "Obsidian": "Obszidián", "Obsidian Brick": "Obszidián tégla", - "Ornate Obsidian": "Díszes obszidián", - "Obsidian Wall": "Obszidián fal", "Obsidian Door": "Oszidián ajtó", - "Wool": "Gyapjú", + "Obsidian Wall": "Obszidián fal", + "Orange Clothes": "Narancssárga ruha", + "Ornate Obsidian": "Díszes obszidián", + "Ornate Stone": "Díszes kő", + "Oven": "Sütő", + "Pickaxe": "Csákány", + "Pig Spawner": "Malac idéző", + "Plank": "Deszka", + "Plank Wall": "Deszkafal", + "Player": "Játékos", + "Pork Chop": "Sült disznóhús", + "Potato": "Burgonya", + "Potion": "Bájital", + "Power Glove": "Érőkesztyű", + "Purple Clothes": "Lila ruha", + "Raw Beef": "Nyers marhahús", + "Raw Fish": "Nyers hal", + "Raw Pork": "Nyers disznóhús", + "Red Clothes": "Piros ruha", "Red Wool": "Piros gyapjú", - "Blue Wool": "Kék gyapjú", - "Green Wool": "Zöld gyapjú", - "Yellow Wool": "Sárga gyapjú", - "Black Wool": "Fekete gyapjú", + "Reg Clothes": "Reg ruha", + "Regen Potion": "Regenálódás bájital", + "Rock": "kő", + "Rose": "Rózsa", "Sand": "Homok", - "Cactus": "Kaktusz", + "Scale": "Pikkely", "Seeds": "Vetőmag", - "Wheat Seeds": "Búza vetőmagok", - "Grass Seeds": "Fűmag", - "Bone": "Csont", - "Cloud": "Felhő", - "Rock": "kő", - "Gem": "Kristály", - "Potato": "Burgonya", - "Wood Fishing Rod": "Fa horgászbot", - "Iron Fishing Rod": "Vas horgászbot", - "Gold Fishing Rod": "Arany horgászbot", - "Gem Fishing Rod": "Kristály horgászbot", + "Shard": "Szilánk", + "Shears": "olló", + "Sheep Spawner": "Bárány idéző", + "Shield Potion": "Pajzs bájital", "Shovel": "Ásó", - "Hoe": "Kapa", + "Skeleton Spawner": "Csontváz idéző", + "Slime": "Nyálka", + "Slime Spawner": "Nyálka idéző", + "Snake Armor": "Kígyópáncél", + "Snake Spawner": "Kígyó idéző", + "Speed Potion": "Gyorsaság bájital", + "Stairs Down": "Lefelé vezető lépcső", + "Stairs Up": "Felfelé vezető lépcső", + "Steak": "Steak", + "Stone": "Kő", + "Stone Brick": "Kőtégla", + "Stone Bricks": "Kőtégla", + "Stone Door": "Kő ajtó", + "Stone Wall": "Kőfal", + "String": "Fonál", + "Swim Potion": "Úszás bájital", "Sword": "Kard", - "Pickaxe": "Csákány", - "Axe": "Balta", - "Bow": "Íj", - "Claymore": "Nagykard", - "Shears": "olló", + "Time Potion": "Idő bájital", + "Tnt": "TNT", "Torch": "Fáklya", - "Gem Ore": "Kristályérc", - "Wood Planks": "Fadeszka", - "Stone Bricks": "Kőtégla", - "Obsidian": "Obszidián", - "Wood Wall": "Fafal", - "Grass": "Fű", - "Hole": "Lyuk", - "Stairs Up": "Felfelé vezető lépcső", - "Stairs Down": "Lefelé vezető lépcső", - "Water": "Víz", "Tree": "Fa", "Tree Sapling": "Facsemete", - "Cactus Sapling": "Kaktuszcsemete", - "Lava": "Láva", - "Lava Brick": "Lávatégla", - "Explode": "Felrobban", - "Farmland": "Termőföld", - "Hard Rock": "Nehéz kő", - "Infinite Fall": "Végtelen esés", - "Cloud Cactus": "Felhőkaktusz", - "Ore": "Érc", - "host not found": "gazda nem található", - "unable to get localhost address": "nem lehet localhost címjét megkapni", - "World Saved!": "A világ megmenekült!", - "On": "Be", - "Off": "Ki", - "There is nothing of use here.": "Itt nincs semmi hasznos.", - "Still nothing... :P": "Még mindig semmi... :)", - "Have:": "Van:", - "Cost:": "Ár:", - "Time: ": "Idő: ", - "Score: ": "Pont: ", - "Quit": "Kilépés", - "Respawn": "Újraéledés", - "You died! Aww!": "Meghaltál%", - "Player Score: ": "Pontok: ", - "": "", - "Final Score: ": "Utolsó pont: ", - "Exit to Menu": "Kilépés a menűre", - "Time Played: ": "Játékidő: ", - "Current Score: ": "Jelenlegi pont: ", - "Exit": "Kilépés", - "Player Stats": "Statisztikák", - "Controls": "Irányítások", - "Press the desired": "Nyomd meg egy", - "key sequence": "billentyűkombinációt", - "minicraft.display.key_input.confirm_popup": "Akarod az öszzes irányítást az alapra újrakezdeni?", + "Water": "Víz", + "Water Bucket": "Vizesvödör", + "Wheat": "Búza", + "Wheat Seeds": "Búza vetőmagok", + "Wood": "Fa", + "Wood Door": "Faajtó", + "Wood Fishing Rod": "Fa horgászbot", + "Wood Planks": "Fadeszka", + "Wood Wall": "Fafal", + "Wool": "Gyapjú", + "Workbench": "Barkácsaztal", + "Yellow Clothes": "Sárga ruha", + "Yellow Wool": "Sárga gyapjú", + "Zombie Spawner": "Zombi idéző", + "minicraft.achievement.airwizard": "Győzd le... a levegőt?", + "minicraft.achievement.airwizard.desc": "Győzd le az első légvarázslót!", + "minicraft.achievement.benchmarking": "Ideje munkához látni!", + "minicraft.achievement.benchmarking.desc": "Készítsen egy munkapadot.", + "minicraft.achievement.bow": "Hajoljatok meg előttem!", + "minicraft.achievement.bow.desc": "Lőj ki egy nyilat egy íjjal.", + "minicraft.achievement.clothes": "Legyen színes a napod!", + "minicraft.achievement.clothes.desc": "Készíts bármilyen színű ruhát", + "minicraft.achievement.demolition": "Dinamitát", + "minicraft.achievement.demolition.desc": "Használj Dinamitát.", + "minicraft.achievement.doors": "Adooring védelem", + "minicraft.achievement.doors.desc": "Készítsen egy faajtót.", + "minicraft.achievement.find_gem": "Oooh Shiny!", + "minicraft.achievement.find_gem.desc": "Találd meg a Gem Ore-t és bányászd ki.", + "minicraft.achievement.fish": "Menjetek horgászni!", + "minicraft.achievement.fish.desc": "Szerezz egy halat", + "minicraft.achievement.lava": "Forró ügyek", + "minicraft.achievement.lava.desc": "Használj lávaitalt a lávában való úszáshoz", + "minicraft.achievement.lowest_caves": "Sötétség a fény mögött", + "minicraft.achievement.lowest_caves.desc": "Elérni a legalacsonyabb barlangokat.", + "minicraft.achievement.obsidian_dungeon": "Of Knights and Men", + "minicraft.achievement.obsidian_dungeon.desc": "Érje el az obszidiánbörtönt.", + "minicraft.achievement.planks": "Sétálj a deszkákon!", + "minicraft.achievement.planks.desc": "Fadeszkák készítése.", + "minicraft.achievement.skin": "Divatbemutató", + "minicraft.achievement.skin.desc": "Változtassa meg a bőrét.", + "minicraft.achievement.survive_darkness": "Félsz a sötétségtől?", + "minicraft.achievement.survive_darkness.desc": "Túlélni 5 percet teljes sötétségben.", + "minicraft.achievement.upgrade": "Frissítés!", + "minicraft.achievement.upgrade.desc": "Készítsen bármilyen kőszerszámot.", + "minicraft.achievement.woodcutter": "Favágó", + "minicraft.achievement.woodcutter.desc": "Szerezd meg a fát", "minicraft.display.popup.enter_confirm": "Enter ha jó", "minicraft.display.popup.escape_cancel": "Escape a visszamenéshez", - "Confirm Action": "Akció végzése", - "Press C/Enter to change key binding": "Nyomd meg a C-t/Entert hogy a billentyűt változtasd", - "Press A to add key binding": "A-val billentyt adsz hozzá", - "Shift-D to reset all keys to default": "Shift-D-vel alapra állítod a billentyűket", - "ESCAPE to Return to menu": "Escape-pel visszamész a menűre", - "Loading": "Világ", - "Generating": "Generálás", - "World": "Betöltése", - "waiting...": "várakozás...", - "nothing": "semmi", - "attempting log in": "bejelentkezés probálkozás", - "no internet connection, but no login data saved; cannot enter offline mode.": "nincs internet, és nincs bejelentkezési adat mentve; nem lehet offline módra lépni.", - "connecting to server": "csatlakozás a szerverre", - "logging in": "bejelentkezés", - "saving credentials": "bejelentkezésadat mentése", - "login failed.": "bejelentkezés hibásul készült el.", - "problem with saved login data; please exit and login again.": "probléma a mentett adattal: lépj ki és jelentkezz be újra.", - "Internal server error: Couldn't fetch username from uuid": "Belső szerverhiba: Nem lehetett felhasználónevet kapni uuid-től", - "logged in as: ": "ezként bejelentkezve: ", - "offline mode: local servers only": "offline mód: csak közeli server", - "Enter ip address to connect to:": "Írj be egy IP-t hogy csatlakozz:", - "Press Shift-Escape to logout": "Nyomd meg a Shift+Escape-t hogy jelentkezz ki", - "Enter email:": "Írd be az emailedet:", - "Enter password:": "Írd be a jelszavadat:", - "field is blank": "szövegdoboz üres", - "get an account at:": "itt szerezz fiókot:", - "Loading ": "Betöltés ", - " from server": " a szerverről", - "Could not connect to server:": "Nem lehetett szerverhez csatlakozni:", - "Press ": "Nyomd ezd: ", - " to return": " hogy menj vissza", - "Change Key Bindings": "Billentyűk változtatása", - "Options": "Beállítások", - "Change language": "Nyelv változtatása", - "Return to Game": "Folytatás", - "Make World Multiplayer": "Világ többjátékossá készítése", - "Save Game": "Mentés", - " and ": " és ", - " to Scroll": " hogy görgess", - ": Choose": ": Válassz", - "Paused": "Szünet", - "Main Menu": "Menű", - "Yes": "Igen", - "No": "Nem", - "Inventory": "Leltár", - "to search.": "keresni.", - "Play": "Indítás", - "Load World": "Világ betöltése", - "New World": "Új világ", - "Multiplayer": "Többjátékos", - "Singleplayer": "Egyjátékos", - "Help": "Segítség", - "Instructions": "Játékleírás", - "Storyline Guide (for the weak)": "Játéksztori", - "About": "Névjegy", - "Credits": "Hitelek", - " to select": " hogy válassz", - " to accept": " ha jó", - "New World Name:": "Új világnév:", - "Are you sure you want to delete": "Akarod törölni", - "This can not be undone!": "Ézt nem lehet visszatenni!", - " to confirm": " ha jó", - " to cancel": " hogy menj vissza", - "World Seed": "Világmag", - "Enter World Name": "Világ neve", - "Trouble with world name?": "Nehezen tudsz tudsz nevet adni?", - "by default, w and s move the cursor up and down. This can be changed in the key binding menu. To type the letter instead of moving the cursor, hold the shift key while typing the world name.": "Alapból, a W és S a választásot mozgatja. Ez a billentyűmenűben válzoztatható. Hogy a betűt írd és ne mozgasz a választásot, tartsd le a Shift billentyűt míg írsz.", - "Create World": "Világ létrehozása", - "World Gen Options": "Generálásbeállítások", - " to Copy": " a Másolás", - " to Rename": " a Átnevezés", - " to Delete": " a Törlés", - "Select World": "Világválasztás", - "Select a World to Delete": "Törlendő világ kiválasztása", - "Select a World to Rename": "Válasszon ki egy világot az átnevezéshez", - "Select a World to Copy": "Másolandó világ kiválasztása", - "Higher version, cannot load world!": "Magasabb verzió, nem lehet betölteni a világot!", - "World Version:": "Világverzió:", - "Languages": "Nyelvek", - "Language": "Nyelv", - "Select": "Választás", - "Max FPS": "Maximum képkockasebesség", - "Difficulty": "Nehézség", - "Easy": "Könnyű", - "Normal": "Normális", - "Hard": "Nehés", - "Game Mode": "Játékmód", - "Survival": "Túlélő", - "Creative": "Kreatív", - "Hardcore": "Hardcore", - "Score": "Pont", - "Time (Score Mode)": "Idő ellen (Pont mód)", - "Sound": "Hang", - "Autosave": "Automatikus mentés", - "World Size": "Világméret", - "World Theme": "Világtéma", - "Forest": "Erdő", - "Desert": "Sivatag", - "Plain": "Sima", - "Hell": "Pokol", - "Terrain Type": "Domborzatféle", - "Island": "Sziget", - "Box": "Doboz", - "Mountain": "Hegy", - "Irregular": "Szabálytalan", - "Wear Suit": "Ruha viselése", - "You have the latest version.": "Önnek a legújabb verziója van.", - "minicraft.display.skin": "Skins", - "minicraft.skin.paul": "Paul", - "minicraft.skin.paul_cape": "Paul with cape", - "minicraft.skin.minecraft_steve": "Familiar boy", - "minicraft.skin.minecraft_alex": "Familiar girl", + "minicraft.notification.achievement_unlocked": "Elérés feloldva:", + "minicraft.notification.dig_hole": "Először áss egy gödröt!", "minicraft.notification.invalid_placement": "Csak a következőkre helyezhető el", - "minicraft.notification.dig_hole": "Először áss egy gödröt!" + "minicraft.skin.minecraft_alex": "Familiar girl", + "minicraft.skin.minecraft_steve": "Familiar boy", + "minicraft.skin.paul": "Paul", + "minicraft.skin.paul_cape": "Paul with cape" } diff --git a/src/client/resources/assets/localization/id-id.json b/src/client/resources/assets/localization/id-id.json index 667435ccc..7c646caa4 100644 --- a/src/client/resources/assets/localization/id-id.json +++ b/src/client/resources/assets/localization/id-id.json @@ -1,351 +1,470 @@ { - "minicraft.achievement.woodcutter": "Penebang", - "minicraft.achievement.woodcutter.desc": "Dapatkan kayu.", - "minicraft.achievement.benchmarking": "Bekerja!", - "minicraft.achievement.benchmarking.desc": "Membuat meja kerja.", - "minicraft.achievement.upgrade": "Meningkatkan!", - "minicraft.achievement.upgrade.desc": "Buat alat Batu apa saja.", - "minicraft.achievement.bow": "Tunduk padaku!", - "minicraft.achievement.bow.desc": "Menembak anak panah dengan busur.", - "minicraft.achievement.fish": "Pergi Ikan!", - "minicraft.achievement.fish.desc": "Memancing Ikan!", - "minicraft.achievement.doors": "Perlindungan Pintu", - "minicraft.achievement.doors.desc": "Buat pintu kayu.", - "minicraft.achievement.planks": "Berjalan di Papan!", - "minicraft.achievement.planks.desc": "Kerajinan papan kayu.", - "minicraft.achievement.clothes": "Semoga harimu penuh warna!", - "minicraft.achievement.clothes.desc": "Buat warna pakaian apa saja", - "minicraft.achievement.demolition": "Pembongkaran", - "minicraft.achievement.demolition.desc": "Gunakan TNT.", - "minicraft.achievement.survive_darkness": "Takut kegelapan?", - "minicraft.achievement.survive_darkness.desc": "Bertahan 5 menit dalam kegelapan total.", - "minicraft.achievement.lava": "Urusan Panas", - "minicraft.achievement.lava.desc": "Gunakan ramuan lava untuk berenang di lava.", - "minicraft.achievement.find_gem": "Ooh Mengkilap!", - "minicraft.achievement.find_gem.desc": "Temukan Bijih Permata dan menambangnya.", - "minicraft.achievement.lowest_caves": "Kegelapan di balik cahaya", - "minicraft.achievement.lowest_caves.desc": "Mencapai gua terendah.", - "minicraft.achievement.obsidian_dungeon": "Ksatria dan Pria", - "minicraft.achievement.obsidian_dungeon.desc": "Mencapai ruang bawah tanah obsidian.", - "minicraft.achievement.airwizard": "Mengalahkan... udara?", - "minicraft.achievement.airwizard.desc": "Kalahkan penyihir Udara pertama", - "minicraft.achievement.skin": "Peragaan busana", - "minicraft.achievement.skin.desc": "Ubah kulit Anda.", - "minicraft.display.achievement": "Prestasi", - "minicraft.display.achievement.achieved": "Tercapai!", - "minicraft.display.achievement.not_achieved": "Tidak tercapai", - "minicraft.display.achievement.score": "Skor Prestasi:", - "minicraft.notification.achievement_unlocked": "Prestasi tidak terkunci:", - "Entities": "Entitas", - "Air Wizard: Defeated!": "Penyihir Udara: Dikalahkan!", - "The Dungeon is now open!": "Penjara Bawah Tanah terbuka!", - "A costume lies on the ground...": "Sebuah kostum tergeletak di tanah...", - "Can't sleep!": "Tidak bisa tidur!", - "Min ": "Min ", - " Sec left!": " Detik lagi!", - "You hear a noise from the surface!": "Anda mendengar suara dari permukaan!", - "Death Chest": "Peti Mati", - "Player": "Pemain", - "Crafting": "Kerajinan", - "Set your home!": "Tetapkan rumah Anda!", - "Can't set home here!": "Tidak dapat mengatur rumah di sini!", - "Home Sweet Home!": "Rumahku Surgaku!", - "Mode penalty: -2 health": "Penalti mode: -2 darah", - "You don't have a home!": "Anda tidak punya rumah!", - "You can't go home from here!": "Anda tidak bisa pulang dari sini!", - "Leather Armor": "Armor Kulit", - "Snake Armor": "Armor Ular", - "Iron Armor": "Armor Besi", - "Gold Armor": "Armor Emas", - "Gem Armor": "Armor Gem", - "Book": "Buku", + "Acorn": "Biji Pohon", + "AirWizard Spawner": "Pemijahan PenyihirUdara", "Antidious": "Antidious", - "Empty Bucket": "Ember Kosong", - "Water Bucket": "Ember Air", - "Lava Bucket": "Ember Lava", - " Bucket": " Ember", - "Red Clothes": "Pakaian Merah", - "Blue Clothes": "Pakaian Biru", - "Green Clothes": "Pakaian Ijo", - "Yellow Clothes": "Pakaian Kuning", + "Anvil": "Landasan", + "Apple": "Apel", + "Arrow": "Anak panah", + "Axe": "Kapak", + "Baked Potato": "Kentang Panggang", + "Bed": "Tempat tidur", "Black Clothes": "Pakaian Item", - "Orange Clothes": "Pakaian Oranye", - "Purple Clothes": "Pakaian Ungu", - "Cyan Clothes": "Pakaian Cyan", - "Reg Clothes": "Pakaian Reg", + "Black Wool": "Wol Item", + "Blue Clothes": "Pakaian Biru", + "Blue Wool": "Wol Biru", + "Bone": "Tulang", + "Book": "Buku", + "Bow": "Busur", "Bread": "Roti", - "Apple": "Apel", - "Raw Pork": "Babi Mentah", - "Raw Fish": "Ikan Mentah", - "Raw Beef": "Daging Mentah", - "Pork Chop": "Daging Babi", + "Cactus": "Kaktus", + "Cactus Sapling": "Kaktus Muda", + "Chest": "Peti", + "Claymore": "Claymore", + "Cloth": "Kain", + "Cloud": "Awan", + "Cloud Cactus": "Kaktus Awan", + "Cloud Ore": "Bijih Awan", + "Coal": "Batu Bara", "Cooked Fish": "Ikan Matang", "Cooked Pork": "Daging Babi Matang", - "Steak": "Daging Panggang", - "Gold Apple": "Apel Emas", - "Baked Potato": "Kentang Panggang", "Cow Spawner": "Pemijahan Sapi", - "Pig Spawner": "Pemijahan Babi", - "Sheep Spawner": "Pemijahan Kambing", - "Slime Spawner": "Pemijahan Slime", - "Zombie Spawner": "Pemijahan Zombie", "Creeper Spawner": "Pemijahan Creeper", - "Skeleton Spawner": "Pemijahan Skeleton", - "Snake Spawner": "Pemijahan Ular", - "Knight Spawner": "Pemijahan Kesatria", - "AirWizard Spawner": "Pemijahan PenyihirUdara", - "Workbench": "Meja Kerja", - "Oven": "Oven", - "Furnace": "Perapian", - "Anvil": "Landasan", + "Cyan Clothes": "Pakaian Cyan", + "Death Chest": "Peti Mati", + "Dirt": "Tanah", + "Empty Bucket": "Ember Kosong", "Enchanter": "Enchanter", - "Loom": "Mesin Tenun", - "Lantern": "Lentera", - "Iron Lantern": "Lentera Besi", - "Gold Lantern": "Lentera Emas", - "Tnt": "Tnt", - "Bed": "Tempat tidur", - "Chest": "Peti", - "None Potion": "Ramuan Kosong", - "Speed Potion": "Ramuan Kecepatan", - "Light Potion": "Ramuan Ringan", - "Swim Potion": "Ramuan Berenang", "Energy Potion": "Ramuan Energi", - "Regen Potion": "Ramuan Regen", - "Health Potion": "Ramuan Darah", - "Time Potion": "Ramuan Waktu", - "Lava Potion": "Ramuan Lava", - "Shield Potion": "Ramuan Perisai", - "Haste Potion": "Ramuan Tergesa-gesa", "Escape Potion": "Ramuan Melarikan Diri", - "Potion": "Ramuan", - "Power Glove": "Sarung Kekuatan", - "Wood": "Kayu", - "Stone": "Batu", - "Leather": "Kulit", - "Wheat": "Gandum", - "Key": "Kunci", - "arrow": "anak panah", - "string": "benang", - "Coal": "Batu Bara", - "Iron Ore": "Bijih Besi", - "Lapis": "Lapis", + "Explode": "Meledak", + "Farmland": "Tanah Pertanian", + "Flower": "Bunga", + "Furnace": "Perapian", + "Gem": "Gem", + "Gem Armor": "Armor Gem", + "Gem Fishing Rod": "Pancing Gem", + "Gem Ore": "Bijih Gem", + "Glass": "Kaca", + "Gold": "Emas", + "Gold Apple": "Apel Emas", + "Gold Armor": "Armor Emas", + "Gold Fishing Rod": "Pancing Emas", + "Gold Lantern": "Lentera Emas", "Gold Ore": "Bijih Emas", + "Grass": "Rumput", + "Grass Seeds": "Bibit Rumput", + "Green Clothes": "Pakaian Ijo", + "Green Wool": "Wol Ijo", + "Gunpowder": "Bubuk Mesiu", + "Hard Rock": "Batu Keras", + "Haste Potion": "Ramuan Tergesa-gesa", + "Health Potion": "Ramuan Darah", + "Hoe": "Cankul", + "Hole": "Lubang", + "Infinite Fall": "Jatuh Tak Terbatas", "Iron": "Besi", - "Gold": "Emas", - "Rose": "Bunga Mawar", - "GunPowder": "Bubuk Mesiu", - "Slime": "lendir", - "glass": "kaca", - "cloth": "kain", - "gem": "gem", - "Scale": "Skala", - "Shard": "Beling", - "Flower": "Bunga", - "Acorn": "Biji Pohon", - "Dirt": "Tanah", + "Iron Armor": "Armor Besi", + "Iron Fishing Rod": "Pancing Besi", + "Iron Lantern": "Lentera Besi", + "Iron Ore": "Bijih Besi", + "Key": "Kunci", + "Knight Spawner": "Pemijahan Kesatria", + "Lantern": "Lentera", + "Lapis": "Lapis", + "Lava": "Lava", + "Lava Brick": "Bata Lava", + "Lava Bucket": "Ember Lava", + "Lava Potion": "Ramuan Lava", + "Leather": "Kulit", + "Leather Armor": "Armor Kulit", + "Light Potion": "Ramuan Ringan", + "Loom": "Mesin Tenun", "Natural Rock": "Batu Alam", - "Plank": "Papan", - "Plank Wall": "Dinding Papan", - "Wood Door": "Pintu Kayu", - "Stone Brick": "Batu Bata", - "Ornate Stone": "Batu Hiasan", - "Stone Wall": "Dinding Batu", - "Stone Door": "Pintu Batu", + "None Potion": "Ramuan Kosong", + "Obsidian": "Obsidian", "Obsidian Brick": "Bata Obsidian", - "Ornate Obsidian": "Obsidian hiasan", - "Obsidian Wall": "Dinding Obsidian", "Obsidian Door": "Pintu Obsidian", - "Wool": "Wol", - "Red Wool": "Wol", - "Blue Wool": "Wol Biru", - "Green Wool": "Wol Ijo", - "Yellow Wool": "Wol Kuning", - "Black Wool": "Wol Item", + "Obsidian Wall": "Dinding Obsidian", + "Orange Clothes": "Pakaian Oranye", + "Ornate Obsidian": "Obsidian hiasan", + "Ornate Stone": "Batu Hiasan", + "Oven": "Oven", + "Pickaxe": "Beliung", + "Pig Spawner": "Pemijahan Babi", + "Plank": "Papan", + "Plank Wall": "Dinding Papan", + "Player": "Pemain", + "Pork Chop": "Daging Babi", + "Potato": "Kentang", + "Potion": "Ramuan", + "Power Glove": "Sarung Tangan Kekuatan", + "Purple Clothes": "Pakaian Ungu", + "Raw Beef": "Daging Mentah", + "Raw Fish": "Ikan Mentah", + "Raw Obsidian": "Obsidian Mentah", + "Raw Pork": "Babi Mentah", + "Red Clothes": "Pakaian Merah", + "Red Wool": "Wol Merah", + "Reg Clothes": "Pakaian Reguler", + "Regen Potion": "Ramuan Regen", + "Rock": "Batu", + "Rose": "Bunga Mawar", "Sand": "Pasir", - "Cactus": "Kaktus", + "Scale": "Skala", "Seeds": "Biji", - "Wheat Seeds": "Biji Gandum", - "Grass Seeds": "Bibit Rumput", - "Bone": "Tulang", - "Cloud": "Awan", - "Rock": "Batu", - "Gem": "Gem", - "Potato": "Kentang", - "Wood Fishing Rod": "Pancing Kayu", - "Iron Fishing Rod": "Pancing Besi", - "Gold Fishing Rod": "Pancing Emas", - "Gem Fishing Rod": "Pancing Gem", - "Shovel": "Sekop", - "Hoe": "Cankul", - "Sword": "pedang", - "Pickaxe": "Beliung", - "Axe": "Kapak", - "Bow": "Busur", - "Claymore": "Claymore", + "Shard": "Beling", "Shears": "Sepasang gunting", - "Torch": "Obor", - "Gem Ore": "Bijih Gem", - "Wood Planks": "Papan Kayu", - "Stone Bricks": "Batu Bata", - "Obsidian": "Obsidian", - "Wood Wall": "Dinding Kayu", - "Grass": "Rumput", - "Hole": "Lubang", - "Stairs Up": "Tangga Naik", + "Sheep Spawner": "Pemijahan Kambing", + "Shield Potion": "Ramuan Perisai", + "Shovel": "Sekop", + "Skeleton Spawner": "Pemijahan Skeleton", + "Slime": "Lendir", + "Slime Spawner": "Pemijahan Slime", + "Snake Armor": "Armor Ular", + "Snake Spawner": "Pemijahan Ular", + "Speed Potion": "Ramuan Kecepatan", "Stairs Down": "Tangga Turun", - "Water": "Air", + "Stairs Up": "Tangga Naik", + "Steak": "Daging Panggang", + "Stone": "Batu", + "Stone Brick": "Batu Bata", + "Stone Bricks": "Batu Bata", + "Stone Door": "Pintu Batu", + "Stone Wall": "Dinding Batu", + "String": "Benang", + "Swim Potion": "Ramuan Berenang", + "Sword": "Pedang", + "Time Potion": "Ramuan Waktu", + "Tnt": "Tnt", + "Torch": "Obor", + "Totem of Air": "Totem Udara", "Tree": "Pohon", "Tree Sapling": "Pohon Muda", - "Cactus Sapling": "Kaktus Muda", - "Lava": "Lava", - "Lava Brick": "Bata Lava", - "Explode": "Meledak", - "Farmland": "Tanah Pertanian", - "Hard Rock": "Batu Keras", - "Infinite Fall": "Jatuh Tak Terbatas", - "Cloud Cactus": "Kaktus Awan", - "Ore": "Bijih", - "host not found": "host tidak ditemukan", - "unable to get localhost address": "tidak bisa mendapatkan alamat localhost", - "World Saved!": "Dunia Disimpan!", - "On": "Aktif", - "Off": "Nonaktif", - "There is nothing of use here.": "Tidak ada yang bisa digunakan disini.", - "Still nothing... :P": "Masih tidak ada... :V", - "Have:": "Punya:", - "Cost:": "Harga", - "Time: ": "Waktu: ", - "Score: ": "Skor: ", - "Quit": "Quit", - "Respawn": "Respawn", - "You died! Aww!": "Anda mati! Aww!", - "Player Score: ": "Skor Pemain: ", - "": "", - "Final Score: ": "Skor Terakhir: ", - "Exit to Menu": "Keluar ke Menu", - "Time Played: ": "Waktu Dimainkan: ", - "Current Score: ": "Skor saat ini: ", - "Exit": "Exit", - "Player Stats": "Statistik Pemain", - "Controls": "Kontrol", - "Press the desired": "Tekan yang diinginkan", - "key sequence": "urutan tombol", - "minicraft.display.key_input.confirm_popup": "Apakah Anda yakin ingin mengatur ulang semua ikatan kunci ke kunci default?", + "Water": "Air", + "Water Bucket": "Ember Air", + "Wheat": "Gandum", + "Wheat Seeds": "Biji Gandum", + "Wood": "Kayu", + "Wood Door": "Pintu Kayu", + "Wood Fishing Rod": "Pancing Kayu", + "Wood Planks": "Papan Kayu", + "Wood Wall": "Dinding Kayu", + "Wool": "Wol", + "Workbench": "Meja Kerja", + "Yellow Clothes": "Pakaian Kuning", + "Yellow Wool": "Wol Kuning", + "Zombie Spawner": "Pemijahan Zombie", + "minicraft.achievement.airwizard": "Mengalahkan... udara?", + "minicraft.achievement.airwizard.desc": "Kalahkan Penyihir Angin pertama!", + "minicraft.achievement.benchmarking": "Bekerja", + "minicraft.achievement.benchmarking.desc": "Membuat meja kerja.", + "minicraft.achievement.bow": "Tunduk padaku!", + "minicraft.achievement.bow.desc": "Menembak anak panah dengan busur.", + "minicraft.achievement.clothes": "Semoga harimu penuh warna!", + "minicraft.achievement.clothes.desc": "Buat warna pakaian apa saja", + "minicraft.achievement.demolition": "Pembongkaran", + "minicraft.achievement.demolition.desc": "Gunakan TNT.", + "minicraft.achievement.doors": "Perlindungan Pintu", + "minicraft.achievement.doors.desc": "Buat pintu kayu.", + "minicraft.achievement.find_gem": "Ooh Mengkilap!", + "minicraft.achievement.find_gem.desc": "Temukan Bijih Permata dan menambangnya.", + "minicraft.achievement.fish": "Pergi Ikan!", + "minicraft.achievement.fish.desc": "Memancing Ikan!", + "minicraft.achievement.lava": "Urusan Panas", + "minicraft.achievement.lava.desc": "Gunakan ramuan lava untuk berenang di lava.", + "minicraft.achievement.lowest_caves": "Kegelapan di balik cahaya", + "minicraft.achievement.lowest_caves.desc": "Mencapai gua terendah.", + "minicraft.achievement.obsidian_dungeon": "Ksatria dan Pria", + "minicraft.achievement.obsidian_dungeon.desc": "Mencapai ruang bawah tanah obsidian.", + "minicraft.achievement.planks": "Berjalan di Papan!", + "minicraft.achievement.planks.desc": "Kerajinan papan kayu.", + "minicraft.achievement.skin": "Peragaan busana", + "minicraft.achievement.skin.desc": "Ubah kulit Anda.", + "minicraft.achievement.survive_darkness": "Takut kegelapan?", + "minicraft.achievement.survive_darkness.desc": "Bertahan 5 menit dalam kegelapan total.", + "minicraft.achievement.upgrade": "Meningkatkan!", + "minicraft.achievement.upgrade.desc": "Buat alat Batu apa saja.", + "minicraft.achievement.woodcutter": "Penebang", + "minicraft.achievement.woodcutter.desc": "Dapatkan kayu.", + "minicraft.control_guide.attack": "Gunakan %s untuk menyerang atau menghancur.", + "minicraft.control_guide.craft": "Gunakan %s untuk membuka menu kerajinanmu.", + "minicraft.control_guide.menu": "Gunakan %s untuk membuka menu inventaris.", + "minicraft.control_guide.move": "Gunakan %s untuk bergerak.", + "minicraft.display.entries.boolean.false": "Mati", + "minicraft.display.entries.boolean.true": "Hidup", + "minicraft.display.gui.link_opening": "Membuka dengan browser...", + "minicraft.display.gui.perm_status.saving": "Menyimpan... %s%%", + "minicraft.display.gui.perm_status.sleep_cancel": "Tekan %s untuk membatalkan", + "minicraft.display.gui.perm_status.sleeping": "Sedang tidur...", + "minicraft.display.gui.potion_effects.hide_hint": "(%s untuk disembunyikan!)", + "minicraft.display.gui.potion_effects.potion_dur": "%s (%d:%02d)", + "minicraft.display.gui.score.current_score": "Skor saat ini: %s", + "minicraft.display.gui.score.time_left": "Waktu tersisa %s%sm %sd", + "minicraft.display.menus.inventory": "Inventaris", + "minicraft.display.options_display": "Opsi", + "minicraft.display.options_display.change_key_bindings": "Ganti Tombol Pintasan", + "minicraft.display.options_display.language": "Bahasa", + "minicraft.display.options_display.resource_packs": "Resours pack", "minicraft.display.popup.enter_confirm": "tekan enter untuk konfirmasi", "minicraft.display.popup.escape_cancel": "tekan escape untuk membatalkan", - "Confirm Action": "Konfirmasi Tindakan", - "Press C/Enter to change key binding": "Tekan C/Enter untuk mengubah ikatan tombol", - "Press A to add key binding": "Tekan A untuk menambahkan pengikatan tombol", - "Shift-D to reset all keys to default": "Shift-D untuk mengatur ulang semua tombol ke default", - "ESCAPE to Return to menu": "Tekan ESCAPE untuk Kembali ke menu", - "Loading": "Memuat", - "Generating": "Membuat", - "World": "Dunia", - "waiting...": "menunggu...", - "nothing": "tidak ada apa-apa", - "attempting log in": "mencoba masuk", - "no internet connection, but no login data saved; cannot enter offline mode.": "tidak ada koneksi internet, tetapi tidak ada data login yang disimpan; tidak dapat masuk ke mode offline.", - "connecting to server": "menghubungkan ke server", - "logging in": "masuk", - "saving credentials": "menyimpan kredensial", - "login failed.": "gagal masuk.", - "problem with saved login data; please exit and login again.": "masalah dengan data login yang disimpan; silahkan keluar dan login kembali.", - "Internal server error: Couldn't fetch username from uuid": "Kesalahan server internal: Tidak dapat mengambil nama pengguna dari uuid", - "logged in as: ": "masuk sebagai:", - "offline mode: local servers only": "mode offline: hanya server lokal", - "Enter ip address to connect to:": "Masukkan alamat ip untuk terhubung ke:", - "Press Shift-Escape to logout": "Tekan Shift-Escape untuk keluar", - "Enter email:": "Masukan email:", - "Enter password:": "Masukkan sandi:", - "field is blank": "tidak ada isi", - "get an account at:": "dapatkan akun di:", - "Loading ": "Memuat ", - " from server": " dari server", - "Could not connect to server:": "Tidak bisa terhubung ke server:", - "Press ": "tekan ", - " to return": " mengembalikan", - "Change Key Bindings": "Ubah Ikatan Tombol", - "Options": "Opsi", - "Change language": "Ganti bahasa", - "Return to Game": "Kembali ke Permainan", - "Make World Multiplayer": "Jadikan Multiplayer Dunia", - "Save Game": "Simpan permainan", - " and ": " dan ", - " to Scroll": " untuk Menggulir", - ": Choose": ": Memilih", - "Paused": "Dijeda", - "Main Menu": "Menu utama", - "No": "Tidak", - "Yes": "Ya", - "Inventory": "Inventaris", - "to search.": "untuk mencari.", - "Play": "Bermain", - "Load World": "Muat Dunia", - "New World": "Dunia baru", - "Multiplayer": "Bermain Bersama", - "Singleplayer": "Bermain Sendiri", - "Help": "Bantu", - "Instructions": "Instruksi", - "Storyline Guide": "Panduan alur cerita", - "About": "Tentang", - "Credits": "Kredit", - " to select": " memilih", - " to accept": " menerima", - "New World Name:": "Nama Dunia Baru:", - "Are you sure you want to delete": "Anda yakin ingin menghapus", - "This can not be undone!": "Ini tidak dapat dibatalkan!", - " to confirm": " untuk mengkonfirmasi", - " to cancel": " untuk membatalkan", - "World Seed": "Benih Dunia", - "Enter World Name": "Masukkan Nama Dunia", - "Trouble with world name?": "Masalah dengan nama dunia?", - "by default, w and s move the cursor up and down. This can be changed in the key binding menu. To type the letter instead of moving the cursor, hold the shift key while typing the world name.": "secara default, w dan s memindahkan kursor ke atas dan ke bawah. Ini dapat diubah di menu pengikatan kunci. Untuk mengetik huruf alih-alih memindahkan kursor, tahan tombol shift saat mengetik nama dunia.", - "Create World": "Buat Dunia", - "World Gen Options": "Opsi Generasi Dunia", - " to Copy": " untuk Menyalin", - " to Rename": " untuk Mengganti Nama", - " to Delete": " untuk Menghapus", - "Select World": "Pilih Dunia", - "Select a World to Delete": "Pilih Dunia untuk Dihapus", - "Select a World to Rename": "Pilih Dunia untuk Diganti Nama", - "Select a World to Copy": "Pilih Dunia untuk Disalin", - "Higher version, cannot load world!": "Versi yang lebih tinggi, tidak dapat memuat dunia!", - "World Version:": "Versi Dunia:", - "Languages": "Bahasa-Bahasa", - "Language": "Bahasa", - "Select": "Pilih", - "Max FPS": "FPS maks", - "Difficulty": "Kesulitan", - "Easy": "Mudah", - "Normal": "Normal", - "Hard": "Susah", - "Game Mode": "Mode Permainan", - "Survival": "Bertahan hidup", - "Creative": "Kreatif", - "Hardcore": "Hardcore", - "Score": "Skor", - "Time (Score Mode)": "Waktu (Mode Skor)", - "Sound": "Suara", - "Autosave": "Penyimpanan otomatis", - "World Size": "Ukuran dunia", - "World Theme": "Tema Dunia", - "Forest": "hutan", - "Desert": "Gurun", - "Plain": "Polos", - "Hell": "Neraka", - "Terrain Type": "Tipe Terrain", - "Island": "Pulau", - "Box": "Kotak", - "Mountain": "Gunung", - "Irregular": "Tidak Teratur", - "Wear Suit": "Pakai Jas", - "You have the latest version.": "Anda memiliki versi terbaru.", - "minicraft.display.skin": "Kulit", + "minicraft.display.popup.title_confirm": "Konfirm Aksi", + "minicraft.displays.achievements": "Pencapaian", + "minicraft.displays.achievements.display.achieved": "Tercapai!", + "minicraft.displays.achievements.display.help": "Gunakan %s dan %s untuk bergerak.", + "minicraft.displays.achievements.display.not_achieved": "Tidak Tercapai", + "minicraft.displays.achievements.display.score": "Skor Pencapaian: %s", + "minicraft.displays.book.default_book": "Buku ini tidak memiliki teks.", + "minicraft.displays.controls": "Kontrol", + "minicraft.displays.controls.display.controller": "Kontroller", + "minicraft.displays.controls.display.controller.00": "Menggerak pemain menggunakan DPAD", + "minicraft.displays.controls.display.controller.01": "Menggerak kursor menggunakan DPAD", + "minicraft.displays.controls.display.controller.02": "Memilih entri menggunakan A", + "minicraft.displays.controls.display.controller.03": "Keluar halaman menggunakan B", + "minicraft.displays.controls.display.controller.04": "Menyerang entitas, menghancurkan dan berinteraksi tile menggunakan A", + "minicraft.displays.controls.display.controller.05": "Membuka menu dalam game menggunakan X", + "minicraft.displays.controls.display.controller.06": "Membuka menu kerajinan menggunakan Y", + "minicraft.displays.controls.display.controller.07": "Mengambil furnitur menggunakan LEFTBUMPER", + "minicraft.displays.controls.display.controller.08": "Menjatuhkan 1 item menggunakan RIGHTBUMPER", + "minicraft.displays.controls.display.controller.09": "Menjatuhkan seluruh tumpukan item menggunakan RIGHTSTICK", + "minicraft.displays.controls.display.controller.10": "Mengalihkan bilah pencarian di menu-menu item menggunakan START", + "minicraft.displays.controls.display.controller.11": "Menjeda permainan menggunakan START", + "minicraft.displays.controls.display.controller.12": "Gunakan X untuk mengaktifkan keyboard on-screen pada input", + "minicraft.displays.controls.display.controller.13": "Gunakan B sebagai pinstasan buat backspace di keyboard on-screen", + "minicraft.displays.controls.display.controller.14": "Gunakan X untuk menghapus item dalam inventaris mode kreatif", + "minicraft.displays.controls.display.controller.15": "Gunakan Y untuk menghapus seluruh tumpukan item dalam inventaris mode kreatif", + "minicraft.displays.controls.display.controller.desc.0": "Pemetaan debug tidak dapat diakses", + "minicraft.displays.controls.display.controller.desc.1": "Pemetaan terperinci tidak dapat digunakan", + "minicraft.displays.controls.display.help.0": "%s/%s untuk melihat kontrol-kontrol lain.", + "minicraft.displays.controls.display.keyboard": "Keyboard", + "minicraft.displays.controls.display.keyboard.00": "Menggerak pemain menggunakan MOVE-(DIRECTION)", + "minicraft.displays.controls.display.keyboard.01": "Menggerak kursor menggunakan CURSOR-(DIRECTION)", + "minicraft.displays.controls.display.keyboard.02": "Mempilih entri menggunakan SELECT", + "minicraft.displays.controls.display.keyboard.03": "Keluar halaman menggunakan EXIT", + "minicraft.displays.controls.display.keyboard.04": "Menyimpan cepat menggunakan QUICKSAVE", + "minicraft.displays.controls.display.keyboard.05": "Menyerang entitas, menghancur dan interaksi pada tile menggunakan ATTACK", + "minicraft.displays.controls.display.keyboard.06": "Membuka menu-menu dalam game menggunakan MENU", + "minicraft.displays.controls.display.keyboard.07": "Membuka menu kerajinan menggunakan CRAFT", + "minicraft.displays.controls.display.keyboard.08": "Mengangkat furnitur menggunakan PICKUP", + "minicraft.displays.controls.display.keyboard.09": "Menjatuhkan 1 item menggunakan DROP-ONE", + "minicraft.displays.controls.display.keyboard.10": "Menjatuhkan seluruh tumpukan item menggunakan DROP-STACK", + "minicraft.displays.controls.display.keyboard.11": "Beralih bilah pencarian di menu item menggunakan SEARCHER-BAR", + "minicraft.displays.controls.display.keyboard.12": "Browsing hasil pencarian menggunakan PAGE-UP/DOWN", + "minicraft.displays.controls.display.keyboard.13": "Menjeda game menggunakan PAUSE", + "minicraft.displays.controls.display.keyboard.14": "Mengalih tampilan efek ramuan menggunakan POTIONEFFECTS", + "minicraft.displays.controls.display.keyboard.15": "Beralih tampilan ramuan yang disederhanakan menggunakan SIMPPOTIONEFFECTS", + "minicraft.displays.controls.display.keyboard.16": "Mengembang tampilan misi dalam game menggunakan EXPANDQUESTDISPLAY", + "minicraft.displays.controls.display.keyboard.17": "Mengalih HUD menggunakan TOGGLEHUD", + "minicraft.displays.controls.display.keyboard.18": "Mengambil tangkapan layar menggunakan SCREENSHOT", + "minicraft.displays.controls.display.keyboard.19": "Menampil info dalam game menggunakan INFO", + "minicraft.displays.controls.display.keyboard.20": "Mengalih fullscreen menggunakan FULLSCREEN", + "minicraft.displays.controls.display.keyboard.21": "Gunakan D untuk menghapus item terpilih dalam inventaris mode kreatif", + "minicraft.displays.controls.display.keyboard.22": "Gunakan SHIFT-D untuk menghapus seluruh tumpukan item dalam inventaris mode kreatif", + "minicraft.displays.controls.display.keyboard.desc": "Pemetaan debug tidak dijelaskan", + "minicraft.displays.crafting": "Kerajinan", + "minicraft.displays.crafting.container_title.cost": "Biaya:", + "minicraft.displays.crafting.container_title.have": "Memiliki:", + "minicraft.displays.end_game.display.bonuses": "", + "minicraft.displays.end_game.display.final_score": "Skor Akhir: %s", + "minicraft.displays.end_game.display.player_score": "Skor Pemain: %s", + "minicraft.displays.end_game.display.unlocked": "Terbuka! %s Waktu Skor", + "minicraft.displays.end_game.exit": "Keluar ke Menu", + "minicraft.displays.info.display.exit_help": "%s/%s:Keluar", + "minicraft.displays.info.display.score": "Skor saat ini: %s", + "minicraft.displays.info.display.time": "Waktu Bermain: %s", + "minicraft.displays.info.title": "Statistik Pemain", + "minicraft.displays.key_input.display.help.0": "Tekan C/Enter untuk mengganti tombol pintasan", + "minicraft.displays.key_input.display.help.1": "Tekan A untuk menambah tombol pintasan", + "minicraft.displays.key_input.display.help.2": "Shift-D untuk mengatur ulang semua tombol pintasan ke default", + "minicraft.displays.key_input.display.help.3": "%s untuk Kembali ke menu", + "minicraft.displays.key_input.popup_display.confirm_reset": "Apakah anda yakin ingin menyetel ulang semua pengikatan tombol pintasan ke tombol pintasan default?", + "minicraft.displays.key_input.popup_display.press_key_sequence": "Tekan urutan tombol yang diinginkan", + "minicraft.displays.key_input.title": "Kontrol", + "minicraft.displays.language_settings.title": "Bahasa...", + "minicraft.displays.loading.message.dungeon_regeneration": "Regenerasi B4", + "minicraft.displays.loading.message.entities": "Entitas", + "minicraft.displays.loading.message.generating": "Sedang Menggenerasi", + "minicraft.displays.loading.message.level": "Level %s", + "minicraft.displays.loading.message.levels": "Level", + "minicraft.displays.loading.message.loading": "Memuat", + "minicraft.displays.loading.message.quests": "Misi-misi", + "minicraft.displays.loading.message.saving": "Menyimpan", + "minicraft.displays.loading.message.world": "Dunia", + "minicraft.displays.loading.regeneration_cancellation_popup.display": "Pemuatan dunia telah dibatalkan", + "minicraft.displays.loading.regeneration_popup.display.0": "Versi dungeon lama (B4 floor) terdeteksi.", + "minicraft.displays.loading.regeneration_popup.display.1": "Diperlukan regenerasi.", + "minicraft.displays.loading.regeneration_popup.display.2": "Data lama di lantai itu akan dihapus:", + "minicraft.displays.loading.regeneration_popup.display.3": "%s untuk melanjutkan", + "minicraft.displays.loading.regeneration_popup.display.4": "%s untuk membatalkan pemuatan dunia", + "minicraft.displays.options_main_menu": "Pilihan Menu Utama", + "minicraft.displays.options_main_menu.resource_packs": "Resourse Pack", + "minicraft.displays.options_world": "Opsi Dunia", + "minicraft.displays.options_world.off_tutorials_confirm_popup": "Apakah anda yakin ingin mematikan tutorial selamanya?", + "minicraft.displays.options_world.turn_off_tutorials": "Matikan tutorial", + "minicraft.displays.pause": "Dijeda", + "minicraft.displays.pause.display.exit_popup.0": "Apakah anda yakin ingin keluar dari permainan?", + "minicraft.displays.pause.display.exit_popup.1": "Semua progres yang belum disimpan akan hilang", + "minicraft.displays.pause.display.exit_popup.cancel": "Batalkan", + "minicraft.displays.pause.display.exit_popup.quit": "Keluar tanpa menyimpan", + "minicraft.displays.pause.display.help.choose": "%s: Pilih", + "minicraft.displays.pause.display.help.scroll": "%s dan %s untuk Menggulir", + "minicraft.displays.pause.menu": "Menu Utama", + "minicraft.displays.pause.return": "Kembali ke permainan", + "minicraft.displays.pause.save": "Simpan Game", + "minicraft.displays.player_death.display.score": "Skor: %s", + "minicraft.displays.player_death.display.time": "Waktu: %s", + "minicraft.displays.player_death.quit": "Keluar", + "minicraft.displays.player_death.respawn": "Respawn", + "minicraft.displays.player_death.save_quit": "Simpan dan Keluar", + "minicraft.displays.player_death.title": "Kamu mati! Aww!", + "minicraft.displays.player_inv.container_title.items": "Item", + "minicraft.displays.player_inv.display.help": "(%s) untuk mencari.", + "minicraft.displays.quests": "Misi", + "minicraft.displays.quests.display.header.completed": "Selesai", + "minicraft.displays.quests.display.header.unlocked": "Terbuka", + "minicraft.displays.quests.display.no_quest": "Tidak ada misi terbuka", + "minicraft.displays.quests.display.no_quest_desc": "Tidak ada misi", + "minicraft.displays.resource_packs.display.help.keyboard_needed": "Hanya input melalui keyboard diterima.", + "minicraft.displays.resource_packs.display.help.move": "Gunakan %s dan %s untuk bergerak.", + "minicraft.displays.resource_packs.display.help.position": "SHIFT-[LEFT|RIGHT|UP|DOWN] untuk menggerak pack. ", + "minicraft.displays.resource_packs.display.help.select": "%s untuk periksa.", + "minicraft.displays.resource_packs.display.title": "Resourse pack", + "minicraft.displays.skin": "Skin-skin", + "minicraft.displays.skin.display.help.move": "Gunakan %s dan %s untuk bergerak.", + "minicraft.displays.skin.display.help.select": "%s untuk memilih, dan %s untuk membatalkan.", + "minicraft.displays.title.display.cannot_check": "Tidak dapat cek pembaruan.", + "minicraft.displays.title.display.checking": "Mengecek pembaruan...", + "minicraft.displays.title.display.help.0": "(%s, %s untuk memilih)", + "minicraft.displays.title.display.help.1": "(%s untuk menerima)", + "minicraft.displays.title.display.help.2": "(%s untuk kembali)", + "minicraft.displays.title.display.latest_already": "Anda memiliki versi terbaru.", + "minicraft.displays.title.display.new_version": "Versi Baru: %s", + "minicraft.displays.title.display.version": "Versi %s", + "minicraft.displays.title.help": "Bantu", + "minicraft.displays.title.help.about": "Tentang", + "minicraft.displays.title.help.credits": "Kredit-kredit", + "minicraft.displays.title.help.instructions": "Instruksi", + "minicraft.displays.title.help.storyline_guide": "Panduan Alur Cerita", + "minicraft.displays.title.link_to_version": "Tautan langsung ke versi terbaru: %s", + "minicraft.displays.title.play": "Main", + "minicraft.displays.title.play.load_world": "Muat Dunia", + "minicraft.displays.title.play.new_world": "Dunia Baru", + "minicraft.displays.title.quit": "Keluar", + "minicraft.displays.title.select_to_download": "--Pilih di sini untuk Mengunduh--", + "minicraft.displays.tutorial_display_handler.display.element_examine_help": "Tekan %s untuk meneliti rincian tutorial.", + "minicraft.displays.world_gen.create_world": "Ciptakan Dunia", + "minicraft.displays.world_gen.enter_world": "Masukkan Nama Dunia", + "minicraft.displays.world_gen.title": "Opsi Generasi Dunia", + "minicraft.displays.world_gen.troublesome_input": "Masalah dengan nama dunia?", + "minicraft.displays.world_gen.troublesome_input.msg": "sepertinya Anda telah menyetel huruf sebagai kontrol untuk menggerakkan kursor ke atas dan ke bawah, yang mungkin mengganggu. Ini dapat diubah di menu pengikatan tombol sebagai tombol \"cursor-XXX\". Untuk saat ini, untuk mengetik huruf daripada menggerakkan kursor, tahan tombol shift saat mengetik.", + "minicraft.displays.world_gen.world_seed": "Benih Dunia", + "minicraft.displays.world_select.display.help.0": "%s untuk konfirmasi", + "minicraft.displays.world_select.display.help.1": "%s untuk kembali", + "minicraft.displays.world_select.display.help.2": "SHIFT-C untuk menyalin", + "minicraft.displays.world_select.display.help.3": "SHIFT-R untuk mengganti nama", + "minicraft.displays.world_select.display.help.4": "SHIFT-D untuk menghapus", + "minicraft.displays.world_select.display.world_too_new": "Versi yang lebih tinggi, tidak dapat memuat dunia!", + "minicraft.displays.world_select.display.world_version": "Versi Dunia: %s", + "minicraft.displays.world_select.popups.display.cancel": "%s untuk membatalkan", + "minicraft.displays.world_select.popups.display.change": "Nama Dunia Baru:", + "minicraft.displays.world_select.popups.display.confirm": "%s untuk konfirmasi", + "minicraft.displays.world_select.popups.display.delete": "Anda yakin ingin menghapus\n%s\"%s\"%s?\nIni tidak dapat dibatalkan!", + "minicraft.displays.world_select.select_world": "Pilih Dunia", + "minicraft.notification.achievement_unlocked": "Prestasi terbuka: %s", + "minicraft.notification.air_wizard_defeated": "Penyihir Udara Dikalahkan!", + "minicraft.notification.boss_limit": "Tidak ada lagi bos yang bisa dihasilkan", + "minicraft.notification.cannot_sleep": "Tidak bisa tidur! %sMin %s Detik tersisa!", + "minicraft.notification.death_chest_retrieved": "Peti kematian diambil!", + "minicraft.notification.defeat_air_wizard_first": "Penyihir udara harus dikalahkan terlebih dahulu.", + "minicraft.notification.defeat_obsidian_knight_first": "Ksatria Obsidian harus dikalahkan terlebih dahulu.", + "minicraft.notification.dig_hole": "Gali lubang dulu!", + "minicraft.notification.dungeon_opened": "Dungeon sekarang terbuka!", + "minicraft.notification.gem_pickaxe_required": "Beliung Gem Diperlukan.", + "minicraft.notification.invalid_placement": "Hanya dapat ditempatkan pada %s!", + "minicraft.notification.obsidian_knight_awoken": "Ksatria Obsidian telah terbangun!", + "minicraft.notification.obsidian_knight_defeated": "Ksatria Obsidian: Dikalahkan!", + "minicraft.notification.quest_completed": "Misi selesai", + "minicraft.notification.quest_unlocked": "Misi terbuka", + "minicraft.notification.spawn_on_boss_tile": "Hanya bisa dipanggil di Boss Room", + "minicraft.notification.world_saved": "Dunia tersimpan!", + "minicraft.notification.wrong_level_dungeon": "Hanya bisa dipanggil di level dungeon", + "minicraft.notification.wrong_level_sky": "Hanya bisa summon di tingkat langit", + "minicraft.notifications.statue_tapped": "Anda mendengar bisikan bergema...", + "minicraft.notifications.statue_touched": "Anda mendengar patungnya bergetar...", + "minicraft.quest.farming": "Petani Pertanian", + "minicraft.quest.farming.crafting_hoe": "Membuat cangkul", + "minicraft.quest.farming.crafting_hoe.description": "Membuat cangkul apa pun dari meja kerja", + "minicraft.quest.farming.description": "Dasar-dasar sebagai petani.", + "minicraft.quest.farming.getting_wheat": "Memanen gandum", + "minicraft.quest.farming.getting_wheat.description": "Memanen gandum dengan menghancur tanaman gandum yang tumbuh.", + "minicraft.quest.farming.making_farmland": "Membuat tanah pertanian", + "minicraft.quest.farming.making_farmland.description": "Membuat tanah pertanian dengan menggunakan cangkul untuk berinteraksi dengan tile tanah.", + "minicraft.quest.farming.planting_potato": "Menanam kentang", + "minicraft.quest.farming.planting_potato.description": "Menanam kentang dengan cara meletakkan kentang di tanah pertanian", + "minicraft.quest.farming.planting_wheat": "Menanam gandum", + "minicraft.quest.farming.planting_wheat.description": "Menanam gandum dengan cara meletakkan biji gandum di tanah pertanian.", + "minicraft.quest.gems": "Jalan Gem", + "minicraft.quest.gems.description": "Mempersiapkan peralatan gem.", + "minicraft.quest.gems.gem_armor": "Master akan Pelindungan", + "minicraft.quest.gems.gem_armor.description": "Mendapatkan armor gem.", + "minicraft.quest.gems.gem_claymore": "Master akan Senjata", + "minicraft.quest.gems.gem_claymore.description": "Mendapatkan gem claymore.", + "minicraft.quest.iron_equipments": "Master akan Besi", + "minicraft.quest.iron_equipments.description": "Mendapatkan semua peralatan besi.", + "minicraft.quest.iron_equipments.getting_more_iron": "Kaya akan Besi", + "minicraft.quest.iron_equipments.getting_more_iron.description": "Mendapatkan lebih banyak besi.", + "minicraft.quest.iron_equipments.iron_armor": "Meningkat armor", + "minicraft.quest.iron_equipments.iron_armor.description": "Meningkat armor ke besi.", + "minicraft.quest.iron_equipments.iron_tools": "Meningkat semua alat", + "minicraft.quest.iron_equipments.iron_tools.description": "Meningkat alat-alatmu ke besi.", + "minicraft.quest.iron_equipments.upgrading_pickaxe": "Beliung Advanced", + "minicraft.quest.iron_equipments.upgrading_pickaxe.description": "Meningkat beliungmu.", + "minicraft.quest.potions": "Master akan Ramuan", + "minicraft.quest.potions.all_potions_prepared": "Murid akan Ramuan", + "minicraft.quest.potions.all_potions_prepared.description": "Mendapatkan semua ramuan sekaligus.", + "minicraft.quest.potions.awkward_potions": "Ramuan Canggung", + "minicraft.quest.potions.awkward_potions.description": "Mendapatkan ramuan canggung.", + "minicraft.quest.potions.description": "Mendapatkan ramuan-ramuannya.", + "minicraft.quest.potions.powerful_potions": "Ramuan Kuat", + "minicraft.quest.potions.powerful_potions.description": "Mendapatkan ramuan yang berguna dan kuat.", + "minicraft.settings.autosave": "Simpan otomatis", + "minicraft.settings.difficulty": "Kesulitan", + "minicraft.settings.difficulty.easy": "Mudah", + "minicraft.settings.difficulty.hard": "Susah", + "minicraft.settings.difficulty.normal": "Normal", + "minicraft.settings.fps": "FPS Maks", + "minicraft.settings.mode": "Mode Permainan", + "minicraft.settings.mode.creative": "Kreatif", + "minicraft.settings.mode.hardcore": "Hardcore", + "minicraft.settings.mode.score": "Skor", + "minicraft.settings.mode.survival": "Surviv", + "minicraft.settings.scoretime": "Waktu (Mode Skor)", + "minicraft.settings.screenshot_scale": "Skala Tangkapan Layar", + "minicraft.settings.size": "Ukuran dunia", + "minicraft.settings.sound": "Suara", + "minicraft.settings.theme": "Tema Dunia", + "minicraft.settings.theme.desert": "Gurun", + "minicraft.settings.theme.forest": "Hutan", + "minicraft.settings.theme.hell": "Neraka", + "minicraft.settings.theme.normal": "Normal", + "minicraft.settings.theme.plain": "Plain", + "minicraft.settings.type": "Tipe Terrain", + "minicraft.settings.type.box": "Kotak", + "minicraft.settings.type.irregular": "Tidak teratur", + "minicraft.settings.type.island": "Pulau", + "minicraft.settings.type.mountain": "Gunung", + "minicraft.skin.minecraft_alex": "Gadis yang akrab", + "minicraft.skin.minecraft_steve": "Anak laki-laki yang akrab", "minicraft.skin.paul": "Paul", "minicraft.skin.paul_cape": "Paul dengan jubah", - "minicraft.skin.minecraft_steve": "Anak laki-laki yang akrab", - "minicraft.skin.minecraft_alex": "Gadis yang akrab", - "minicraft.notification.invalid_placement": "Hanya dapat ditempatkan pada", - "minicraft.notification.dig_hole": "Gali lubang dulu!" + "minicraft.text_particales.key_consumed": "-1 tombol", + "minicraft.tutorial.getting_rocks": "Mendapatkan batu dan bara", + "minicraft.tutorial.getting_rocks.description": "Dapatkan setidaknya 5 item batu dan 5 item batu bara dengan menghancurkan batu dengan beliung yang dibuat.", + "minicraft.tutorial.getting_wood": "Mendapatkan lebih banyak kayu", + "minicraft.tutorial.getting_wood.description": "Mendapatkan setidaknya 10 item kayu dari pohon-pohon.", + "minicraft.tutorial.getting_wooden_pickaxe": "Mendapatkan beliung kayu", + "minicraft.tutorial.getting_wooden_pickaxe.description": "Membuat beliung kayu di menu kerajinan dari meja kerja.", + "minicraft.tutorial.getting_workbench": "Mendapatkan meja kerja", + "minicraft.tutorial.getting_workbench.description": "Membuat meja kerja di menu kerajinan. Menempatkannya setelah itu.", + "minicraft.tutorial.start_getting_wood": "Awal dari Semua", + "minicraft.tutorial.start_getting_wood.description": "Terus Menyerang pohon untuk mendapatkan kayu." } diff --git a/src/client/resources/assets/localization/it-it.json b/src/client/resources/assets/localization/it-it.json index 4a8a54c43..198fc0485 100644 --- a/src/client/resources/assets/localization/it-it.json +++ b/src/client/resources/assets/localization/it-it.json @@ -1,351 +1,470 @@ { - "minicraft.achievement.woodcutter": "Taglialegna", - "minicraft.achievement.woodcutter.desc": "Prendi del legno.", - "minicraft.achievement.benchmarking": "Ora del lavoro", - "minicraft.achievement.benchmarking.desc": "Costruisci un banco da lavoro", - "minicraft.achievement.upgrade": "Potenzia!", - "minicraft.achievement.upgrade.desc": "Costruisci qualsiasi utensile di ferro.", - "minicraft.achievement.bow": "Scocca la freccia verso di me!", - "minicraft.achievement.bow.desc": "Scocca una freccia con un arco.", - "minicraft.achievement.fish": "Pesca!", - "minicraft.achievement.fish.desc": "Pesca un pesce!", - "minicraft.achievement.doors": "Adooro la protezione", - "minicraft.achievement.doors.desc": "Costruisci una porta di legno.", - "minicraft.achievement.planks": "Cammina sulle asse!", - "minicraft.achievement.planks.desc": "Costruisci delle assi di legno", - "minicraft.achievement.clothes": "Che tu abbia una giornata colorata!", - "minicraft.achievement.clothes.desc": "Costruisci un vestito di qualsiasi colore", - "minicraft.achievement.demolition": "Demolizione Demo", - "minicraft.achievement.demolition.desc": "Usa una TNT.", - "minicraft.achievement.survive_darkness": "Hai paura del buio?", - "minicraft.achievement.survive_darkness.desc": "Sopravvivi 5 minuti nel buio totale.", - "minicraft.achievement.lava": "Affari bollenti", - "minicraft.achievement.lava.desc": "Usa una pozione di resistenza alla lava per nuotare nella lava.", - "minicraft.achievement.find_gem": "Oooh Splendente!", - "minicraft.achievement.find_gem.desc": "Trova dell'oro grezzo e minalo.", - "minicraft.achievement.lowest_caves": "Oscurità dietro la luce", - "minicraft.achievement.lowest_caves.desc": "Raggiungi il livello più basso di caverne", - "minicraft.achievement.obsidian_dungeon": "Di cavalieri e uomini", - "minicraft.achievement.obsidian_dungeon.desc": "Raggiungi il dungeon di ossidiana.", - "minicraft.achievement.airwizard": "Sconfiggi... l'aria?", - "minicraft.achievement.airwizard.desc": "Sconfiggi il primo mago del vento", - "minicraft.achievement.skin": "Sfilata di moda", - "minicraft.achievement.skin.desc": "Cambia la tua skin.", - "minicraft.display.achievement": "Achievements", - "minicraft.display.achievement.achieved": "Completato!", - "minicraft.display.achievement.not_achieved": "Non completato", - "minicraft.display.achievement.score": "Punteggio degli achievement:", - "minicraft.notification.achievement_unlocked": "Achivement unlocked:", - "Entities": "Entitià", - "Air Wizard: Defeated!": "Mago del Vento: Sconfitto!", - "The Dungeon is now open!": "Ora il dungeon è aperto!", - "A costume lies on the ground...": "Un costume e sul terreno...", - "Can't sleep!": "Non puoi dormire!", - "Min ": "Minuti ", - " Sec left!": " Secondi mancanti!", - "You hear a noise from the surface!": "Senti un rumore dalla superfice!", - "Death Chest": "Cassa della morte", - "Player": "Giocatore", - "Crafting": "Fabbricazione", - "Set your home!": "Piazza la tua casa!", - "Can't set home here!": "Non puoi piazzare la tua casa qui!", - "Home Sweet Home!": "Casa dolce casa!", - "Mode penalty: -2 health": "Modalità penalità: -2 punti vita", - "You don't have a home!": "Non hai una casa!", - "You can't go home from here!": "Non puoi andare a casa da qui", - "Leather Armor": "Armatura di pelle", - "Snake Armor": "Armatura di serpenti", - "Iron Armor": "Armatura di ferro", - "Gold Armor": "Armatura d'oro", - "Gem Armor": "Armatura di gemma", - "Book": "Libro", + "Acorn": "Ghianda", + "AirWizard Spawner": "Generatore di maghi del vento", "Antidious": "Antidoto", - "Empty Bucket": "Secchio vuoto", - "Water Bucket": "Secchio d'acqua", - "Lava Bucket": "Secchio di lava", - " Bucket": " Secchio", - "Red Clothes": "Vestiti rossi", - "Blue Clothes": "Vestiti blu", - "Green Clothes": "Vestiti verdi", - "Yellow Clothes": "Vestiti gialli", + "Anvil": "Incudine", + "Apple": "Mela", + "Arrow": "Freccia", + "Axe": "Ascia", + "Baked Potato": "Patata cotta", + "Bed": "Letto", "Black Clothes": "Vestiti neri", - "Orange Clothes": "Vestiti arancioni", - "Purple Clothes": "Vestiti viola", - "Cyan Clothes": "Vestiti ciano", - "Reg Clothes": "Vestiti regolari", + "Black Wool": "Lana nera", + "Blue Clothes": "Vestiti blu", + "Blue Wool": "Lana blu", + "Bone": "Ossa", + "Book": "Libro", + "Bow": "Arco", "Bread": "Pane", - "Apple": "Mela", - "Raw Pork": "Maiale crudo", - "Raw Fish": "Pesce crudo", - "Raw Beef": "Manzo crudo", - "Pork Chop": "Carne di maiale cruda", + "Cactus": "Cactus", + "Cactus Sapling": "Alberello di cactus", + "Chest": "Cassa", + "Claymore": "Claymore", + "Cloth": "Stoffa", + "Cloud": "Nuvola", + "Cloud Cactus": "Cactus di nuvole", + "Cloud Ore": "Oro del cielo", + "Coal": "Carbone", "Cooked Fish": "Pesce cotto", "Cooked Pork": "Carne di maiale cotta", - "Steak": "Bistecca", - "Gold Apple": "Mela d'oro", - "Baked Potato": "Patata cotta", "Cow Spawner": "Generatore di mucche", - "Pig Spawner": "Generatore di maiali", - "Sheep Spawner": "Generatore di pecore", - "Slime Spawner": "Generatore di slime", - "Zombie Spawner": "Generatore di zombie", "Creeper Spawner": "Generatore di creeper", - "Skeleton Spawner": "Generatore di scheletri", - "Snake Spawner": "Generatore di serpenti", - "Knight Spawner": "Generatore di cavalieri", - "AirWizard Spawner": "Generatore di mago del vento", - "Workbench": "Banco da lavoro", - "Oven": "Forno", - "Furnace": "Fornace", - "Anvil": "Incudine", + "Cyan Clothes": "Vestiti ciano", + "Death Chest": "Cassa della morte", + "Dirt": "Terra", + "Empty Bucket": "Secchio vuoto", "Enchanter": "Incantatore", - "Loom": "Telaio", - "Lantern": "Lanterna", - "Iron Lantern": "Lanterna di ferro", - "Gold Lantern": "Lanterna d'oro", - "Tnt": "TNT", - "Bed": "Letto", - "Chest": "Cassa", - "None Potion": "Pozione vuota", - "Speed Potion": "Pozione di velocità", - "Light Potion": "Pozione di luce", - "Swim Potion": "Pozione di nuoto", "Energy Potion": "Pozione di energia", - "Regen Potion": "Pozione di rigenerazione", - "Health Potion": "Pozione di salute", - "Time Potion": "Pozione del tempo", - "Lava Potion": "Pozione di resistenza alla lava", - "Shield Potion": "Pozione scudo", - "Haste Potion": "Pozione di rapidità", "Escape Potion": "Pozione di fuga", - "Potion": "Pozione", - "Power Glove": "Guanto potente", - "Wood": "Legno", - "Stone": "Pietra", - "Leather": "Pelle", - "Wheat": "Grano", - "Key": "Chiave", - "arrow": "freccia", - "string": "corda", - "Coal": "Carbone", - "Iron Ore": "Ferro grezzo", - "Lapis": "Lapislazzuli", + "Explode": "Esplodi", + "Farmland": "Terreno da coltivare", + "Flower": "Fiore", + "Furnace": "Fornace", + "Gem": "Gemma", + "Gem Armor": "Armatura di gemma", + "Gem Fishing Rod": "Canna da pesca di gemme", + "Gem Ore": "Gemma grezza", + "Glass": "Vetro", + "Gold": "Oro", + "Gold Apple": "Mela d'oro", + "Gold Armor": "Armatura d'oro", + "Gold Fishing Rod": "Canna da pesca d'oro", + "Gold Lantern": "Lanterna d'oro", "Gold Ore": "Oro grezzo", + "Grass": "Erba", + "Grass Seeds": "Semi d'erba", + "Green Clothes": "Vestiti verdi", + "Green Wool": "Lana verde", + "Gunpowder": "Polvere da sparo", + "Hard Rock": "Terra dura", + "Haste Potion": "Pozione di rapidità", + "Health Potion": "Pozione di salute", + "Hoe": "Zappa", + "Hole": "Buco", + "Infinite Fall": "Caduta infinita", "Iron": "Ferro", - "Gold": "Oro", - "Rose": "Rosa", - "GunPowder": "Polvere da sparo", - "Slime": "Slime", - "glass": "vetro", - "cloth": "stoffa", - "gem": "gemma", - "Scale": "Squama", - "Shard": "Coccio", - "Flower": "Fiore", - "Acorn": "Ghianda", - "Dirt": "Terra", + "Iron Armor": "Armatura di ferro", + "Iron Fishing Rod": "Canna da pesca di ferro", + "Iron Lantern": "Lanterna di ferro", + "Iron Ore": "Ferro grezzo", + "Key": "Chiave", + "Knight Spawner": "Generatore di cavalieri", + "Lantern": "Lanterna", + "Lapis": "Lapislazzuli", + "Lava": "Lava", + "Lava Brick": "Mattoni di lava", + "Lava Bucket": "Secchio di lava", + "Lava Potion": "Pozione di resistenza alla lava", + "Leather": "Pelle", + "Leather Armor": "Armatura di pelle", + "Light Potion": "Pozione di luce", + "Loom": "Telaio", "Natural Rock": "Roccia naturale", + "None Potion": "Pozione vuota", + "Obsidian": "Ossidiana", + "Obsidian Brick": "Mattone d'ossidiana", + "Obsidian Door": "Porta d'ossidiana", + "Obsidian Wall": "Muro d'ossidiana", + "Orange Clothes": "Vestiti arancioni", + "Ornate Obsidian": "Ornamento d'ossidiana", + "Ornate Stone": "Pietra ornamentale", + "Oven": "Forno", + "Pickaxe": "Piccone", + "Pig Spawner": "Generatore di maiali", "Plank": "Assi", "Plank Wall": "Muro d'assi", - "Wood Door": "Porta di legno", - "Stone Brick": "Mattone di pietra", - "Ornate Stone": "Pietra d'ornamento", - "Stone Wall": "Muro di pietra", - "Stone Door": "Porta di pietra", - "Obsidian Brick": "Mattono d'ossidiana", - "Ornate Obsidian": "Ornamento d'ossidiana", - "Obsidian Wall": "Muro d'ossidiana", - "Obsidian Door": "Porta d'ossidiana", - "Wool": "Lana", + "Player": "Giocatore", + "Pork Chop": "Carne di maiale cruda", + "Potato": "Patata", + "Potion": "Pozione", + "Power Glove": "Guanto potente", + "Purple Clothes": "Vestiti viola", + "Raw Beef": "Manzo crudo", + "Raw Fish": "Pesce crudo", + "Raw Obsidian": "Ossidiana grezza", + "Raw Pork": "Maiale crudo", + "Red Clothes": "Vestiti rossi", "Red Wool": "Lana rossa", - "Blue Wool": "Lana blu", - "Green Wool": "Lana verde", - "Yellow Wool": "Lana gialla", - "Black Wool": "Lana nera", + "Reg Clothes": "Vestiti regolari", + "Regen Potion": "Pozione di rigenerazione", + "Rock": "Roccia", + "Rose": "Rosa", "Sand": "Sabbia", - "Cactus": "Cactus", + "Scale": "Squama", "Seeds": "Semi", - "Wheat Seeds": "Semi di grano", - "Grass Seeds": "Semi d'erba", - "Bone": "Ossa", - "Cloud": "Nuvola", - "Rock": "Roccia", - "Gem": "Gemma", - "Potato": "Patata", - "Wood Fishing Rod": "Canna da pesca di legno", - "Iron Fishing Rod": "Canna da pesca di ferro", - "Gold Fishing Rod": "Canna da pesca d'oro", - "Gem Fishing Rod": "Canna da pesca di gemme", + "Shard": "Coccio", + "Shears": "Cesoie", + "Sheep Spawner": "Generatore di pecore", + "Shield Potion": "Pozione scudo", "Shovel": "Pala", - "Hoe": "Zappa", + "Skeleton Spawner": "Generatore di scheletri", + "Slime": "Slime", + "Slime Spawner": "Generatore di slime", + "Snake Armor": "Armatura di serpenti", + "Snake Spawner": "Generatore di serpenti", + "Speed Potion": "Pozione di velocità", + "Stairs Down": "Scale in giù", + "Stairs Up": "Scale in sù", + "Steak": "Bistecca", + "Stone": "Pietra", + "Stone Brick": "Mattone di pietra", + "Stone Bricks": "Mattoni di ferro", + "Stone Door": "Porta di pietra", + "Stone Wall": "Muro di pietra", + "String": "Corda", + "Swim Potion": "Pozione di nuoto", "Sword": "Spada", - "Pickaxe": "Piccone", - "Axe": "Ascia", - "Bow": "Arco", - "Claymore": "Claymore", - "Shears": "Cesoie", + "Time Potion": "Pozione del tempo", + "Tnt": "TNT", "Torch": "Torcia", - "Gem Ore": "Gemma grezza", - "Wood Planks": "Assi di legno", - "Stone Bricks": "Mattoni di ferro", - "Obsidian": "Ossidiana", - "Wood Wall": "Muro di legno", - "Grass": "Erba", - "Hole": "Buco", - "Stairs Up": "Scale in sù", - "Stairs Down": "Scale in giù", - "Water": "Acqua", + "Totem of Air": "Totem dell'aria", "Tree": "Albero", "Tree Sapling": "Alberello", - "Cactus Sapling": "Alberello di cactus", - "Lava": "Lava", - "Lava Brick": "Mattoni di lava", - "Explode": "Esplodi", - "Farmland": "Terreno da coltivare", - "Hard Rock": "Terra dura", - "Infinite Fall": "Caduta infinita", - "Cloud Cactus": "Cactus di nuvole", - "Ore": "grezzo", - "host not found": "host non trovato", - "unable to get localhost address": "impossibile ricevere l'indirizzo localhost", - "World Saved!": "Mondo salvato!", - "On": "On", - "Off": "Off", - "There is nothing of use here.": "Non c'è nulla da usare qui.", - "Still nothing... :P": "Ancora niente... :P", - "Have:": "Hai:", - "Cost:": "Costo:", - "Time: ": "Tempo: ", - "Score: ": "Punteggio: ", - "Quit": "Esci", - "Respawn": "Respawn", - "You died! Aww!": "Sei morto! Aww!", - "Player Score: ": "Punteggo del giocatore: ", - "": "", - "Final Score: ": "Punteggio finale: ", - "Exit to Menu": "Esci al menù", - "Time Played: ": "Tempo di gioco: ", - "Current Score: ": "Punteggio attuale: ", - "Exit": "Esci", - "Player Stats": "Statistiche del giocatore:", - "Controls": "Controlli", - "Press the desired": "Premi la desiderata", - "key sequence": "sequenza di tasti", - "minicraft.display.key_input.confirm_popup": "Sei sicuro di voler ripristinare le sequenza di tasti a quelle predefinite?", + "Water": "Acqua", + "Water Bucket": "Secchio d'acqua", + "Wheat": "Grano", + "Wheat Seeds": "Semi di grano", + "Wood": "Legno", + "Wood Door": "Porta di legno", + "Wood Fishing Rod": "Canna da pesca di legno", + "Wood Planks": "Assi di legno", + "Wood Wall": "Muro di legno", + "Wool": "Lana", + "Workbench": "Banco da lavoro", + "Yellow Clothes": "Vestiti gialli", + "Yellow Wool": "Lana gialla", + "Zombie Spawner": "Generatore di zombie", + "minicraft.achievement.airwizard": "Sconfiggi... l'aria?", + "minicraft.achievement.airwizard.desc": "Sconfiggi il primo mago del vento!", + "minicraft.achievement.benchmarking": "Ora del lavoro", + "minicraft.achievement.benchmarking.desc": "Costruisci un banco da lavoro.", + "minicraft.achievement.bow": "Scocca la freccia verso di me!", + "minicraft.achievement.bow.desc": "Scocca una freccia con un arco.", + "minicraft.achievement.clothes": "Che tu abbia una giornata colorata!", + "minicraft.achievement.clothes.desc": "Costruisci un vestito di qualsiasi colore", + "minicraft.achievement.demolition": "Demolizione Demo", + "minicraft.achievement.demolition.desc": "Usa una TNT.", + "minicraft.achievement.doors": "Adooro la protezione", + "minicraft.achievement.doors.desc": "Costruisci una porta di legno.", + "minicraft.achievement.find_gem": "Oooh Splendente!", + "minicraft.achievement.find_gem.desc": "Trova dell'oro grezzo e minalo.", + "minicraft.achievement.fish": "Pesca!", + "minicraft.achievement.fish.desc": "Pesca un pesce!", + "minicraft.achievement.lava": "Affari bollenti", + "minicraft.achievement.lava.desc": "Usa una pozione di resistenza alla lava per nuotare nella lava.", + "minicraft.achievement.lowest_caves": "Oscurità dietro la luce", + "minicraft.achievement.lowest_caves.desc": "Raggiungi il livello più basso delle caverne.", + "minicraft.achievement.obsidian_dungeon": "Di cavalieri e uomini", + "minicraft.achievement.obsidian_dungeon.desc": "Raggiungi il dungeon di ossidiana.", + "minicraft.achievement.planks": "Cammina sulle assi!", + "minicraft.achievement.planks.desc": "Costruisci delle assi di legno.", + "minicraft.achievement.skin": "Sfilata di moda", + "minicraft.achievement.skin.desc": "Cambia la tua skin.", + "minicraft.achievement.survive_darkness": "Hai paura del buio?", + "minicraft.achievement.survive_darkness.desc": "Sopravvivi 5 minuti nel buio totale.", + "minicraft.achievement.upgrade": "Potenzia!", + "minicraft.achievement.upgrade.desc": "Costruisci qualsiasi utensile di ferro.", + "minicraft.achievement.woodcutter": "Taglialegna", + "minicraft.achievement.woodcutter.desc": "Prendi del legno.", + "minicraft.control_guide.attack": "Usa %s per attaccare i mostri o distruggere le piastrelle.", + "minicraft.control_guide.craft": "Usa %s per aprire il menù di creazione.", + "minicraft.control_guide.menu": "Usa %s per aprire l'inventario.", + "minicraft.control_guide.move": "Usa %s per muoverti.", + "minicraft.display.entries.boolean.false": "Off", + "minicraft.display.entries.boolean.true": "On", + "minicraft.display.gui.link_opening": "Apertura con il browser...", + "minicraft.display.gui.perm_status.saving": "Salvataggio... %s%%", + "minicraft.display.gui.perm_status.sleep_cancel": "Premi %s per annullare", + "minicraft.display.gui.perm_status.sleeping": "Dormendo...", + "minicraft.display.gui.potion_effects.hide_hint": "(%s per nasconderti!)", + "minicraft.display.gui.potion_effects.potion_dur": "%s (%d:%02d)", + "minicraft.display.gui.score.current_score": "Puntaggio attuale: %s", + "minicraft.display.gui.score.time_left": "Tempo rimanente %s%sm %ss", + "minicraft.display.menus.inventory": "Inventario", + "minicraft.display.options_display": "Opzioni", + "minicraft.display.options_display.change_key_bindings": "Cambia la sequenza tasti", + "minicraft.display.options_display.language": "Lingua", + "minicraft.display.options_display.resource_packs": "Pacchetti di risorse", "minicraft.display.popup.enter_confirm": "invio per confermare", "minicraft.display.popup.escape_cancel": "esc per annullare", - "Confirm Action": "Conferma", - "Press C/Enter to change key binding": "Premi C/Invio per cambiare il tasto", - "Press A to add key binding": "Premi A per aggiungere una sequenza di tasti", - "Shift-D to reset all keys to default": "Maiusc-D per ripristinare tutte le sequenze di tasti a quelle predefinite", - "ESCAPE to Return to menu": "ESC per ritornare al menù", - "Loading": "Caricamento", - "Generating": "Generazione", - "World": "Mondo", - "waiting...": "attesa...", - "nothing": "nulla", - "attempting log in": "tentando di entrare", - "no internet connection, but no login data saved; cannot enter offline mode.": "no connessione internet, ma niente dati di login, non puoi entrare la modalità offline.", - "connecting to server": "connessione al server", - "logging in": "entrando", - "saving credentials": "salvando le credenziali", - "login failed.": "Login fallito. F", - "problem with saved login data; please exit and login again.": "problemi con il salvataggio dei dati di login, per favore esci e rientra.", - "Internal server error: Couldn't fetch username from uuid": "Errore del server interno: non è possibile ricevere il nome utente dall'UUID", - "logged in as: ": "entrato come: ", - "offline mode: local servers only": "modalità offline: solo server interni", - "Enter ip address to connect to:": "Inserisci l'indirizzo IP alla quale connettersi:", - "Press Shift-Escape to logout": "Premi Maiusc-Esc per uscire dall'account", - "Enter email:": "Inserisci email:", - "Enter password:": "Inserisci la password:", - "field is blank": "campo vuoto", - "get an account at:": "fai un account a:", - "Loading ": "Caricamento ", - " from server": " dal server", - "Could not connect to server:": "Impossibile connettersi al server:", - "Press ": "Premi ", - " to return": " per ritornare", - "Change Key Bindings": "Cambia tasti", - "Options": "Opzioni", - "Change language": "Cambia linguaggio", - "Return to Game": "Ritorna al gioco", - "Make World Multiplayer": "Crea mondo multiplayer", - "Save Game": "Salva gioco", - " and ": " e ", - " to Scroll": " per scendere", - ": Choose": ": Scegli", - "Paused": "Pausa", - "Main Menu": "Menù", - "Yes": "Si", - "No": "No", - "Inventory": "Inventaeio", - "to search.": "per cercare.", - "Play": "Gioca", - "Load World": "Carica mondo", - "New World": "Nuovo mondo", - "Multiplayer": "Multiplayer", - "Singleplayer": "Singlolo giocatore", - "Help": "Aiuto", - "Instructions": "Istruzioni", - "Storyline Guide": "Guiida alla storia", - "About": "Info", - "Credits": "Crediti", - " to select": " per selezionare", - " to accept": " per accettare", - "New World Name:": "Nome del nuovo mondo:", - "Are you sure you want to delete": "Sei sicuro di voler eliminare", - "This can not be undone!": "Questo non può essere fatto!", - " to confirm": " per confermare", - " to cancel": " per annullare", - "World Seed": "Seme del mondo", - "Enter World Name": "Inserisci nome del mondo", - "Trouble with world name?": "Problemi col nome del mondo?", - "by default, w and s move the cursor up and down. This can be changed in the key binding menu. To type the letter instead of moving the cursor, hold the shift key while typing the world name.": "secondo le impostazioni predefinite, w e s muovono il cursore su e giu'. Questo puo' essere cambiato nel menu dei tasti. Per scrivere la lettera invece di scorrere, tieni premuto shift mentre stai scrivendo.", - "Create World": "Crea Mondo", - "World Gen Options": "Opzioni di generazione del mondo", - " to Copy": " per copiare", - " to Rename": " per rinominare", - " to Delete": " per eliminare", - "Select World": "seleziona mondo", - "Select a World to Delete": "seleziona un mondo da eliminare", - "Select a World to Rename": "seleziona un mondo da rinominare", - "Select a World to Copy": "Seleziona un mondo da copiare", - "Higher version, cannot load world!": "Versione troppo nuova, il mondo non può essere caricato", - "World Version:": "Versione del mondo:", - "Languages": "Lingue", - "Language": "Lingua", - "Select": "Seleziona", - "Max FPS": "FPS massimi", - "Difficulty": "Difficoltà", - "Easy": "Facile", - "Normal": "Normale", - "Hard": "Difficile", - "Game Mode": "Modalità", - "Survival": "Sopravvivenza", - "Creative": "Creativa", - "Hardcore": "Hardcore", - "Score": "Punteggio", - "Time (Score Mode)": "Tempo (Modalità punteggio)", - "Sound": "Suono", - "Autosave": "Autosalvataggi", - "World Size": "Dimensione del mondo", - "World Theme": "Tema del mondo", - "Forest": "Foresta", - "Desert": "Deserto", - "Plain": "Piatto", - "Hell": "Inferno", - "Terrain Type": "Tipo di terreno", - "Island": "Isola", - "Box": "Scatola", - "Mountain": "Montagna", - "Irregular": "Irregolare", - "Wear Suit": "Indossa vestito", - "You have the latest version.": "Hai l'ultima versione.", - "minicraft.display.skin": "Skin", + "minicraft.display.popup.title_confirm": "Conferma azione", + "minicraft.displays.achievements": "Obiettivi", + "minicraft.displays.achievements.display.achieved": "Obiettivo completato!", + "minicraft.displays.achievements.display.help": "Usa %s e %s per muoverti.", + "minicraft.displays.achievements.display.not_achieved": "Non completato", + "minicraft.displays.achievements.display.score": "Punteggio Obiettivi: %s", + "minicraft.displays.book.default_book": "Questo libro non contiene scritte.", + "minicraft.displays.controls": "Controlli", + "minicraft.displays.controls.display.controller": "Joystick", + "minicraft.displays.controls.display.controller.00": "Muovi il giocatore con gli analogici", + "minicraft.displays.controls.display.controller.01": "Muovi il cursore con gli analogici", + "minicraft.displays.controls.display.controller.02": "Seleziona con il tasto A", + "minicraft.displays.controls.display.controller.03": "Esci dalle pagine con il tasto B", + "minicraft.displays.controls.display.controller.04": "Attaccare entità, distruggere e interagire con la piestrelle con il tasto A", + "minicraft.displays.controls.display.controller.05": "Aprire i menù di gioco con il tasto X", + "minicraft.displays.controls.display.controller.06": "Aprire i menù di creazione con il tasto Y", + "minicraft.displays.controls.display.controller.07": "Raccogli gli arredamenti con il Grilletto di Sinistra", + "minicraft.displays.controls.display.controller.08": "Butta un oggetto con il Grilletto di Destra", + "minicraft.displays.controls.display.controller.09": "Butta una pila di oggetti schiacciando l'Analogico di Destra", + "minicraft.displays.controls.display.controller.10": "Usa il tasto START per Attivare/Disattivare la barra di ricerca nel menù dell'oggetto", + "minicraft.displays.controls.display.controller.11": "Usa il tasto START per mettere in pausa il gioco", + "minicraft.displays.controls.display.controller.12": "Usa il tasto X per Attivare/Disattivare la tastiera a schermo", + "minicraft.displays.controls.display.controller.13": "Usa il tasto B come scorciatoia per lo spazio nella tastiera a schermo", + "minicraft.displays.controls.display.controller.14": "Usa il tasto X per rimuovere l'oggetto selezionato nell'inventario in modalità creativa", + "minicraft.displays.controls.display.controller.15": "Usa il tasto Y per rimuovere un'intera pila di oggetti dall'inventario in modalità creativa", + "minicraft.displays.controls.display.controller.desc.0": "Debugging delle mappe non accessibile", + "minicraft.displays.controls.display.controller.desc.1": "Mappe Dettagliate non utilizzabili", + "minicraft.displays.controls.display.help.0": "%s/%s per vedere altri controlli.", + "minicraft.displays.controls.display.keyboard": "Tastiera", + "minicraft.displays.controls.display.keyboard.00": "Muovere il giocatore con MOVIMENTO-(DIREZIONE)", + "minicraft.displays.controls.display.keyboard.01": "Muovere il cursore con CURSORE-(DIREZIONE)", + "minicraft.displays.controls.display.keyboard.02": "Seleziona con il tasto SELEZIONA", + "minicraft.displays.controls.display.keyboard.03": "Esci dalle pagine con il tasto ESCI", + "minicraft.displays.controls.display.keyboard.04": "Salvataggio rapido con SALVATAGGIO-RAPIDO", + "minicraft.displays.controls.display.keyboard.05": "Attaccare entità, distruggere e interagire con le piastrelle con ATTACCO", + "minicraft.displays.controls.display.keyboard.06": "Aprire i menù di gioco con MENU", + "minicraft.displays.controls.display.keyboard.07": "Aprire i menù di creazione con CREAZIONE", + "minicraft.displays.controls.display.keyboard.08": "Raccogli gli arredamenti con RACCOLTA", + "minicraft.displays.controls.display.keyboard.09": "Butta un oggetto con BUTTA-UNO", + "minicraft.displays.controls.display.keyboard.10": "Butta una pila di oggetti con BUTTA-PILA", + "minicraft.displays.controls.display.keyboard.11": "Usa BARRA-DI-RICERCA per Attivare/Disattivare la barra di ricerca nel menù dell'oggetto", + "minicraft.displays.controls.display.keyboard.12": "Consulta i risultati di ricerca con PAGINA-SU/GIU'", + "minicraft.displays.controls.display.keyboard.13": "Usa PAUSA per mettere in pausa il gioco", + "minicraft.displays.controls.display.keyboard.14": "Attiva/Disattiva gli effetti della pozione con POZIONEEFFETTI", + "minicraft.displays.controls.display.keyboard.15": "Attiva/Disattiva la semplificazione delle pozioni con POZIONEEFFETTISEMPL", + "minicraft.displays.controls.display.keyboard.16": "Espanzione moderata della schermata delle quest con QUESTSCHERMATAESPANDI", + "minicraft.displays.controls.display.keyboard.17": "Attiva/Disattiva l'HDU con ALTERNAHUD", + "minicraft.displays.controls.display.keyboard.18": "Fai uno screenshot con SCREENSHOT", + "minicraft.displays.controls.display.keyboard.19": "Mostra informazioni in-gioco con INFO", + "minicraft.displays.controls.display.keyboard.20": "Attiva/Disattiva lo schermo intero con SCHERMOINTERO", + "minicraft.displays.controls.display.keyboard.21": "Usa D per rimuovere l'oggetto selezionato dall'inventario in modalità creativa", + "minicraft.displays.controls.display.keyboard.22": "Usa MAIUSC-D per rimuovere l'intera pila di articoli nell'inventario in modalità creativa", + "minicraft.displays.controls.display.keyboard.desc": "Debug delle mappe non spiegato", + "minicraft.displays.crafting": "Creazione", + "minicraft.displays.crafting.container_title.cost": "Costo:", + "minicraft.displays.crafting.container_title.have": "Hai:", + "minicraft.displays.end_game.display.bonuses": "", + "minicraft.displays.end_game.display.final_score": "Punteggio finale: %s", + "minicraft.displays.end_game.display.player_score": "Punteggio giocatore: %s", + "minicraft.displays.end_game.display.unlocked": "Sbloccato! %s Punteggio a tempo", + "minicraft.displays.end_game.exit": "Esci al menù", + "minicraft.displays.info.display.exit_help": "%s/%s:Esci", + "minicraft.displays.info.display.score": "Punteggio attuale: %s", + "minicraft.displays.info.display.time": "Tempo di gioco: %s", + "minicraft.displays.info.title": "Statistiche giocatore", + "minicraft.displays.key_input.display.help.0": "Premi C/Invio per cambiare la sequenza tasti", + "minicraft.displays.key_input.display.help.1": "Premi A per aggiungere la sequenza tasti", + "minicraft.displays.key_input.display.help.2": "Maiusc-D per resettare le sequenza tasti", + "minicraft.displays.key_input.display.help.3": "%s per tornare al menù", + "minicraft.displays.key_input.popup_display.confirm_reset": "Sei sicuro di voler resettare tutte le sequenza tasti?", + "minicraft.displays.key_input.popup_display.press_key_sequence": "Premi la sequenza t asti desiderata", + "minicraft.displays.key_input.title": "Controlli", + "minicraft.displays.language_settings.title": "Lingua...", + "minicraft.displays.loading.message.dungeon_regeneration": "Rigenerazione B4", + "minicraft.displays.loading.message.entities": "Entità", + "minicraft.displays.loading.message.generating": "Generazione", + "minicraft.displays.loading.message.level": "Livello %s", + "minicraft.displays.loading.message.levels": "Livelli", + "minicraft.displays.loading.message.loading": "Caricamento", + "minicraft.displays.loading.message.quests": "Quest", + "minicraft.displays.loading.message.saving": "Salvataggio", + "minicraft.displays.loading.message.world": "Mondo", + "minicraft.displays.loading.regeneration_cancellation_popup.display": "Caricamento del mondo annullato", + "minicraft.displays.loading.regeneration_popup.display.0": "Una vecchia versione del dungeon (piano B4) è stata rilevata.", + "minicraft.displays.loading.regeneration_popup.display.1": "Rigenerazione necessaria.", + "minicraft.displays.loading.regeneration_popup.display.2": "I dati vecchi in quel piano verranno cancellati:", + "minicraft.displays.loading.regeneration_popup.display.3": "%s per continuare", + "minicraft.displays.loading.regeneration_popup.display.4": "%s per annullare il caricamento del mondo", + "minicraft.displays.options_main_menu": "Opzioni del menù principale", + "minicraft.displays.options_main_menu.resource_packs": "Pacchetti risorse", + "minicraft.displays.options_world": "Opzioni del mondo", + "minicraft.displays.options_world.off_tutorials_confirm_popup": "Sei sicuro di voler disattivare i tutorial per sempre?", + "minicraft.displays.options_world.turn_off_tutorials": "Disattiva tutorial", + "minicraft.displays.pause": "In pausa", + "minicraft.displays.pause.display.exit_popup.0": "Sei sicuro di voler uscire dal gioco?", + "minicraft.displays.pause.display.exit_popup.1": "Tutti i progressi non salvati andranno persi", + "minicraft.displays.pause.display.exit_popup.cancel": "Annulla", + "minicraft.displays.pause.display.exit_popup.quit": "Esci senza salvare", + "minicraft.displays.pause.display.help.choose": "%s: scegli", + "minicraft.displays.pause.display.help.scroll": "%s e %s per scorrere", + "minicraft.displays.pause.menu": "Menù principal", + "minicraft.displays.pause.return": "Torna al gioco", + "minicraft.displays.pause.save": "Salva gioco", + "minicraft.displays.player_death.display.score": "Punteggio: %s", + "minicraft.displays.player_death.display.time": "Tempo: %s", + "minicraft.displays.player_death.quit": "Esci", + "minicraft.displays.player_death.respawn": "Rinasci", + "minicraft.displays.player_death.save_quit": "Salva ed esci", + "minicraft.displays.player_death.title": "Sei morto! Aww!", + "minicraft.displays.player_inv.container_title.items": "Oggetti", + "minicraft.displays.player_inv.display.help": "(%s) per cercare.", + "minicraft.displays.quests": "Quest", + "minicraft.displays.quests.display.header.completed": "Completato", + "minicraft.displays.quests.display.header.unlocked": "Sbloccato", + "minicraft.displays.quests.display.no_quest": "Nessuna quest sbloccata", + "minicraft.displays.quests.display.no_quest_desc": "Nessuna quest", + "minicraft.displays.resource_packs.display.help.keyboard_needed": "Sono accettati solo input dalla tastiera.", + "minicraft.displays.resource_packs.display.help.move": "Usa %s e %s per muoverti.", + "minicraft.displays.resource_packs.display.help.position": "MAIUSC-[SINISTRA|DESTRA|SU|GIU'] per spostare i pacchetti.␣", + "minicraft.displays.resource_packs.display.help.select": "%s per esaminare.", + "minicraft.displays.resource_packs.display.title": "Pacchetti risorse", + "minicraft.displays.skin": "Skin", + "minicraft.displays.skin.display.help.move": "Usa %s e %s per muoverti.", + "minicraft.displays.skin.display.help.select": "%s per selezionare, %s per annullare.", + "minicraft.displays.title.display.cannot_check": "Non è stato possibile cercare aggiornamenti.", + "minicraft.displays.title.display.checking": "Cerco gli aggiornamenti...", + "minicraft.displays.title.display.help.0": "(%s, %s per selezionare)", + "minicraft.displays.title.display.help.1": "(%s per accettare)", + "minicraft.displays.title.display.help.2": "(%s per tornare indietro)", + "minicraft.displays.title.display.latest_already": "Hai la versione più recente.", + "minicraft.displays.title.display.new_version": "Nuova: %s", + "minicraft.displays.title.display.version": "Versione %s", + "minicraft.displays.title.help": "Aiuto", + "minicraft.displays.title.help.about": "Informazioni", + "minicraft.displays.title.help.credits": "Crediti", + "minicraft.displays.title.help.instructions": "Istruzioni", + "minicraft.displays.title.help.storyline_guide": "Guida alla storia", + "minicraft.displays.title.link_to_version": "Link diretto all'ultima versione: %s", + "minicraft.displays.title.play": "Gioca", + "minicraft.displays.title.play.load_world": "Carica mondo", + "minicraft.displays.title.play.new_world": "Nuovo mondo", + "minicraft.displays.title.quit": "Esci", + "minicraft.displays.title.select_to_download": "--Seleziona per scaricare--", + "minicraft.displays.tutorial_display_handler.display.element_examine_help": "Premere %s per esaminare i dettagli del tutorial attuale.", + "minicraft.displays.world_gen.create_world": "Crea mondo", + "minicraft.displays.world_gen.enter_world": "Inserisci il nome del mondo", + "minicraft.displays.world_gen.title": "Opzioni di generazione del mondo", + "minicraft.displays.world_gen.troublesome_input": "Problemi con il nome del mondo?", + "minicraft.displays.world_gen.troublesome_input.msg": "sembra tu abbia scelto delle lettere come controlli per muovere il cursore su e giù, il che è probabilmente fastidioso. Puoi modificarlo nel menù per la sequenza dei tasti al tasto \"cursore-XXX\". Al momento per scrivere una lettera puoi tenere premuto il tasto MAIUSC e poi cliccare sulla lettera.", + "minicraft.displays.world_gen.world_seed": "Seme del mondo", + "minicraft.displays.world_select.display.help.0": "%s per confermare", + "minicraft.displays.world_select.display.help.1": "%s per tornare indietro", + "minicraft.displays.world_select.display.help.2": "MAIUSC-C per copiare", + "minicraft.displays.world_select.display.help.3": "MAIUSC-R per rinominare", + "minicraft.displays.world_select.display.help.4": "MAIUSC-D per cancellare", + "minicraft.displays.world_select.display.world_too_new": "La tua versione è più recente, non è possibile caricare il mondo!", + "minicraft.displays.world_select.display.world_version": "Versione mondo: %s", + "minicraft.displays.world_select.popups.display.cancel": "%s per cancallare", + "minicraft.displays.world_select.popups.display.change": "Nome del nuovo mondo:", + "minicraft.displays.world_select.popups.display.confirm": "%s per confermare", + "minicraft.displays.world_select.popups.display.delete": "Sei sicuro di voler cancellare\n%s\"%s\"%s?\nNon si può tornare indietro!", + "minicraft.displays.world_select.select_world": "Scegli il mondo", + "minicraft.notification.achievement_unlocked": "Obiettivo sbloccato: %s", + "minicraft.notification.air_wizard_defeated": "Stregone dell'Aria sconfitto!", + "minicraft.notification.boss_limit": "Non possono essere generati altri boss", + "minicraft.notification.cannot_sleep": "Non puoi dormire! %sMinuti %s Secondi rimasti!", + "minicraft.notification.death_chest_retrieved": "Cassa della morte recuperata!", + "minicraft.notification.defeat_air_wizard_first": "Devi prima sconfiggere lo Stregone dell'Aria.", + "minicraft.notification.defeat_obsidian_knight_first": "Devi prima sconfiggere il Cavaliere d'Ossidiana.", + "minicraft.notification.dig_hole": "Scava una buca prima!", + "minicraft.notification.dungeon_opened": "Il Dungeon è aperto!", + "minicraft.notification.gem_pickaxe_required": "Piccozza di gemme richiesta.", + "minicraft.notification.invalid_placement": "Può essere collocato solo su %s!", + "minicraft.notification.obsidian_knight_awoken": "Il Cavaliere d'Ossidiana si è risvegliato!", + "minicraft.notification.obsidian_knight_defeated": "Cavaliere d'Ossidiana: sconfitto!", + "minicraft.notification.quest_completed": "Quest completata", + "minicraft.notification.quest_unlocked": "Quest sbloccata", + "minicraft.notification.spawn_on_boss_tile": "Può essere evocato solo in una Stanza del Boss", + "minicraft.notification.world_saved": "Mondo salvato!", + "minicraft.notification.wrong_level_dungeon": "Può essere evocato solo al livello dei dungeon", + "minicraft.notification.wrong_level_sky": "Può essere evocato solo al livello del cielo", + "minicraft.notifications.statue_tapped": "Senti echeggiare dei sussurri...", + "minicraft.notifications.statue_touched": "Senti vibrare la statua...", + "minicraft.quest.farming": "Contadino che lavora", + "minicraft.quest.farming.crafting_hoe": "Creare una zappa", + "minicraft.quest.farming.crafting_hoe.description": "Creare qualunque zappa dal banco da lavoro", + "minicraft.quest.farming.description": "Le basi dell'essere un contadino.", + "minicraft.quest.farming.getting_wheat": "Raccolta di grano", + "minicraft.quest.farming.getting_wheat.description": "Raccolta di grano rompendo il grano maturo.", + "minicraft.quest.farming.making_farmland": "Creare una fattoria", + "minicraft.quest.farming.making_farmland.description": "Creare una fattoria con una zappa interagento con le pistrelle di terra.", + "minicraft.quest.farming.planting_potato": "Piantare una patata", + "minicraft.quest.farming.planting_potato.description": "Piantare una patata nella fattoria", + "minicraft.quest.farming.planting_wheat": "Piantare il grano", + "minicraft.quest.farming.planting_wheat.description": "Piantare il grano con i semi nella fattoria.", + "minicraft.quest.gems": "Via delle Gemme", + "minicraft.quest.gems.description": "Preparare equipaggiamenti di gemme.", + "minicraft.quest.gems.gem_armor": "Maestro della Protezione", + "minicraft.quest.gems.gem_armor.description": "Ottenere un'armatura di gemme.", + "minicraft.quest.gems.gem_claymore": "Maestro dell'Arma", + "minicraft.quest.gems.gem_claymore.description": "Ottenere una spada di gemme.", + "minicraft.quest.iron_equipments": "Maestro del Ferro", + "minicraft.quest.iron_equipments.description": "Ottenere gli equipaggiamenti di ferro.", + "minicraft.quest.iron_equipments.getting_more_iron": "Ricco in ferro", + "minicraft.quest.iron_equipments.getting_more_iron.description": "Ottenere più ferro.", + "minicraft.quest.iron_equipments.iron_armor": "Migliorara un'armatura", + "minicraft.quest.iron_equipments.iron_armor.description": "Migliorare l'armatura di ferro.", + "minicraft.quest.iron_equipments.iron_tools": "Migliorare tutti gli utensili", + "minicraft.quest.iron_equipments.iron_tools.description": "Trasformare gli utensili in utensili di ferro.", + "minicraft.quest.iron_equipments.upgrading_pickaxe": "Piccozza avanzata", + "minicraft.quest.iron_equipments.upgrading_pickaxe.description": "Migliorare la piccozza.", + "minicraft.quest.potions": "Maestro delle Pozioni", + "minicraft.quest.potions.all_potions_prepared": "Studioso delle Pozioni", + "minicraft.quest.potions.all_potions_prepared.description": "Ottenere tutte le pozioni in una volta.", + "minicraft.quest.potions.awkward_potions": "Pozione Strana", + "minicraft.quest.potions.awkward_potions.description": "Ottenere una pozione strana.", + "minicraft.quest.potions.description": "Ottenere le pozioni.", + "minicraft.quest.potions.powerful_potions": "Pozioni potenti", + "minicraft.quest.potions.powerful_potions.description": "Ottenere pozioni utili e potenti.", + "minicraft.settings.autosave": "Autosalvataggio", + "minicraft.settings.difficulty": "Difficoltà", + "minicraft.settings.difficulty.easy": "Facile", + "minicraft.settings.difficulty.hard": "Difficile", + "minicraft.settings.difficulty.normal": "Normale", + "minicraft.settings.fps": "Massimo FPS", + "minicraft.settings.mode": "Modaligà di gioco", + "minicraft.settings.mode.creative": "Creativa", + "minicraft.settings.mode.hardcore": "Hardcore", + "minicraft.settings.mode.score": "Punteggio", + "minicraft.settings.mode.survival": "Sopravvivenza", + "minicraft.settings.scoretime": "Tempo (Modalità a Punteggio)", + "minicraft.settings.screenshot_scale": "Proporzioni Screenshot", + "minicraft.settings.size": "Dimensione mondo", + "minicraft.settings.sound": "Suono", + "minicraft.settings.theme": "Tema mondo", + "minicraft.settings.theme.desert": "Deserto", + "minicraft.settings.theme.forest": "Foresta", + "minicraft.settings.theme.hell": "Inferno", + "minicraft.settings.theme.normal": "Normale", + "minicraft.settings.theme.plain": "Pianura", + "minicraft.settings.type": "Tipo di terreno", + "minicraft.settings.type.box": "Scatola", + "minicraft.settings.type.irregular": "Irregolare", + "minicraft.settings.type.island": "Isola", + "minicraft.settings.type.mountain": "Montagna", + "minicraft.skin.minecraft_alex": "Ragazza familiare", + "minicraft.skin.minecraft_steve": "Ragazzo familiare", "minicraft.skin.paul": "Paul", "minicraft.skin.paul_cape": "Paul col mantello", - "minicraft.skin.minecraft_steve": "Ragazzo familiare", - "minicraft.skin.minecraft_alex": "Ragazza familiare", - "minicraft.notification.invalid_placement": "Può essere collocato solo su", - "minicraft.notification.dig_hole": "Scavare una buca prima!" + "minicraft.text_particales.key_consumed": "-1 chiave", + "minicraft.tutorial.getting_rocks": "Ottenere Pietra e Carbone", + "minicraft.tutorial.getting_rocks.description": "Ottenere almeno 5 oggetti di Pietra e 5 di Carbone distruggendo rocce con la piccozza craftata.", + "minicraft.tutorial.getting_wood": "Ottenere più legno", + "minicraft.tutorial.getting_wood.description": "Ottenere almeno 10 oggetti di legno dagli alberi.", + "minicraft.tutorial.getting_wooden_pickaxe": "Ottenere una piccozza di legno.", + "minicraft.tutorial.getting_wooden_pickaxe.description": "Creare una piccozza di legno nel menù di creazione con il banco di lavoro.", + "minicraft.tutorial.getting_workbench": "Ottenere un bagno di lavoro", + "minicraft.tutorial.getting_workbench.description": "Creare un banco di lavoro nel menù di creazione. E piazzarlo.", + "minicraft.tutorial.start_getting_wood": "L'inizio di tutto", + "minicraft.tutorial.start_getting_wood.description": "Attacca continuamente gli alberi per ottenere il legno." } diff --git a/src/client/resources/assets/localization/nb-no.json b/src/client/resources/assets/localization/nb-no.json index 81ecd8049..3c114fcdd 100644 --- a/src/client/resources/assets/localization/nb-no.json +++ b/src/client/resources/assets/localization/nb-no.json @@ -1,352 +1,420 @@ { - "minicraft.achievement.woodcutter": "Woodcutter", - "minicraft.achievement.woodcutter.desc": "Få tak i tre.", - "minicraft.achievement.benchmarking": "Benchmarking", - "minicraft.achievement.benchmarking.desc": "Lag en arbeidsbenk.", - "minicraft.achievement.upgrade": "Upgrade!", - "minicraft.achievement.upgrade.desc": "Få tak i et redskap med bedre materiell enn tre.", - "minicraft.achievement.bow": "Bow down to me!", - "minicraft.achievement.bow.desc": "Drep et monster med en bue.", - "minicraft.achievement.fish": "Go Fish!", - "minicraft.achievement.fish.desc": "Fisk opp en fisk.", - "minicraft.achievement.doors": "Adooring Protection", - "minicraft.achievement.doors.desc": "Plasser alle dørtyper", - "minicraft.achievement.planks": "Walk the Planks!", - "minicraft.achievement.planks.desc": "Plasser alle typer planke.", - "minicraft.achievement.clothes": "Have a colourful day!", - "minicraft.achievement.clothes.desc": "Lag alle mulige fargede klær.", - "minicraft.achievement.demolition": "Demolition Demo", - "minicraft.achievement.demolition.desc": "Bruk TNT.", - "minicraft.achievement.survive_darkness": "Afraid of the Dark?", - "minicraft.achievement.survive_darkness.desc": "Overlev 5 minutter i mørket.", - "minicraft.achievement.lava": "Hot Affairs", - "minicraft.achievement.lava.desc": "Bruk en lava potion for å svømme i lava.", - "minicraft.achievement.find_gem": "Oooh Shiny!", - "minicraft.achievement.find_gem.desc": "Finn juvelmalm og utgrav den.", - "minicraft.achievement.lowest_caves": "Darkness behind light", - "minicraft.achievement.lowest_caves.desc": "Nå de dypeste huler.", - "minicraft.achievement.obsidian_dungeon": "Of Knights and Men", - "minicraft.achievement.obsidian_dungeon.desc": "Nå obsidian fangehullet.", - "minicraft.achievement.airwizard": "Defeat... the air?", - "minicraft.achievement.airwizard.desc": "Beseire den første lufttrollmannen!", - "minicraft.achievement.skin": "Fashion Show", - "minicraft.achievement.skin.desc": "Endre utseendet ditt.", - "minicraft.display.achievement": "Oppnåelser", - "minicraft.display.achievement.achieved": "Oppnådd!", - "minicraft.display.achievement.not_achieved": "Ikke oppnådd", - "minicraft.display.achievement.score": "Oppnåelse score:", - "minicraft.display.key_input.confirm_popup": "Er du sikker på at du vil resette alle tastene?", - "minicraft.display.popup.enter_confirm": "enter for å bekrefte", - "minicraft.display.popup.escape_cancel": "escape for åvbyte", - "minicraft.display.skin": "Utseender", - "minicraft.skin.paul": "Pål", - "minicraft.skin.paul_cape": "Pål med kappe", - "minicraft.skin.minecraft_steve": "Gjenkjennelig gutt", - "minicraft.skin.minecraft_alex": "Gjenkjennelig jente", - "minicraft.notification.invalid_placement": "Kan kun bli plassert på", - "minicraft.notification.dig_hole": "Grav et hull først!", - "minicraft.notification.achievement_unlocked": "Oppnåelse låst opp:", - "You have the latest version.": "Du har den nyeste versjonen.", - "Entities": "Enheter", - "Air Wizard: Defeated!": "Luft Trollmann: Slått", - "The Dungeon is now open!": "Fangehullet er nå åpent!", - "A costume lies on the ground...": "Et kostyme ligger på bakken...", - "Can't sleep!": "Kan ikke sove!", - "Min ": "Minst ", - " Sec left!": " sekunder igjen!", - "You hear a noise from the surface!": "Du hører en lyd fra overflaten!", - "Death Chest": "Døds Kiste", - "Player": "Spiller", - "Crafting": "Sløyd", - "Set your home!": "Velg hjem!", - "Can't set home here!": "Kan ikke sette hjem her!", - "Home Sweet Home!": "Hjem kjære hjem!", - "Mode penalty: -2 health": "Modus straff: -2 helse", - "You don't have a home!": "Du har ikke et hjem!", - "You can't go home from here!": "Du kan ikke gå hjem herfra!", - "Leather Armor": "Lær rustning", - "Snake Armor": "Slange rustning", - "Iron Armor": "Jern rustning", - "Gold Armor": "Gull rustning", - "Gem Armor": "Juvel rustning", - "Book": "Bok", + "Acorn": "Eikenøtt", + "AirWizard Spawner": "LuftTrollmann Spawner", "Antidious": "Antidious", - "Empty Bucket": "Tom Bøtte", - "Water Bucket": "Vann Bøtte", - "Lava Bucket": "Lava Bøtte", - " Bucket": " Bøtte", - "Red Clothes": "Røde Klær", - "Blue Clothes": "Blå Klær", - "Green Clothes": "Grønne Klær", - "Yellow Clothes": "Gule Klær", + "Anvil": "Ambolt", + "Apple": "Eple", + "Arrow": "Pil", + "Axe": "Øks", + "Baked Potato": "Bakt Potet", + "Bed": "Seng", "Black Clothes": "Svarte Klær", - "Orange Clothes": "Oransje Klær", - "Purple Clothes": "Lilla Klær", - "Cyan Clothes": "Cyan Klær", - "Reg Clothes": "Vanlige Klær", + "Black Wool": "Svart Ull", + "Blue Clothes": "Blå Klær", + "Blue Wool": "Blå Ull", + "Bone": "Bein", + "Book": "Bok", + "Bow": "Bue", "Bread": "Brød", - "Apple": "Eple", - "Raw Pork": "Rått svinekjøtt", - "Raw Fish": "Rå fisk", - "Raw Beef": "Rå biff", - "Pork Chop": "Svinekjøtt", + "Cactus": "Kaktus", + "Cactus Sapling": "Kaktus Spire", + "Chest": "Kiste", + "Claymore": "Claymore", + "Cloth": "Tøystykke", + "Cloud": "Sky", + "Cloud Cactus": "Sky kaktus", + "Cloud Ore": "Sky malm", + "Coal": "Kull", "Cooked Fish": "Kokt fisk", "Cooked Pork": "Stekt svinekjøtt", - "Steak": "Biff", - "Gold Apple": "Gull Eple", - "Baked Potato": "Bakt Potet", "Cow Spawner": "Ku Spawner", - "Pig Spawner": "Gris Spawner", - "Sheep Spawner": "Sau Spawner", - "Slime Spawner": "Slim Spawner", - "Zombie Spawner": "Zombie Spawner", "Creeper Spawner": "Creeper Spawner", - "Skeleton Spawner": "Skjelett Spawner", - "Snake Spawner": "Slange Spawner", - "Knight Spawner": "Ridder Spawner", - "AirWizard Spawner": "LuftTrollmann Spawner", - "Workbench": "Arbeidsbenk", - "Oven": "Stekeovn", - "Furnace": "Ovn", - "Anvil": "Ambolt", + "Cyan Clothes": "Cyan Klær", + "Death Chest": "Døds Kiste", + "Dirt": "Jord", + "Empty Bucket": "Tom Bøtte", "Enchanter": "Forhekser", - "Loom": "Vevstol", - "Lantern": "Lykt", - "Iron Lantern": "Jern Lykt", - "Gold Lantern": "Gull Lykt", - "Tnt": "TNT", - "Bed": "Seng", - "Chest": "Kiste", - "None Potion": "Ingen Trylledrikk", - "Speed Potion": "Fart Trylledrikk", - "Light Potion": "Lys Trylledrikk", - "Swim Potion": "Svomme Trylledrikk", "Energy Potion": "Energi Trylledrikk", - "Regen Potion": "Regen Trylledrikk", - "Health Potion": "Helse Trylledrikk", - "Time Potion": "Tid Trylledrikk", - "Lava Potion": "Lava Trylledrikk", - "Shield Potion": "Skjold Trylledrikk", - "Haste Potion": "Hastighet Trylledrikk", "Escape Potion": "Forsvinnelses Trylledrikk", - "Potion": "Trylledrikk", - "Power Glove": "Kraft hanske", - "Wood": "Tre", - "Stone": "Stein", - "Leather": "Lær", - "Wheat": "Hvete", - "Key": "Nøkkel", - "arrow": "pil", - "string": "tråd", - "Coal": "Kull", - "Iron Ore": "Jernmalm", - "Gold Ore": "Gullmalm", + "Explode": "Eksploder", + "Farmland": "Dyrket mark", + "Flower": "Blomst", + "Furnace": "Ovn", + "Gem": "Juvel", + "Gem Armor": "Juvel rustning", + "Gem Fishing Rod": "Juvel Fiskestang", "Gem Ore": "Juvel malm", - "Cloud Ore": "Sky malm", - "Iron": "Jern", + "Glass": "Glass", "Gold": "Gull", + "Gold Apple": "Gull Eple", + "Gold Armor": "Gull rustning", + "Gold Fishing Rod": "Gull Fiskestang", + "Gold Lantern": "Gull Lykt", + "Gold Ore": "Gullmalm", + "Grass": "Gress", + "Grass Seeds": "Grass Frø", + "Green Clothes": "Grønne Klær", + "Green Wool": "Grønn Ull", + "Gunpowder": "Krutt", + "Hard Rock": "Hard Stein", + "Haste Potion": "Hastighet Trylledrikk", + "Health Potion": "Helse Trylledrikk", + "Hoe": "Ljå", + "Hole": "Hull", + "Infinite Fall": "Uendelig Fall", + "Iron": "Jern", + "Iron Armor": "Jern rustning", + "Iron Fishing Rod": "Jern Fiskestang", + "Iron Lantern": "Jern Lykt", + "Iron Ore": "Jernmalm", + "Key": "Nøkkel", + "Knight Spawner": "Ridder Spawner", + "Lantern": "Lykt", "Lapis": "Lapis", - "Rose": "Rose", - "GunPowder": "Krutt", - "Slime": "Slim", - "glass": "glass", - "cloth": "tøystykke", - "gem": "juvel", - "Scale": "skala", - "Shard": "Fragment", - "Flower": "Blomst", - "Acorn": "Eikenøtt", - "Dirt": "Jord", + "Lava": "Lava", + "Lava Brick": "Lava Murstein", + "Lava Bucket": "Lava Bøtte", + "Lava Potion": "Lava Trylledrikk", + "Leather": "Lær", + "Leather Armor": "Lær rustning", + "Light Potion": "Lys Trylledrikk", + "Loom": "Vevstol", "Natural Rock": "Naturstein", - "Plank": "Planke", - "Plank Wall": "Planke Vegg", - "Wood Door": "Tre dør", - "Stone Brick": "Stein murstein", - "Ornate Stone": "Dekorert Stone", - "Stone Wall": "Stein vegg", - "Stone Door": "Stein dør", + "None Potion": "Ingen Trylledrikk", + "Obsidian": "Lavastein", "Obsidian Brick": "Lavastein murstein", - "Ornate Obsidian": "Dekorert Obsidian", - "Obsidian Wall": "Lavastein vegg", "Obsidian Door": "Lavastein dør", - "Wool": "Ull", + "Obsidian Wall": "Lavastein vegg", + "Orange Clothes": "Oransje Klær", + "Ornate Obsidian": "Dekorert Obsidian", + "Ornate Stone": "Dekorert Stone", + "Oven": "Stekeovn", + "Pickaxe": "Hakke", + "Pig Spawner": "Gris Spawner", + "Plank": "Planke", + "Plank Wall": "Planke Vegg", + "Player": "Spiller", + "Pork Chop": "Svinekjøtt", + "Potato": "Potet", + "Potion": "Trylledrikk", + "Power Glove": "Kraft hanske", + "Purple Clothes": "Lilla Klær", + "Raw Beef": "Rå biff", + "Raw Fish": "Rå fisk", + "Raw Obsidian": "Rå obsidian", + "Raw Pork": "Rått svinekjøtt", + "Red Clothes": "Røde Klær", "Red Wool": "Rød Ull", - "Blue Wool": "Blå Ull", - "Green Wool": "Grønn Ull", - "Yellow Wool": "Gul Ull", - "Black Wool": "Svart Ull", + "Reg Clothes": "Vanlige Klær", + "Regen Potion": "Regen Trylledrikk", + "Rock": "Stein", + "Rose": "Rose", "Sand": "Sand", - "Cactus": "Kaktus", + "Scale": "skala", "Seeds": "frø", - "Wheat Seeds": "Hvete Frø", - "Grass Seeds": "Grass Frø", - "Bone": "Bein", - "Cloud": "Sky", - "Rock": "Stein", - "Gem": "Juvel", - "Potato": "Potet", - "Wood Fishing Rod": "Tre Fiskestang", - "Iron Fishing Rod": "Jern Fiskestang", - "Gold Fishing Rod": "Gull Fiskestang", - "Gem Fishing Rod": "Juvel Fiskestang", + "Shard": "Fragment", + "Shears": "Saks", + "Sheep Spawner": "Sau Spawner", + "Shield Potion": "Skjold Trylledrikk", "Shovel": "Spade", - "Hoe": "Ljå", + "Skeleton Spawner": "Skjelett Spawner", + "Slime": "Slim", + "Slime Spawner": "Slim Spawner", + "Snake Armor": "Slange rustning", + "Snake Spawner": "Slange Spawner", + "Speed Potion": "Fart Trylledrikk", + "Stairs Down": "Trapp ned", + "Stairs Up": "Trapp opp", + "Steak": "Biff", + "Stone": "Stein", + "Stone Brick": "Stein murstein", + "Stone Bricks": "Stein murstein", + "Stone Door": "Stein dør", + "Stone Wall": "Stein vegg", + "String": "Tråd", + "Swim Potion": "Svomme Trylledrikk", "Sword": "Sverd", - "Pickaxe": "Hakke", - "Axe": "Øks", - "Bow": "Bue", - "Claymore": "Claymore", - "Shears": "Saks", + "Time Potion": "Tid Trylledrikk", + "Tnt": "TNT", "Torch": "Fakkel", - "Wood Planks": "Treplanker", - "Stone Bricks": "Stein murstein", - "Obsidian": "Lavastein", - "Wood Wall": "Tre vegg", - "Grass": "Gress", - "Hole": "Hull", - "Stairs Up": "Trapp opp", - "Stairs Down": "Trapp ned", - "Water": "Vann", + "Totem of Air": "Totem av luft", "Tree": "Tre", "Tree Sapling": "Tre Spire", - "Cactus Sapling": "Kaktus Spire", - "Lava": "Lava", - "Lava Brick": "Lava Murstein", - "Explode": "Eksploder", - "Farmland": "Dyrket mark", - "Hard Rock": "Hard Stein", - "Infinite Fall": "Uendelig Fall", - "Cloud Cactus": "Sky kaktus", - "Raw Obsidian": "Rå obsidian", - "Totem of Air": "Totem av luft", - - "host not found": "finner ikke verten", - "unable to get localhost address": "kan ikke hente localhost adressen", - "World Saved!": "Verden Lagret!", - "On": "På", - "Off": "Av", - "Have:": "Har:", - "Cost:": "Kostnad:", - "Time: ": "Tid: ", - "Score: ": "Poeng: ", - "Quit": "Avslutt", - "Respawn": "Gjennoppstå", - "You died! Aww!": "Du døde! Aww!", - "Player Score: ": "Spiller poeng: ", - "": "", - "Final Score: ": "Endelig poeng: ", - "Exit to Menu": "Avslutt til menyen", - "Time Played: ": "Tid Spillt: ", - "Current Score: ": "Nåværende poeng: ", - "Exit": "Gå ut", - "Player Stats": "Spiller statistikk", - "Controls": "Kontroller", - "Press the desired": "Trykk ønsket", - "key sequence": "tastesekvens", - "Confirm Action": "Bekreft handling", - "Press C/Enter to change key binding": "Trykk C/Enter for å endre tast", - "Press A to add key binding": "Trykk A for å legge til tastebinding", - "Shift-D to reset all keys to default": "Shift-D for å resette alle tastene", - "ESCAPE to Return to menu": "ESC for å gå tilbake til menyen ", - "Loading": "Laster", - "Generating": "Genererer", - "World": "Verden", - "waiting...": "venter...", - "nothing": "ingenting", - "attempting log in": "forsøker å logge inn", - "no internet connection, but no login data saved; cannot enter offline mode.": "ingen internett tilgang, og ingen login data lagret; kan ikke gå i offline modus.", - "connecting to server": "kobler til serveren", - "logging in": "logger inn", - "saving credentials": "lagrer legitimasjon", - "login failed.": "login mislyktes.", - "problem with saved login data; please exit and login again.": "problemer med lagret login data; vennligst logg inn på nytt.", - "Internal server error: Couldn't fetch username from uuid": "Intern server feil: Kunne ikke hente brukernavn fra uuid", - "logged in as: ": "logget inn som: ", - "offline mode: local servers only": "offline modus: bare lokale servere", - "Enter ip address to connect to:": "Skriv inn ipadressen du vil koble til", - "Press Shift-Escape to logout": "Trykk Shift-Escape for å logge ut", - "Enter email:": "Skriv email:", - "Enter password:": "Skriv passord:", - "field is blank": "feltet er tomt", - "get an account at:": "få en bruker på:", - "Loading ": "Laster ", - " from server": " fra server", - "Could not connect to server:": "Kunne ikke koble til server:", - "Press ": "Trykk ", - " to return": " for å avbryte", - "Change Key Bindings": "Endre tastene", - "Options": "Innstilinger", - "Change language": "Skift språk", - "Return to Game": "Gå tilbake til spillet", - "Make World Multiplayer": "Gjør verdenen til flerspiller", - "Save Game": "Lagre spill", - " and ": " og ", - " to Scroll": " for å skrolle", - ": Choose": ": Velg", - "Paused": "Pauset", - "Main Menu": "Hovedmeny", - "Yes": "Ja", - "No": "Nei", - "Inventory": "Inventar", - "to search.": "for å søke.", - "Play": "Start spill", - "Load World": "Last verden", - "New World": "Ny verden", - "Multiplayer": "Flerspiller", - "Singleplayer": "Enspiller", - "Help": "Hjelp", - "Instructions": "Instruksjoner", - "Storyline Guide": "Historie guide", - "About": "Om spillet", - "Credits": "Credits", - " to select": " for å velge", - " to accept": " for å akseptere", - "New World Name:": "Nytt navn:", - "Are you sure you want to delete": "Er du sikker på at du vil slette", - "This can not be undone!": "Du kan ikke angre dette!", - " to confirm": " for å bekrefte", - " to cancel": " for å avbryte", - "World Seed": "Verden frø", - "Enter World Name": "Navn på verden", - "Trouble with world name?": "Problemer med navnet?", - "by default, w and s move the cursor up and down. This can be changed in the key binding menu. To type the letter instead of moving the cursor, hold the shift key while typing the world name.": "vanligvis brukes w og s til å flytte pekeren opp og ned. Dette kan du endre i key binding menyen. For å skrive i stedet for å flytte pekeren kan du holde inne shift knappen.", - "Create World": "Lag verden", - "World Gen Options": "Verden instillinger", - " to Copy": " for å kopiere", - " to Rename": " for å gi nytt navn", - " to Delete": " for å slette", - "Select World": "Velg verden", - "Select a World to Delete": "Velg en verden til å Slette", - "Select a World to Rename": "Velg en verden til å endre navn", - "Select a World to Copy": "Velg en verden til å Kopiere", - "Higher version, cannot load world!": "Høyere versjon, kan ikke laste verden!", - "World Version:": "Verden Versjon:", - "Languages": "Språkmeny", - "Language": "Språk", - "Select": "Velg", - "Max FPS": "Maks FPS", - "Difficulty": "Vanskelighetsgrad", - "Easy": "Lett", - "Normal": "Normal", - "Hard": "Vanskelig", - "Game Mode": "Spillmodus", - "Survival": "Overlevelse", - "Creative": "Kreativ", - "Hardcore": "Hardcore", - "Score": "Poeng", - "Time (Score Mode)": "Tid (Poeng modus)", - "Sound": "Lyd", - "Autosave": "Autolagre", - "World Size": "Verden størrelse", - "World Theme": "Verden tema", - "Forest": "Skog", - "Desert": "Ørken", - "Plain": "Slette", - "Hell": "Helvete", - "Terrain Type": "Terreng type", - "Island": "Øy", - "Box": "Boks", - "Mountain": "Fjell", - "Irregular": "Uregulær", - "Wear Suit": "Ta på drakt" + "Water": "Vann", + "Water Bucket": "Vann Bøtte", + "Wheat": "Hvete", + "Wheat Seeds": "Hvete Frø", + "Wood": "Tre", + "Wood Door": "Tre dør", + "Wood Fishing Rod": "Tre Fiskestang", + "Wood Planks": "Treplanker", + "Wood Wall": "Tre vegg", + "Wool": "Ull", + "Workbench": "Arbeidsbenk", + "Yellow Clothes": "Gule Klær", + "Yellow Wool": "Gul Ull", + "Zombie Spawner": "Zombie Spawner", + "minicraft.achievement.airwizard": "Defeat... the air?", + "minicraft.achievement.airwizard.desc": "Beseire den første lufttrollmannen!", + "minicraft.achievement.benchmarking": "Benchmarking", + "minicraft.achievement.benchmarking.desc": "Lag en arbeidsbenk.", + "minicraft.achievement.bow": "Bow down to me!", + "minicraft.achievement.bow.desc": "Drep et monster med en bue.", + "minicraft.achievement.clothes": "Have a colourful day!", + "minicraft.achievement.clothes.desc": "Lag alle mulige fargede klær.", + "minicraft.achievement.demolition": "Demolition Demo", + "minicraft.achievement.demolition.desc": "Bruk TNT.", + "minicraft.achievement.doors": "Adooring Protection", + "minicraft.achievement.doors.desc": "Plasser alle dørtyper", + "minicraft.achievement.find_gem": "Oooh Shiny!", + "minicraft.achievement.find_gem.desc": "Finn juvelmalm og utgrav den.", + "minicraft.achievement.fish": "Go Fish!", + "minicraft.achievement.fish.desc": "Fisk opp en fisk.", + "minicraft.achievement.lava": "Hot Affairs", + "minicraft.achievement.lava.desc": "Bruk en lava potion for å svømme i lava.", + "minicraft.achievement.lowest_caves": "Darkness behind light", + "minicraft.achievement.lowest_caves.desc": "Nå de dypeste huler.", + "minicraft.achievement.obsidian_dungeon": "Of Knights and Men", + "minicraft.achievement.obsidian_dungeon.desc": "Nå obsidian fangehullet.", + "minicraft.achievement.planks": "Walk the Planks!", + "minicraft.achievement.planks.desc": "Plasser alle typer planke.", + "minicraft.achievement.skin": "Fashion Show", + "minicraft.achievement.skin.desc": "Endre utseendet ditt.", + "minicraft.achievement.survive_darkness": "Afraid of the Dark?", + "minicraft.achievement.survive_darkness.desc": "Overlev 5 minutter i mørket.", + "minicraft.achievement.upgrade": "Upgrade!", + "minicraft.achievement.upgrade.desc": "Få tak i et redskap med bedre materiell enn tre.", + "minicraft.achievement.woodcutter": "Woodcutter", + "minicraft.achievement.woodcutter.desc": "Få tak i tre.", + "minicraft.control_guide.attack": "Bruk %s for å angripe eller ødelegge.", + "minicraft.control_guide.craft": "Bruk %s for å åpne skapermeny.", + "minicraft.control_guide.menu": "Bruk %s for å åpne inventar.", + "minicraft.control_guide.move": "Bruk %s for å bevege deg.", + "minicraft.display.entries.boolean.false": "Av", + "minicraft.display.entries.boolean.true": "På", + "minicraft.display.gui.link_opening": "Åpner med nettleser...", + "minicraft.display.gui.perm_status.saving": "Lager... %s%%", + "minicraft.display.gui.perm_status.sleep_cancel": "Trykk på %s for å avbryte", + "minicraft.display.gui.perm_status.sleeping": "Sover...", + "minicraft.display.gui.potion_effects.hide_hint": "(%s for å gjømme!)", + "minicraft.display.gui.potion_effects.potion_dur": "%s (%d:%02d)", + "minicraft.display.gui.score.current_score": "Nåværende stilling: %s", + "minicraft.display.gui.score.time_left": "Tid igjen %s%sm %ss", + "minicraft.display.menus.inventory": "Inventar", + "minicraft.display.options_display": "Instillinger", + "minicraft.display.options_display.change_key_bindings": "Endre tastaturoppsett", + "minicraft.display.popup.enter_confirm": "Enter for å bekrefte", + "minicraft.display.popup.escape_cancel": "Escape for åvbyte", + "minicraft.display.popup.title_confirm": "Bekreft handling", + "minicraft.displays.achievements": "Oppnåelser", + "minicraft.displays.achievements.display.achieved": "Oppnådd!", + "minicraft.displays.achievements.display.help": "Bruk %s og %s for å bevege deg.", + "minicraft.displays.achievements.display.not_achieved": "Ikkje oppnådd", + "minicraft.displays.achievements.display.score": "Stilling av oppnåelser: %s", + "minicraft.displays.book.default_book": "Denne boka har ingen tekst.", + "minicraft.displays.controls": "Kontroller", + "minicraft.displays.controls.display.controller": "Spillkontroller", + "minicraft.displays.controls.display.controller.desc.1": "Detaljerte bindinskart er ubrukelige", + "minicraft.displays.controls.display.help.0": "%s/%s for å se andre kontroller.", + "minicraft.displays.controls.display.keyboard": "Tastatur", + "minicraft.displays.crafting": "Skaping", + "minicraft.displays.crafting.container_title.cost": "Koster:", + "minicraft.displays.crafting.container_title.have": "Har:", + "minicraft.displays.end_game.display.bonuses": "", + "minicraft.displays.end_game.display.final_score": "Endelig stilling: %s", + "minicraft.displays.end_game.display.player_score": "Spillers stilling: %s", + "minicraft.displays.end_game.display.unlocked": "Låst opp! Det tok %s", + "minicraft.displays.end_game.exit": "Gå tilbake til meny", + "minicraft.displays.info.display.exit_help": "%s/%s:Lukk", + "minicraft.displays.info.display.score": "Nåværende stilling: %s", + "minicraft.displays.info.display.time": "Tid spillt: %s", + "minicraft.displays.info.title": "Statistikk", + "minicraft.displays.key_input.display.help.0": "Trykk på C/Enter for å endre bindinger", + "minicraft.displays.key_input.display.help.1": "Trykk på A for å legge til binding", + "minicraft.displays.key_input.display.help.2": "Shift-D for å stille bindingene tilbake til standard", + "minicraft.displays.key_input.display.help.3": "%s for å gå tilbake til meny", + "minicraft.displays.key_input.popup_display.confirm_reset": "Er du sikker på at du vil stille alle tastebindinger tilbake til standard?", + "minicraft.displays.key_input.popup_display.press_key_sequence": "Trykk på den ønskede tastesekvensen", + "minicraft.displays.key_input.title": "Kontroller", + "minicraft.displays.loading.message.entities": "Enheter", + "minicraft.displays.loading.message.generating": "Genererer", + "minicraft.displays.loading.message.level": "Nivå %s", + "minicraft.displays.loading.message.levels": "Nivåer", + "minicraft.displays.loading.message.loading": "Laster", + "minicraft.displays.loading.message.quests": "Oppgaver", + "minicraft.displays.loading.message.saving": "Lagrer", + "minicraft.displays.loading.message.world": "Verden", + "minicraft.displays.loading.regeneration_cancellation_popup.display": "Lasting av verden avbrutt", + "minicraft.displays.loading.regeneration_popup.display.1": "Regenereing er krevd.", + "minicraft.displays.loading.regeneration_popup.display.2": "Gammel informasjon på bakken vil bli slettet:", + "minicraft.displays.loading.regeneration_popup.display.3": "%s for å fortsette", + "minicraft.displays.loading.regeneration_popup.display.4": "%s for å avbryte lastingen av verden", + "minicraft.displays.options_main_menu": "Hovedmenyinstillinger", + "minicraft.displays.options_main_menu.resource_packs": "Resurspakker", + "minicraft.displays.options_world": "Verdensinstillinger", + "minicraft.displays.options_world.off_tutorials_confirm_popup": "Er du sikker på at du vil sku av spillmanualen permanent?", + "minicraft.displays.options_world.turn_off_tutorials": "Sku av spillmanual", + "minicraft.displays.pause": "Pauset", + "minicraft.displays.pause.display.exit_popup.0": "Er du sikker på at du ønsker å lukke spillet?", + "minicraft.displays.pause.display.exit_popup.1": "All ulagra framgang vil gå tapt", + "minicraft.displays.pause.display.exit_popup.cancel": "Avbryt", + "minicraft.displays.pause.display.exit_popup.quit": "Lukk uten å lagre", + "minicraft.displays.pause.display.help.choose": "%s: Velg", + "minicraft.displays.pause.display.help.scroll": "%s og %s for å skrolle", + "minicraft.displays.pause.menu": "Hovedmeny", + "minicraft.displays.pause.return": "Gå tilbake til spill", + "minicraft.displays.pause.save": "Lagre spill", + "minicraft.displays.player_death.display.score": "Stilling: %s", + "minicraft.displays.player_death.display.time": "Tid: %s", + "minicraft.displays.player_death.quit": "Lukk program", + "minicraft.displays.player_death.respawn": "Start på nytt", + "minicraft.displays.player_death.save_quit": "Lagre og lukk program", + "minicraft.displays.player_death.title": "Du døde! Bedre lykke neste gang!", + "minicraft.displays.player_inv.container_title.items": "Gjenstander", + "minicraft.displays.player_inv.display.help": "(%s) for å søke.", + "minicraft.displays.quests": "Oppgaver", + "minicraft.displays.quests.display.header.completed": "Ferdig", + "minicraft.displays.quests.display.header.unlocked": "Låst opp", + "minicraft.displays.quests.display.no_quest": "Ingen oppgave låst opp", + "minicraft.displays.quests.display.no_quest_desc": "Ingen oppgave", + "minicraft.displays.resource_packs.display.help.keyboard_needed": "Kun tastaturinndata er godtatt.", + "minicraft.displays.resource_packs.display.help.move": "Brul %s og %s for bevege.", + "minicraft.displays.resource_packs.display.help.position": "Shift-[Venstetast|Høyretast|Opptast|Nedtast] for å bevege ressurspakker. ", + "minicraft.displays.resource_packs.display.help.select": "%s for å eksaminere.", + "minicraft.displays.resource_packs.display.title": "Resurspakker", + "minicraft.displays.skin": "Drakter", + "minicraft.displays.skin.display.help.move": "Bruk %s og %s for å bevege.", + "minicraft.displays.skin.display.help.select": "%s for å velge og %s for å kansellere.", + "minicraft.displays.title.display.cannot_check": "Kunne ikke skjekke etter oppdateringer.", + "minicraft.displays.title.display.checking": "Skjekker etter oppdateringer...", + "minicraft.displays.title.display.help.0": "(%s, %s for å velge)", + "minicraft.displays.title.display.help.1": "(%s for å akseptere)", + "minicraft.displays.title.display.help.2": "(%s for å gå tilbake)", + "minicraft.displays.title.display.latest_already": "Du har den nyeste versjonen.", + "minicraft.displays.title.display.new_version": "Ny: %s", + "minicraft.displays.title.display.version": "Versjon %s", + "minicraft.displays.title.help": "Hjelp", + "minicraft.displays.title.help.about": "Om spillet", + "minicraft.displays.title.help.credits": "Akkreditasjon", + "minicraft.displays.title.help.instructions": "Instrukser", + "minicraft.displays.title.help.storyline_guide": "Historieomviser", + "minicraft.displays.title.link_to_version": "Direktelink til nyeste versjon: %s", + "minicraft.displays.title.play": "Spill", + "minicraft.displays.title.play.load_world": "Last verden", + "minicraft.displays.title.play.new_world": "Ny verden", + "minicraft.displays.title.quit": "Lukk spill", + "minicraft.displays.title.select_to_download": "--Trykk her for å laste ned--", + "minicraft.displays.tutorial_display_handler.display.element_examine_help": "Trykk på %s for å se detaljene av spillmanualen.", + "minicraft.displays.world_gen.create_world": "Lag verden", + "minicraft.displays.world_gen.enter_world": "Skriv inn navnet til verdenen", + "minicraft.displays.world_gen.title": "Verdengenerator-instillinger", + "minicraft.displays.world_gen.troublesome_input": "Problemer med navnet til verdenen?", + "minicraft.displays.world_gen.world_seed": "Verdengenerator-frø", + "minicraft.displays.world_select.display.help.0": "%s for å bekrefte", + "minicraft.displays.world_select.display.help.1": "%s for å gå tilbake", + "minicraft.displays.world_select.display.help.2": "Shift-C for å kopiere", + "minicraft.displays.world_select.display.help.3": "Shift-R for å endre navn", + "minicraft.displays.world_select.display.help.4": "Shift-d for slette", + "minicraft.displays.world_select.display.world_too_new": "Nyere versjon, kan ikke laste verden!", + "minicraft.displays.world_select.display.world_version": "Verdens spillversjon: %s", + "minicraft.displays.world_select.popups.display.cancel": "%s for å avbryte", + "minicraft.displays.world_select.popups.display.change": "Nytt navn:", + "minicraft.displays.world_select.popups.display.confirm": "%s for å bekrefte", + "minicraft.displays.world_select.popups.display.delete": "Er du sikker på at du vil slette\n%s\"%s\"%s?\nDette er en irreversibel handling!", + "minicraft.displays.world_select.select_world": "Velg verden", + "minicraft.notification.achievement_unlocked": "Oppnåelse låst opp:", + "minicraft.notification.air_wizard_defeated": "Lufttrollmann bekjempet!", + "minicraft.notification.boss_limit": "Ingen flere hovedfiender kan bli tilkalt", + "minicraft.notification.cannot_sleep": "Kan ikkje sove! %s:%s igjen!", + "minicraft.notification.death_chest_retrieved": "Dødskiste plukket opp!", + "minicraft.notification.defeat_air_wizard_first": "Lufttrollmannen må bekjempes først.", + "minicraft.notification.dig_hole": "Grav et hull først!", + "minicraft.notification.dungeon_opened": "Hulen er nå åpen!", + "minicraft.notification.gem_pickaxe_required": "Juvelsteinhakke er krevd.", + "minicraft.notification.invalid_placement": "Kan kun bli plassert på", + "minicraft.notification.quest_completed": "Oppgave gjennomført", + "minicraft.notification.quest_unlocked": "Oppgave låst opp", + "minicraft.notification.spawn_on_boss_tile": "Kan kun bli tilkalt i sluttrommet", + "minicraft.notification.world_saved": "Lagret verden!", + "minicraft.notification.wrong_level_dungeon": "Kan kun bli tilkalt i hulen", + "minicraft.notification.wrong_level_sky": "Kan kun bli framkalt i skyene", + "minicraft.notifications.statue_tapped": "Du hører gjenklang av kviskring...", + "minicraft.notifications.statue_touched": "Du skimter at stuatuen vibrerer...", + "minicraft.quest.farming": "Jordbrukende jordbruker", + "minicraft.quest.farming.crafting_hoe": "Lag en hjå", + "minicraft.quest.farming.crafting_hoe.description": "Lag en hjå på arbeidsbenken.", + "minicraft.quest.farming.description": "Det grunnleggende som jordbruker.", + "minicraft.quest.farming.getting_wheat": "Høsting av hvete", + "minicraft.quest.farming.getting_wheat.description": "Høst hvete.", + "minicraft.quest.farming.making_farmland": "Lag dyrka mark", + "minicraft.quest.farming.making_farmland.description": "Lag dyka mark ved å bruke en hjå.", + "minicraft.quest.farming.planting_potato": "Plant en potet", + "minicraft.quest.farming.planting_potato.description": "Plant en potet på dryrka mark.", + "minicraft.quest.farming.planting_wheat": "Plant hvete", + "minicraft.quest.farming.planting_wheat.description": "Plant frø på dyrka mark.", + "minicraft.quest.gems": "Veien av juveler", + "minicraft.quest.gems.description": "Få klart juvelutstyr.", + "minicraft.quest.gems.gem_armor": "Mester av beskyttelse", + "minicraft.quest.gems.gem_armor.description": "Få tak i juvelrustning.", + "minicraft.quest.gems.gem_claymore": "Mester av våpen", + "minicraft.quest.gems.gem_claymore.description": "Få tak i et juvelsverd. (claymore)", + "minicraft.quest.iron_equipments": "Mester av jern", + "minicraft.quest.iron_equipments.description": "Få tak i alt av jernutstyr.", + "minicraft.quest.iron_equipments.getting_more_iron": "Rik på jern", + "minicraft.quest.iron_equipments.getting_more_iron.description": "Få tak i enda mer jern.", + "minicraft.quest.iron_equipments.iron_armor": "Oppgrader rustning", + "minicraft.quest.iron_equipments.iron_armor.description": "Oppgrader rustningen din til jern.", + "minicraft.quest.iron_equipments.iron_tools": "Oppgrader alle redskaper", + "minicraft.quest.iron_equipments.iron_tools.description": "Oppgrader alle redskapene dine til jern.", + "minicraft.quest.iron_equipments.upgrading_pickaxe": "Avansert hakke", + "minicraft.quest.iron_equipments.upgrading_pickaxe.description": "Oppgrader hakken din til jern.", + "minicraft.quest.potions": "Mester av trylledrikker", + "minicraft.quest.potions.all_potions_prepared": "Ekspert på trylledrikker", + "minicraft.quest.potions.all_potions_prepared.description": "Få tak i alle trylledrikker på samme tid.", + "minicraft.quest.potions.awkward_potions": "Klein trylledrikk", + "minicraft.quest.potions.awkward_potions.description": "Få tak i en klein trylledrikk.", + "minicraft.quest.potions.description": "Få tak i trylledrikkene.", + "minicraft.quest.potions.powerful_potions": "Kraftige trylledrikker", + "minicraft.quest.potions.powerful_potions.description": "Få tak i brukbare og kraftige trylledrikker.", + "minicraft.settings.autosave": "Lagre automatisk", + "minicraft.settings.difficulty": "Vanskelighetsgrad", + "minicraft.settings.difficulty.easy": "Lett", + "minicraft.settings.difficulty.hard": "Vanskelig", + "minicraft.settings.difficulty.normal": "Normal", + "minicraft.settings.fps": "Maks FPS", + "minicraft.settings.mode": "Spillmodus", + "minicraft.settings.mode.creative": "Kreativ", + "minicraft.settings.mode.hardcore": "Hardcore", + "minicraft.settings.mode.score": "Stilling", + "minicraft.settings.mode.survival": "Overlevelse", + "minicraft.settings.scoretime": "Tid (Stillingmodus)", + "minicraft.settings.screenshot_scale": "Skala til skjermbilde", + "minicraft.settings.size": "Størrelse på verden", + "minicraft.settings.sound": "Lyd", + "minicraft.settings.theme": "Tema på verden", + "minicraft.settings.theme.desert": "Ørken", + "minicraft.settings.theme.forest": "Skog", + "minicraft.settings.theme.hell": "Helvete", + "minicraft.settings.theme.normal": "Normal", + "minicraft.settings.theme.plain": "Slette", + "minicraft.settings.type": "Terrengtype", + "minicraft.settings.type.box": "Boks", + "minicraft.settings.type.irregular": "Unormalt", + "minicraft.settings.type.island": "Øy", + "minicraft.settings.type.mountain": "Fjell", + "minicraft.skin.minecraft_alex": "Gjenkjennelig jente", + "minicraft.skin.minecraft_steve": "Gjenkjennelig gutt", + "minicraft.skin.paul": "Pål", + "minicraft.skin.paul_cape": "Pål med kappe", + "minicraft.text_particales.key_consumed": "-1 nøkkel", + "minicraft.tutorial.getting_rocks": "Få tak i stein og kull", + "minicraft.tutorial.getting_rocks.description": "Få tak i minst 5 stein og 5 kull av å ødelegge stein med en hakke.", + "minicraft.tutorial.getting_wood": "Få tak i mer tre", + "minicraft.tutorial.getting_wood.description": "Få tak i minst 10 tre fra trær.", + "minicraft.tutorial.getting_wooden_pickaxe": "Få tak i trehakke", + "minicraft.tutorial.getting_wooden_pickaxe.description": "Lag en trehakke i skapermenyen til arbeidsbenken.", + "minicraft.tutorial.getting_workbench": "Få tak i en arbeidsbenk", + "minicraft.tutorial.getting_workbench.description": "Lag en arbeidsbenk i skapermenyen. Plasser den etterpå.", + "minicraft.tutorial.start_getting_wood": "Starten på alt", + "minicraft.tutorial.start_getting_wood.description": "Slå trer for å få tak i tre." } diff --git a/src/client/resources/assets/localization/nl-nl.json b/src/client/resources/assets/localization/nl-nl.json new file mode 100644 index 000000000..bad9e5bf7 --- /dev/null +++ b/src/client/resources/assets/localization/nl-nl.json @@ -0,0 +1,365 @@ +{ + "Acorn": "Eikel", + "AirWizard Spawner": "Lucht Tovenaar Spawner", + "Antidious": "Tegendraads", + "Anvil": "Aambeeld", + "Apple": "Appel", + "Axe": "Bijl", + "Baked Potato": "Gebakken Aardappel", + "Bed": "Bed", + "Black Clothes": "Zwarte Kleren", + "Black Wool": "Zwart Wol", + "Blue Clothes": "Blauwe Kleren", + "Blue Wool": "Blauw Wol", + "Bone": "Bot", + "Book": "Boek", + "Bow": "Boog", + "Bread": "Brood", + "Cactus": "Cactus", + "Cactus Sapling": "Cactus Kiemplant", + "Chest": "Kist", + "Claymore": "Claymore", + "Cloud": "Wolk", + "Cloud Cactus": "Wolk Cactus", + "Cloud Ore": "Wolk Erts", + "Coal": "Steenkool", + "Cooked Fish": "Gekookte Vis", + "Cooked Pork": "Gebraden Varkensvlees", + "Cow Spawner": "Koe Spawner", + "Creeper Spawner": "Creeper Spawner", + "Cyan Clothes": "Cyaan Kleren", + "Death Chest": "Doodskist", + "Dirt": "Aarde", + "Empty Bucket": "Lege Emmer", + "Enchanter": "Betoveraar", + "Energy Potion": "Energie Drank", + "Escape Potion": "Onstappings Drank", + "Explode": "Explodeer", + "Farmland": "Akkerland", + "Flower": "Bloem", + "Furnace": "Smeltoven", + "Gem": "Edelsteen", + "Gem Armor": "Edelsteen Uitrusting", + "Gem Fishing Rod": "Edelsteen Vishengel", + "Gem Ore": "Edelsteen Erts", + "Gold": "Goud", + "Gold Apple": "Gouden Appel", + "Gold Armor": "Gouden Uitrusting", + "Gold Fishing Rod": "Gouden Vishengel", + "Gold Lantern": "Gouden Lantaarn", + "Gold Ore": "Gouderts", + "Grass": "Gras", + "Grass Seeds": "Gras Zaden", + "Green Clothes": "Groene Kleren", + "Green Wool": "Groen Wol", + "Gunpowder": "Buskruit", + "Hard Rock": "Hard Steen", + "Haste Potion": "Haast Drank", + "Health Potion": "Genezings Drank", + "Hoe": "Schoffel", + "Hole": "Put", + "Infinite Fall": "Oneindige Val", + "Iron": "Ijzer", + "Iron Armor": "Ijzeren Uitrusting", + "Iron Fishing Rod": "Ijzeren Vishengel", + "Iron Lantern": "Ijzeren Lantaarn", + "Iron Ore": "Ijzererts", + "Key": "Sleutel", + "Knight Spawner": "Ridder Spawner", + "Lantern": "Lantaarn", + "Lapis": "Lapis", + "Lava": "Lava", + "Lava Brick": "Lava Baksteen", + "Lava Bucket": "Emmer met Lava", + "Lava Potion": "Lava Drank", + "Leather": "Leer", + "Leather Armor": "Leren Uitrusting", + "Light Potion": "Licht Drank", + "Loom": "Weefgetouw", + "Natural Rock": "Natuurlijke Steen", + "None Potion": "Geen Drank", + "Obsidian": "Obsidiaan", + "Obsidian Brick": "Obsidaan Baksteen", + "Obsidian Door": "Obsidiaan Muur", + "Obsidian Wall": "Obsidiaan Muur", + "Orange Clothes": "Oranje Kleren", + "Ornate Obsidian": "Sierlijk Obsidiaan", + "Ornate Stone": "Sierlijk Steen", + "Oven": "Oven", + "Pickaxe": "Pikhouweel", + "Pig Spawner": "Varken Spawner", + "Plank": "Plank", + "Plank Wall": "Planken Muur", + "Player": "Speler", + "Pork Chop": "Varkensvlees", + "Potato": "Aardappel", + "Potion": "Drank", + "Power Glove": "Power Handschoen", + "Purple Clothes": "Paarse Kleren", + "Raw Beef": "Rauw Biefstuk", + "Raw Fish": "Rauwe Vis", + "Raw Obsidian": "Rauw Obsidiaan", + "Raw Pork": "Rauw Varkensvlees", + "Red Clothes": "Rode Kleren", + "Red Wool": "Rood Wol", + "Reg Clothes": "Reg Kleren", + "Regen Potion": "Regeneratie Drank", + "Rock": "Rots", + "Rose": "Roos", + "Sand": "Zand", + "Scale": "Grootte", + "Seeds": "Zaden", + "Shard": "Scherf", + "Shears": "Schaar", + "Sheep Spawner": "Schaap Spawner", + "Shield Potion": "Schild Drank", + "Shovel": "Schep", + "Skeleton Spawner": "Skelet Spawner", + "Slime": "Slijm", + "Slime Spawner": "Slijm Spawner", + "Snake Armor": "Slangen Uitrusting", + "Snake Spawner": "Slang Spawner", + "Speed Potion": "Snelheids Drank", + "Stairs Down": "Trappen Omloog", + "Stairs Up": "Trappen Omhoog", + "Steak": "Biefstuk", + "Stone": "Steen", + "Stone Brick": "Stenen Baksteen", + "Stone Bricks": "Stenen Bakstenen", + "Stone Door": "Stenen Deur", + "Stone Wall": "Stenen Muur", + "Swim Potion": "Zwem Drank", + "Sword": "Zwaard", + "Time Potion": "Tijd Drank", + "Tnt": "Tnt", + "Torch": "Toorts", + "Totem of Air": "Totem van de Lucht", + "Tree": "Boom", + "Tree Sapling": "Boom Kiemplant", + "Water": "Water", + "Water Bucket": "Emmer met Water", + "Wheat": "Tarwe", + "Wheat Seeds": "Tarwe Zaden", + "Wood": "Hout", + "Wood Door": "Houten Deur", + "Wood Fishing Rod": "Houten Vishengel", + "Wood Planks": "Houten Planken", + "Wood Wall": "Houten Muur", + "Wool": "Wol", + "Workbench": "Werkbank", + "Yellow Clothes": "Gele Kleren", + "Yellow Wool": "Geel Wol", + "Zombie Spawner": "Zombie Spawner", + "minicraft.achievement.airwizard": "Versla... de lucht?", + "minicraft.achievement.airwizard.desc": "Versla de eerste Lucht Tovenaar!", + "minicraft.achievement.benchmarking": "Benchmarking", + "minicraft.achievement.benchmarking.desc": "Maak een werkbank.", + "minicraft.achievement.bow": "Buig voor mij!", + "minicraft.achievement.bow.desc": "Schiet een pijl met een boog.", + "minicraft.achievement.clothes": "Heb een kleurrijke dag!", + "minicraft.achievement.clothes.desc": "Maak kleren met een kleur", + "minicraft.achievement.demolition": "Ouwe slopert!", + "minicraft.achievement.demolition.desc": "Gebruik TNT.", + "minicraft.achievement.doors": "Met de deur in huis vallen", + "minicraft.achievement.doors.desc": "Maak een houten deur.", + "minicraft.achievement.find_gem": "Oooh glimmend!", + "minicraft.achievement.find_gem.desc": "Zoek een Juweel Steen and hak het.", + "minicraft.achievement.fish": "Ga Vissen!", + "minicraft.achievement.fish.desc": "Vis een Vis!", + "minicraft.achievement.lava": "Hete Zaken", + "minicraft.achievement.lava.desc": "Gebruik een lava brouwsel om in lava te zwemmen.", + "minicraft.achievement.lowest_caves": "Duisternis achter licht", + "minicraft.achievement.lowest_caves.desc": "Bereik de laagste grotten.", + "minicraft.achievement.obsidian_dungeon": "Van Ridders en Men", + "minicraft.achievement.obsidian_dungeon.desc": "Bereik de obsidiaan kerker.", + "minicraft.achievement.planks": "De Planken Lopen!", + "minicraft.achievement.planks.desc": "Maak houten planken.", + "minicraft.achievement.skin": "Mode Show", + "minicraft.achievement.skin.desc": "Verander jouw uiterlijk.", + "minicraft.achievement.survive_darkness": "Bang van het Donker?", + "minicraft.achievement.survive_darkness.desc": "Overleef 5 minuten in totale duisternis.", + "minicraft.achievement.upgrade": "Upgrade!", + "minicraft.achievement.upgrade.desc": "Maak een stenen werktuig.", + "minicraft.achievement.woodcutter": "Houthakker", + "minicraft.achievement.woodcutter.desc": "Krijg hout.", + "minicraft.control_guide.attack": "Gebruik %s om monsters aan te vallen of om tegels te verwoesten.", + "minicraft.control_guide.craft": "Gebruik %s om je werk menu te openen.", + "minicraft.control_guide.menu": "Gebruik %s om je inventaris te openen.", + "minicraft.control_guide.move": "Gebruik %s om te bewegen.", + "minicraft.display.entries.boolean.false": "Uit", + "minicraft.display.entries.boolean.true": "Aan", + "minicraft.display.gui.link_opening": "Aan het openen met web browser...", + "minicraft.display.gui.perm_status.saving": "Aan het opslaan... %s%%", + "minicraft.display.gui.perm_status.sleep_cancel": "Druk %s om te annuleren", + "minicraft.display.gui.perm_status.sleeping": "Aan het slapen...", + "minicraft.display.gui.potion_effects.hide_hint": "(%s om te verbergen!)", + "minicraft.display.gui.potion_effects.potion_dur": "%s (%d:%02d)", + "minicraft.display.gui.score.current_score": "Huidige score: %s", + "minicraft.display.gui.score.time_left": "Tijd over %s%sm %ss", + "minicraft.display.menus.inventory": "Inventaris", + "minicraft.display.options_display": "Opties", + "minicraft.display.options_display.change_key_bindings": "Verander toets opties", + "minicraft.display.popup.enter_confirm": "Enter om te bevestigen", + "minicraft.display.popup.escape_cancel": "Escape om te annuleren", + "minicraft.display.popup.title_confirm": "Bevestig Actie", + "minicraft.displays.achievements": "Prestaties", + "minicraft.displays.achievements.display.achieved": "Behaald!", + "minicraft.displays.achievements.display.help": "Gebruik %s and %s om te bewegen.", + "minicraft.displays.achievements.display.not_achieved": "Nog niet behaald", + "minicraft.displays.achievements.display.score": "Prestatie Score: %s", + "minicraft.displays.book.default_book": "Dit boek heeft geen tekst.", + "minicraft.displays.controls": "Besturing", + "minicraft.displays.controls.display.controller": "Controller", + "minicraft.displays.controls.display.controller.00": "Speler bewegen gebruikt DPAD", + "minicraft.displays.controls.display.controller.01": "Cursor bewegen gebruikt DPAD", + "minicraft.displays.controls.display.controller.02": "Items selecteren gebruikt A", + "minicraft.displays.controls.display.controller.03": "Pagina's verlaten gebruikt B", + "minicraft.displays.controls.display.controller.04": "Aanvallen, tegels kapot maken en gebruiken via A", + "minicraft.displays.controls.display.controller.05": "Menu in-spel openen via X", + "minicraft.displays.controls.display.controller.06": "Maak menu openen via Y", + "minicraft.displays.controls.display.controller.07": "Meubels oppakken via LEFTBUMPER", + "minicraft.displays.controls.display.controller.08": "1 item laten vallen via RIGHTBUMPER", + "minicraft.displays.controls.display.controller.09": "Een hele stack van items laten vallen via RIGHTSTICK", + "minicraft.displays.controls.display.controller.11": "Het spel pauzeren via START", + "minicraft.displays.crafting": "Maken", + "minicraft.displays.crafting.container_title.cost": "Kost:", + "minicraft.displays.crafting.container_title.have": "Heeft:", + "minicraft.displays.end_game.display.bonuses": "", + "minicraft.displays.end_game.display.final_score": "Uiteneindelijke Score: %s", + "minicraft.displays.end_game.display.player_score": "Speler Score: %s", + "minicraft.displays.end_game.display.unlocked": "Ontgrendeld! %s Scorren tijd", + "minicraft.displays.end_game.exit": "Terug naar het Menu", + "minicraft.displays.info.display.exit_help": "%s/%s:Verlaten", + "minicraft.displays.info.display.score": "Huidige Score: %s", + "minicraft.displays.info.display.time": "Tijd gespeeld: %s", + "minicraft.displays.info.title": "Speler statisktieken", + "minicraft.displays.key_input.display.help.0": "Toets C/Enter om de toets binding the veranderen", + "minicraft.displays.key_input.display.help.1": "Toets A om een toets binding te maken", + "minicraft.displays.key_input.display.help.2": "Shift-D om alle toetsen to resetten", + "minicraft.displays.key_input.display.help.3": "%s om Terug te gaan naar het menu", + "minicraft.displays.key_input.popup_display.confirm_reset": "Ben je zeker dat je alle sneltoetsen wilt resetten naar de standaard toetsen?", + "minicraft.displays.key_input.popup_display.press_key_sequence": "Druk op de gewenste reeks toetsen", + "minicraft.displays.key_input.title": "Besturing", + "minicraft.displays.loading.message.entities": "Entiteiten", + "minicraft.displays.loading.message.generating": "Generen", + "minicraft.displays.loading.message.level": "Level %s", + "minicraft.displays.loading.message.levels": "Levels", + "minicraft.displays.loading.message.loading": "Laden", + "minicraft.displays.loading.message.saving": "Aan het Opslaan", + "minicraft.displays.loading.message.world": "Wereld", + "minicraft.displays.options_main_menu": "Hoofdmenu opties", + "minicraft.displays.options_main_menu.resource_packs": "resourcepakketten", + "minicraft.displays.options_world": "Wereld Opties", + "minicraft.displays.options_world.off_tutorials_confirm_popup": "Weet je zeker dat je de uitleg wilt uitzetten voor altijd?", + "minicraft.displays.options_world.turn_off_tutorials": "Uitleg uitzetten", + "minicraft.displays.pause": "gepauzeerd", + "minicraft.displays.pause.display.exit_popup.0": "Weet je zeker dat je uit het spel wilt gaan?", + "minicraft.displays.pause.display.exit_popup.1": "Alle niet opgeslagen progressie zal verloren gaan", + "minicraft.displays.pause.display.exit_popup.cancel": "Annuleer", + "minicraft.displays.pause.display.exit_popup.quit": "Stoppen zonder opteslaan", + "minicraft.displays.pause.display.help.choose": "%s: Kiezen", + "minicraft.displays.pause.display.help.scroll": "%s en %s om te Scrollen", + "minicraft.displays.pause.menu": "Hoofdmenu", + "minicraft.displays.pause.return": "Terug naar het spel", + "minicraft.displays.pause.save": "Spel opslaan", + "minicraft.displays.player_death.display.score": "Score: %s", + "minicraft.displays.player_death.display.time": "Tijd: %s", + "minicraft.displays.player_death.quit": "Stoppen", + "minicraft.displays.player_death.respawn": "Hereizen", + "minicraft.displays.player_death.save_quit": "Opslaan en stoppen", + "minicraft.displays.player_death.title": "Oh nee! je bent dood!", + "minicraft.displays.player_inv.container_title.items": "Spullen", + "minicraft.displays.player_inv.display.help": "(%s) om te zoeken.", + "minicraft.displays.quests": "Uitdagingen", + "minicraft.displays.quests.display.header.completed": "Voltooid", + "minicraft.displays.quests.display.header.unlocked": "Ontgrendeld", + "minicraft.displays.quests.display.no_quest_desc": "Geen uitdaging", + "minicraft.displays.resource_packs.display.help.move": "Gebruik %s en %s om te bewegen.", + "minicraft.displays.resource_packs.display.help.position": "SHIFT-[LINKS|RECHTS|OMHOOG|OMLAAG] om pakketten te bewegen.", + "minicraft.displays.resource_packs.display.help.select": "%s om te onderzoeken.", + "minicraft.displays.resource_packs.display.title": "resourcepakketten", + "minicraft.displays.skin": "Skins", + "minicraft.displays.skin.display.help.move": "Gebruik %s en %s om te bewegen.", + "minicraft.displays.skin.display.help.select": "%s om te selecteren en %s om te annuleren.", + "minicraft.displays.title.display.cannot_check": "Kon niet checken voor updates.", + "minicraft.displays.title.display.checking": "Aan het kijken voor updates..", + "minicraft.displays.title.display.help.0": "(%s, %s om te selecteren)", + "minicraft.displays.title.display.help.1": "(%s om te accepteren)", + "minicraft.displays.title.display.help.2": "(%s om terug te keren)", + "minicraft.displays.title.display.latest_already": "Je hebt de nieuwste versie.", + "minicraft.displays.title.display.new_version": "Nieuwe: %s", + "minicraft.displays.title.display.version": "Versie %s", + "minicraft.displays.title.help": "Help", + "minicraft.displays.title.help.about": "Over", + "minicraft.displays.title.help.credits": "Credits", + "minicraft.displays.title.help.instructions": "Intructies", + "minicraft.displays.title.help.storyline_guide": "Verhaallijn Gids", + "minicraft.displays.title.link_to_version": "Directe link naar de nieuwste versie: %s", + "minicraft.displays.title.play": "Spelen", + "minicraft.displays.title.play.load_world": "Laad Wereld", + "minicraft.displays.title.play.new_world": "Nieuwe werled", + "minicraft.displays.title.quit": "Stoppen", + "minicraft.displays.title.select_to_download": "--Selecteer hier om te downloaden--", + "minicraft.displays.world_gen.create_world": "Maak Wereld", + "minicraft.displays.world_gen.enter_world": "Schrijf hier de wereld naam", + "minicraft.displays.world_gen.title": "Wereld Gen Opties", + "minicraft.displays.world_gen.troublesome_input": "Problemen met de wereld naam?", + "minicraft.displays.world_gen.troublesome_input.msg": "Het ziet er naar uit dat je letter toetsen hebt gebruikt om de muis omhoog en omlaag te bewegen, dat is waarschijnlijk irritant. Dit kan veranderd worden in de toetsen bindings menu. Dit staat er als \"cursor-XXX\" toetsen. Voor nu typ de letters inplaats de muis bewegen. Hou shift in gedrukt terwijl je typt.", + "minicraft.displays.world_gen.world_seed": "Wereld zaad", + "minicraft.displays.world_select.display.help.0": "%s om te bevestigen", + "minicraft.displays.world_select.display.help.1": "%s om terug te keren", + "minicraft.displays.world_select.display.help.2": "SHIFT-C om te kopiëren", + "minicraft.displays.world_select.display.help.3": "SHIFT-R om te hernoemen", + "minicraft.displays.world_select.display.help.4": "SHIFT-D om te verwijderen", + "minicraft.displays.world_select.display.world_too_new": "Hogere versie, kan de wereld niet laden!", + "minicraft.displays.world_select.display.world_version": "Wereld Versie: %s", + "minicraft.displays.world_select.popups.display.cancel": "%s om te annuleren", + "minicraft.displays.world_select.popups.display.change": "Nieuwe Wereld Naam:", + "minicraft.displays.world_select.popups.display.confirm": "%s om te bevestigen", + "minicraft.displays.world_select.popups.display.delete": "Ben je zeker dat je\n%s\"%s\"%s wilt verwijderen?\nDit kan niet ongedaan worden!", + "minicraft.displays.world_select.select_world": "Selecteer Wereld", + "minicraft.notification.achievement_unlocked": "Prestatie ontgrendeld: %s", + "minicraft.notification.air_wizard_defeated": "Lucht Tovenaar Verslagen!", + "minicraft.notification.cannot_sleep": "Kan niet slapen! %sMin %s Sec over!", + "minicraft.notification.death_chest_retrieved": "Doodskist verkregen!", + "minicraft.notification.defeat_air_wizard_first": "De lucht tovenaar moet eerst verslagen worden.", + "minicraft.notification.dig_hole": "Graaf eerst een put!", + "minicraft.notification.dungeon_opened": "De Kerker is nu open!", + "minicraft.notification.gem_pickaxe_required": "Edelsteen Pikhouweel Vereist.", + "minicraft.notification.invalid_placement": "Kan alleen op %s geplaatst worden!", + "minicraft.notification.quest_completed": "Uitdaging voltooid", + "minicraft.notification.quest_unlocked": "Uitdaging ontgrendeld", + "minicraft.notification.world_saved": "Wereld Opgeslagen!", + "minicraft.notification.wrong_level_sky": "Kan alleen op lucht level opgeroepen worden", + "minicraft.settings.autosave": "Automatisch opslaan", + "minicraft.settings.difficulty": "Moeilijkheid", + "minicraft.settings.difficulty.easy": "Makkelijk", + "minicraft.settings.difficulty.hard": "Moeilijk", + "minicraft.settings.difficulty.normal": "Normaal", + "minicraft.settings.fps": "Max FPS", + "minicraft.settings.mode": "Spel Modus", + "minicraft.settings.mode.creative": "Creatief", + "minicraft.settings.mode.hardcore": "Hardcore", + "minicraft.settings.mode.score": "Score", + "minicraft.settings.mode.survival": "Survival", + "minicraft.settings.scoretime": "Tijd (Score Modus)", + "minicraft.settings.screenshot_scale": "Schermafbeelding Grootte", + "minicraft.settings.size": "Wereld Grootte", + "minicraft.settings.sound": "Geluid", + "minicraft.settings.theme": "Wereld Thema", + "minicraft.settings.theme.desert": "Woestijn", + "minicraft.settings.theme.forest": "Bos", + "minicraft.settings.theme.hell": "Hel", + "minicraft.settings.theme.normal": "Normaal", + "minicraft.settings.theme.plain": "Vlakte", + "minicraft.settings.type": "Type Terrein", + "minicraft.settings.type.box": "Doos", + "minicraft.settings.type.irregular": "Onregelmatig", + "minicraft.settings.type.island": "Eiland", + "minicraft.settings.type.mountain": "Berg", + "minicraft.skin.minecraft_alex": "Bekend meisje", + "minicraft.skin.minecraft_steve": "Bekende jongen", + "minicraft.skin.paul": "Paul", + "minicraft.skin.paul_cape": "Paul met cape", + "minicraft.text_particales.key_consumed": "-1 sleutel" +} diff --git a/src/client/resources/assets/localization/pl-pl.json b/src/client/resources/assets/localization/pl-pl.json new file mode 100644 index 000000000..dadf07806 --- /dev/null +++ b/src/client/resources/assets/localization/pl-pl.json @@ -0,0 +1,146 @@ +{ + "Acorn": "Żołądź", + "AirWizard Spawner": "Spawner AirWizarda", + "Anvil": "Kowadło", + "Apple": "Jabłko", + "Axe": "Topór", + "Baked Potato": "Pieczony ziemniak", + "Bed": "Łóżko", + "Black Clothes": "Czarne ubranie", + "Black Wool": "Czarna wełna", + "Blue Clothes": "Niebieskie ubranie", + "Blue Wool": "Niebieska wełna", + "Bone": "Kość", + "Book": "Książka", + "Bow": "Łuk", + "Bread": "Chleb", + "Cactus": "Kaktus", + "Cactus Sapling": "Sadzonka kaktusa", + "Chest": "Skrzynia", + "Cloud": "Chmura", + "Coal": "Węgiel", + "Cooked Fish": "Przyrządzona ryba", + "Cooked Pork": "Przyrządzona wołowina", + "Cow Spawner": "Spawner krów", + "Creeper Spawner": "Spawner creeperów", + "Cyan Clothes": "Turkusowe ubranie", + "Death Chest": "Skrzynia śmierci", + "Dirt": "Ziemia", + "Empty Bucket": "Puste wiaderko", + "Energy Potion": "Mikstura energii", + "Escape Potion": "Mikstura ucieczki", + "Farmland": "Ziemia uprawna", + "Flower": "Kwiatek", + "Furnace": "Piec", + "Gold": "Złoto", + "Gold Apple": "Złote jabłko", + "Gold Armor": "Złota zbroja", + "Gold Fishing Rod": "Złota wędka", + "Gold Lantern": "Złoty lampion", + "Gold Ore": "Złoże złota", + "Grass": "Trawa", + "Grass Seeds": "Nasiona trawy", + "Green Clothes": "Zielone ubranie", + "Green Wool": "Zielona wełna", + "Gunpowder": "Proch", + "Hard Rock": "Twarda skała", + "Haste Potion": "Mikstura pośpiechu", + "Health Potion": "Mikstura zdrowia", + "Hoe": "Motyka", + "Hole": "Dziura", + "Iron": "Żelazo", + "Iron Armor": "Żelazna zbroja", + "Iron Fishing Rod": "Żelazna wędka", + "Iron Lantern": "Żelazny lampion", + "Iron Ore": "Złoże żelaza", + "Key": "Klucz", + "Knight Spawner": "Spawner rycerzy", + "Lantern": "Lampion", + "Lapis": "Lapis", + "Lava": "Lawa", + "Lava Brick": "Lawowa cegła", + "Lava Bucket": "Wiaderko z lawą", + "Lava Potion": "Mikstura pływania w lawie", + "Leather": "Skóra", + "Leather Armor": "Skórzana zbroja", + "minicraft.achievement.airwizard": "Pokonaj... powietrze?", + "minicraft.achievement.airwizard.desc": "Pokonaj pierwszego Air Wizarda!", + "minicraft.achievement.benchmarking.desc": "Stwórz warsztat.", + "minicraft.achievement.bow": "Uklęknij przede mną!", + "minicraft.achievement.bow.desc": "Wystrzel strzałę z łuku.", + "minicraft.achievement.clothes.desc": "Stwórz ubranie dowolnego koloru", + "minicraft.achievement.demolition.desc": "Użyj TNT.", + "minicraft.achievement.doors.desc": "Stwórz drewniane drzwi.", + "minicraft.achievement.find_gem": "Oooo, świeci się!", + "minicraft.achievement.fish": "Idź na ryby!", + "minicraft.achievement.fish.desc": "Wyłów rybę!", + "minicraft.achievement.lowest_caves.desc": "Dojdź do najniższych jaskiń.", + "minicraft.achievement.obsidian_dungeon.desc": "Dostań się do lochu z obsydianu.", + "minicraft.achievement.planks.desc": "Stwórz deski.", + "minicraft.achievement.skin": "Pokaz mody", + "minicraft.achievement.skin.desc": "Zmień swoją skórkę.", + "minicraft.achievement.survive_darkness": "Boisz się ciemności?", + "minicraft.achievement.survive_darkness.desc": "Przetrwaj 5 minut w zupełnej ciemności.", + "minicraft.achievement.upgrade": "Ulepszenie!", + "minicraft.achievement.upgrade.desc": "Stwórz dowolne kamienne narzędzie.", + "minicraft.achievement.woodcutter": "Drwal", + "minicraft.achievement.woodcutter.desc": "Zdobądź drewno.", + "minicraft.control_guide.move": "Używaj %s do poruszania się.", + "minicraft.display.entries.boolean.false": "Wył.", + "minicraft.display.entries.boolean.true": "Wł.", + "minicraft.display.gui.perm_status.saving": "Zapisywanie... %s%%", + "minicraft.display.gui.perm_status.sleep_cancel": "Naciśnij %s aby anulować", + "minicraft.display.gui.perm_status.sleeping": "Spanie...", + "minicraft.display.gui.score.current_score": "Bieżący wynik: %s", + "minicraft.display.gui.score.time_left": "Pozostało %s%sm %ss", + "minicraft.display.menus.inventory": "Ekwipunek", + "minicraft.display.options_display": "Opcje", + "minicraft.display.options_display.change_key_bindings": "Zmień przypisanie klawiszy", + "minicraft.display.popup.title_confirm": "Potwierdź akcję", + "minicraft.displays.achievements": "Osiągnięcia", + "minicraft.displays.achievements.display.achieved": "Osiągnięto!", + "minicraft.displays.achievements.display.not_achieved": "Nie osiągnięto", + "minicraft.displays.controls": "Sterowanie", + "minicraft.displays.controls.display.controller": "Kontroler", + "minicraft.displays.crafting.container_title.cost": "Koszt:", + "minicraft.displays.end_game.display.final_score": "Wynik ostateczny: %s", + "minicraft.displays.end_game.display.player_score": "Wynik gracza: %s", + "minicraft.displays.end_game.exit": "Wyjdź do Menu", + "minicraft.displays.info.display.score": "Bieżący wynik: %s", + "minicraft.displays.info.title": "Statystyki gracza", + "minicraft.displays.key_input.display.help.0": "Naciśnij C/Enter aby zmienić", + "minicraft.displays.key_input.display.help.1": "Naciśnij A aby dodać", + "minicraft.displays.key_input.popup_display.confirm_reset": "Czy jesteś pewien że chcesz zresetować wszystkie przypisania klawiszy do ustawień domyślnych?", + "minicraft.displays.key_input.title": "Sterowanie", + "minicraft.displays.options_main_menu": "Opcje menu głównego", + "minicraft.displays.options_main_menu.resource_packs": "Paczki z zasobami", + "minicraft.displays.options_world": "Opcje świata", + "minicraft.displays.options_world.off_tutorials_confirm_popup": "Czy jesteś pewien że chcesz trawle wyłączyć samouczki?", + "minicraft.displays.options_world.turn_off_tutorials": "Wyłącz samouczki", + "minicraft.displays.resource_packs.display.title": "Paczki z zasobami", + "minicraft.displays.skin": "Skórki", + "minicraft.displays.title.display.checking": "Sprawdzanie aktualizacji...", + "minicraft.displays.title.display.latest_already": "Posiadasz już najnowszą wersję.", + "minicraft.displays.title.display.new_version": "Nowa wersja: %s", + "minicraft.displays.title.display.version": "Wersja %s", + "minicraft.displays.title.help": "Pomoc", + "minicraft.displays.title.help.about": "O grze", + "minicraft.displays.title.help.credits": "Autorzy", + "minicraft.displays.title.help.instructions": "Instrukcja", + "minicraft.displays.title.help.storyline_guide": "Przewodnik fabularny", + "minicraft.displays.title.link_to_version": "Bezpośredni link do najnowszej wersji: %s", + "minicraft.displays.title.play": "Graj", + "minicraft.displays.title.play.load_world": "Załaduj świat", + "minicraft.displays.title.play.new_world": "Nowy świat", + "minicraft.displays.title.quit": "Wyjdź", + "minicraft.displays.world_gen.title": "Opcje generatora świata", + "minicraft.displays.world_select.display.world_too_new": "Zbyt nowa wersja, nie można załadować!", + "minicraft.displays.world_select.display.world_version": "Wersja Świata: %s", + "minicraft.settings.fps": "Maksymalne FPS", + "minicraft.settings.screenshot_scale": "Skala zrzutów ekranu", + "minicraft.settings.sound": "Dźwięk", + "minicraft.skin.minecraft_alex": "Znajoma dziewczyna", + "minicraft.skin.minecraft_steve": "Znajomy chłopak", + "minicraft.skin.paul": "Paweł", + "minicraft.skin.paul_cape": "Paweł z peleryną" +} diff --git a/src/client/resources/assets/localization/pt-pt.json b/src/client/resources/assets/localization/pt-pt.json index 9d2690063..e55850c6c 100644 --- a/src/client/resources/assets/localization/pt-pt.json +++ b/src/client/resources/assets/localization/pt-pt.json @@ -1,351 +1,341 @@ { - "minicraft.achievement.woodcutter": "Lenhador", - "minicraft.achievement.woodcutter.desc": "Obtenha madeira.", - "minicraft.achievement.benchmarking": "Trabalhar!", - "minicraft.achievement.benchmarking.desc": "Faça uma mesa de trabalho.", - "minicraft.achievement.upgrade": "Melhoria!", - "minicraft.achievement.upgrade.desc": "Crie qualquer ferramenta de pedra.", - "minicraft.achievement.bow": "Curve-se a mim!", - "minicraft.achievement.bow.desc": "Dispare uma flecha com um arco.", - "minicraft.achievement.fish": "Vai pescar!", - "minicraft.achievement.fish.desc": "Pesque um peixe!", - "minicraft.achievement.doors": "Proteção Adorável", - "minicraft.achievement.doors.desc": "Faça uma porta de madeira.", - "minicraft.achievement.planks": "Ande nas pranchas!", - "minicraft.achievement.planks.desc": "Faça pranchas de madeira.", - "minicraft.achievement.clothes": "Tenha um dia colorido!", - "minicraft.achievement.clothes.desc": "Crie qualquer cor de roupa", - "minicraft.achievement.demolition": "Demonstração de demolição", - "minicraft.achievement.demolition.desc": "Usa TNT.", - "minicraft.achievement.survive_darkness": "Medo do escuro?", - "minicraft.achievement.survive_darkness.desc": "Sobreviva 5 minutos na escuridão total.", - "minicraft.achievement.lava": "Assuntos quentes", - "minicraft.achievement.lava.desc": "Usa uma poção de lava para nadar na lava.", - "minicraft.achievement.find_gem": "Oooh Brilhante!", - "minicraft.achievement.find_gem.desc": "Encontra um minério de gema e minere-o.", - "minicraft.achievement.lowest_caves": "Escuridão atrás da luz", - "minicraft.achievement.lowest_caves.desc": "Alcance as cavernas mais baixas.", - "minicraft.achievement.obsidian_dungeon": "De cavaleiros e homens", - "minicraft.achievement.obsidian_dungeon.desc": "Alcance a masmorra de obsidiana.", - "minicraft.achievement.airwizard": "Derrotar... o ar?", - "minicraft.achievement.airwizard.desc": "Derrote o primeiro Mago dos ventos!", - "minicraft.achievement.skin": "Desfile de moda", - "minicraft.achievement.skin.desc": "Muda a tua skin", - "minicraft.display.achievement": "Conquistas", - "minicraft.display.achievement.achieved": "Alcançou!", - "minicraft.display.achievement.not_achieved": "Não alcançado", - "minicraft.display.achievement.score": "Pontuação da conquista:", - "minicraft.notification.achievement_unlocked": "Conquista desbloqueada:", - "Entities": "Entidades", - "Air Wizard: Defeated!": "Mago dos ventos: Derrotado!", - "The Dungeon is now open!": "A masmorra agora está aberta!", - "A costume lies on the ground...": "Uma fantasia se encontra no chão...", - "Can't sleep! ": "Impossível dormir no momento! ", - "Min ": "Min ", - " Sec left!": "Segundo restante!", - "You hear a noise from the surface!": "Ouviste um som vindo da superfíce!", - "Death Chest": "Baú da Morte", - "Player": "Jogador", - "Crafting": "Fabricação", - "Set your home!": "Define a tua casa!", - "Can't set home here!": "Não é possível definir uma casa aqui!", - "Home Sweet Home!": "Lar Doce Lar!", - "Mode penalty: -2 health": "Penalita': -2 pontos de vida", - "You don't have a home!": "Não tens uma casa!", - "You can't go home from here!": "Não podes voltar para a tua casa daqui!", - "Leather Armor": "Armadura de Couro", - "Snake Armor": "Armadura de Serpente", - "Iron Armor": "Armadura de Ferro", - "Gold Armor": "Armadura Dourada", - "Gem Armor": "Armadura de Gema", - "Book": "Livro", + "Acorn": "Noz", + "AirWizard Spawner": "Invocar Mago dos Ventos", "Antidious": "Gibi", - "Empty Bucket": "Balde vazio", - "Water Bucket": "Balde com Água", - "Lava Bucket": "Balde com Lava", - " Bucket": " Balde", - "Red Clothes": "Camisa Vermelha", - "Blue Clothes": "Camisa Azul", - "Green Clothes": "Camisa Verde", - "Yellow Clothes": "Camisa Amarela", + "Anvil": "Bigorna", + "Apple": "Maçã", + "Arrow": "Flecha", + "Axe": "Machado", + "Baked Potato": "Batata assada", + "Bed": "Cama", "Black Clothes": "Camisa Preta", - "Orange Clothes": "Camisa Laranja", - "Purple Clothes": "Camisa Roxa", - "Cyan Clothes": "Camisa Ciana", - "Reg Clothes": "Camisa Regular", + "Black Wool": "Lã Preta", + "Blue Clothes": "Camisa Azul", + "Blue Wool": "Lã Azul", + "Bone": "Osso", + "Book": "Livro", + "Bow": "Arco", "Bread": "Pão", - "Apple": "Maçã", - "Raw Pork": "Carne de Porco crua", - "Raw Fish": "Peixe Cru", - "Raw Beef": "Bife Cru", - "Pork Chop": "Carne de Porco", + "Cactus": "Cacto", + "Cactus Sapling": "Semente de Cacto", + "Chest": "Baú", + "Claymore": "Espada Escocesa", + "Cloth": "Tecido", + "Cloud": "Nuvem", + "Cloud Cactus": "Nuvem de Cacto", + "Coal": "Carvão", "Cooked Fish": "Peixe Assado", "Cooked Pork": "Carne de Porco Assada", - "Steak": "Bife Cozido", - "Gold Apple": "Maçã Dourada", - "Baked Potato": "Batata assada", "Cow Spawner": "Invocar Vaca", - "Pig Spawner": "Invocar Porco", - "Sheep Spawner": "Invocar Cabra", - "Slime Spawner": "Invocar Gosma", - "Zombie Spawner": "Invocar Zumbi", "Creeper Spawner": "Invocar Creeper", - "Skeleton Spawner": "Invocar Esqueleto", - "Snake Spawner": "Invocar Cobra", - "Knight Spawner": "Invocar Cavaleiro", - "AirWizard Spawner": "Invocar Mago dos Ventos", - "Workbench": "Mesa de trabalho", - "Oven": "Forno", - "Furnace": "Fornalha", - "Anvil": "Bigorna", + "Cyan Clothes": "Camisa Ciana", + "Death Chest": "Baú da Morte", + "Dirt": "Terra", + "Empty Bucket": "Balde vazio", "Enchanter": "Encantadora", - "Loom": "Costureira", - "Lantern": "Lamparina", - "Iron Lantern": "Lamparina de Ferro", - "Gold Lantern": "Lamparina de Ouro", - "Tnt": "Dinamite", - "Bed": "Cama", - "Chest": "Baú", - "None Potion": "Poção vazia", - "Speed Potion": "Poção de Agilidade", - "Light Potion": "Poção da Luz", - "Swim Potion": "Poção da Natação", "Energy Potion": "Poção da Energia", - "Regen Potion": "Poção de Regeneração", - "Health Potion": "Poção da Vida", - "Time Potion": "Poção do Tempo", - "Lava Potion": "Poção da Lava", - "Shield Potion": "Poção do Escudo", - "Haste Potion": "Poção de Pressa", "Escape Potion": "Poção de Fuga", - "Potion": "Poção", - "Power Glove": "Luva do Poder", - "Wood": "Madeira", - "Stone": "Pedra", - "Leather": "Couro", - "Wheat": "Trigo", - "Key": "Chave", - "arrow": "Flecha", - "string": "Linha", - "Coal": "Carvão", - "Iron Ore": "Minério de Ferro", - "Lapis": "Lápis", + "Explode": "Explodir", + "Farmland": "Terra Arrada", + "Flower": "Flor", + "Furnace": "Fornalha", + "Gem": "Gema", + "Gem Armor": "Armadura de Gema", + "Gem Fishing Rod": "Vara de pescar de gema", + "Gem Ore": "Minério de gema", + "Glass": "Vidro", + "Gold": "Ouro", + "Gold Apple": "Maçã Dourada", + "Gold Armor": "Armadura Dourada", + "Gold Fishing Rod": "Vara de pescar de ouro", + "Gold Lantern": "Lamparina de Ouro", "Gold Ore": "Minério de Ouro", + "Grass": "Grama", + "Grass Seeds": "Sementes de Erva", + "Green Clothes": "Camisa Verde", + "Green Wool": "Lã Verde", + "Gunpowder": "Pólvora", + "Hard Rock": "Pedra Dura", + "Haste Potion": "Poção de Pressa", + "Health Potion": "Poção da Vida", + "Hoe": "Enxada", + "Hole": "Buraco", + "Infinite Fall": "Queda Infinita", "Iron": "Ferro", - "Gold": "Ouro", - "Rose": "Rosa", - "GunPowder": "Pólvora", - "Slime": "Gosma", - "glass": "Vidro", - "cloth": "Tecido", - "gem": "Gema", - "Scale": "Esquama", - "Shard": "Fragmento", - "Flower": "Flor", - "Acorn": "Noz", - "Dirt": "Terra", + "Iron Armor": "Armadura de Ferro", + "Iron Fishing Rod": "Vara de pescar de ferro", + "Iron Lantern": "Lamparina de Ferro", + "Iron Ore": "Minério de Ferro", + "Key": "Chave", + "Knight Spawner": "Invocar Cavaleiro", + "Lantern": "Lamparina", + "Lapis": "Lápis", + "Lava": "Lava", + "Lava Brick": "Tijolos de Lava", + "Lava Bucket": "Balde com Lava", + "Lava Potion": "Poção da Lava", + "Leather": "Couro", + "Leather Armor": "Armadura de Couro", + "Light Potion": "Poção da Luz", + "Loom": "Costureira", "Natural Rock": "Rocha Natural", - "Plank": "Tábua", - "Plank Wall": "Parede de Madeira", - "Wood Door": "Porta de Madeira", - "Stone Brick": "Tijolos de Pedra", - "Ornate Stone": "Pedra Ornamentada", - "Stone Wall": "Parede de Pedra", - "Stone Door": "Porta de Pedra", + "None Potion": "Poção vazia", + "Obsidian": "Obsidiana", "Obsidian Brick": "Tijolos de Obsidiana", - "Ornate Obsidian": "Obsidiana ornamentada", - "Obsidian Wall": "Parede de Obsidiana", "Obsidian Door": "Porta de Obsidiana", - "Wool": "Lã", + "Obsidian Wall": "Parede de Obsidiana", + "Orange Clothes": "Camisa Laranja", + "Ornate Obsidian": "Obsidiana ornamentada", + "Ornate Stone": "Pedra Ornamentada", + "Oven": "Forno", + "Pickaxe": "Picareta", + "Pig Spawner": "Invocar Porco", + "Plank": "Tábua", + "Plank Wall": "Parede de Madeira", + "Player": "Jogador", + "Pork Chop": "Carne de Porco", + "Potato": "Batata", + "Potion": "Poção", + "Power Glove": "Luva do Poder", + "Purple Clothes": "Camisa Roxa", + "Raw Beef": "Bife Cru", + "Raw Fish": "Peixe Cru", + "Raw Pork": "Carne de Porco crua", + "Red Clothes": "Camisa Vermelha", "Red Wool": "Lã Vermelha", - "Blue Wool": "Lã Azul", - "Green Wool": "Lã Verde", - "Yellow Wool": "Lã Amarela", - "Black Wool": "Lã Preta", + "Reg Clothes": "Camisa Regular", + "Regen Potion": "Poção de Regeneração", + "Rock": "Pedra", + "Rose": "Rosa", "Sand": "Areia", - "Cactus": "Cacto", + "Scale": "Esquama", "Seeds": "Sementes", - "Wheat Seeds": "Sementes de Trigo", - "Grass Seeds": "Sementes de Erva", - "Bone": "Osso", - "Cloud": "Nuvem", - "Rock": "Pedra", - "Gem": "Gema", - "Potato": "Batata", - "Wood Fishing Rod": "Vara de pescar de madeira", - "Iron Fishing Rod": "Vara de pescar de ferro", - "Gold Fishing Rod": "Vara de pescar de ouro", - "Gem Fishing Rod": "Vara de pescar de gema", + "Shard": "Fragmento", + "Shears": "Tesoura", + "Sheep Spawner": "Invocar Cabra", + "Shield Potion": "Poção do Escudo", "Shovel": "Pá", - "Hoe": "Enxada", + "Skeleton Spawner": "Invocar Esqueleto", + "Slime": "Gosma", + "Slime Spawner": "Invocar Gosma", + "Snake Armor": "Armadura de Serpente", + "Snake Spawner": "Invocar Cobra", + "Speed Potion": "Poção de Agilidade", + "Stairs Down": "Escadas abaixo", + "Stairs Up": "Escadas acima", + "Steak": "Bife Cozido", + "Stone": "Pedra", + "Stone Brick": "Tijolos de Pedra", + "Stone Bricks": "Tijolos de Pedra", + "Stone Door": "Porta de Pedra", + "Stone Wall": "Parede de Pedra", + "String": "Linha", + "Swim Potion": "Poção da Natação", "Sword": "Espada", - "Pickaxe": "Picareta", - "Axe": "Machado", - "Bow": "Arco", - "Claymore": "Espada Escocesa", - "Shears": "Tesoura", + "Time Potion": "Poção do Tempo", + "Tnt": "Dinamite", "Torch": "Tocha", - "Gem Ore": "Minério de gema", - "Wood Planks": "Tábuas de Madeira", - "Stone Bricks": "Tijolos de Pedra", - "Obsidian": "Obsidiana", - "Wood Wall": "Parede de Madeira", - "Grass": "Grama", - "Hole": "Buraco", - "Stairs Up": "Escadas acima", - "Stairs Down": "Escadas abaixo", - "Water": "Água", + "Totem of Air": "Totem do ar", "Tree": "Árvore", "Tree Sapling": "Muda de Árvore", - "Cactus Sapling": "Semente de Cacto", - "Lava": "Lava", - "Lava Brick": "Tijolos de Lava", - "Explode": "Explodir", - "Farmland": "Terra Arrada", - "Hard Rock": "Pedra Dura", - "Infinite Fall": "Queda Infinita", - "Cloud Cactus": "Nuvem de Cacto", - "Ore": "Minério", - "host not found": "host não foi encontrado", - "unable to get localhost address": "não foi possível obter o endereço local", - "World Saved!": "Mundo salvo!", - "On": "Ativado", - "Off": "Desativado", - "There is nothing of use here.": "Não há nada de útil aqui.", - "Still nothing... :P": "Ainda nada... :P", - "Have:": "Tem:", - "Cost:": "Custo:", - "Time: ": "Tempo: ", - "Score: ": "Pontuação: ", - "Quit": "Sair", - "Respawn": "Renascer", - "You died! Aww!": "Morreste! Aww!", - "Player Score: ": "Pontuação do jogador: ", - "": "", - "Final Score: ": "Pontuação final: ", - "Exit to Menu": "Voltar ao Menu", - "Time Played: ": "Tempo Jogado: ", - "Current Score: ": "Pontuação atual: ", - "Exit": "Sair", - "Player Stats": "Estatísticas", - "Controls": "Controles", - "Press the desired": "Pressione o botão desejado", - "key sequence": "sequência de teclas", - "minicraft.display.key_input.confirm_popup": "Tens a certeza de que queres redefinir todas as teclas para os padrões?", + "Water": "Água", + "Water Bucket": "Balde com Água", + "Wheat": "Trigo", + "Wheat Seeds": "Sementes de Trigo", + "Wood": "Madeira", + "Wood Door": "Porta de Madeira", + "Wood Fishing Rod": "Vara de pescar de madeira", + "Wood Planks": "Tábuas de Madeira", + "Wood Wall": "Parede de Madeira", + "Wool": "Lã", + "Workbench": "Mesa de trabalho", + "Yellow Clothes": "Camisa Amarela", + "Yellow Wool": "Lã Amarela", + "Zombie Spawner": "Invocar Zumbi", + "minicraft.achievement.airwizard": "Derrotar... o ar?", + "minicraft.achievement.airwizard.desc": "Derrote o primeiro Mago dos ventos!", + "minicraft.achievement.benchmarking": "Trabalhar!", + "minicraft.achievement.benchmarking.desc": "Faça uma mesa de trabalho.", + "minicraft.achievement.bow": "Curve-se a mim!", + "minicraft.achievement.bow.desc": "Dispare uma flecha com um arco.", + "minicraft.achievement.clothes": "Tenha um dia colorido!", + "minicraft.achievement.clothes.desc": "Crie qualquer cor de roupa", + "minicraft.achievement.demolition": "Demonstração de demolição", + "minicraft.achievement.demolition.desc": "Usa TNT.", + "minicraft.achievement.doors": "Proteção Adorável", + "minicraft.achievement.doors.desc": "Faça uma porta de madeira.", + "minicraft.achievement.find_gem": "Oooh Brilhante!", + "minicraft.achievement.find_gem.desc": "Encontra um minério de gema e minere-o.", + "minicraft.achievement.fish": "Vai pescar!", + "minicraft.achievement.fish.desc": "Pesque um peixe!", + "minicraft.achievement.lava": "Assuntos quentes", + "minicraft.achievement.lava.desc": "Usa uma poção de lava para nadar na lava.", + "minicraft.achievement.lowest_caves": "Escuridão atrás da luz", + "minicraft.achievement.lowest_caves.desc": "Alcance as cavernas mais baixas.", + "minicraft.achievement.obsidian_dungeon": "De cavaleiros e homens", + "minicraft.achievement.obsidian_dungeon.desc": "Alcance a masmorra de obsidiana.", + "minicraft.achievement.planks": "Ande nas pranchas!", + "minicraft.achievement.planks.desc": "Faça pranchas de madeira.", + "minicraft.achievement.skin": "Desfile de moda", + "minicraft.achievement.skin.desc": "Muda a tua skin", + "minicraft.achievement.survive_darkness": "Medo do escuro?", + "minicraft.achievement.survive_darkness.desc": "Sobreviva 5 minutos na escuridão total.", + "minicraft.achievement.upgrade": "Melhoria!", + "minicraft.achievement.upgrade.desc": "Crie qualquer ferramenta de pedra.", + "minicraft.achievement.woodcutter": "Lenhador", + "minicraft.achievement.woodcutter.desc": "Obtenha madeira.", + "minicraft.control_guide.move": "Usa %s para te movimentares.", + "minicraft.display.entries.boolean.false": "Não", + "minicraft.display.entries.boolean.true": "Sim", + "minicraft.display.gui.link_opening": "A abrir no browser...", + "minicraft.display.gui.perm_status.saving": "A guardar... %s%%", + "minicraft.display.gui.perm_status.sleep_cancel": "Pressiona %s para cancelar", + "minicraft.display.gui.perm_status.sleeping": "A dormir...", + "minicraft.display.gui.potion_effects.hide_hint": "(%s to ocultar!)", + "minicraft.display.gui.score.current_score": "Pontuação atual: %s", + "minicraft.display.gui.score.time_left": "Tempo restante %s%sm %ss", + "minicraft.display.menus.inventory": "Inventário", + "minicraft.display.options_display": "Definições", + "minicraft.display.options_display.change_key_bindings": "Redefinir atalhos", + "minicraft.display.options_display.language": "Idioma", + "minicraft.display.options_display.resource_packs": "Pacotes de recursos", "minicraft.display.popup.enter_confirm": "enter para confirmar", "minicraft.display.popup.escape_cancel": "esc para cancelar", - "Confirm Action": "Confirmar Ação", - "Press C/Enter to change key binding": "Pressione C/Enter para mudar a vinculação de tecla", - "Press A to add key binding": "Pressione A para adicionar vinculação nova", - "Shift-D to reset all keys to default": "Shift-D para redefinir as teclas para o padrão", - "ESCAPE to Return to menu": "ESC para Retornar ao menu ", - "Loading": "A carregar", - "Generating": "A gerar", - "World": "Mundo", - "waiting": "A esperar", - "nothing": "nada", - "attempting log in": "a tentar iniciar sessão", - "no internet connection, but no login data saved; cannot enter offline mode.": "não há conexão à internet, mas não foi salvo os dados de login; não foi possível entrar no modo offline.", - "connecting to server": "a conectar ao servidor", - "logging in": "a iniciar sessão", - "saving credentials": "a salvar credenciais", - "login failed.": "login falhou.", - "problem with saved login data; please exit and login again.": "problema ao salvar dados de login; por favor saia e inicie uma nova sessão.", - "Internal server error: Couldn't fetch username from uuid": "Erro: Não foi possível obter o nome de usuário por uuid", - "logged in as: ": "identificado como: ", - "offline mode: local servers only": "modo offline: apenas servidores locais", - "Enter ip address to connect to:": "Insira o endereço de conexão:", - "Press Shift-Escape to logout": "Pressione Shift-Escape para encerrar sessão", - "Enter email:": "Insira o e-mail:", - "Enter password:": "Insira a senha:", - "field is blank": "o campo está vazio", - "get an account at:": "cria uma conta em:", - "Loading ": "A carregar ", - " from server": " do servidor", - "Could not connect to server:": "Não foi possível conectar ao servidor:", - "Press ": "Pressione ", - " to return": " para retornar", - "Change Key Bindings": "Mudar atalhos", - "Options": "Opções", - "Change language": "Mudar idioma", - "Return to Game": "Voltar ao Jogo", - "Make World Multiplayer": "Abrir para Multiplayer", - "Save Game": "Salvar o Mundo", - " and ": " e ", - " to Scroll": " para rolar", - ": Choose": ": Selecione", - "Paused": "Pausado", - "Main Menu": "Menu Principal", - "Yes": "Sim", - "No": "Não", - "Inventory": "Inventário", - "to search.": "para pesquisar item", - "Play": "Jogar", - "Load World": "Carregar Mundo", - "New World": "Novo Mundo", - "Multiplayer": "Multijogador", - "Singleplayer": "Um jogador", - "Help": "Ajuda", - "Instructions": "Instruções", - "Storyline Guide": "História", - "About": "Sobre", - "Credits": "Créditos", - " to select": " para selecionar", - " to accept": " para aceitar", - "New World Name:": "Nome do Mundo:", - "Are you sure you want to delete": "Queres mesmo remover", - "This can not be undone!": "Não podes voltar a trás!", - " to confirm": " para confirmar", - " to cancel": " para cancelar", - "World Seed": "Semente", - "Enter World Name": "Insira o nome do mundo", - "Trouble with world name?": "Problemas com o nome?", - "by default, w and s move the cursor up and down. This can be changed in the key binding menu. To type the letter instead of moving the cursor, hold the shift key while typing the world name.": "por padrão, w e s movem o cursor para cima e para baixo. Isso pode ser mudado no menu de atalhos de tecla. Para digitar a letra ao invés de mover o cursor, segure shift enquanto digita o nome do mundo.", - "Create World": "Criar Mundo", - "World Gen Options": "Opções de Geração", - " to Copy": " para Copiar", - " to Rename": " para Renomear", - " to Delete": " para Deletar", - "Select World": "Selecionar mundo", - "Select a World to Delete": "Seleciona um mundo para deletar", - "Select a World to Rename": "Seleciona um mundo para renomear", - "Select a World to Copy": "Seleciona um mundo para copiar", - "Higher version, cannot load world!": "Versão superior, não podes carregar o mundo!", - "World Version:": "Versão do mundo:", - "Languages": "Idiomas", - "Language": "Idioma", - "Select": "Selecione", - "Max FPS": "Limite de fps", - "Difficulty": "Dificuldade", - "Easy": "Fácil", - "Normal": "Normal", - "Hard": "Difícil", - "Game Mode": "Modo de Jogo", - "Survival": "Sobrevivência", - "Creative": "Criativo", - "Hardcore": "Extremo", - "Score": "Pontuação", - "Time (Score Mode)": "Tempo (Modo Pontuação)", - "Sound": "Som", - "Autosave": "Autosalvar", - "World Size": "Tamanho", - "World Theme": "Tema", - "Forest": "Floresta", - "Desert": "Deserto", - "Plain": "Planíce", - "Hell": "Inferno", - "Terrain Type": "Tipo de Terreno", - "Island": "Ilha", - "Box": "Caixa", - "Mountain": "Montanha", - "Irregular": "Irregular", - "Wear Suit": "Guarda-Roupa", - "You have the latest version.": "Tens a última versão.", - "minicraft.display.skin": "Skins", + "minicraft.display.popup.title_confirm": "Confirmar ação", + "minicraft.displays.achievements": "Conquistas", + "minicraft.displays.achievements.display.achieved": "Conquistado!", + "minicraft.displays.achievements.display.help": "Usa %s e %s para te movimentares.", + "minicraft.displays.achievements.display.not_achieved": "Não conquistado", + "minicraft.displays.achievements.display.score": "Pontuação da conquista: %s", + "minicraft.displays.book.default_book": "Este livro não contém nenhum texto.", + "minicraft.displays.controls": "Controlos", + "minicraft.displays.controls.display.controller": "Comando", + "minicraft.displays.controls.display.controller.11": "Para pausar o jogo usa START", + "minicraft.displays.controls.display.keyboard": "Teclado", + "minicraft.displays.crafting": "Criação", + "minicraft.displays.crafting.container_title.cost": "Custo:", + "minicraft.displays.crafting.container_title.have": "Tens:", + "minicraft.displays.end_game.display.final_score": "Pontuação final: %s", + "minicraft.displays.end_game.display.player_score": "Pontuação do jogador: %s", + "minicraft.displays.end_game.exit": "Sair para o menu principal", + "minicraft.displays.info.display.exit_help": "%s/%s:Sair", + "minicraft.displays.info.display.score": "Pontuação atual: %s", + "minicraft.displays.info.display.time": "Tempo de jogo: %s", + "minicraft.displays.info.title": "Estatísticas do jogador", + "minicraft.displays.key_input.display.help.1": "Prime A para adicionar atalho", + "minicraft.displays.key_input.display.help.2": "Shift-D para repor teclas", + "minicraft.displays.key_input.display.help.3": "%s para voltar ao menu principal", + "minicraft.displays.key_input.title": "Controlos", + "minicraft.displays.language_settings.title": "Idioma...", + "minicraft.displays.loading.message.entities": "Entidades", + "minicraft.displays.loading.message.generating": "A gerar", + "minicraft.displays.loading.message.level": "Nível %s", + "minicraft.displays.loading.message.levels": "Níveis", + "minicraft.displays.loading.message.loading": "A carregar", + "minicraft.displays.loading.message.quests": "Missões", + "minicraft.displays.loading.message.saving": "A salvar", + "minicraft.displays.loading.message.world": "Mundo", + "minicraft.displays.loading.regeneration_cancellation_popup.display": "Carregamento do mundo foi cancelado", + "minicraft.displays.loading.regeneration_popup.display.3": "%s para continuar", + "minicraft.displays.loading.regeneration_popup.display.4": "%s para cancelar o carregamento do mundo", + "minicraft.displays.options_main_menu.resource_packs": "Pacotes de recursos", + "minicraft.displays.options_world.off_tutorials_confirm_popup": "Tens a certeza que queres desativar tutoriais para sempre?", + "minicraft.displays.options_world.turn_off_tutorials": "Desativar tutoriais", + "minicraft.displays.pause": "Pausa", + "minicraft.displays.pause.display.exit_popup.0": "Tens a certeza que queres sair do jogo?", + "minicraft.displays.pause.display.exit_popup.cancel": "Cancelar", + "minicraft.displays.pause.display.exit_popup.quit": "Sair sem guardar", + "minicraft.displays.pause.display.help.choose": "%s: Escolher", + "minicraft.displays.pause.menu": "Menu principal", + "minicraft.displays.pause.return": "Voltar ao jogo", + "minicraft.displays.pause.save": "Guardar jogo", + "minicraft.displays.player_death.display.score": "Pontuação: %s", + "minicraft.displays.player_death.display.time": "Tempo: %s", + "minicraft.displays.player_death.quit": "Sair", + "minicraft.displays.player_death.respawn": "Renascer", + "minicraft.displays.player_death.save_quit": "Guardar e sair", + "minicraft.displays.player_death.title": "Morreste! Ah!", + "minicraft.displays.player_inv.container_title.items": "Itens", + "minicraft.displays.player_inv.display.help": "(%s) para procurar.", + "minicraft.displays.quests": "Missões", + "minicraft.displays.quests.display.header.completed": "Completado", + "minicraft.displays.quests.display.header.unlocked": "Desbloqueada", + "minicraft.displays.quests.display.no_quest": "Nenhuma missão desbloqueada", + "minicraft.displays.quests.display.no_quest_desc": "Nenhuma missão", + "minicraft.displays.resource_packs.display.help.move": "Usa %s e %s para te movimentares.", + "minicraft.displays.resource_packs.display.help.position": "SHIFT-[LEFT|RIGHT|UP|DOWN] para mover pacotes.␣", + "minicraft.displays.resource_packs.display.help.select": "%s para examinar.", + "minicraft.displays.resource_packs.display.title": "Pacotes de recurso", + "minicraft.displays.skin": "Skins", + "minicraft.displays.skin.display.help.move": "Usa %s e %s para te movimentares.", + "minicraft.displays.skin.display.help.select": "%s para selecionar e %s para cancelar.", + "minicraft.displays.title.display.help.0": "(%s, %s para selecionar)", + "minicraft.displays.title.display.help.1": "(%s para aceitar)", + "minicraft.displays.title.display.help.2": "(%s para voltar)", + "minicraft.displays.title.display.version": "Versão %s", + "minicraft.displays.title.help": "Ajuda", + "minicraft.displays.title.help.about": "Sobre", + "minicraft.displays.title.help.credits": "Créditos", + "minicraft.displays.title.help.instructions": "Instruções", + "minicraft.displays.title.play": "Jogar", + "minicraft.displays.title.play.load_world": "Carregar mundo", + "minicraft.displays.title.play.new_world": "Novo mundo", + "minicraft.displays.title.quit": "Sair", + "minicraft.displays.world_gen.create_world": "Criar mundo", + "minicraft.displays.world_gen.world_seed": "Seed do mundo", + "minicraft.displays.world_select.display.help.0": "%s para confirmar", + "minicraft.displays.world_select.display.help.1": "%s para voltar", + "minicraft.displays.world_select.display.help.2": "SHIFT-C para copiar", + "minicraft.displays.world_select.display.help.3": "SHIFT-R para renomear", + "minicraft.displays.world_select.display.help.4": "SHIFT-D para eliminar", + "minicraft.displays.world_select.display.world_version": "Versão do mundo: %s", + "minicraft.displays.world_select.popups.display.cancel": "%s para cancelar", + "minicraft.displays.world_select.popups.display.confirm": "%s para confirmar", + "minicraft.displays.world_select.select_world": "Selecionar mundo", + "minicraft.notification.achievement_unlocked": "Conquista desbloqueada:", + "minicraft.notification.air_wizard_defeated": "Mago do Ar foi derrotado!", + "minicraft.notification.dig_hole": "Cava um buraco primeiro!", + "minicraft.notification.invalid_placement": "Só pode ser colocado em", + "minicraft.notification.quest_completed": "Missão completada", + "minicraft.notification.quest_unlocked": "Missão desbloqueada", + "minicraft.notification.world_saved": "O mundo foi salvo!", + "minicraft.quest.farming.crafting_hoe": "Criar uma enxada", + "minicraft.quest.farming.getting_wheat": "Recolher trigo", + "minicraft.quest.iron_equipments.getting_more_iron": "Rico em ferro", + "minicraft.quest.iron_equipments.getting_more_iron.description": "Recolhe mais ferro.", + "minicraft.quest.iron_equipments.iron_armor": "Melhorar armadura", + "minicraft.quest.iron_equipments.iron_armor.description": "Melhorar a tua armadura para ferro.", + "minicraft.quest.iron_equipments.iron_tools": "Melhorar todas as ferramentas", + "minicraft.quest.iron_equipments.iron_tools.description": "Melhorar todas as tuas ferramentas para ferro.", + "minicraft.quest.iron_equipments.upgrading_pickaxe": "Picareta avançada", + "minicraft.quest.iron_equipments.upgrading_pickaxe.description": "Melhorar a tua picareta.", + "minicraft.quest.potions.description": "Obtém poções", + "minicraft.settings.autosave": "Gravação automática", + "minicraft.settings.difficulty": "Dificuldade", + "minicraft.settings.difficulty.easy": "Fácil", + "minicraft.settings.difficulty.hard": "Difícil", + "minicraft.settings.difficulty.normal": "Normal", + "minicraft.settings.mode": "Modo de jogo", + "minicraft.settings.mode.creative": "Criativo", + "minicraft.settings.mode.score": "Pontuação", + "minicraft.settings.mode.survival": "Sobrevivência", + "minicraft.settings.size": "Tamanho do mundo", + "minicraft.settings.sound": "Som", + "minicraft.settings.theme": "Tema do mundo", + "minicraft.settings.theme.desert": "Deserto", + "minicraft.settings.theme.forest": "Floresta", + "minicraft.settings.theme.hell": "Inferno", + "minicraft.settings.theme.plain": "Planície", + "minicraft.settings.type": "Tipo de terreno", + "minicraft.settings.type.island": "Ilha", + "minicraft.settings.type.mountain": "Montanha", + "minicraft.skin.minecraft_alex": "Rapariga conhecida", + "minicraft.skin.minecraft_steve": "Rapaz conhecido", "minicraft.skin.paul": "Paul", "minicraft.skin.paul_cape": "Paul com capa", - "minicraft.skin.minecraft_steve": "Rapaz conhecido", - "minicraft.skin.minecraft_alex": "Rapariga conhecida", - "minicraft.notification.invalid_placement": "Só pode ser colocado em", - "minicraft.notification.dig_hole": "Cava um buraco primeiro!" + "minicraft.tutorial.getting_rocks": "Recolhe pedra e carvão", + "minicraft.tutorial.getting_wood": "Recolhe mais madeira", + "minicraft.tutorial.getting_wooden_pickaxe": "Obtém uma picareta de madeira", + "minicraft.tutorial.getting_workbench": "Obtém uma mesa de trabalho", + "minicraft.tutorial.start_getting_wood": "O começo" } diff --git a/src/client/resources/assets/localization/ru-ru.json b/src/client/resources/assets/localization/ru-ru.json index 04cde3322..e4188b03f 100644 --- a/src/client/resources/assets/localization/ru-ru.json +++ b/src/client/resources/assets/localization/ru-ru.json @@ -1,355 +1,501 @@ { - "minicraft.achievement.woodcutter": "Лесоруб", - "minicraft.achievement.woodcutter.desc": "Добыть древесину.", - "minicraft.achievement.benchmarking": "Бенчмаркинг", - "minicraft.achievement.benchmarking.desc": "Смастерите верстак.", - "minicraft.achievement.upgrade": "Обновка!", - "minicraft.achievement.upgrade.desc": "Создайте любой каменный инструмент.", - "minicraft.achievement.bow": "Кланяйтесь мне!", - "minicraft.achievement.bow.desc": "Выпустить стрелу из лука.", - "minicraft.achievement.fish": "Смотри! Клюнуло!", - "minicraft.achievement.fish.desc": "Словите рыбу!", - "minicraft.achievement.doors": "Дверная защита", - "minicraft.achievement.doors.desc": "Сделайте деревянную дверь.", - "minicraft.achievement.planks": "Ходите по доскам!", - "minicraft.achievement.planks.desc": "Сделайте деревянные доски.", - "minicraft.achievement.clothes": "Желаю красочного вам дня!", - "minicraft.achievement.clothes.desc": "Создайте одежду любого цвета.", - "minicraft.achievement.demolition": "Демонстрация разрушения", - "minicraft.achievement.demolition.desc": "Используйте динамит.", - "minicraft.achievement.survive_darkness": "Боишся темноты?", - "minicraft.achievement.survive_darkness.desc": "Выживите 5 минут в полной темноте.", - "minicraft.achievement.lava": "Горячие делишки", - "minicraft.achievement.lava.desc": "Используйте зелье лавы, чтобы плавать в лаве.", - "minicraft.achievement.find_gem": "Ооо, блестяшка!", - "minicraft.achievement.find_gem.desc": "Найдите самоцветную руду и добывайте ее.", - "minicraft.achievement.lowest_caves": "Тьма за светом", - "minicraft.achievement.lowest_caves.desc": "Достигните самый нижнего уровня пещер.", - "minicraft.achievement.obsidian_dungeon": "О рыцарях и людях", - "minicraft.achievement.obsidian_dungeon.desc": "Достигните обсидианового подземелья.", - "minicraft.achievement.airwizard": "Победить... воздух?", - "minicraft.achievement.airwizard.desc": "Победите первого Небесного Колдуна!", - "minicraft.achievement.second_airwizard": "Воздушный подвиг!", - "minicraft.achievement.second_airwizard.desc": "Победите второго Небесного Колдуна!", - "minicraft.achievement.skin": "Модный приговор", - "minicraft.achievement.skin.desc": "Измените свой прикид.", - "minicraft.display.achievement": "Достижения", - "minicraft.display.achievement.achieved": "Достигнуто!", - "minicraft.display.achievement.not_achieved": "Не достигнуто", - "minicraft.display.achievement.score": "Количество достижений:", - "minicraft.display.key_input.confirm_popup": "Вы уверены, что хотите сбросить все настройки управления по умолчанию?", - "minicraft.display.popup.enter_confirm": "ENTER, чтобы подтвердить", - "minicraft.display.popup.escape_cancel": "ESCAPE, чтобы отменить", - "minicraft.display.skin": "Костюмы", - "minicraft.skin.paul": "Paul", - "minicraft.skin.paul_cape": "Paul с накидкой", - "minicraft.skin.minecraft_steve": "Знакомый парень", - "minicraft.skin.minecraft_alex": "Знакомая девушка", - "minicraft.notification.invalid_placement": "Данный предмет можно поместить только на", - "minicraft.notification.dig_hole": "Сначала выкопайте яму!", - "minicraft.notification.achievement_unlocked": "Достижение получено:", - "minicraft.notification.wrong_level_sky": "Может быть призван только в небесах", - "Entities": "Сущности", - "Air Wizard: Defeated!": "Воздушный Колдун: Побежден!", - "The Dungeon is now open!": "Подземелье теперь открыто!", - "A costume lies on the ground...": "Костюм лежит на земле...", - "Can't sleep!": "Не могу спать!", - "Min ": "Мин ", - " Sec left!": " Остались секунды!", - "You hear a noise from the surface!": "Вы слышите шум с поверхности!", - "Death Chest": "Послесмертный сундук", - "Player": "Игрок", - "Crafting": "Крафтинг", - "Set your home!": "Установите свой дом!", - "Can't set home here!": "Здесь дом не может быть установлен!", - "Home Sweet Home!": "Дом, милый дом!", - "Mode penalty: -2 health": "Штраф за режим: -2 здоровья", - "You don't have a home!": "У тебя нет дома!", - "You can't go home from here!": "Отсюда нельзя вернуться домой!", - "Leather Armor": "Кожаные доспехи", - "Snake Armor": "Змеиная броня", - "Iron Armor": "Железная броня", - "Gold Armor": "Золотая броня", - "Gem Armor": "Алмазная броня", - "Book": "Книга", + "Acorn": "Жёлудь", + "AirWizard Spawner": "Призыватель Небесных колдунов", "Antidious": "Антидия (английский)", - "Empty Bucket": "Пустое ведро", - "Water Bucket": "Ведро с водой", - "Lava Bucket": "Ведро с лавой", - " Bucket": " Ведро", - "Red Clothes": "Красная одежда", - "Blue Clothes": "Синяя одежда", - "Green Clothes": "Зеленая одежда", - "Yellow Clothes": "Желтая одежда", + "Anvil": "Наковальня", + "Apple": "Яблоко", + "Arrow": "Стрела", + "Awkward Potion": "Странное зелье", + "Axe": "Топор", + "Baked Potato": "Печёный картофель", + "Bed": "Кровать", "Black Clothes": "Черная одежда", - "Orange Clothes": "Оранжевая одежда", - "Purple Clothes": "Фиолетовая одежда", - "Cyan Clothes": "Голубая одежда", - "Reg Clothes": "Поношенная одежда", + "Black Wool": "Черная шерсть", + "Blue Clothes": "Синяя одежда", + "Blue Wool": "Синяя шерсть", + "Bone": "Кость", + "Book": "Книга", + "Bow": "Лук", "Bread": "Хлеб", - "Apple": "Яблоко", - "Raw Pork": "Сырая свинина", - "Raw Fish": "Сырая рыба", - "Raw Beef": "Сырая говядина", - "Pork Chop": "Свинная отбивная", - "Cooked Fish": "Приготовленная рыба", - "Cooked Pork": "Приготовленная свинина", - "Steak": "Стейк", - "Gold Apple": "Золотое яблоко", - "Baked Potato": "Печёная картошка", + "Cactus": "Кактус", + "Cactus Sapling": "Саженец кактуса", + "Chest": "Сундук", + "Claymore": "Клеймор", + "Cloth": "Ткань", + "Cloud": "Облако", + "Cloud Cactus": "Облачный кактус", + "Cloud Ore": "Облачная руда", + "Coal": "Уголь", + "Cooked Fish": "Копченая рыба", + "Cooked Pork": "Жареная свинина", "Cow Spawner": "Призыватель коров", - "Pig Spawner": "Призыватель свиней", - "Sheep Spawner": "Призыватель овец", - "Slime Spawner": "Призыватель слизней", - "Zombie Spawner": "Призыватель зомби", - "Creeper Spawner": "Призыватель крипера", - "Skeleton Spawner": "Призыватель скелетов", - "Snake Spawner": "Призыватель змей", - "Knight Spawner": "Призыватель рыцарей", - "AirWizard Spawner": "Призыватель Небесного Колдуна", - "Workbench": "Верстак", - "Oven": "Духовка", + "Creeper Spawner": "Призыватель криперов", + "Cyan Clothes": "Голубая одежда", + "Death Chest": "Сундук смерти", + "Dirt": "Земля", + "Dungeon Chest": "Сундук подземелья", + "Empty Bucket": "Пустое ведро", + "Enchanter": "Алтарь", + "Energy Potion": "Зелье энергии", + "Escape Potion": "Зелье возврата", + "Explode": "Взорвать", + "Farmland": "Вспаханная земля", + "Flower": "Цветок", "Furnace": "Печь", - "Anvil": "Наковальня", - "Enchanter": "Алтарь зачарований", - "Loom": "Ткацкий станок", - "Lantern": "Фонарь", - "Iron Lantern": "Железный фонарь", + "Gem": "Самоцвет", + "Gem Armor": "Самоцветная броня", + "Gem Fishing Rod": "Самоцветовая удочка", + "Gem Ore": "Самоцветная руда", + "Glass": "Стекло", + "Glass Bottle": "Стеклянный пузырёк", + "Gold": "Золотой слиток", + "Gold Apple": "Золотое яблоко", + "Gold Armor": "Золотая броня", + "Gold Fishing Rod": "Золотая удочка", "Gold Lantern": "Золотой фонарь", - "Tnt": "Динамит", - "Bed": "Кровать", - "Chest": "Сундук", - "None Potion": "Зелье без эффекта", - "Speed Potion": "Зелье скорости", - "Light Potion": "Зелье света", - "Swim Potion": "Зелье плаванья", - "Energy Potion": "Зелье энергии", - "Regen Potion": "Зелье регенерации", - "Health Potion": "Зелье здоровья", - "Time Potion": "Зелье времени", - "Lava Potion": "Зелье плаванья в лаве", - "Shield Potion": "Зелье щита", + "Gold Ore": "Золотая руда", + "Grass": "Трава", + "Grass Seeds": "Семена травы", + "Green Clothes": "Зеленая одежда", + "Green Wool": "Зеленая шерсть", + "Gunpowder": "Порох", + "Hard Rock": "Твёрдая скала", "Haste Potion": "Зелье спешки", - "Escape Potion": "Зелье возврата", - "Potion": "Зелье", - "Power Glove": "Перчатка силы", - "Wood": "Дерево", - "Stone": "Камень", - "Leather": "Кожа", - "Wheat": "Пшеница", - "Key": "Ключ", - "arrow": "стрелка", - "string": "строка", - "Coal": "Уголь", + "Health Potion": "Зелье здоровья", + "Hoe": "Мотыга", + "Hole": "Дыра", + "Infinite Fall": "Бездна", + "Iron": "Железный слиток", + "Iron Armor": "Железная броня", + "Iron Fishing Rod": "Железная удочка", + "Iron Lantern": "Железный фонарь", "Iron Ore": "Железная руда", + "Key": "Ключ", + "Knight Spawner": "Призыватель рыцарей", + "Lantern": "Фонарь", "Lapis": "Лазурит", - "Gold Ore": "Золотая руда", - "Iron": "Железный слиток", - "Gold": "Золотой слиток", - "Rose": "Роза", - "GunPowder": "Порох", - "Slime": "Слизь", - "glass": "Стекло", - "cloth": "Ткань", - "gem": "Алмаз", - "Scale": "Змеиная чешуя", - "Shard": "Осколок", - "Flower": "Цветок", - "Acorn": "Желудь", - "Dirt": "Грязь", - "Plank": "Доска", - "Plank Wall": "Стена из досок", - "Wood Door": "Деревянная дверь", - "Stone Brick": "Каменный кирпич", - "Ornate Stone": "Украшенный камень", - "Stone Wall": "Каменная стена", - "Stone Door": "Каменная дверь", + "Lava": "Лава", + "Lava Brick": "Лавовый кирпич", + "Lava Bucket": "Ведро лавы", + "Lava Potion": "Зелье жаростойкости", + "Leather": "Кожа", + "Leather Armor": "Кожаные доспехи", + "Light Potion": "Зелье ночного зрения", + "Loom": "Ткацкий станок", + "Natural Rock": "Природный камень", + "None Potion": "Пустое зелье", + "Obsidian": "Обсидиан", "Obsidian Brick": "Обсидиановый кирпич", - "Ornate Obsidian": "Украшенный обсидиан", - "Obsidian Wall": "Обсидиановая стена", "Obsidian Door": "Обсидиановая дверь", - "Wool": "Шерсть", + "Obsidian Fence": "Обсидиановый забор", + "Obsidian Heart": "Обсидиановое сердце", + "Obsidian Poppet": "Обсидиановая кукла", + "Obsidian Wall": "Обсидиановая стена", + "Orange Clothes": "Оранжевая одежда", + "Ornate Obsidian": "Резной обсидиан", + "Ornate Stone": "Резной камень", + "Oven": "Духовка", + "Path": "Путь", + "Pickaxe": "Кирка", + "Pig Spawner": "Призыватель свиней", + "Plank": "Доска", + "Plank Wall": "Деревянная стена", + "Player": "Игрок", + "Pork Chop": "Жареная свинина", + "Potato": "Картофель", + "Potion": "Зелье", + "Power Glove": "Перчатка силы", + "Purple Clothes": "Фиолетовая одежда", + "Raw Beef": "Сырая говядина", + "Raw Fish": "Сырая рыба", + "Raw Obsidian": "Обсидиан", + "Raw Pork": "Сырая свинина", + "Red Clothes": "Красная одежда", "Red Wool": "Красная шерсть", - "Blue Wool": "Синяя шерсть", - "Green Wool": "Зеленая шерсть", - "Yellow Wool": "Желтая шерсть", - "Black Wool": "Черная шерсть", - "Sand": "Песок", - "Cactus": "Кактус", - "Wheat Seeds": "Семена пшеницы", - "Grass Seeds": "Семена травы", - "Bone": "Кость", - "Cloud": "Облако", + "Reg Clothes": "Обычная одежда", + "Regen Potion": "Зелье регенерации", "Rock": "Камень", - "Gem": "Алмаз", - "Potato": "Картофель", - "Wood Fishing Rod": "Деревянная удочка", - "Iron Fishing Rod": "Железная удочка", - "Gold Fishing Rod": "Золотая удочка", - "Gem Fishing Rod": "Алмазная удочка", + "Rose": "Роза", + "Sand": "Песок", + "Scale": "Чешуя", + "Seeds": "Семена", + "Shard": "Осколок", + "Shears": "Ножницы", + "Sheep Spawner": "Призыватель овец", + "Shield Potion": "Зелье защиты", "Shovel": "Лопата", - "Hoe": "Мотыга", + "Skeleton Spawner": "Призыватель скелетов", + "Slime": "Слизь", + "Slime Spawner": "Призыватель слизней", + "Snake Armor": "Змеиная броня", + "Snake Spawner": "Призыватель змей", + "Speed Potion": "Зелье скорости", + "Stairs Down": "Лестница вниз", + "Stairs Up": "Лестница вверх", + "Steak": "Стейк", + "Stone": "Камень", + "Stone Brick": "Каменный кирпич", + "Stone Bricks": "Каменные кирпичи", + "Stone Door": "Каменная дверь", + "Stone Fence": "Каменный забор", + "Stone Wall": "Каменная стена", + "String": "Нить", + "Swim Potion": "Зелье плавучести", "Sword": "Меч", - "Pickaxe": "Кирка", - "Axe": "Топор", - "Bow": "Лук", - "Claymore": "Клеймор", - "Shears": "Ножницы", + "Time Potion": "Зелье времени", + "Tnt": "Взрывчатка", "Torch": "Факел", - "Gem Ore": "Алмазная руда", - "Wood Planks": "Деревянные доски", - "Stone Bricks": "Каменные кирпичи", - "Obsidian": "Обсидиан", - "Wood Wall": "Деревянная стена", - "Grass": "Трава", - "Natural Rock": "Природный камень", - "Hole": "Дыра", - "Stairs Up": "Лестница вверх", - "Stairs Down": "Лестница вниз", - "Water": "Вода", + "Totem of Air": "Тотем воздуха", "Tree": "Дерево", "Tree Sapling": "Саженец дерева", - "Cactus Sapling": "Саженец кактуса", - "Lava": "Лава", - "Lava Brick": "Лавовый кирпич", - "Explode": "Взорвать", - "Farmland": "Фермерские угодья", - "Hard Rock": "Хард-рок", - "Infinite Fall": "Бесконечное падение", - "Cloud Cactus": "Облачный кактус", - "Ore": "Руда", - "host not found": "хост не найден", - "unable to get localhost address": "не удается получить адрес localhost", - "World Saved!": "Мир спасен!", - "On": "Включено", - "Off": "Не включено", - "There is nothing of use here.": "Здесь нет ничего полезного.", - "Still nothing... :P": "Все еще ничего... :P", - "Have:": "Есть:", - "Cost:": "Затраты:", - "Time: ": "Время: ", - "Score: ": "Счет: ", - "Quit": "Выйти", - "Respawn": "Возродится", - "You died! Aww!": "Ты умер! Какая жалость!", - "Player Score: ": "Счет игрока: ", - "": "<Бонусы>", - "Final Score: ": "Итоговый счет: ", - "Exit to Menu": "Выход в меню", - "Time Played: ": "Время игры: ", - "Current Score: ": "Текущий счет: ", - "Exit": "Выход", - "Player Stats": "Статистика игрока", - "Controls": "Управление", - "Press the desired": "Нажмите нужную", - "key sequence": "последовательность клавиш", - "Are you sure you want to reset all key bindings to the default keys?": "Вы уверены, что хотите сбросить управление полностью по умолчанию?", - "enter to confirm": "ENTER, чтобы подтвердить", - "escape to cancel": "ESCAPE, чтобы отменить", - "Confirm Action": "Подтвердить действие", - "Press C/Enter to change key binding": "Нажмите C/Enter, чтобы изменить привязку клавиш", - "Press A to add key binding": "Нажмите A, чтобы добавить привязку клавиш", - "Shift-D to reset all keys to default": "Нажмите Shift-D для сброса управления по умолчанию", - "ESCAPE to Return to menu": "ESCAPE для возврата к меню ", - "Loading": "Загрузка", - "Generating": "Генерация", - "World": "Мир", - "waiting...": "жду...", - "nothing": "ничего", - "attempting log in": "попытка входа в систему", - "no internet connection, but no login data saved; cannot enter offline mode.": "нет подключения к Интернету, но данные для входа не сохранены; невозможно войти в автономный режим.", - "connecting to server": "подключение к серверу", - "logging in": "вход в систему", - "saving credentials": "сохранение реквизитов", - "login failed.": "не удалось войти в систему", - "problem with saved login data; please exit and login again.": "проблема с сохраненными данными входа; пожалуйста, выйдите и войдите снова.", - "Internal server error: Couldn't fetch username from uuid": "Внутренняя ошибка сервера: Не удалось получить имя пользователя из uuid", - "logged in as: ": "вошел в систему как: ", - "offline mode: local servers only": "автономный режим: только локальные серверы", - "Enter ip address to connect to:": "Введите ip-адрес для подключения:", - "Press Shift-Escape to logout": "Нажмите Shift-Escape для выхода из системы", - "Enter email:": "Введите e-mail:", - "Enter password:": "Введите пароль:", - "field is blank": "поле пустое", - "get an account at:": "получите аккаунт на:", - " from server": " с сервера", - "Could not connect to server:": "Не удалось подключиться к серверу:", - "Press ": "Нажмите ", - " to return": " вернутся", - "Change Key Bindings": "Изменение управления", - "Options": "Опции", - "Change language": "Изменить язык", - "Return to Game": "Вернуться в игру", - "Make World Multiplayer": "Сделать мир многопользовательским", - "Save Game": "Сохранить игру", - " and ": " и ", - " to Scroll": " прокручивать", - ": Choose": ": Выберите", - "Paused": "Приостановлено", - "Main Menu": "Главное меню", - "No": "Нет", - "Yes": "Да", - "Inventory": "Инвентарь", - "to search.": "для поиска.", - "Play": "Играть", - "Load World": "Загрузить мир", - "New World": "Новый мир", - "Multiplayer": "Мультиплеер", - "Singleplayer": "Одиночная игра", - "Help": "Помощь", - "Instructions": "Инструкции", - "Storyline Guide": "Руководство по сюжету", - "About": "О сайте", - "Credits": "Титры", - " to select": " чтобы выбрать", - " to accept": " чтобы принять", - "New World Name:": "Имя нового мира:", - "Are you sure you want to delete": "Вы уверены, что хотите удалить", - "This can not be undone!": "Этого нельзя отменить!", - " to confirm": " чтобы подтвердить", - " to cancel": " чтобы отменить", - "World Seed": "Сид мира", - "Enter World Name": "Введите имя мира", - "Trouble with world name?": "Проблема с названием мира?", - "by default, w and s move the cursor up and down. This can be changed in the key binding menu. To type the letter instead of moving the cursor, hold the shift key while typing the world name.": "по умолчанию w и s перемещают курсор вверх и вниз. Это можно изменить в меню привязки клавиш. Чтобы набрать букву вместо перемещения курсора, удерживайте клавишу shift при наборе названия мира.", - "Create World": "Создать мир", - "World Gen Options": "Опции генерации мира", - " to Copy": " чтобы копировать", - " to Rename": " чтобы переименовать", - " to Delete": " чтобы удалить", - "Select World": "Выбрать мир", - "Select a World to Delete": "Выберите мир для удаления", - "Select a World to Rename": "Выберите мир для переименования", - "Select a World to Copy": "Выберите мир для копирования", - "Higher version, cannot load world!": "Более высокая версия, невозможно загрузить мир!", - "World Version:": "Версия мира:", - "Languages": "Языки", - "Language": "Язык", - "Select": "Выберите", - "Max FPS": "Максимальный FPS", - "Difficulty": "Сложность", - "Easy": "Легко", - "Normal": "Нормально", - "Hard": "Сложно", - "Game Mode": "Игровой режим", - "Survival": "Выживание", - "Creative": "Творческий", - "Hardcore": "Хардкор", - "Score": "На счет", - "Time (Score Mode)": "Время (режим на счет)", - "Sound": "Звук", - "Autosave": "Автосохранение", - "World Size": "Размер мира", - "World Theme": "Тематика мира", - "Forest": "Лес", - "Desert": "Пустыня", - "Plain": "Простой", - "Hell": "Ад", - "Terrain Type": "Тип местности", - "Island": "Остров", - "Box": "Коробка", - "Mountain": "Горная", - "Irregular": "Необычная", - "Wear Suit": "Надеть костюм", - "You have the latest version.": "У вас последняя версия." + "Water": "Вода", + "Water Bucket": "Ведро воды", + "Wheat": "Пшеница", + "Wheat Seeds": "Семена пшеницы", + "Wood": "Древесина", + "Wood Door": "Деревянная дверь", + "Wood Fence": "Деревянный забор", + "Wood Fishing Rod": "Деревянная удочка", + "Wood Planks": "Деревянные доски", + "Wood Wall": "Деревянная стена", + "Wool": "Шерсть", + "Workbench": "Верстак", + "Yellow Clothes": "Желтая одежда", + "Yellow Wool": "Желтая шерсть", + "Zombie Spawner": "Призыватель зомби", + "minicraft.achievement.airwizard": "Победить... воздух?", + "minicraft.achievement.airwizard.desc": "Победите первого Небесного колдуна!", + "minicraft.achievement.benchmarking": "Верстачество", + "minicraft.achievement.benchmarking.desc": "Создайте верстак.", + "minicraft.achievement.boat": "Лодочные права", + "minicraft.achievement.boat.desc": "Смастерите лодку.", + "minicraft.achievement.bow": "Стрелок!", + "minicraft.achievement.bow.desc": "Выстрелить из лука.", + "minicraft.achievement.clothes": "Красочного вам дня!", + "minicraft.achievement.clothes.desc": "Создайте одежду любого цвета.", + "minicraft.achievement.demolition": "Демонстрация Разрушения", + "minicraft.achievement.demolition.desc": "Используйте взрывчатку.", + "minicraft.achievement.doors": "Дверная защита", + "minicraft.achievement.doors.desc": "Создайте деревянную дверь.", + "minicraft.achievement.find_gem": "Ооо, блестяшка!", + "minicraft.achievement.find_gem.desc": "Найдите самоцветную руду и вскопайте ее.", + "minicraft.achievement.fish": "Идем рыбачить!", + "minicraft.achievement.fish.desc": "Поймайте рыбу!", + "minicraft.achievement.lava": "Горячие делишки", + "minicraft.achievement.lava.desc": "Используйте зелье жаростойкости, чтобы плавать в лаве.", + "minicraft.achievement.lowest_caves": "Тьма за светом", + "minicraft.achievement.lowest_caves.desc": "Достигните самого нижнего уровня пещер.", + "minicraft.achievement.obsidian_dungeon": "О рыцарях и людях", + "minicraft.achievement.obsidian_dungeon.desc": "Попадите в обсидиановое подземелье.", + "minicraft.achievement.obsidianknight": "Разбитое Пылающее Сердце", + "minicraft.achievement.obsidianknight.desc": "Победи Обсидианового Рыцаря и заполучи его сердце!", + "minicraft.achievement.planks": "Пройдись по доскам!", + "minicraft.achievement.planks.desc": "Создайте деревянные доски.", + "minicraft.achievement.plant_seed": "Поле чудес", + "minicraft.achievement.plant_seed.desc": "Посадите семечко и наблюдайте как оно растёт.", + "minicraft.achievement.skin": "Модный приговор", + "minicraft.achievement.skin.desc": "Измените свой прикид.", + "minicraft.achievement.survive_darkness": "Боишься темноты?", + "minicraft.achievement.survive_darkness.desc": "Выживите 5 минут в полной темноте.", + "minicraft.achievement.upgrade": "Обновка!", + "minicraft.achievement.upgrade.desc": "Создайте любой каменный инструмент.", + "minicraft.achievement.woodcutter": "Лесоруб", + "minicraft.achievement.woodcutter.desc": "Добудьте древесину.", + "minicraft.control_guide.attack": "Используйте %s, чтобы атаковать мобов или разрушать блоки.", + "minicraft.control_guide.craft": "Используйте %s, чтобы открыть Меню создания.", + "minicraft.control_guide.menu": "Используйте %s, чтобы открыть Меню инвентаря.", + "minicraft.control_guide.move": "Используйте %s, чтобы двигатся.", + "minicraft.display.entries.boolean.false": "Выкл", + "minicraft.display.entries.boolean.true": "Вкл", + "minicraft.display.gui.link_opening": "Открывается в браузере...", + "minicraft.display.gui.perm_status.saving": "Сохранение... %s%%", + "minicraft.display.gui.perm_status.sleep_cancel": "Нажмите %s чтобы отменить", + "minicraft.display.gui.perm_status.sleeping": "Ночёвка...", + "minicraft.display.gui.potion_effects.hide_hint": "(%s чтобы спрятать!)", + "minicraft.display.gui.potion_effects.potion_dur": "%s (%d:%02d)", + "minicraft.display.gui.score.current_score": "Текущий счёт: %s", + "minicraft.display.gui.score.time_left": "Осталось %s%s мин %s сек", + "minicraft.display.menus.inventory": "Инвентарь", + "minicraft.display.options_display": "Настройки", + "minicraft.display.options_display.change_key_bindings": "Изменить управление", + "minicraft.display.options_display.language": "Язык", + "minicraft.display.options_display.resource_packs": "Наборы ресурсов", + "minicraft.display.popup.enter_confirm": "ENTER, чтобы подтвердить", + "minicraft.display.popup.escape_cancel": "ESCAPE для отмены", + "minicraft.display.popup.title_confirm": "Подтвердить действие", + "minicraft.displays.achievements": "Достижения", + "minicraft.displays.achievements.display.achieved": "Получено!", + "minicraft.displays.achievements.display.help": "Используйте %s и %s для навигации.", + "minicraft.displays.achievements.display.not_achieved": "Не получено", + "minicraft.displays.achievements.display.score": "Очков достижений: %s", + "minicraft.displays.book.default_book": "В данной книге нет текста.", + "minicraft.displays.controls": "Управление", + "minicraft.displays.controls.display.controller": "Контроллер", + "minicraft.displays.controls.display.controller.00": "За передвижение игрока отвечает DPAD", + "minicraft.displays.controls.display.controller.01": "За передвижение курсора отвечает DPAD", + "minicraft.displays.controls.display.controller.02": "За выбор элемента отвечает A", + "minicraft.displays.controls.display.controller.03": "За выход со страниц отвечает B", + "minicraft.displays.controls.display.controller.04": "За атаку, разрушение и использование отвечает A", + "minicraft.displays.controls.display.controller.05": "За открытие меню в игре отвечает X", + "minicraft.displays.controls.display.controller.06": "За открытие меню создания отвечает Y", + "minicraft.displays.controls.display.controller.07": "За перетаскивание мебели отвечает LEFTBUMPER", + "minicraft.displays.controls.display.controller.08": "За выбрасывание 1 предмета отвечает RIGHTBUMPER", + "minicraft.displays.controls.display.controller.09": "За выбрасывание стака предметов отвечает RIGHTSTICK", + "minicraft.displays.controls.display.controller.10": "За открытие строки поиска в инвентаре отвечает START", + "minicraft.displays.controls.display.controller.11": "За паузу во время игры отвечает START", + "minicraft.displays.controls.display.controller.12": "Используйте X, чтобы активировать экранную клавиатуру", + "minicraft.displays.controls.display.controller.13": "Используйте B как Backspace на экранной клавиатуре", + "minicraft.displays.controls.display.controller.14": "Используйте X, чтобы убрать выбранный предмет в инвентаре Творческого режима", + "minicraft.displays.controls.display.controller.15": "Используйте Y, чтобы удалить стак предметов в инвентаре Творческого режима", + "minicraft.displays.controls.display.controller.desc.0": "Клавиши отладки недоступны", + "minicraft.displays.controls.display.controller.desc.1": "Детализированные назначения неиспользуемы", + "minicraft.displays.controls.display.help.0": "%s/%s чтобы увидеть другие клавиши управления.", + "minicraft.displays.controls.display.keyboard": "Клавиатура", + "minicraft.displays.controls.display.keyboard.00": "За передвижение игрока отвечает MOVE-(DIRECTION)", + "minicraft.displays.controls.display.keyboard.01": "За передвижение курсора отвечает CURSOR-(DIRECTION)", + "minicraft.displays.controls.display.keyboard.02": "За выбор ячеек отвечает SELECT", + "minicraft.displays.controls.display.keyboard.03": "За выход со страниц отвечает EXIT", + "minicraft.displays.controls.display.keyboard.04": "За быстрое сохранение отвечает QUICKSAVE", + "minicraft.displays.controls.display.keyboard.05": "За атаку, разрушение и использование отвечает ATTACK", + "minicraft.displays.controls.display.keyboard.06": "За открытие внутриигровых меню отвечает MENU", + "minicraft.displays.controls.display.keyboard.07": "За открытие меню создания отвечает CRAFT", + "minicraft.displays.controls.display.keyboard.08": "За перетаскивание мебели отвечает PICKUP", + "minicraft.displays.controls.display.keyboard.09": "За выбрасывание 1 предмета отвечает DROP-ONE", + "minicraft.displays.controls.display.keyboard.10": "За выбрасывание стака предметов отвечает DROP-STACK", + "minicraft.displays.controls.display.keyboard.11": "За переключение строки поиска в меню предметов отвечает SEARCHER_BAR", + "minicraft.displays.controls.display.keyboard.12": "За навигацию по результатам поиска отвечает PAGE-UP/DOWN", + "minicraft.displays.controls.display.keyboard.13": "За паузу отвечает PAUSE", + "minicraft.displays.controls.display.keyboard.14": "За переключение экрана эффектов зелий отвечает POTIONEFFECTS", + "minicraft.displays.controls.display.keyboard.15": "За переключение упрощенного экрана зелий отвечает SIMPPOTIONEFFECTS", + "minicraft.displays.controls.display.keyboard.16": "За временное разворачивание экрана заданий во время игры отвечает EXPANDQUESTDISPLAY", + "minicraft.displays.controls.display.keyboard.17": "За переключение интерфейса отвечает TOGGLEHUD", + "minicraft.displays.controls.display.keyboard.18": "За создание скриншота отвечает SCREENSHOT", + "minicraft.displays.controls.display.keyboard.19": "За отображение внутриигровой информации отвечает INFO", + "minicraft.displays.controls.display.keyboard.20": "За переключение полноэкранного режима отвечает FULLSCREEN", + "minicraft.displays.controls.display.keyboard.21": "Используйте D, чтобы удалить выбранный предмет в инвентаре творческого режима", + "minicraft.displays.controls.display.keyboard.22": "Используйте SHIFT-D чтобы удалить стак предметов в инвентаре в творческого режима", + "minicraft.displays.controls.display.keyboard.desc": "Отладочные клавиши не описаны", + "minicraft.displays.crafting": "Создание", + "minicraft.displays.crafting.container_title.cost": "Цена:", + "minicraft.displays.crafting.container_title.have": "Есть:", + "minicraft.displays.end_game.display.bonuses": "<Бонусы>", + "minicraft.displays.end_game.display.final_score": "Финальный счёт: %s", + "minicraft.displays.end_game.display.player_score": "Счёт игрока: %s", + "minicraft.displays.end_game.display.unlocked": "Открыто! %s Счёт на время", + "minicraft.displays.end_game.exit": "Выйти в меню", + "minicraft.displays.info.display.exit_help": "%s/%s: Выйти", + "minicraft.displays.info.display.score": "Счёт: %s", + "minicraft.displays.info.display.time": "Время игры: %s", + "minicraft.displays.info.title": "Статистика игрока", + "minicraft.displays.key_input.display.help.0": "Нажмите C/Enter чтобы поменять назначенную клавишу.", + "minicraft.displays.key_input.display.help.1": "Нажмите A чтобы добавить клавишу управления.", + "minicraft.displays.key_input.display.help.2": "Shift-D чтобы сбросить управление.", + "minicraft.displays.key_input.display.help.3": "%s чтобы вернутся в меню", + "minicraft.displays.key_input.popup_display.confirm_reset": "Вы уверены, что хотите сбросить все клавиши управления?", + "minicraft.displays.key_input.popup_display.press_key_sequence": "Нажмите желаемую последовательность клавиш", + "minicraft.displays.key_input.title": "Управление", + "minicraft.displays.language_settings.title": "Язык...", + "minicraft.displays.loading.message.dungeon_regeneration": "Восстановление B4", + "minicraft.displays.loading.message.entities": "Существа", + "minicraft.displays.loading.message.generating": "Генерация", + "minicraft.displays.loading.message.level": "Уровень %s", + "minicraft.displays.loading.message.levels": "Уровни", + "minicraft.displays.loading.message.loading": "Загрузка", + "minicraft.displays.loading.message.quests": "Задания", + "minicraft.displays.loading.message.saving": "Сохранение", + "minicraft.displays.loading.message.world": "Мир", + "minicraft.displays.loading.regeneration_cancellation_popup.display": "Загрузка мира отменена", + "minicraft.displays.loading.regeneration_popup.display.0": "Обнаружено подземелье старой версии (этаж B4).", + "minicraft.displays.loading.regeneration_popup.display.1": "Необходима регенерация.", + "minicraft.displays.loading.regeneration_popup.display.2": "Старые данные на этом этаже будут стёрты:", + "minicraft.displays.loading.regeneration_popup.display.3": "%s чтобы продолжить", + "minicraft.displays.loading.regeneration_popup.display.4": "%s чтобы отменить загрузку мира", + "minicraft.displays.options_main_menu": "Настройки", + "minicraft.displays.options_main_menu.resource_packs": "Пакеты ресурсов", + "minicraft.displays.options_world": "Настройки мира", + "minicraft.displays.options_world.off_tutorials_confirm_popup": "Вы уверены, что хотите навсегда выключить обучение?", + "minicraft.displays.options_world.skip_current_tutorial": "Пропустить текущее обучение", + "minicraft.displays.options_world.turn_off_tutorials": "Выключить обучение", + "minicraft.displays.pause": "Пауза", + "minicraft.displays.pause.display.exit_popup.0": "Вы уверены, что хотите выйти из игры?", + "minicraft.displays.pause.display.exit_popup.1": "Весь несохранённый прогресс будет потерян", + "minicraft.displays.pause.display.exit_popup.cancel": "Отмена", + "minicraft.displays.pause.display.exit_popup.quit": "Выйти без сохранения", + "minicraft.displays.pause.display.help.choose": "%s: Выбрать", + "minicraft.displays.pause.display.help.scroll": "%s и %s для навигации", + "minicraft.displays.pause.menu": "Главное меню", + "minicraft.displays.pause.return": "Вернутся к игре", + "minicraft.displays.pause.save": "Сохранить игру", + "minicraft.displays.player_death.display.score": "Счёт: %s", + "minicraft.displays.player_death.display.time": "Время: %s", + "minicraft.displays.player_death.quit": "Выйти", + "minicraft.displays.player_death.respawn": "Возродится", + "minicraft.displays.player_death.save_quit": "Сохранить и выйти", + "minicraft.displays.player_death.title": "Ой! Вы умерли!", + "minicraft.displays.player_inv.container_title.items": "Предметы", + "minicraft.displays.player_inv.display.help": "(%s) для поиска.", + "minicraft.displays.quests": "Задания", + "minicraft.displays.quests.display.header.completed": "Выполнено", + "minicraft.displays.quests.display.header.unlocked": "Открыто", + "minicraft.displays.quests.display.no_quest": "Нет открытых заданий", + "minicraft.displays.quests.display.no_quest_desc": "Нет задания", + "minicraft.displays.quests.quest_info.display.description": "Описание: %s", + "minicraft.displays.quests.quest_info.display.ongoing_quests": "Текущие задания: %s", + "minicraft.displays.quests.quest_info.display.progress": "Прогресс: (%d/%d)", + "minicraft.displays.quests.quest_info.display.progress_uncompleted": "Не завершено", + "minicraft.displays.quests.quest_info.display.quests_completed_count": "Завершённые задания: %d", + "minicraft.displays.quests.quest_info.display.status": "Статус: %s", + "minicraft.displays.quests.quest_info.display.status.completed": "Завершено", + "minicraft.displays.quests.quest_info.display.status.locked": "Закрыто", + "minicraft.displays.quests.quest_info.display.status.unlocked": "Разблокировано", + "minicraft.displays.quests.quest_info.view_quests": "Посмотреть все задания этой серии", + "minicraft.displays.resource_packs.display.help.keyboard_needed": "Доступен только ввод с клавиатуры.", + "minicraft.displays.resource_packs.display.help.move": "Используйте %s и %s для навигации.", + "minicraft.displays.resource_packs.display.help.position": "SHIFT-[LEFT|RIGHT|UP|DOWN] чтобы двигать пакеты. ", + "minicraft.displays.resource_packs.display.help.select": "%s чтобы изучить.", + "minicraft.displays.resource_packs.display.title": "Пакеты ресурсов", + "minicraft.displays.skin": "Скины", + "minicraft.displays.skin.display.help.move": "Используйте %s и %s для навигации.", + "minicraft.displays.skin.display.help.select": "%s для выбора, и %s для отмены.", + "minicraft.displays.title.display.cannot_check": "Невозможно проверить обновления.", + "minicraft.displays.title.display.checking": "Проверка наличия обновлений...", + "minicraft.displays.title.display.help.0": "(%s, %s чтобы выбрать)", + "minicraft.displays.title.display.help.1": "(%s чтобы принять)", + "minicraft.displays.title.display.help.2": "(%s чтобы вернутся)", + "minicraft.displays.title.display.latest_already": "У вас последняя версия.", + "minicraft.displays.title.display.new_version": "Новая: %s", + "minicraft.displays.title.display.version": "Версия %s", + "minicraft.displays.title.help": "Помощь", + "minicraft.displays.title.help.about": "Об игре", + "minicraft.displays.title.help.credits": "Титры", + "minicraft.displays.title.help.instructions": "Инструкции", + "minicraft.displays.title.help.storyline_guide": "Сюжетная линия", + "minicraft.displays.title.link_to_version": "Прямая ссылка на последнюю версию: %s", + "minicraft.displays.title.play": "Играть", + "minicraft.displays.title.play.load_world": "Загрузить мир", + "minicraft.displays.title.play.new_world": "Создать мир", + "minicraft.displays.title.quit": "Выйти", + "minicraft.displays.title.select_to_download": "--Выберите это, чтобы скачать--", + "minicraft.displays.tutorial_display_handler.display.element_examine_help": "Нажмите %s, чтобы узнать подробности текущего обучения.", + "minicraft.displays.world_gen.create_world": "Создать мир", + "minicraft.displays.world_gen.enter_world": "Название мира", + "minicraft.displays.world_gen.title": "Настройки генератора", + "minicraft.displays.world_gen.troublesome_input": "Не можете придумать название?", + "minicraft.displays.world_gen.troublesome_input.msg": "Похоже, вы поставили буквенные клавиши в качестве навигационных. Вы можете изменить это в меню Настроек управления, где они обозначены как \"Курсор-XXX\". Сейчас, чтобы вводить текст вместо перемещения курсора, зажимайте Shift.", + "minicraft.displays.world_gen.world_seed": "Ключ генерации", + "minicraft.displays.world_select.display.help.0": "%s чтобы подтвердить", + "minicraft.displays.world_select.display.help.1": "%s чтобы вернутся", + "minicraft.displays.world_select.display.help.2": "%s чтобы скопировать", + "minicraft.displays.world_select.display.help.3": "%s чтобы переименовать", + "minicraft.displays.world_select.display.help.4": "%s чтобы удалить", + "minicraft.displays.world_select.display.world_too_new": "Более новая версия, невозможно загрузить!", + "minicraft.displays.world_select.display.world_version": "Версия мира: %s", + "minicraft.displays.world_select.popups.display.cancel": "%s для отмены", + "minicraft.displays.world_select.popups.display.change": "Новое название мира:", + "minicraft.displays.world_select.popups.display.confirm": "%s, чтобы подтвердить", + "minicraft.displays.world_select.popups.display.delete": "Вы уверены, что вы хотите удалить %s\"%s\"%s? Это действие необратимо!", + "minicraft.displays.world_select.select_world": "Выбор мира", + "minicraft.notification.achievement_unlocked": "Получено достижение: %s", + "minicraft.notification.air_wizard_defeated": "Небесный колдун побеждён!", + "minicraft.notification.boss_limit": "Нельзя призвать больше боссов", + "minicraft.notification.cannot_sleep": "Вы сможете спать через %s мин %s сек!", + "minicraft.notification.death_chest_retrieved": "Сундук смерти возвращён!", + "minicraft.notification.defeat_air_wizard_first": "Сначала необходимо победить Небесного колдуна.", + "minicraft.notification.defeat_obsidian_knight_first": "Сначала необходимо победить Обсидианового Рыцаря.", + "minicraft.notification.dig_hole": "Сначала выкопайте яму!", + "minicraft.notification.dungeon_opened": "Темница теперь открыта!", + "minicraft.notification.gem_pickaxe_required": "Нужна самоцветная кирка.", + "minicraft.notification.invalid_placement": "Это можно разместить только на %s!", + "minicraft.notification.knight_statue_exists": "Статуя рыцаря существует", + "minicraft.notification.obsidian_knight_awoken": "Обсидиановый Рыцарь был пробужден!", + "minicraft.notification.obsidian_knight_defeated": "Обсидиановый Рыцарь: Повержен!", + "minicraft.notification.quest_completed": "Задание выполнено", + "minicraft.notification.quest_unlocked": "Задание открыто", + "minicraft.notification.spawn_on_boss_tile": "Может быть призван только в Комнате Босса", + "minicraft.notification.tutorials_completed": "Обучения завершены.", + "minicraft.notification.world_saved": "Мир сохранён!", + "minicraft.notification.wrong_level_dungeon": "Может быть призван только на этаже темницы", + "minicraft.notification.wrong_level_sky": "Можно призвать только на небесах", + "minicraft.notifications.statue_tapped": "Вы слышите раздающийся эхом шёпот...", + "minicraft.notifications.statue_touched": "Вы слышите, как статуя вибрирует...", + "minicraft.quest.farming": "Фермерство", + "minicraft.quest.farming.crafting_hoe": "Создание мотыги", + "minicraft.quest.farming.crafting_hoe.description": "Создание любой мотыги на верстаке", + "minicraft.quest.farming.description": "Основы фермерства.", + "minicraft.quest.farming.getting_wheat": "Сбор пшеницы", + "minicraft.quest.farming.getting_wheat.description": "Сбор пшеницы ломанием выросшего урожая.", + "minicraft.quest.farming.making_farmland": "Вспахивание земли", + "minicraft.quest.farming.making_farmland.description": "Вспахивание земли мотыгой путём взаимодействия ей с плиткой земли.", + "minicraft.quest.farming.planting_potato": "Посадка картофеля", + "minicraft.quest.farming.planting_potato.description": "Посадка картофеля путём его размещения во вспаханную землю", + "minicraft.quest.farming.planting_wheat": "Посев пшеницы", + "minicraft.quest.farming.planting_wheat.description": "Посев пшеницы путём рассыпания её семян на вспаханную землю.", + "minicraft.quest.gems": "Дорога самоцветов", + "minicraft.quest.gems.description": "Получение самоцветной экипировки.", + "minicraft.quest.gems.gem_armor": "Мастер защиты", + "minicraft.quest.gems.gem_armor.description": "Получение самоцветной брони.", + "minicraft.quest.gems.gem_claymore": "Мастер оружия", + "minicraft.quest.gems.gem_claymore.description": "Получение самоцветного клеймора.", + "minicraft.quest.iron_equipments": "Мастер железа", + "minicraft.quest.iron_equipments.description": "Получение всей железной экипировки.", + "minicraft.quest.iron_equipments.getting_more_iron": "Железный магнат", + "minicraft.quest.iron_equipments.getting_more_iron.description": "Ещё больше железа.", + "minicraft.quest.iron_equipments.iron_armor": "Улучшение брони", + "minicraft.quest.iron_equipments.iron_armor.description": "Улучшение вашей брони до железной.", + "minicraft.quest.iron_equipments.iron_tools": "Улучшение всех инструментов", + "minicraft.quest.iron_equipments.iron_tools.description": "Улучшение ваших инструментов до железных.", + "minicraft.quest.iron_equipments.upgrading_pickaxe": "Улучшенная кирка", + "minicraft.quest.iron_equipments.upgrading_pickaxe.description": "Улучшение вашей кирки.", + "minicraft.quest.potions": "Зельевар", + "minicraft.quest.potions.all_potions_prepared": "Изучатель зелий", + "minicraft.quest.potions.all_potions_prepared.description": "Получение всех зелий одновременно.", + "minicraft.quest.potions.awkward_potions": "Странное зелье", + "minicraft.quest.potions.awkward_potions.description": "Получение странного зелья", + "minicraft.quest.potions.description": "Получение зелий.", + "minicraft.quest.potions.powerful_potions": "Мощные Зелья", + "minicraft.quest.potions.powerful_potions.description": "Получение полезных и мощных зелий.", + "minicraft.settings.autosave": "Автосохранение", + "minicraft.settings.difficulty": "Сложность", + "minicraft.settings.difficulty.easy": "Легкая", + "minicraft.settings.difficulty.hard": "Тяжелая", + "minicraft.settings.difficulty.normal": "Нормальная", + "minicraft.settings.fps": "Максимальный FPS", + "minicraft.settings.mode": "Режим игры", + "minicraft.settings.mode.creative": "Творческий", + "minicraft.settings.mode.hardcore": "Хардкор", + "minicraft.settings.mode.score": "Счёт", + "minicraft.settings.mode.survival": "Выживание", + "minicraft.settings.quests": "Задания", + "minicraft.settings.scoretime": "Время (Режим счёта)", + "minicraft.settings.screenshot_scale": "Масштаб скриншота", + "minicraft.settings.show_quests": "Панель заданий", + "minicraft.settings.size": "Размер мира", + "minicraft.settings.sound": "Звук", + "minicraft.settings.theme": "Тип мира", + "minicraft.settings.theme.desert": "Пустыня", + "minicraft.settings.theme.forest": "Лес", + "minicraft.settings.theme.hell": "Ад", + "minicraft.settings.theme.normal": "Обычный", + "minicraft.settings.theme.plain": "Плоский", + "minicraft.settings.tutorials": "Обучения", + "minicraft.settings.type": "Тип ландшафта", + "minicraft.settings.type.box": "Коробка", + "minicraft.settings.type.irregular": "Неравномерный", + "minicraft.settings.type.island": "Остров", + "minicraft.settings.type.mountain": "Гора", + "minicraft.skin.minecraft_alex": "Знакомая девушка", + "minicraft.skin.minecraft_steve": "Знакомый парень", + "minicraft.skin.paul": "Павел", + "minicraft.skin.paul_cape": "Павел в плаще", + "minicraft.text_particales.key_consumed": "-1 ключ", + "minicraft.tutorial.getting_rocks": "Получение камня и угля", + "minicraft.tutorial.getting_rocks.description": "Получение как минимум 5 камней и 5 углей путём разрушения скал при помощи кирки.", + "minicraft.tutorial.getting_wood": "Больше дерева", + "minicraft.tutorial.getting_wood.description": "Получение как минимум 10 древесины из деревьев.", + "minicraft.tutorial.getting_wooden_pickaxe": "Получение деревянной кирки", + "minicraft.tutorial.getting_wooden_pickaxe.description": "Создание деревянной кирки в меню создания на верстаке.", + "minicraft.tutorial.getting_workbench": "Получение верстака", + "minicraft.tutorial.getting_workbench.description": "Создание верстака в меню создания и размещение его.", + "minicraft.tutorial.start_getting_wood": "Начало Начал", + "minicraft.tutorial.start_getting_wood.description": "Продолжительно атаковать деревья для получения древесины." } diff --git a/src/client/resources/assets/localization/tr-tr.json b/src/client/resources/assets/localization/tr-tr.json index 397b17dc0..6637b7bee 100644 --- a/src/client/resources/assets/localization/tr-tr.json +++ b/src/client/resources/assets/localization/tr-tr.json @@ -1,351 +1,389 @@ { - "minicraft.achievement.woodcutter": "Oduncu", - "minicraft.achievement.woodcutter.desc": "Ahşap alın.", - "minicraft.achievement.benchmarking": "Çalışmak!", - "minicraft.achievement.benchmarking.desc": "Bir tezgah yapın.", - "minicraft.achievement.upgrade": "Güncelleme!", - "minicraft.achievement.upgrade.desc": "Herhangi bir Taş aleti yapın.", - "minicraft.achievement.bow": "Bana boyun eğ!", - "minicraft.achievement.bow.desc": "Bir yay ile bir ok ateşleyin.", - "minicraft.achievement.fish": "Git Balık!", - "minicraft.achievement.fish.desc": "Bir Balığa Balık Tut!", - "minicraft.achievement.doors": "Kapıda Koruma", - "minicraft.achievement.doors.desc": "Ahşap bir kapı yapın.", - "minicraft.achievement.planks": "Plank'larda Yürüyün!", - "minicraft.achievement.planks.desc": "Ahşap plakalar yapın.", - "minicraft.achievement.clothes": "Renkli bir gün geçirin!", - "minicraft.achievement.clothes.desc": "Herhangi bir renk giysi yapın", - "minicraft.achievement.demolition": "Yıkım Demosu", - "minicraft.achievement.demolition.desc": "TNT'yi kullanın.", - "minicraft.achievement.survive_darkness": "Karanlıktan korkmak?", - "minicraft.achievement.survive_darkness.desc": "Toplam karanlıkta 5 dakika hayatta kalın.", - "minicraft.achievement.lava": "Sıcak işler", - "minicraft.achievement.lava.desc": "Lavda yüzmek için bir lav iksiri kullanın.", - "minicraft.achievement.find_gem": "Oooh Parlak!", - "minicraft.achievement.find_gem.desc": "Gem Cevherini bulun ve benimseyin.", - "minicraft.achievement.lowest_caves": "Işığın ardındaki karanlık", - "minicraft.achievement.lowest_caves.desc": "En alçak mağaralara ulaşın.", - "minicraft.achievement.obsidian_dungeon": "Şövalyeler ve Erkekler", - "minicraft.achievement.obsidian_dungeon.desc": "Obsidyen zindanına ulaşın.", - "minicraft.achievement.airwizard": "Yenilgi... rüzgar mı?", - "minicraft.achievement.airwizard.desc": "İlk Hava Sihirbazını yen!", - "minicraft.achievement.skin": "Moda şovu", - "minicraft.achievement.skin.desc": "Cildinizi değiştirin.", - "minicraft.display.achievement": "Başarılar", - "minicraft.display.achievement.achieved": "Başarıldı!", - "minicraft.display.achievement.not_achieved": "Başarılamadı", - "minicraft.display.achievement.score": "Başarı Puanı:", - "minicraft.notification.achievement_unlocked": "Başarının kilidi açıldı:", - "Entities": "Varlıklar", - "Air Wizard: Defeated!": "Hava Büyücüsü: Yenildi!", - "The Dungeon is now open!": "Zindan açıldı!", - "A costume lies on the ground...": "Bir kostüm yerde duruyor...", - "Can't sleep! ": "Uyuyamam! ", - "Min ": "Dk", - " Sec left!": " Sn kaldı!", - "You hear a noise from the surface!": "Yeryüzünden Bir Ses Duydun!", - "Death Chest": "Ölüm Sandığı", - "Player": "Karakter", - "Crafting": "Üretim", - "Set your home!": "Eviniz ayarlandı!", - "Can't set home here!": "Burası ev ayarlanamıyor!", - "Home Sweet Home!": "Evim Evim Güzel Evim!", - "Mode penalty: -2 health": "Mod cezası: -2 can", - "You don't have a home!": "Eviniz yok!", - "You can't go home from here!": "Buradan eve gidemezsiniz!", - "Leather Armor": "Deri Zırh", - "Snake Armor": "Yılan Zırh", - "Iron Armor": "Demir Zırh", - "Gold Armor": "Altın Zırh", - "Gem Armor": "Kristal Zırh", - "Book": "Kitap", + "Acorn": "Palamut", + "AirWizard Spawner": "HavaBüyücüsü Doğurucu", "Antidious": "Atidos", - "Empty Bucket": "Boş Kova", - "Water Bucket": "Su Kovası", - "Lava Bucket": "Lav Kovası", - " Bucket": " Kova", - "Red Clothes": "Kırmızı Kıyafet", - "Blue Clothes": "Mavi Kıyafet", - "Green Clothes": "Yeşil Kıyafet", - "Yellow Clothes": "Sarı Kıyafet", + "Anvil": "Örs", + "Apple": "Elma", + "Arrow": "Ok", + "Axe": "Balta", + "Baked Potato": "Fırınlanmış patates", + "Bed": "Yatak", "Black Clothes": "Siyah Kıyafet", - "Orange Clothes": "Turuncu Kıyafet", - "Purple Clothes": "Mor Kıyafet", - "Cyan Clothes": "Turkuaz Kıyafet", - "Reg Clothes": "Kıyafet", + "Black Wool": "Siyah Yün", + "Blue Clothes": "Mavi Kıyafet", + "Blue Wool": "Mavi Yün", + "Bone": "Kemik", + "Book": "Kitap", + "Bow": "Yay", "Bread": "Ekmek", - "Apple": "Elma", - "Raw Pork": "Çiğ Domuz Eti", - "Raw Fish": "Çiğ Balık", - "Raw Beef": "Çiğ İnek Eti", - "Pork Chop": "Domuz Pirzola", + "Cactus": "Kaktüs", + "Cactus Sapling": "Kaktüs Fidanı", + "Chest": "Sandık", + "Claymore": "Güçlü Kılıç", + "Cloth": "Kumaş", + "Cloud": "Bulut", + "Cloud Cactus": "Bulut Kaktüsü", + "Cloud Ore": "Bulut Madeni", + "Coal": "Kömür", "Cooked Fish": "Pişmiş Balık", "Cooked Pork": "Pişmiş Domuz Eti", - "Steak": "Pişmiş İnek Eti", - "Gold Apple": "Altın Elma", - "Baked Potato": "Fırınlanmış patates", "Cow Spawner": "İnek Doğurucu", - "Pig Spawner": "Domuz Doğurucu", - "Sheep Spawner": "Koyun Doğurucu", - "Slime Spawner": "Balçık Doğurucu", - "Zombie Spawner": "Hortlak Doğurucu", "Creeper Spawner": "Kripır Doğurucu", - "Skeleton Spawner": "İskelet Doğurucu", - "Snake Spawner": "Yılan Doğurucu", - "Knight Spawner": "Şovalye Doğurucu", - "AirWizard Spawner": "HavaBüyücüsü Doğurucu", - "Workbench": "Çalışma Masası", - "Oven": "Ocak", - "Furnace": "Fırın", - "Anvil": "Örs", + "Cyan Clothes": "Turkuaz Kıyafet", + "Death Chest": "Ölüm Sandığı", + "Dirt": "Toprak", + "Empty Bucket": "Boş Kova", "Enchanter": "Büyü Masası", - "Loom": "Dokuma Tahtası", - "Lantern": "Lamba", - "Iron Lantern": "Demir Lamba", - "Gold Lantern": "Altın Lamba", - "Tnt": "Patlayıcı", - "Bed": "Yatak", - "Chest": "Sandık", - "None Potion": "Boş İksir", - "Speed Potion": "Hız İksiri", - "Light Potion": "Işık İksiri", - "Swim Potion": "Yüzme İksiri", "Energy Potion": "Enerji İksiri", - "Regen Potion": "Yenilenme İksiri", - "Health Potion": "Can İksiri", - "Time Potion": "Zaman İksiri", - "Lava Potion": "Lav İksiri", - "Shield Potion": "Kalkan İksiri", - "Haste Potion": "Acele İksiri", "Escape Potion": "Kaçış İksiri", - "Potion": "Zehir", - "Power Glove": "Güç Eldiveni", - "Wood": "Odun", - "Stone": "Taş", - "Leather": "Deri", - "Wheat": "Buğday", - "Key": "Anahtar", - "arrow": "Ok", - "string": "İp", - "Coal": "Kömür", - "Iron Ore": "Çiğ Demir", - "Lapis": "Lapis", + "Explode": "Patlama", + "Farmland": "Çapalanmış Toprak", + "Flower": "Çiçek", + "Furnace": "Fırın", + "Gem": "Kristal", + "Gem Armor": "Kristal Zırh", + "Gem Fishing Rod": "Mücevher Olta", + "Gem Ore": "Çiğ Kristal", + "Glass": "Cam", + "Gold": "Altın", + "Gold Apple": "Altın Elma", + "Gold Armor": "Altın Zırh", + "Gold Fishing Rod": "Altın Olta", + "Gold Lantern": "Altın Lamba", "Gold Ore": "Çiğ Altın", + "Grass": "Çimen", + "Grass Seeds": "Çimen Tohumu", + "Green Clothes": "Yeşil Kıyafet", + "Green Wool": "Yeşil Yün", + "Gunpowder": "Barut", + "Hard Rock": "Sert Taş", + "Haste Potion": "Acele İksiri", + "Health Potion": "Can İksiri", + "Hoe": "Çapa", + "Hole": "Delik", + "Infinite Fall": "Sonsuz Uçurum", "Iron": "Demir", - "Gold": "Altın", - "Rose": "Gül", - "GunPowder": "Barut", - "Slime": "Balçık", - "glass": "Cam", - "cloth": "Kumaş", - "gem": "Kristal", - "Scale": "Pul", - "Shard": "Kırık Parça", - "Flower": "Çiçek", - "Acorn": "Palamut", - "Dirt": "Toprak", + "Iron Armor": "Demir Zırh", + "Iron Fishing Rod": "Demir Olta", + "Iron Lantern": "Demir Lamba", + "Iron Ore": "Çiğ Demir", + "Key": "Anahtar", + "Knight Spawner": "Şovalye Doğurucu", + "Lantern": "Lamba", + "Lapis": "Lapis", + "Lava": "Lav", + "Lava Brick": "Lav Tuğla", + "Lava Bucket": "Lav Kovası", + "Lava Potion": "Lav İksiri", + "Leather": "Deri", + "Leather Armor": "Deri Zırh", + "Light Potion": "Işık İksiri", + "Loom": "Dokuma Tahtası", "Natural Rock": "Doğal Kaya", - "Plank": "Tahta", - "Plank Wall": "Tahta Duvar", - "Wood Door": "Tahta Kapı", - "Stone Brick": "Taş Tuğla", - "Ornate Stone": "süslü taş", - "Stone Wall": "Taş Duvar", - "Stone Door": "Taş Kapı", + "None Potion": "Boş İksir", + "Obsidian": "Obsidyen", "Obsidian Brick": "Obsidyen Tuğla", - "Ornate Obsidian": "süslü obsidyen", - "Obsidian Wall": "Obsidyen Duvar", "Obsidian Door": "Obsidyen Kapı", - "Wool": "Yün", + "Obsidian Wall": "Obsidyen Duvar", + "Orange Clothes": "Turuncu Kıyafet", + "Ornate Obsidian": "süslü obsidyen", + "Ornate Stone": "süslü taş", + "Oven": "Ocak", + "Pickaxe": "Kazma", + "Pig Spawner": "Domuz Doğurucu", + "Plank": "Tahta", + "Plank Wall": "Tahta Duvar", + "Player": "Karakter", + "Pork Chop": "Domuz Pirzola", + "Potato": "Patates", + "Potion": "Zehir", + "Power Glove": "Güç Eldiveni", + "Purple Clothes": "Mor Kıyafet", + "Raw Beef": "Çiğ İnek Eti", + "Raw Fish": "Çiğ Balık", + "Raw Obsidian": "İşlenmemiş Obsidyen", + "Raw Pork": "Çiğ Domuz Eti", + "Red Clothes": "Kırmızı Kıyafet", "Red Wool": "Kırmızı Yün", - "Blue Wool": "Mavi Yün", - "Green Wool": "Yeşil Yün", - "Yellow Wool": "Sarı Yün", - "Black Wool": "Siyah Yün", + "Reg Clothes": "Kıyafet", + "Regen Potion": "Yenilenme İksiri", + "Rock": "Taş", + "Rose": "Gül", "Sand": "Kum", - "Cactus": "Kaktüs", + "Scale": "Pul", "Seeds": "Tohum", - "Wheat Seeds": "Buğday tohumları", - "Grass Seeds": "Çimen Tohumu", - "Bone": "Kemik", - "Cloud": "Bulut", - "Rock": "Taş", - "Gem": "Kristal", - "Potato": "Patates", - "Wood Fishing Rod": "Ahşap Olta", - "Iron Fishing Rod": "Demir Olta", - "Gold Fishing Rod": "Altın Olta", - "Gem Fishing Rod": "Mücevher Olta", + "Shard": "Kırık Parça", + "Shears": "Makas", + "Sheep Spawner": "Koyun Doğurucu", + "Shield Potion": "Kalkan İksiri", "Shovel": "Kürek", - "Hoe": "Çapa", + "Skeleton Spawner": "İskelet Doğurucu", + "Slime": "Balçık", + "Slime Spawner": "Balçık Doğurucu", + "Snake Armor": "Yılan Zırh", + "Snake Spawner": "Yılan Doğurucu", + "Speed Potion": "Hız İksiri", + "Stairs Down": "Aşağıya Merdiven", + "Stairs Up": "Yukarı Merdiven", + "Steak": "Pişmiş İnek Eti", + "Stone": "Taş", + "Stone Brick": "Taş Tuğla", + "Stone Bricks": "Taş Tuğla", + "Stone Door": "Taş Kapı", + "Stone Wall": "Taş Duvar", + "String": "İp", + "Swim Potion": "Yüzme İksiri", "Sword": "Kılıç", - "Pickaxe": "Kazma", - "Axe": "Balta", - "Bow": "Yay", - "FishingRod": "Olta", - "Claymore": "Güçlü Kılıç", + "Time Potion": "Zaman İksiri", + "Tnt": "Patlayıcı", "Torch": "Meşale", - "Gem Ore": "Çiğ Kristal", - "Wood Planks": "Kalas", - "Stone Bricks": "Taş Tuğla", - "Obsidian": "Obsidyen", - "Wood Wall": "Tahta Duvar", - "Grass": "Çimen", - "Hole": "Delik", - "Stairs Up": "Yukarı Merdiven", - "Stairs Down": "Aşağıya Merdiven", - "Water": "Su", + "Totem of Air": "Hava Totemi", "Tree": "Ağaç", "Tree Sapling": "Fidan", - "Cactus Sapling": "Kaktüs Fidanı", - "Lava": "Lav", - "Lava Brick": "Lav Tuğla", - "Explode": "Patlama", - "Farmland": "Çapalanmış Toprak", - "Hard Rock": "Sert Taş", - "Infinite Fall": "Sonsuz Uçurum", - "Cloud Cactus": "Bulut Kaktüsü", - "Ore": "Maden", - "host not found": "Ağ Bulunamadı", - "unable to get localhost address": "Lokal Ağa Bağlanılamıyor", - "World Saved!": "Dünya Kurtarıldı!", - "On": "Aç", - "Off": "Kapa", - "There is nothing of use here.": "Burda Kullanılcak Birşey Yok.", - "Still nothing... :P": "Hala Bişey Yok... :P", - "Have:": "Elde Bulunan:", - "Cost:": "Gereken Malzemeler:", - "Time: ": "Süre: ", - "Score: ": "Puan: ", - "Quit": "Çıkış", - "Respawn": "Yeniden Doğ", - "You died! Aww!": "Sen Öldün! Iyy!", - "Player Score: ": "Karakter Puanı: ", - "": "", - "Final Score: ": "Final Puan: ", - "Exit to Menu": "Menüye Çık", - "Time Played: ": "Şu Kadar Süre Oynandı: ", - "Current Score: ": "Şuanki Puan: ", - "Exit": "Çıkış", - "Player Stats": "Karakter Özellikleri", - "Controls": "Kontroller", - "Press the desired": "İstenilene Tıkla", - "key sequence": "Tuş Sırası", - "minicraft.display.key_input.confirm_popup": "Bütün Kontrolleri Orjinale Döndürmek İstediğine Eminmisin?", + "Water": "Su", + "Water Bucket": "Su Kovası", + "Wheat": "Buğday", + "Wheat Seeds": "Buğday tohumları", + "Wood": "Odun", + "Wood Door": "Tahta Kapı", + "Wood Fishing Rod": "Ahşap Olta", + "Wood Planks": "Kalas", + "Wood Wall": "Tahta Duvar", + "Wool": "Yün", + "Workbench": "Çalışma Masası", + "Yellow Clothes": "Sarı Kıyafet", + "Yellow Wool": "Sarı Yün", + "Zombie Spawner": "Hortlak Doğurucu", + "minicraft.achievement.airwizard": "Yenilgi... rüzgar mı?", + "minicraft.achievement.airwizard.desc": "İlk Hava Sihirbazını yen!", + "minicraft.achievement.benchmarking": "Çalışmak!", + "minicraft.achievement.benchmarking.desc": "Bir tezgah yapın.", + "minicraft.achievement.bow": "Bana boyun eğ!", + "minicraft.achievement.bow.desc": "Bir yay ile bir ok ateşleyin.", + "minicraft.achievement.clothes": "Renkli bir gün geçirin!", + "minicraft.achievement.clothes.desc": "Herhangi bir renk giysi yapın", + "minicraft.achievement.demolition": "Yıkım Demosu", + "minicraft.achievement.demolition.desc": "TNT'yi kullanın.", + "minicraft.achievement.doors": "Kapıda Koruma", + "minicraft.achievement.doors.desc": "Ahşap bir kapı yapın.", + "minicraft.achievement.find_gem": "Oooh Parlak!", + "minicraft.achievement.find_gem.desc": "Gem Cevherini bulun ve benimseyin.", + "minicraft.achievement.fish": "Git Balık!", + "minicraft.achievement.fish.desc": "Bir Balığa Balık Tut!", + "minicraft.achievement.lava": "Sıcak işler", + "minicraft.achievement.lava.desc": "Lavda yüzmek için bir lav iksiri kullanın.", + "minicraft.achievement.lowest_caves": "Işığın ardındaki karanlık", + "minicraft.achievement.lowest_caves.desc": "En alçak mağaralara ulaşın.", + "minicraft.achievement.obsidian_dungeon": "Şövalyeler ve Erkekler", + "minicraft.achievement.obsidian_dungeon.desc": "Obsidyen zindanına ulaşın.", + "minicraft.achievement.planks": "Plank'larda Yürüyün!", + "minicraft.achievement.planks.desc": "Ahşap plakalar yapın.", + "minicraft.achievement.skin": "Moda şovu", + "minicraft.achievement.skin.desc": "Cildinizi değiştirin.", + "minicraft.achievement.survive_darkness": "Karanlıktan korkmak?", + "minicraft.achievement.survive_darkness.desc": "Toplam karanlıkta 5 dakika hayatta kalın.", + "minicraft.achievement.upgrade": "Güncelleme!", + "minicraft.achievement.upgrade.desc": "Herhangi bir Taş aleti yapın.", + "minicraft.achievement.woodcutter": "Oduncu", + "minicraft.achievement.woodcutter.desc": "Ahşap alın.", + "minicraft.control_guide.attack": "%s ile moblara saldır veya blok kır.", + "minicraft.control_guide.craft": "%s ile üretim menüsünü aç.", + "minicraft.control_guide.menu": "%s ile envater menünü aç.", + "minicraft.control_guide.move": "%s ile haraket et.", + "minicraft.display.entries.boolean.false": "Kapalı", + "minicraft.display.entries.boolean.true": "Açık", + "minicraft.display.gui.link_opening": "Tarayıcıda açılıyor...", + "minicraft.display.gui.perm_status.saving": "Kaydediliyor... %s%%", + "minicraft.display.gui.perm_status.sleep_cancel": "İptal etmek için %s", + "minicraft.display.gui.perm_status.sleeping": "Uyuyor...", + "minicraft.display.gui.potion_effects.hide_hint": "(%s ile saklan!)", + "minicraft.display.gui.potion_effects.potion_dur": "%s (%d:%02d)", + "minicraft.display.gui.score.current_score": "Skor: %s", + "minicraft.display.gui.score.time_left": "Kalan zaman %s%sm %ss", + "minicraft.display.menus.inventory": "Envanter", + "minicraft.display.options_display": "Ayarlar", + "minicraft.display.options_display.change_key_bindings": "Tuş atamalarını değiştir", + "minicraft.display.options_display.language": "Dil", "minicraft.display.popup.enter_confirm": "enter tuşuna basarak kabul edin", "minicraft.display.popup.escape_cancel": "escape tuşuna basarak iptal edin", - "Confirm Action": "Eylemi Kabul Et", - "Press C/Enter to change key binding": "C veya Enter tuşuna basarak kontrolleri değiştirin", - "Press A to add key binding": "A'ya basarak tuş ataması ekle", - "Shift-D to reset all keys to default": "Kontrolleri Resetlemek İçin Shift-D Bas", - "ESCAPE to Return to menu": "Menüye Dönmek İçin Escape'ye Bas ", - "Loading": "Yükleniyor", - "Generating": "Oluşturuluyor", - "World": "Dünya", - "waiting...": "Bekleniyor...", - "nothing": "Hiçbişey Yok", - "attempting log in": "Girilmeye Çalışılıyor", - "no internet connection, but no login data saved; cannot enter offline mode.": "İnternet Yok, Fakat Giriş Bilgisi Kaydedilmedi; Offline Moda Geçiliyor.", - "connecting to server": "Servere Bağlanılıyor", - "logging in": "Giriş Yapılıyor", - "saving credentials": "Bilgiler Kaydediliyor", - "login failed.": "Giriş Yapılamadı.", - "problem with saved login data; please exit and login again.": "Giriş Bilgisinde Sorun Oldu; Lütfen Çıkıp Tekrar Girin.", - "Internal server error: Couldn't fetch username from uuid": "Server Sorunu: Uuid'den Kullanıcı Adı Getirilemedi", - "logged in as: ": "Şu Hesapla Girildi: ", - "offline mode: local servers only": "Offline Mod: Sadece Lokal Serverler Kullanılabilir", - "Enter ip address to connect to:": "İp Adresi Girin Ve Buraya Katılın:", - "Press Shift-Escape to logout": "Shift-Escape Bas Ve Hesaptan Çık", - "Enter email:": "Eposta Girin:", - "Enter password:": "Şifre Girin:", - "field is blank": "Alan Boş!", - "get an account at:": "Şuradan Bir Hesap Alın:", - "Loading ": "Yükleniyor ", - " from server": " Serverden", - "Could not connect to server:": "Bu Yüzden Servere Girilmedi:", - "Press ": "Bas ", - " to return": " İle Geri Dönün", - "Change Key Bindings": "Kontrolleri Değiştir", - "Options": "Ayarlar", - "Change language": "Dil Değiştir", - "Return to Game": "Oyuna Dön", - "Make World Multiplayer": "Dünyayı Çokoyunculu Yapın", - "Save Game": "Oyunu Kaydet", - " and ": " Ve ", - " to Scroll": " Kaydırmak İçin", - ": Choose": ": Seç", - "Paused": "Durduruldu", - "Main Menu": "Ana Menü", - "No": "Hayır", - "Yes": "Evet", - "Inventory": "Envanter", - "to search.": "öğe aramak için.", - "Play": "Oyna", - "Load World": "Dünya Yükle", - "New World": "Yeni Dünya", - "Multiplayer": "Online Dünyaya Katıl", - "Singleplayer": "Tek oyuncu", - "Help": "Yardım", - "Instructions": "Talimatlar", - "Storyline Guide": "Hikaye Kılavuzu", - "About": "Hakkında", - "Credits": "Krediler", - " to select": " ile seç", - " to accept": " ile kabul et", - "New World Name:": "Dünya İsmi:", - "Are you sure you want to delete": "Silmek İçin Eminmisiniz?", - "This can not be undone!": "Bu Tamamlanamıyor!", - " to confirm": " İle Kabul Et", - " to cancel": " İle İptal Et", - "World Seed": "Dünya Oluşum Tohumu", - "Enter World Name": "Dünya İsmi Girin", - "Trouble with world name?": "Dünya İsmi İçin Emin misiniz?", - "by default, w and s move the cursor up and down. This can be changed in the key binding menu. To type the letter instead of moving the cursor, hold the shift key while typing the world name.": "Orjinal Kontrollerle W ve S İle Fareyi Yukarı Ve Aşağı Hareket Ettirin. Bu Kontrol Değiştirme Menüsünden Değiştirilebilir.", - "Create World": "Dünya Oluşturun", - "World Gen Options": "Dünya Oluşum Ayarları", - " to Copy": " kopyalamak", - " to Rename": " yeniden adlandırmak", - " to Delete": " silmek", - "Select World": "Dünya Seç", - "Select a World to Delete": "Silinecek Bir Dünya Seçin", - "Select a World to Rename": "Yeniden Adlandırılacak Bir Dünya Seçin", - "Select a World to Copy": "Kopyalanacak Bir Dünya Seçin", - "Higher version, cannot load world!": "Daha yüksek sürüm, dünyayı yükleyemez!", - "World Version:": "Dünya Versiyonu:", - "Languages": "Diller", - "Language": "Dil", - "Select": "Seç", - "Max FPS": "Maks FPS", - "Difficulty": "Zorluk", - "Easy": "Kolay", - "Normal": "Normal", - "Hard": "Zor", - "Game Mode": "Oyun Modu", - "Survival": "Hayatta Kalma", - "Creative": "Yaratıcılık", - "Hardcore": "Aşırı Zor", - "Score": "Puan", - "Time (Score Mode)": "Süre (Puan Modu)", - "Sound": "Ses", - "Autosave": "Oto-Kayıt", - "World Size": "Dünya Boyutu", - "World Theme": "Dünya Teması", - "Forest": "Orman", - "Desert": "Çöl", - "Plain": "Çayır", - "Hell": "Cehennem", - "Terrain Type": "Arazi Tipi", - "Island": "Ada", - "Box": "Kutu", - "Mountain": "Dağ", - "Irregular": "Düzensiz", - "Wear Suit": "Kıyafet Giy", - "You have the latest version.": "En son sürüme sahipsiniz.", - "minicraft.display.skin": "Ciltler", + "minicraft.display.popup.title_confirm": "Onayla", + "minicraft.displays.achievements": "Başarımlar", + "minicraft.displays.achievements.display.achieved": "Başarıldı!", + "minicraft.displays.achievements.display.help": "%s ve %s ile haraket et", + "minicraft.displays.achievements.display.not_achieved": "Başarılmadı", + "minicraft.displays.achievements.display.score": "Başarım Skoru: %s", + "minicraft.displays.book.default_book": "Bu kitapta yazı yok.", + "minicraft.displays.controls": "Kontroller", + "minicraft.displays.controls.display.controller": "Kontrolcü", + "minicraft.displays.controls.display.controller.00": "Oyuncu DPAD ile haraket ettirilir", + "minicraft.displays.controls.display.controller.01": "İmleç DPAD ile haraket ettirilir", + "minicraft.displays.controls.display.controller.03": "Sayfalardan B ile çıkılır", + "minicraft.displays.controls.display.controller.04": "Varlıklara saldırmak, parçalamak ve bloklarla etkileşime geçmek A'yı kullanır", + "minicraft.displays.controls.display.controller.05": "Oyun içi menüleri X ile açılır", + "minicraft.displays.controls.display.controller.06": "Üretim menüsü Y ile açılır", + "minicraft.displays.controls.display.keyboard.05": "Varlıklara saldırmak, parçalamak ve bloklarla etkileşime geçmek SALDIRI'yı kullanır", + "minicraft.displays.crafting": "Üretim", + "minicraft.displays.crafting.container_title.cost": "Maaliyet:", + "minicraft.displays.crafting.container_title.have": "Sahip:", + "minicraft.displays.end_game.display.bonuses": "", + "minicraft.displays.end_game.display.final_score": "Son skor: %s", + "minicraft.displays.end_game.display.player_score": "Oyuncu skoru: %s", + "minicraft.displays.end_game.display.unlocked": "Açıldı! %s Skor Zamanı", + "minicraft.displays.end_game.exit": "Menüye çık", + "minicraft.displays.info.display.exit_help": "%s/%s: Çık", + "minicraft.displays.info.display.score": "Skor: %s", + "minicraft.displays.info.display.time": "Oynama süresi: %s", + "minicraft.displays.info.title": "Oyuncu İstatistikleri", + "minicraft.displays.key_input.display.help.0": "Atama değiştirmek için C/Enter'a bas", + "minicraft.displays.key_input.display.help.1": "Atama eklemek için A'ya bas", + "minicraft.displays.key_input.display.help.2": "Bütün tuşları sıfırlamak için Shift-D'ye bas", + "minicraft.displays.key_input.display.help.3": "%s ile menüye dön", + "minicraft.displays.key_input.popup_display.confirm_reset": "Bütm atamaları sıfırlamak istediğine emin misin?", + "minicraft.displays.key_input.popup_display.press_key_sequence": "Atamak istediğin tuş sekansına bas", + "minicraft.displays.key_input.title": "Kontroller", + "minicraft.displays.loading.message.entities": "Varlıklar", + "minicraft.displays.loading.message.generating": "Oluşturuluyor", + "minicraft.displays.loading.message.level": "Katman %s", + "minicraft.displays.loading.message.levels": "Katmanlar", + "minicraft.displays.loading.message.loading": "Yükleniyor", + "minicraft.displays.loading.message.saving": "Kaydediliyor", + "minicraft.displays.loading.message.world": "Dünya", + "minicraft.displays.options_main_menu": "Ana Menü Ayaları", + "minicraft.displays.options_main_menu.resource_packs": "Kaynak paketleri", + "minicraft.displays.options_world": "Dünya Ayarları", + "minicraft.displays.options_world.off_tutorials_confirm_popup": "Eğitimleri kalıcı olarak kapatmak istediğinize emin misiniz?", + "minicraft.displays.options_world.turn_off_tutorials": "Eğitimleri kapat", + "minicraft.displays.pause": "Durduruldu", + "minicraft.displays.pause.display.exit_popup.0": "Oyunu kapatmak istediğinize emin misiniz?", + "minicraft.displays.pause.display.exit_popup.1": "Kaydedilmemiş ilerleme kaybedilecek", + "minicraft.displays.pause.display.exit_popup.cancel": "İptal et", + "minicraft.displays.pause.display.exit_popup.quit": "Kaydetmeden Çık", + "minicraft.displays.pause.display.help.choose": "%s: Seç", + "minicraft.displays.pause.display.help.scroll": "%s ve %s ile kaydır", + "minicraft.displays.pause.menu": "Ana Menü", + "minicraft.displays.pause.return": "Oyuna Dön", + "minicraft.displays.pause.save": "Oyunu Kaydet", + "minicraft.displays.player_death.display.score": "Skor: %s", + "minicraft.displays.player_death.display.time": "Zaman: %s", + "minicraft.displays.player_death.quit": "Çık", + "minicraft.displays.player_death.respawn": "Yeniden Doğ", + "minicraft.displays.player_death.save_quit": "Kaydet ve Çık", + "minicraft.displays.player_death.title": "Ah, öldün!", + "minicraft.displays.player_inv.container_title.items": "Eşyalar", + "minicraft.displays.player_inv.display.help": "(%s) ile ara.", + "minicraft.displays.quests": "Görevler", + "minicraft.displays.quests.display.header.completed": "Tamamlandı", + "minicraft.displays.quests.display.header.unlocked": "Açıldı", + "minicraft.displays.quests.display.no_quest_desc": "Görev yok", + "minicraft.displays.resource_packs.display.help.move": "%s ve %s ile haraket et.", + "minicraft.displays.resource_packs.display.help.position": "SHIFT-[SOL|SAĞ|YUKARI|AŞAĞI] ile paketleri sırala", + "minicraft.displays.resource_packs.display.help.select": "%s ile incele.", + "minicraft.displays.resource_packs.display.title": "Kaynak Paketleri", + "minicraft.displays.skin": "Skinler", + "minicraft.displays.skin.display.help.move": "%s ve %s ile hareket et", + "minicraft.displays.skin.display.help.select": "%s ile seç, %s ile iptal et", + "minicraft.displays.title.display.cannot_check": "Güncellemeler kontrol edilemedi", + "minicraft.displays.title.display.checking": "Güncellemer kontrol ediliyor...", + "minicraft.displays.title.display.help.0": "(%s, %s ile seç)", + "minicraft.displays.title.display.help.1": "(%s ile kabul et)", + "minicraft.displays.title.display.help.2": "(%s ile geri dön)", + "minicraft.displays.title.display.latest_already": "En son versiyondasınız.", + "minicraft.displays.title.display.new_version": "Yeni: %s", + "minicraft.displays.title.display.version": "Versiyon %s", + "minicraft.displays.title.help": "Yardım", + "minicraft.displays.title.help.about": "Hakkında", + "minicraft.displays.title.help.credits": "Jenerik", + "minicraft.displays.title.help.instructions": "Talimatlar", + "minicraft.displays.title.help.storyline_guide": "Hikaye Rehberi", + "minicraft.displays.title.link_to_version": "En yeni versiyon linki: %s", + "minicraft.displays.title.play": "Oyna", + "minicraft.displays.title.play.load_world": "Dünya Yükle", + "minicraft.displays.title.play.new_world": "Yeni Dünya", + "minicraft.displays.title.quit": "Çık", + "minicraft.displays.title.select_to_download": "--İndirmek için seç--", + "minicraft.displays.world_gen.create_world": "Dünya Oluştur", + "minicraft.displays.world_gen.enter_world": "Dünya İsmini Gir", + "minicraft.displays.world_gen.title": "Dünya Jenerasyon Ayarları", + "minicraft.displays.world_gen.troublesome_input": "Dünya isminde sorun mu var?", + "minicraft.displays.world_select.display.help.0": "%s ile onayla", + "minicraft.displays.world_select.display.help.1": "%s ile geri dön", + "minicraft.displays.world_select.display.help.2": "SHIFT-C ile kopyala", + "minicraft.displays.world_select.display.help.3": "SHIFT-R ile ismini değiştir", + "minicraft.displays.world_select.display.help.4": "SHIFT-D ile sil", + "minicraft.displays.world_select.display.world_too_new": "Yeni versiyon, dünya yüklenemez!", + "minicraft.displays.world_select.display.world_version": "Dünya Versiyonu: %s", + "minicraft.displays.world_select.popups.display.cancel": "%s ile iptal et", + "minicraft.displays.world_select.popups.display.change": "Yeni Dünya İsmi:", + "minicraft.displays.world_select.popups.display.confirm": "%s ile ", + "minicraft.displays.world_select.popups.display.delete": "%s\"%s\"%s dünyasını silmek istediğine emin misin? Bu geri alınamaz!", + "minicraft.displays.world_select.select_world": "Dünya Seç", + "minicraft.notification.achievement_unlocked": "Başarının kilidi açıldı:", + "minicraft.notification.boss_limit": "Daha fazla Boss çağırılamaz", + "minicraft.notification.cannot_sleep": "Uyuyamazsın! %s Dakika %s Saniye kaldı!", + "minicraft.notification.death_chest_retrieved": "Ölüm sandığı alındı!", + "minicraft.notification.dig_hole": "Önce bir delik kazın!", + "minicraft.notification.dungeon_opened": "Zindan artık açık!", + "minicraft.notification.gem_pickaxe_required": "Mücevher Kazma Gerekli.", + "minicraft.notification.invalid_placement": "Sadece üzerine yerleştirilebilir", + "minicraft.notification.quest_completed": "Görev tamamlandı", + "minicraft.notification.quest_unlocked": "Görev açıldı", + "minicraft.notification.spawn_on_boss_tile": "Sadece Boss odasında çağırılabilir", + "minicraft.notification.world_saved": "Dünya Kaydedildi!", + "minicraft.notification.wrong_level_sky": "Sadece gökyüzü seviyesinde çağırılabilir", + "minicraft.quest.farming.crafting_hoe": "Çapa üretmek", + "minicraft.quest.farming.crafting_hoe.description": "Tezgahtan herhangi bir çapa üret", + "minicraft.quest.farming.description": "Çiftçi olmanın", + "minicraft.quest.farming.getting_wheat": "Buğday Hasadı", + "minicraft.quest.farming.making_farmland": "Tarım arazisi yapmak", + "minicraft.quest.farming.making_farmland.description": "Toprak bloğunu çapa ile işleyerek tarım arazisi yap", + "minicraft.quest.farming.planting_potato": "Patates ekmek", + "minicraft.quest.farming.planting_wheat": "Buğday ekmek", + "minicraft.quest.gems": "Mücevher Yolu", + "minicraft.quest.gems.gem_armor": "Korunmanın Ustası", + "minicraft.quest.iron_equipments": "Demirin Ustası", + "minicraft.quest.iron_equipments.getting_more_iron": "Demirden Zengin", + "minicraft.quest.iron_equipments.iron_tools": "Bütün aletlerini geliştir", + "minicraft.quest.iron_equipments.upgrading_pickaxe": "Gelişmiş kazma", + "minicraft.quest.iron_equipments.upgrading_pickaxe.description": "Kazmanı geliştir.", + "minicraft.quest.potions": "İksirlerin Ustası", + "minicraft.quest.potions.all_potions_prepared": "İksirlerin Araştırmacısı", + "minicraft.quest.potions.all_potions_prepared.description": "Bütün iksirlerini aynı anda elde et.", + "minicraft.quest.potions.awkward_potions": "Garip İksir", + "minicraft.quest.potions.awkward_potions.description": "Garip iksir elde et.", + "minicraft.settings.autosave": "Otomatik Kayıt", + "minicraft.settings.difficulty": "Zorluk", + "minicraft.settings.difficulty.easy": "Kolay", + "minicraft.settings.difficulty.hard": "Zor", + "minicraft.settings.difficulty.normal": "Normal", + "minicraft.settings.fps": "Maks FPS", + "minicraft.settings.mode": "Oyun Modu", + "minicraft.settings.mode.creative": "Yaratıcı", + "minicraft.settings.mode.hardcore": "Zorlayıcı", + "minicraft.settings.mode.score": "Skor", + "minicraft.settings.mode.survival": "Hayatta Kalma", + "minicraft.settings.scoretime": "Zaman (Skor Modu)", + "minicraft.settings.screenshot_scale": "Ekran Görüntüsü Büyüklüğü", + "minicraft.settings.size": "Dün Büyüklüğü", + "minicraft.settings.sound": "Ses", + "minicraft.settings.theme": "Dünya Teması", + "minicraft.settings.theme.desert": "Çöl", + "minicraft.settings.theme.forest": "Orman", + "minicraft.settings.theme.hell": "Cehennem", + "minicraft.settings.theme.normal": "Normal", + "minicraft.settings.theme.plain": "Düzlük", + "minicraft.settings.type": "Arazi Türü", + "minicraft.settings.type.box": "Kutu", + "minicraft.settings.type.irregular": "Düzensiz", + "minicraft.settings.type.island": "Ada", + "minicraft.settings.type.mountain": "Dağ", + "minicraft.skin.minecraft_alex": "tanıdık kız", + "minicraft.skin.minecraft_steve": "tanıdık çocuk", "minicraft.skin.paul": "Paul", "minicraft.skin.paul_cape": "Paul pelerinli", - "minicraft.skin.minecraft_steve": "tanıdık çocuk", - "minicraft.skin.minecraft_alex": "tanıdık kız", - "minicraft.notification.invalid_placement": "Sadece üzerine yerleştirilebilir", - "minicraft.notification.dig_hole": "Önce bir delik kazın!" + "minicraft.text_particales.key_consumed": "-1 anahtar", + "minicraft.tutorial.getting_wood": "Daha fazla odun", + "minicraft.tutorial.getting_wooden_pickaxe": "Tahta kazma elde etmek", + "minicraft.tutorial.getting_workbench": "Tezgah masası almak", + "minicraft.tutorial.start_getting_wood": "Her şeyin başlangıcı", + "minicraft.tutorial.start_getting_wood.description": "Ağaçlara aralıksız saldırarak odun alırsın" } diff --git a/src/client/resources/assets/localization/uk-ua.json b/src/client/resources/assets/localization/uk-ua.json new file mode 100644 index 000000000..7ee9a6d8c --- /dev/null +++ b/src/client/resources/assets/localization/uk-ua.json @@ -0,0 +1,466 @@ +{ + "Acorn": "Жолудь", + "AirWizard Spawner": "Викликач повітряного чарівника", + "Antidious": "Античний", + "Anvil": "Ковадло", + "Apple": "Яблуко", + "Axe": "Сокира", + "Baked Potato": "Приготована картопля", + "Bed": "Ліжко", + "Black Clothes": "Чорний одяг", + "Black Wool": "Чорна шерсть", + "Blue Clothes": "Синій одяг", + "Blue Wool": "Синя шерсть", + "Bone": "Кістка", + "Book": "Книга", + "Bow": "Лук", + "Bread": "Хліб", + "Cactus": "Кактус", + "Cactus Sapling": "Саджанець кактуса", + "Chest": "Скриня", + "Claymore": "Великий меч", + "Cloud": "Хмара", + "Cloud Cactus": "Повітряний кактус", + "Cloud Ore": "Повітряна руда", + "Coal": "Вугілля", + "Cooked Fish": "Приготована риба", + "Cooked Pork": "Приготована яловичина", + "Cow Spawner": "Викликач корови", + "Creeper Spawner": "Викликач кріперів", + "Cyan Clothes": "Блакитний одяг", + "Death Chest": "Скриня мертв'яка", + "Dirt": "Земля", + "Empty Bucket": "Пусте відро", + "Enchanter": "Чарувальний стіл", + "Energy Potion": "Зілля енергії", + "Escape Potion": "Зілля втечі", + "Explode": "Взірвати", + "Farmland": "Угіддя", + "Flower": "Квітка", + "Furnace": "Піч", + "Gem": "Кристал", + "Gem Armor": "Кристалічна броня", + "Gem Fishing Rod": "Кристалічна вудка", + "Gem Ore": "Кристалічна руда", + "Gold": "Золото", + "Gold Apple": "Золоте яблука", + "Gold Armor": "Золота броня", + "Gold Fishing Rod": "Золота вудка", + "Gold Lantern": "Золотий ліхтар", + "Gold Ore": "Золота руда", + "Grass": "Трава", + "Grass Seeds": "Зерно трави", + "Green Clothes": "Зелений одяг", + "Green Wool": "Зелена шерсть", + "Gunpowder": "Порох", + "Hard Rock": "Міцний камінь", + "Haste Potion": "Зілля поспіху", + "Health Potion": "Зілля здоров'я", + "Hoe": "Мотика", + "Hole": "Яма", + "Infinite Fall": "Нескінчене падіння", + "Iron": "Залізо", + "Iron Armor": "Залізна броня", + "Iron Fishing Rod": "Залізна вудка", + "Iron Lantern": "Залізний ліхтар", + "Iron Ore": "Залізна руда", + "Key": "Ключ", + "Knight Spawner": "Викликач лицарів", + "Lantern": "Ліхтар", + "Lapis": "Ляпіс", + "Lava": "Лава", + "Lava Brick": "Лавова цегла", + "Lava Bucket": "Відро з лавою", + "Lava Potion": "Зілля лави", + "Leather": "Шкіра", + "Leather Armor": "Шкіряна броня", + "Light Potion": "Зілля світла", + "Loom": "Ткацький станок", + "Natural Rock": "Натуральний камінь", + "None Potion": "Пусте зілля", + "Obsidian": "Обсідіан", + "Obsidian Brick": "Обсидіанова цегля", + "Obsidian Door": "Обсідіанові двері", + "Obsidian Wall": "Обсідіанова стіна", + "Orange Clothes": "Помаранчевий одяг", + "Ornate Obsidian": "Оздоблений обсидіан", + "Ornate Stone": "Оздоблений камінь", + "Oven": "Духова шафа", + "Pickaxe": "Кирка", + "Pig Spawner": "Викликач свині", + "Plank": "Доска", + "Plank Wall": "Стіна з досок", + "Player": "Гравець", + "Pork Chop": "Свиняча відбивна", + "Potato": "Картопля", + "Potion": "Зілля", + "Power Glove": "Рукавиця сили", + "Purple Clothes": "Фіолетовий одяг", + "Raw Beef": "Сира яловичина", + "Raw Fish": "Сира риба", + "Raw Obsidian": "Сирий обсидіан", + "Raw Pork": "Сира свинина", + "Red Clothes": "Червоний одяг", + "Red Wool": "Червона шерсть", + "Reg Clothes": "Стара одежа", + "Regen Potion": "Зілля відновлення", + "Rock": "Камінь", + "Rose": "Роза", + "Sand": "Пісок", + "Scale": "Зміїна луска", + "Seeds": "Зерно", + "Shard": "Осколок", + "Shears": "Ножиці", + "Sheep Spawner": "Викликач овець", + "Shield Potion": "Зілля захисту", + "Shovel": "Лопата", + "Skeleton Spawner": "Викликач скелетів", + "Slime": "Слайм", + "Slime Spawner": "Викликач слаймів", + "Snake Armor": "Броня зі зміїної шкури", + "Snake Spawner": "Викликач змій", + "Speed Potion": "Зілля швидкості", + "Stairs Down": "Сходи вних", + "Stairs Up": "Сходи вгору", + "Steak": "Стейк", + "Stone": "Каміння", + "Stone Brick": "Кам'яна цегла", + "Stone Bricks": "Кам'яна цегла", + "Stone Door": "Кам'яні двері", + "Stone Wall": "Кам'яна стіна", + "Swim Potion": "Зілля плавання", + "Sword": "Меч", + "Time Potion": "Зілля часу", + "Tnt": "Динаміт", + "Torch": "Смолоскип", + "Totem of Air": "Тотем повітря", + "Tree": "Дерево", + "Tree Sapling": "Саджанець дерева", + "Water": "Вода", + "Water Bucket": "Відро з водою", + "Wheat": "Пшениця", + "Wheat Seeds": "Зерно пшениці", + "Wood": "Деревина", + "Wood Door": "Дерев'яні двері", + "Wood Fishing Rod": "Дерев'яна вудка", + "Wood Planks": "Доски", + "Wood Wall": "Дерев'яна стіна", + "Wool": "Шерсть", + "Workbench": "Верстат", + "Yellow Clothes": "Жовтий одяг", + "Yellow Wool": "Жовта шерсть", + "Zombie Spawner": "Викликач зомбі", + "minicraft.achievement.airwizard": "Перемогти... повітря?", + "minicraft.achievement.airwizard.desc": "Перемогти першого Повітряного Чарівника!", + "minicraft.achievement.benchmarking": "Зверстати верстат", + "minicraft.achievement.benchmarking.desc": "Змайструйте верстат з дерева.", + "minicraft.achievement.bow": "Лук — всьому голова!", + "minicraft.achievement.bow.desc": "Вистреліть з лука.", + "minicraft.achievement.clothes": "Який же кольоровий день!", + "minicraft.achievement.clothes.desc": "Зшийте одяг будь-якого кольору", + "minicraft.achievement.demolition": "Деконструкція", + "minicraft.achievement.demolition.desc": "Використайте динаміт.", + "minicraft.achievement.doors": "Дверний захист", + "minicraft.achievement.doors.desc": "Змайструйте дерев'яні двері.", + "minicraft.achievement.find_gem": "Ох, блищить!", + "minicraft.achievement.find_gem.desc": "Знайдіть та видобудьте кристалічну руду.", + "minicraft.achievement.fish": "Порибальмо!", + "minicraft.achievement.fish.desc": "Впіймайте рибу!", + "minicraft.achievement.lava": "Гаряча ванна", + "minicraft.achievement.lava.desc": "Використайте зілля лави, щоб поплавати у лаві.", + "minicraft.achievement.lowest_caves": "Темрява за світлом", + "minicraft.achievement.lowest_caves.desc": "Досягніть найглибших печер.", + "minicraft.achievement.obsidian_dungeon": "Серед лицарів і людей", + "minicraft.achievement.obsidian_dungeon.desc": "Досягнути обсидіанового підземелля.", + "minicraft.achievement.planks": "Пройдися по дошці!", + "minicraft.achievement.planks.desc": "Змайструйте дошки.", + "minicraft.achievement.skin": "Показ моди", + "minicraft.achievement.skin.desc": "Змініть свій скін.", + "minicraft.achievement.survive_darkness": "Боїтеся темряви?", + "minicraft.achievement.survive_darkness.desc": "Виживіть 5 хвилин в непроглядній тьмі.", + "minicraft.achievement.upgrade": "Оновлення!", + "minicraft.achievement.upgrade.desc": "Змайструйте будь-який кам'яний інструмент.", + "minicraft.achievement.woodcutter": "Лісоруб", + "minicraft.achievement.woodcutter.desc": "Добути деревину.", + "minicraft.control_guide.attack": "Використовуйте %s щоб атакувати істот чи знищувати стіни й скелі.", + "minicraft.control_guide.craft": "Використовуйте %s, щоб відкрити меню крафту.", + "minicraft.control_guide.menu": "Використовуйте %s, щоб відкрити інвентар.", + "minicraft.control_guide.move": "Використовуйте %s для руху.", + "minicraft.display.entries.boolean.false": "Вимк", + "minicraft.display.entries.boolean.true": "Увімк", + "minicraft.display.gui.link_opening": "Відкриваємо в браузері...", + "minicraft.display.gui.perm_status.saving": "Зберігаємось... %s%%", + "minicraft.display.gui.perm_status.sleep_cancel": "Натисніть %s, щоб скасувати", + "minicraft.display.gui.perm_status.sleeping": "Сплю...", + "minicraft.display.gui.potion_effects.hide_hint": "(%s, щоб сховатись!)", + "minicraft.display.gui.potion_effects.potion_dur": "%s (%d:%02d)", + "minicraft.display.gui.score.current_score": "Поточний рахунок: %s", + "minicraft.display.gui.score.time_left": "Часу залишилось %s%sm %ss", + "minicraft.display.menus.inventory": "Інвертар", + "minicraft.display.options_display": "Налаштування", + "minicraft.display.options_display.change_key_bindings": "Змінити прив'язки клавіш", + "minicraft.display.options_display.language": "Мова", + "minicraft.display.options_display.resource_packs": "Пакунки ресурсів", + "minicraft.display.popup.enter_confirm": "enter для підтвердження", + "minicraft.display.popup.escape_cancel": "escape, щоб скасувати", + "minicraft.display.popup.title_confirm": "Підтвердити дію", + "minicraft.displays.achievements": "Досягнення", + "minicraft.displays.achievements.display.achieved": "Досягнено!", + "minicraft.displays.achievements.display.help": "Використовуйте %s і %s для переміщення.", + "minicraft.displays.achievements.display.not_achieved": "Не досягнено", + "minicraft.displays.achievements.display.score": "Рахунок досягнень: %s", + "minicraft.displays.book.default_book": "У цій книзі немає тексту.", + "minicraft.displays.controls": "Керування", + "minicraft.displays.controls.display.controller": "Контролер", + "minicraft.displays.controls.display.controller.00": "Для переміщення гравця використовуйте DPAD", + "minicraft.displays.controls.display.controller.01": "Для переміщення вказівника використовуйте DPAD", + "minicraft.displays.controls.display.controller.02": "Обирайте елементи меню з A", + "minicraft.displays.controls.display.controller.03": "Для виходу зі сторінок використовуйте B", + "minicraft.displays.controls.display.controller.04": "Атакуйте сутності, руйнуйте та взаємодійте з об'єктами використовуючи A", + "minicraft.displays.controls.display.controller.05": "Щоб відкривати ігрові меню використовуйте X", + "minicraft.displays.controls.display.controller.06": "Відкривайте меню крафту з Y", + "minicraft.displays.controls.display.controller.07": "Для підняття меблів використовуйте LEFTBUMPER", + "minicraft.displays.controls.display.controller.08": "Щоб кинути один предмет, використовуйте RIGHTBUMPER", + "minicraft.displays.controls.display.controller.09": "Щоб кинути повний стак предмету, використовуйте RIGHTSTICK", + "minicraft.displays.controls.display.controller.10": "Перемикайте строку пошуку в меню предметів з START", + "minicraft.displays.controls.display.controller.11": "START для призупинки гри", + "minicraft.displays.controls.display.controller.12": "Використовуйте X для перемикання екранної клавіатури при вводі", + "minicraft.displays.controls.display.controller.13": "Використовуйте B як комбінацію клавіш для повернення на екранну клавіатуру", + "minicraft.displays.controls.display.controller.14": "Натисніть X щоб видалити обраний предмет з інвентарю творчого режиму", + "minicraft.displays.controls.display.controller.15": "Натисніть Y щоб видалити стак предметів з інвентарю творчого режиму", + "minicraft.displays.controls.display.controller.desc.0": "Налагоджувальні прив'язки недоступні", + "minicraft.displays.controls.display.controller.desc.1": "Детальні прив'язки дуже важко використовувати", + "minicraft.displays.controls.display.help.0": "%s/%s щоб побачити інші елементи керування.", + "minicraft.displays.controls.display.keyboard": "Клавіатура", + "minicraft.displays.controls.display.keyboard.00": "Рухайте гравця з MOVE-(DIRECTION)", + "minicraft.displays.controls.display.keyboard.01": "Для переміщення вказівника використовуйте CURSOR-(DIRECTION)", + "minicraft.displays.controls.display.keyboard.02": "Обирайте елементи меню з SELECT", + "minicraft.displays.controls.display.keyboard.03": "Виходьте зі сторінок з EXIT", + "minicraft.displays.controls.display.keyboard.04": "Швидке збереження використовує QUICKSAVE", + "minicraft.displays.controls.display.keyboard.05": "Атакуйте істот, знищуйте та взаємодійте з предметами за допомогою ATTACK", + "minicraft.displays.controls.display.keyboard.06": "Відкривайте ігрові меню з MENU", + "minicraft.displays.controls.display.keyboard.07": "Відкривайте меню крафту з CRAFT", + "minicraft.displays.controls.display.keyboard.08": "Для підняття меблів використовуйте PICKUP", + "minicraft.displays.controls.display.keyboard.09": "Щоб кинути один предмет, використовуйте DROP-ONE", + "minicraft.displays.controls.display.keyboard.10": "Щоб кинути цілий стак предмету, використовуйте DROP-STACK", + "minicraft.displays.controls.display.keyboard.11": "Перемикайте пошукову строку з SEARCHER-BAR", + "minicraft.displays.controls.display.keyboard.12": "Проглядайте результати пошуку використовуючи PAGE-UP/DOWN", + "minicraft.displays.controls.display.keyboard.13": "Для призупинки гри використовуйте PAUSE", + "minicraft.displays.controls.display.keyboard.14": "Перемикайте показ зілля з POTIONEFFECTS", + "minicraft.displays.controls.display.keyboard.15": "Перемикайте спрощений показ зілля з SIMPPOTIONEFFECTS", + "minicraft.displays.controls.display.keyboard.16": "Поступове розширення відображення квестів у грі використовує EXPANDQUESTDISPLAY", + "minicraft.displays.controls.display.keyboard.17": "Перемикайте HUD з TOGGLEHUD", + "minicraft.displays.controls.display.keyboard.18": "Використовуйте SCREENSHOT, щоб зняти знімок екрана", + "minicraft.displays.controls.display.keyboard.19": "Показ ігрової інформації використовує INFO", + "minicraft.displays.controls.display.keyboard.20": "Перемикайте повноекранного режиму з FULLSCREEN", + "minicraft.displays.controls.display.keyboard.21": "Натисніть D щоб видалити обраний предмет з інвентарю творчого режиму", + "minicraft.displays.controls.display.keyboard.22": "Використайте SHIFT-D, щоб видалити цілий стак предмету в інвентарі в творчому режимі", + "minicraft.displays.controls.display.keyboard.desc": "Налагоджувальні прив'язки не мають пояснень", + "minicraft.displays.crafting": "Майстрування", + "minicraft.displays.crafting.container_title.cost": "Ціна:", + "minicraft.displays.crafting.container_title.have": "Маю:", + "minicraft.displays.end_game.display.bonuses": "<Бонуси>", + "minicraft.displays.end_game.display.final_score": "Фінальний рахунок: %s", + "minicraft.displays.end_game.display.player_score": "Рахунок гравця: %s", + "minicraft.displays.end_game.display.unlocked": "Розблоковано! Ваш час %s", + "minicraft.displays.end_game.exit": "Вийти у меню", + "minicraft.displays.info.display.exit_help": "%s/%s:Вихід", + "minicraft.displays.info.display.score": "Поточний рахунок: %s", + "minicraft.displays.info.display.time": "Скільки граємо: %s", + "minicraft.displays.info.title": "Статистика гравця", + "minicraft.displays.key_input.display.help.0": "Натисніть C/Enter, щоб змінити прив'язку клавіш", + "minicraft.displays.key_input.display.help.1": "Натисніть A, щоб додати прив'язку клавіш", + "minicraft.displays.key_input.display.help.2": "Shift-D, щоб скинути усі клавіші до налаштувань по замочуванню", + "minicraft.displays.key_input.display.help.3": "%s для повернення в меню", + "minicraft.displays.key_input.popup_display.confirm_reset": "Ви впевнені, що хочете стерти усі прив'язки клавіш?", + "minicraft.displays.key_input.popup_display.press_key_sequence": "Натисніть бажану послідовність клавіш", + "minicraft.displays.key_input.title": "Керування", + "minicraft.displays.language_settings.title": "Мова...", + "minicraft.displays.loading.message.dungeon_regeneration": "Перестворюємо B4", + "minicraft.displays.loading.message.entities": "Істоти", + "minicraft.displays.loading.message.generating": "Генеруємо", + "minicraft.displays.loading.message.level": "Рівень %s", + "minicraft.displays.loading.message.levels": "Рівні", + "minicraft.displays.loading.message.loading": "Завантаження", + "minicraft.displays.loading.message.quests": "Завдання", + "minicraft.displays.loading.message.saving": "Збереження", + "minicraft.displays.loading.message.world": "Світ", + "minicraft.displays.loading.regeneration_cancellation_popup.display": "Завантаження світу скасовано", + "minicraft.displays.loading.regeneration_popup.display.0": "Стара версія підземелля (рівень B4) помічена.", + "minicraft.displays.loading.regeneration_popup.display.1": "Необхідне перестворення.", + "minicraft.displays.loading.regeneration_popup.display.2": "Старі дані на цьому рівні будуть стерті:", + "minicraft.displays.loading.regeneration_popup.display.3": "%s, щоб продовжити", + "minicraft.displays.loading.regeneration_popup.display.4": "%s, щоб скасувати завантаження світу", + "minicraft.displays.options_main_menu": "Опції головного меню", + "minicraft.displays.options_main_menu.resource_packs": "Пакунки ресурсів", + "minicraft.displays.options_world": "Налаштування світу", + "minicraft.displays.options_world.off_tutorials_confirm_popup": "Ви впевнені, що хочете вимкнути підказки назавжди?", + "minicraft.displays.options_world.turn_off_tutorials": "Вимкнути підказки", + "minicraft.displays.pause": "Призупинено", + "minicraft.displays.pause.display.exit_popup.0": "Ви впевнені, що хочете вийти з гри?", + "minicraft.displays.pause.display.exit_popup.1": "Весь незбережений прогрес буде втрачено", + "minicraft.displays.pause.display.exit_popup.cancel": "Скасувати", + "minicraft.displays.pause.display.exit_popup.quit": "Вийти без збереження", + "minicraft.displays.pause.display.help.choose": "%s: оберіть", + "minicraft.displays.pause.display.help.scroll": "%s і %s для прокрутки", + "minicraft.displays.pause.menu": "Головне меню", + "minicraft.displays.pause.return": "Повернутися в гру", + "minicraft.displays.pause.save": "Зберегти гру", + "minicraft.displays.player_death.display.score": "Рахунок: %s", + "minicraft.displays.player_death.display.time": "Час: %s", + "minicraft.displays.player_death.quit": "Вийти", + "minicraft.displays.player_death.respawn": "Відновитись", + "minicraft.displays.player_death.save_quit": "Зберегти та вийти", + "minicraft.displays.player_death.title": "Ви мертвий! Щасти наступного разу!", + "minicraft.displays.player_inv.container_title.items": "Предмети", + "minicraft.displays.player_inv.display.help": "(%s) для пошуку.", + "minicraft.displays.quests": "Завдання", + "minicraft.displays.quests.display.header.completed": "Виконані", + "minicraft.displays.quests.display.header.unlocked": "Розблоковані", + "minicraft.displays.quests.display.no_quest": "Немає розблокованих завдань", + "minicraft.displays.quests.display.no_quest_desc": "Немає завдань", + "minicraft.displays.resource_packs.display.help.keyboard_needed": "Тільки ввід з клавіатури приймається.", + "minicraft.displays.resource_packs.display.help.move": "Використовуйте %s і %s для переміщення.", + "minicraft.displays.resource_packs.display.help.position": "SHIFT-[LEFT|RIGHT|UP|DOWN] щоб переміщати пакунки. ", + "minicraft.displays.resource_packs.display.help.select": "%s, щоб дослідити.", + "minicraft.displays.resource_packs.display.title": "Пакунки ресурсів", + "minicraft.displays.skin": "Скіни", + "minicraft.displays.skin.display.help.move": "Використовуйте %s та %s для переміщення.", + "minicraft.displays.skin.display.help.select": "%s, щоб обрати та %s, щоб скасувати.", + "minicraft.displays.title.display.cannot_check": "Не вдалося перевірити оновлення.", + "minicraft.displays.title.display.checking": "Перевіряємо оновлення...", + "minicraft.displays.title.display.help.0": "(%s, %s, щоб обрати)", + "minicraft.displays.title.display.help.1": "(%s для підтвердження)", + "minicraft.displays.title.display.help.2": "(%s для повернення)", + "minicraft.displays.title.display.latest_already": "Ви маєте останню версію.", + "minicraft.displays.title.display.new_version": "Нова версія: %s", + "minicraft.displays.title.display.version": "Версія %s", + "minicraft.displays.title.help": "Допомога", + "minicraft.displays.title.help.about": "Про", + "minicraft.displays.title.help.credits": "Титри", + "minicraft.displays.title.help.instructions": "Інструкції", + "minicraft.displays.title.help.storyline_guide": "Ввід у сюжет", + "minicraft.displays.title.link_to_version": "Посилання на останню версію: %s", + "minicraft.displays.title.play": "Грати", + "minicraft.displays.title.play.load_world": "Завантажити світ", + "minicraft.displays.title.play.new_world": "Новий світ", + "minicraft.displays.title.quit": "Вийти", + "minicraft.displays.title.select_to_download": "--Оберіть тут для завантаження--", + "minicraft.displays.tutorial_display_handler.display.element_examine_help": "Натисніть %s, щоб переглянути подробиці щодо підказки.", + "minicraft.displays.world_gen.create_world": "Створити світ", + "minicraft.displays.world_gen.enter_world": "Введіть ім'я для світу", + "minicraft.displays.world_gen.title": "Налаштування генерації світу", + "minicraft.displays.world_gen.troublesome_input": "Проблеми з вводом імені?", + "minicraft.displays.world_gen.troublesome_input.msg": "схоже, що ви прив'язали клавіші з літерами до переміщення вказівника вгору та вниз, що може набридати. Це можна змінити в меню прив'язок клавіш у полях \"cursor-XXX\". Доки що ви можете надрукувати літеру не переміщуючи курсор натискаючи клавішу shift.", + "minicraft.displays.world_gen.world_seed": "Сід світу", + "minicraft.displays.world_select.display.help.0": "%s для підтвердження", + "minicraft.displays.world_select.display.help.1": "%s для повернення", + "minicraft.displays.world_select.display.help.2": "SHIFT-C для копіювання", + "minicraft.displays.world_select.display.help.3": "SHIFT-R для перейменування", + "minicraft.displays.world_select.display.help.4": "SHIFT-D для видалення", + "minicraft.displays.world_select.display.world_too_new": "Не можу завантажити світ з вищої версії, ніж у вас!", + "minicraft.displays.world_select.display.world_version": "Версія світу: %s", + "minicraft.displays.world_select.popups.display.cancel": "%s, щоб скасувати", + "minicraft.displays.world_select.popups.display.change": "Нове ім'я світу:", + "minicraft.displays.world_select.popups.display.confirm": "%s для підтвердження", + "minicraft.displays.world_select.popups.display.delete": "Ви впевнені, що хочете видалити\n%s\"%s\"%s?\nЦе не може бути скасовано!", + "minicraft.displays.world_select.select_world": "Оберіть світ", + "minicraft.notification.achievement_unlocked": "Досягнення розблоковано: %s", + "minicraft.notification.air_wizard_defeated": "Повітряного чарівника подолано!", + "minicraft.notification.boss_limit": "Не можна викликати більше босів", + "minicraft.notification.cannot_sleep": "Не можу спати! Залишилося %s хвилин і %s секунд!", + "minicraft.notification.death_chest_retrieved": "Скриню мертв'яка забрано!", + "minicraft.notification.defeat_air_wizard_first": "Спочатку треба перемогти повітряного чарівника.", + "minicraft.notification.defeat_obsidian_knight_first": "Спочатку треба перемогти обсидіанового лицаря.", + "minicraft.notification.dig_hole": "Спочатку викопайте яму!", + "minicraft.notification.dungeon_opened": "Підземелля відчинено!", + "minicraft.notification.gem_pickaxe_required": "Необхідна кристалічна кирка.", + "minicraft.notification.invalid_placement": "Можна поставити тільки на %s!", + "minicraft.notification.obsidian_knight_awoken": "Обсидіановий лицар повстав!", + "minicraft.notification.obsidian_knight_defeated": "Обсидіановий лицар: Знищений!", + "minicraft.notification.quest_completed": "Завдання виконано", + "minicraft.notification.quest_unlocked": "Завдання розблоковано", + "minicraft.notification.spawn_on_boss_tile": "Можна викликати тільки в кімнаті боса", + "minicraft.notification.world_saved": "Світ збережено!", + "minicraft.notification.wrong_level_dungeon": "Можна викликати тільки в підземеллі", + "minicraft.notification.wrong_level_sky": "Можна викликати тільки на повітряному рівні", + "minicraft.notifications.statue_tapped": "Ви чуєте відлуння шепіту...", + "minicraft.notifications.statue_touched": "Ви відчуваєте, що статуя вібрує...", + "minicraft.quest.farming": "Фермер", + "minicraft.quest.farming.crafting_hoe": "Створити мотику", + "minicraft.quest.farming.crafting_hoe.description": "Створіть мотику в будь-якому верстаті", + "minicraft.quest.farming.description": "Основи фермерства.", + "minicraft.quest.farming.getting_wheat": "Збирати врожай пшениці", + "minicraft.quest.farming.getting_wheat.description": "Зберіть врожай пшениці зламавши вирощену пшеницю.", + "minicraft.quest.farming.making_farmland": "Створити угіддя", + "minicraft.quest.farming.making_farmland.description": "Створіть угіддя мотикою, використавши мотику на землі.", + "minicraft.quest.farming.planting_potato": "Посадити картоплю", + "minicraft.quest.farming.planting_potato.description": "Посадіть картоплю поклавши картоплю на угіддя", + "minicraft.quest.farming.planting_wheat": "Посадити пшеницю", + "minicraft.quest.farming.planting_wheat.description": "Посадіть пшеницю поклавши насіння пшениці на угіддя.", + "minicraft.quest.gems": "Дорога кристалів", + "minicraft.quest.gems.description": "Підготувати кристалічні інструменти.", + "minicraft.quest.gems.gem_armor": "Майстер захисту", + "minicraft.quest.gems.gem_armor.description": "Дістати кристалічну броню.", + "minicraft.quest.gems.gem_claymore": "Майстер зброї", + "minicraft.quest.gems.gem_claymore.description": "Дістати великий кристалічний меч.", + "minicraft.quest.iron_equipments": "Майстер заліза", + "minicraft.quest.iron_equipments.description": "Зібрати все залізне устаткування.", + "minicraft.quest.iron_equipments.getting_more_iron": "Залізне багатство", + "minicraft.quest.iron_equipments.getting_more_iron.description": "Дістати більше заліза.", + "minicraft.quest.iron_equipments.iron_armor": "Покращити броню", + "minicraft.quest.iron_equipments.iron_armor.description": "Зробити залізну броню.", + "minicraft.quest.iron_equipments.iron_tools": "Покращити всі інструменти", + "minicraft.quest.iron_equipments.iron_tools.description": "Зробіть інструменти з заліза.", + "minicraft.quest.iron_equipments.upgrading_pickaxe": "Продвинута кирка", + "minicraft.quest.iron_equipments.upgrading_pickaxe.description": "Створіть залізну кирку.", + "minicraft.quest.potions": "Майстер зілля", + "minicraft.quest.potions.all_potions_prepared": "Дослідник зілля", + "minicraft.quest.potions.all_potions_prepared.description": "Дістати всі зілля в один раз.", + "minicraft.quest.potions.awkward_potions": "Дивне зілля", + "minicraft.quest.potions.awkward_potions.description": "Дістати дивне зілля.", + "minicraft.quest.potions.description": "Діставати зілля.", + "minicraft.quest.potions.powerful_potions": "Могутні зілля", + "minicraft.quest.potions.powerful_potions.description": "Дістаньте корисні та могутні зілля.", + "minicraft.settings.autosave": "Автоматичне збереження", + "minicraft.settings.difficulty": "Складність", + "minicraft.settings.difficulty.easy": "Легко", + "minicraft.settings.difficulty.hard": "Важко", + "minicraft.settings.difficulty.normal": "Звичайно", + "minicraft.settings.fps": "Максимальний FPS", + "minicraft.settings.mode": "Режим гри", + "minicraft.settings.mode.creative": "Творчість", + "minicraft.settings.mode.hardcore": "Хардкор", + "minicraft.settings.mode.score": "Рахунок", + "minicraft.settings.mode.survival": "Виживання", + "minicraft.settings.scoretime": "Час (Режим рахунку)", + "minicraft.settings.screenshot_scale": "Розмір знімка екрана", + "minicraft.settings.size": "Розмір світу", + "minicraft.settings.sound": "Звук", + "minicraft.settings.theme": "Тема світу", + "minicraft.settings.theme.desert": "Пустеля", + "minicraft.settings.theme.forest": "Ліс", + "minicraft.settings.theme.hell": "Ад", + "minicraft.settings.theme.normal": "Звичайна", + "minicraft.settings.theme.plain": "Рівнина", + "minicraft.settings.type": "Тип світу", + "minicraft.settings.type.box": "Коробка", + "minicraft.settings.type.irregular": "Незвичайний", + "minicraft.settings.type.island": "Острів", + "minicraft.settings.type.mountain": "Скеля", + "minicraft.skin.minecraft_alex": "Знайома дівчинка", + "minicraft.skin.minecraft_steve": "Знайомий хлопчик", + "minicraft.skin.paul": "Павел", + "minicraft.skin.paul_cape": "Павел з накидкою", + "minicraft.text_particales.key_consumed": "Ключ використано", + "minicraft.tutorial.getting_rocks": "Видобути каміння та вугілля", + "minicraft.tutorial.getting_rocks.description": "Дістаньте хоча б 5 камінців і 5 штук вугілля з каміння раніше створеною киркою.", + "minicraft.tutorial.getting_wood": "Видобути більше деревини", + "minicraft.tutorial.getting_wood.description": "Добудьте хоча б 10 штук деревини.", + "minicraft.tutorial.getting_wooden_pickaxe": "Дістати дерев'яну кирку", + "minicraft.tutorial.getting_wooden_pickaxe.description": "Створіть дерев'яну кирку в меню крафту від верстату.", + "minicraft.tutorial.getting_workbench": "Дістати верстат", + "minicraft.tutorial.getting_workbench.description": "Створіть верстат в меню крафту. Та поставте на землю.", + "minicraft.tutorial.start_getting_wood": "Початок всього", + "minicraft.tutorial.start_getting_wood.description": "Атакуйте дерева, щоб отримати деревину." +} diff --git a/src/client/resources/assets/textures/entity/bed.png b/src/client/resources/assets/textures/entity/bed.png index ded74f0ca..760cb3d21 100644 Binary files a/src/client/resources/assets/textures/entity/bed.png and b/src/client/resources/assets/textures/entity/bed.png differ diff --git a/src/client/resources/assets/textures/entity/composter.png b/src/client/resources/assets/textures/entity/composter.png new file mode 100644 index 000000000..7a97ee3de Binary files /dev/null and b/src/client/resources/assets/textures/entity/composter.png differ diff --git a/src/client/resources/assets/textures/entity/compostor_filled.png b/src/client/resources/assets/textures/entity/compostor_filled.png new file mode 100644 index 000000000..0b230a9df Binary files /dev/null and b/src/client/resources/assets/textures/entity/compostor_filled.png differ diff --git a/src/client/resources/assets/textures/entity/compostor_full.png b/src/client/resources/assets/textures/entity/compostor_full.png new file mode 100644 index 000000000..f4e360244 Binary files /dev/null and b/src/client/resources/assets/textures/entity/compostor_full.png differ diff --git a/src/client/resources/assets/textures/entity/glint.png b/src/client/resources/assets/textures/entity/glint.png new file mode 100644 index 000000000..3b14f6d8f Binary files /dev/null and b/src/client/resources/assets/textures/entity/glint.png differ diff --git a/src/client/resources/assets/textures/entity/sand_dust.png b/src/client/resources/assets/textures/entity/sand_dust.png deleted file mode 100644 index 557c417f4..000000000 Binary files a/src/client/resources/assets/textures/entity/sand_dust.png and /dev/null differ diff --git a/src/client/resources/assets/textures/entity/sand_footsteps.png b/src/client/resources/assets/textures/entity/sand_footsteps.png new file mode 100644 index 000000000..280db1e6b Binary files /dev/null and b/src/client/resources/assets/textures/entity/sand_footsteps.png differ diff --git a/src/client/resources/assets/textures/entity/splash_0.png b/src/client/resources/assets/textures/entity/splash_0.png new file mode 100644 index 000000000..8065908bd Binary files /dev/null and b/src/client/resources/assets/textures/entity/splash_0.png differ diff --git a/src/client/resources/assets/textures/entity/splash_1.png b/src/client/resources/assets/textures/entity/splash_1.png new file mode 100644 index 000000000..f95a7be19 Binary files /dev/null and b/src/client/resources/assets/textures/entity/splash_1.png differ diff --git a/src/client/resources/assets/textures/entity/splash_2.png b/src/client/resources/assets/textures/entity/splash_2.png new file mode 100644 index 000000000..588d463be Binary files /dev/null and b/src/client/resources/assets/textures/entity/splash_2.png differ diff --git a/src/client/resources/assets/textures/entity/splash_3.png b/src/client/resources/assets/textures/entity/splash_3.png new file mode 100644 index 000000000..fcec23a26 Binary files /dev/null and b/src/client/resources/assets/textures/entity/splash_3.png differ diff --git a/src/client/resources/assets/textures/entity/tnt.png b/src/client/resources/assets/textures/entity/tnt.png index a792dc1e4..1584087c3 100644 Binary files a/src/client/resources/assets/textures/entity/tnt.png and b/src/client/resources/assets/textures/entity/tnt.png differ diff --git a/src/client/resources/assets/textures/entity/workbench.png b/src/client/resources/assets/textures/entity/workbench.png index 5501c7922..dcfd7e466 100644 Binary files a/src/client/resources/assets/textures/entity/workbench.png and b/src/client/resources/assets/textures/entity/workbench.png differ diff --git a/src/client/resources/assets/textures/gui/font.png b/src/client/resources/assets/textures/gui/font.png index 4f4da089c..d7e2963a0 100644 Binary files a/src/client/resources/assets/textures/gui/font.png and b/src/client/resources/assets/textures/gui/font.png differ diff --git a/src/client/resources/assets/textures/gui/inventory_counter.png b/src/client/resources/assets/textures/gui/inventory_counter.png new file mode 100644 index 000000000..fb704054f Binary files /dev/null and b/src/client/resources/assets/textures/gui/inventory_counter.png differ diff --git a/src/client/resources/assets/textures/gui/osk.png b/src/client/resources/assets/textures/gui/osk.png new file mode 100644 index 000000000..7972c7f9a Binary files /dev/null and b/src/client/resources/assets/textures/gui/osk.png differ diff --git a/src/client/resources/assets/textures/item/acorn.png b/src/client/resources/assets/textures/item/acorn.png index c48207ce3..ccd9af615 100644 Binary files a/src/client/resources/assets/textures/item/acorn.png and b/src/client/resources/assets/textures/item/acorn.png differ diff --git a/src/client/resources/assets/textures/item/air_wizard_spawner.png b/src/client/resources/assets/textures/item/air_wizard_spawner.png index 04effc15a..da017b521 100644 Binary files a/src/client/resources/assets/textures/item/air_wizard_spawner.png and b/src/client/resources/assets/textures/item/air_wizard_spawner.png differ diff --git a/src/client/resources/assets/textures/item/antidious_book.png b/src/client/resources/assets/textures/item/antidious_book.png index b64094af0..e67c3f102 100644 Binary files a/src/client/resources/assets/textures/item/antidious_book.png and b/src/client/resources/assets/textures/item/antidious_book.png differ diff --git a/src/client/resources/assets/textures/item/arcane_fertilizer.png b/src/client/resources/assets/textures/item/arcane_fertilizer.png new file mode 100644 index 000000000..8b457a0ef Binary files /dev/null and b/src/client/resources/assets/textures/item/arcane_fertilizer.png differ diff --git a/src/client/resources/assets/textures/item/bed.png b/src/client/resources/assets/textures/item/bed.png index c8e77fd37..1f51b8096 100644 Binary files a/src/client/resources/assets/textures/item/bed.png and b/src/client/resources/assets/textures/item/bed.png differ diff --git a/src/client/resources/assets/textures/item/bone_meal.png b/src/client/resources/assets/textures/item/bone_meal.png new file mode 100644 index 000000000..c75a8b731 Binary files /dev/null and b/src/client/resources/assets/textures/item/bone_meal.png differ diff --git a/src/client/resources/assets/textures/item/book.png b/src/client/resources/assets/textures/item/book.png index 6b7c9680d..b1faf5d9d 100644 Binary files a/src/client/resources/assets/textures/item/book.png and b/src/client/resources/assets/textures/item/book.png differ diff --git a/src/client/resources/assets/textures/item/bread.png b/src/client/resources/assets/textures/item/bread.png index e66b87625..818317c6d 100644 Binary files a/src/client/resources/assets/textures/item/bread.png and b/src/client/resources/assets/textures/item/bread.png differ diff --git a/src/client/resources/assets/textures/item/cactus.png b/src/client/resources/assets/textures/item/cactus.png index 7e2325efb..5e236ecec 100644 Binary files a/src/client/resources/assets/textures/item/cactus.png and b/src/client/resources/assets/textures/item/cactus.png differ diff --git a/src/client/resources/assets/textures/item/carrot.png b/src/client/resources/assets/textures/item/carrot.png new file mode 100644 index 000000000..a23486c18 Binary files /dev/null and b/src/client/resources/assets/textures/item/carrot.png differ diff --git a/src/client/resources/assets/textures/item/composter.png b/src/client/resources/assets/textures/item/composter.png new file mode 100644 index 000000000..9ba7a47e9 Binary files /dev/null and b/src/client/resources/assets/textures/item/composter.png differ diff --git a/src/client/resources/assets/textures/item/cow_spawner.png b/src/client/resources/assets/textures/item/cow_spawner.png index 17fec2b8c..aa8360516 100644 Binary files a/src/client/resources/assets/textures/item/cow_spawner.png and b/src/client/resources/assets/textures/item/cow_spawner.png differ diff --git a/src/client/resources/assets/textures/item/creeper_spawner.png b/src/client/resources/assets/textures/item/creeper_spawner.png index 2b2d0ace1..3b562a123 100644 Binary files a/src/client/resources/assets/textures/item/creeper_spawner.png and b/src/client/resources/assets/textures/item/creeper_spawner.png differ diff --git a/src/client/resources/assets/textures/item/enchanter.png b/src/client/resources/assets/textures/item/enchanter.png index 12a9a0c38..02c755039 100644 Binary files a/src/client/resources/assets/textures/item/enchanter.png and b/src/client/resources/assets/textures/item/enchanter.png differ diff --git a/src/client/resources/assets/textures/item/fertilizer.png b/src/client/resources/assets/textures/item/fertilizer.png new file mode 100644 index 000000000..699e9a04d Binary files /dev/null and b/src/client/resources/assets/textures/item/fertilizer.png differ diff --git a/src/client/resources/assets/textures/item/green_wool.png b/src/client/resources/assets/textures/item/green_wool.png index 87e0e1435..63e56b85a 100644 Binary files a/src/client/resources/assets/textures/item/green_wool.png and b/src/client/resources/assets/textures/item/green_wool.png differ diff --git a/src/client/resources/assets/textures/item/heavenly_berries.png b/src/client/resources/assets/textures/item/heavenly_berries.png new file mode 100644 index 000000000..268bbfcd3 Binary files /dev/null and b/src/client/resources/assets/textures/item/heavenly_berries.png differ diff --git a/src/client/resources/assets/textures/item/hellish_berries.png b/src/client/resources/assets/textures/item/hellish_berries.png new file mode 100644 index 000000000..cfd64b963 Binary files /dev/null and b/src/client/resources/assets/textures/item/hellish_berries.png differ diff --git a/src/client/resources/assets/textures/item/knight_spawner.png b/src/client/resources/assets/textures/item/knight_spawner.png index 04effc15a..da017b521 100644 Binary files a/src/client/resources/assets/textures/item/knight_spawner.png and b/src/client/resources/assets/textures/item/knight_spawner.png differ diff --git a/src/client/resources/assets/textures/item/obsidian_fence.png b/src/client/resources/assets/textures/item/obsidian_fence.png new file mode 100644 index 000000000..9a351fedd Binary files /dev/null and b/src/client/resources/assets/textures/item/obsidian_fence.png differ diff --git a/src/client/resources/assets/textures/item/pig_spawner.png b/src/client/resources/assets/textures/item/pig_spawner.png index f49b3a463..83c24c305 100644 Binary files a/src/client/resources/assets/textures/item/pig_spawner.png and b/src/client/resources/assets/textures/item/pig_spawner.png differ diff --git a/src/client/resources/assets/textures/item/plank_wall.png b/src/client/resources/assets/textures/item/plank_wall.png index 7b9444f48..a40a50503 100644 Binary files a/src/client/resources/assets/textures/item/plank_wall.png and b/src/client/resources/assets/textures/item/plank_wall.png differ diff --git a/src/client/resources/assets/textures/item/sheep_spawner.png b/src/client/resources/assets/textures/item/sheep_spawner.png index a32a6b563..d5c66d7f1 100644 Binary files a/src/client/resources/assets/textures/item/sheep_spawner.png and b/src/client/resources/assets/textures/item/sheep_spawner.png differ diff --git a/src/client/resources/assets/textures/item/sign.png b/src/client/resources/assets/textures/item/sign.png new file mode 100644 index 000000000..99fc4f104 Binary files /dev/null and b/src/client/resources/assets/textures/item/sign.png differ diff --git a/src/client/resources/assets/textures/item/skeleton_spawner.png b/src/client/resources/assets/textures/item/skeleton_spawner.png index 563b2b8b6..0ce8f83e4 100644 Binary files a/src/client/resources/assets/textures/item/skeleton_spawner.png and b/src/client/resources/assets/textures/item/skeleton_spawner.png differ diff --git a/src/client/resources/assets/textures/item/slime_spawner.png b/src/client/resources/assets/textures/item/slime_spawner.png index 2764160b5..cd1576183 100644 Binary files a/src/client/resources/assets/textures/item/slime_spawner.png and b/src/client/resources/assets/textures/item/slime_spawner.png differ diff --git a/src/client/resources/assets/textures/item/snake.png b/src/client/resources/assets/textures/item/snake.png index 5a817045a..d3ed8c6fc 100644 Binary files a/src/client/resources/assets/textures/item/snake.png and b/src/client/resources/assets/textures/item/snake.png differ diff --git a/src/client/resources/assets/textures/item/snake_spawner.png b/src/client/resources/assets/textures/item/snake_spawner.png index 05c1242a5..fc3f014f8 100644 Binary files a/src/client/resources/assets/textures/item/snake_spawner.png and b/src/client/resources/assets/textures/item/snake_spawner.png differ diff --git a/src/client/resources/assets/textures/item/spawner.png b/src/client/resources/assets/textures/item/spawner.png index a43b1899d..691e5dff2 100644 Binary files a/src/client/resources/assets/textures/item/spawner.png and b/src/client/resources/assets/textures/item/spawner.png differ diff --git a/src/client/resources/assets/textures/item/stone_bow.png b/src/client/resources/assets/textures/item/stone_bow.png index c37012d78..82a83a87a 100644 Binary files a/src/client/resources/assets/textures/item/stone_bow.png and b/src/client/resources/assets/textures/item/stone_bow.png differ diff --git a/src/client/resources/assets/textures/item/stone_fence.png b/src/client/resources/assets/textures/item/stone_fence.png new file mode 100644 index 000000000..28a72fb4f Binary files /dev/null and b/src/client/resources/assets/textures/item/stone_fence.png differ diff --git a/src/client/resources/assets/textures/item/stone_hoe.png b/src/client/resources/assets/textures/item/stone_hoe.png index 438f6e9cd..2d7707408 100644 Binary files a/src/client/resources/assets/textures/item/stone_hoe.png and b/src/client/resources/assets/textures/item/stone_hoe.png differ diff --git a/src/client/resources/assets/textures/item/stone_wall.png b/src/client/resources/assets/textures/item/stone_wall.png index 38e0bcd68..f073d5a55 100644 Binary files a/src/client/resources/assets/textures/item/stone_wall.png and b/src/client/resources/assets/textures/item/stone_wall.png differ diff --git a/src/client/resources/assets/textures/item/tnt.png b/src/client/resources/assets/textures/item/tnt.png index 7243f21f7..317f83109 100644 Binary files a/src/client/resources/assets/textures/item/tnt.png and b/src/client/resources/assets/textures/item/tnt.png differ diff --git a/src/client/resources/assets/textures/item/tomato.png b/src/client/resources/assets/textures/item/tomato.png new file mode 100644 index 000000000..3d5638a89 Binary files /dev/null and b/src/client/resources/assets/textures/item/tomato.png differ diff --git a/src/client/resources/assets/textures/item/watering_can.png b/src/client/resources/assets/textures/item/watering_can.png new file mode 100644 index 000000000..263ce2749 Binary files /dev/null and b/src/client/resources/assets/textures/item/watering_can.png differ diff --git a/src/client/resources/assets/textures/item/watering_can_filled.png b/src/client/resources/assets/textures/item/watering_can_filled.png new file mode 100644 index 000000000..54d42cc09 Binary files /dev/null and b/src/client/resources/assets/textures/item/watering_can_filled.png differ diff --git a/src/client/resources/assets/textures/item/wood_fence.png b/src/client/resources/assets/textures/item/wood_fence.png new file mode 100644 index 000000000..8088f8edb Binary files /dev/null and b/src/client/resources/assets/textures/item/wood_fence.png differ diff --git a/src/client/resources/assets/textures/item/wooden_bow.png b/src/client/resources/assets/textures/item/wooden_bow.png index 668bca7d4..cdef21787 100644 Binary files a/src/client/resources/assets/textures/item/wooden_bow.png and b/src/client/resources/assets/textures/item/wooden_bow.png differ diff --git a/src/client/resources/assets/textures/item/zombie_spawner.png b/src/client/resources/assets/textures/item/zombie_spawner.png index 88217f842..58c70a67e 100644 Binary files a/src/client/resources/assets/textures/item/zombie_spawner.png and b/src/client/resources/assets/textures/item/zombie_spawner.png differ diff --git a/src/client/resources/assets/textures/tile/ash.png b/src/client/resources/assets/textures/tile/ash.png new file mode 100644 index 000000000..526e17335 Binary files /dev/null and b/src/client/resources/assets/textures/tile/ash.png differ diff --git a/src/client/resources/assets/textures/tile/ash_full.png b/src/client/resources/assets/textures/tile/ash_full.png new file mode 100644 index 000000000..f1e9066f1 Binary files /dev/null and b/src/client/resources/assets/textures/tile/ash_full.png differ diff --git a/src/client/resources/assets/textures/tile/aspen.png b/src/client/resources/assets/textures/tile/aspen.png new file mode 100644 index 000000000..42d1ee24d Binary files /dev/null and b/src/client/resources/assets/textures/tile/aspen.png differ diff --git a/src/client/resources/assets/textures/tile/aspen_full.png b/src/client/resources/assets/textures/tile/aspen_full.png new file mode 100644 index 000000000..81ac0cb25 Binary files /dev/null and b/src/client/resources/assets/textures/tile/aspen_full.png differ diff --git a/src/client/resources/assets/textures/tile/birch.png b/src/client/resources/assets/textures/tile/birch.png new file mode 100644 index 000000000..6022db651 Binary files /dev/null and b/src/client/resources/assets/textures/tile/birch.png differ diff --git a/src/client/resources/assets/textures/tile/birch_full.png b/src/client/resources/assets/textures/tile/birch_full.png new file mode 100644 index 000000000..2b65e2e55 Binary files /dev/null and b/src/client/resources/assets/textures/tile/birch_full.png differ diff --git a/src/client/resources/assets/textures/tile/carrot_stage0.png b/src/client/resources/assets/textures/tile/carrot_stage0.png new file mode 100644 index 000000000..edace2a7b Binary files /dev/null and b/src/client/resources/assets/textures/tile/carrot_stage0.png differ diff --git a/src/client/resources/assets/textures/tile/carrot_stage1.png b/src/client/resources/assets/textures/tile/carrot_stage1.png new file mode 100644 index 000000000..19d4ab299 Binary files /dev/null and b/src/client/resources/assets/textures/tile/carrot_stage1.png differ diff --git a/src/client/resources/assets/textures/tile/carrot_stage2.png b/src/client/resources/assets/textures/tile/carrot_stage2.png new file mode 100644 index 000000000..8426131fe Binary files /dev/null and b/src/client/resources/assets/textures/tile/carrot_stage2.png differ diff --git a/src/client/resources/assets/textures/tile/carrot_stage3.png b/src/client/resources/assets/textures/tile/carrot_stage3.png new file mode 100644 index 000000000..68b50001c Binary files /dev/null and b/src/client/resources/assets/textures/tile/carrot_stage3.png differ diff --git a/src/client/resources/assets/textures/tile/farmland_moist.png b/src/client/resources/assets/textures/tile/farmland_moist.png new file mode 100644 index 000000000..ce33ea207 Binary files /dev/null and b/src/client/resources/assets/textures/tile/farmland_moist.png differ diff --git a/src/client/resources/assets/textures/tile/fern.png b/src/client/resources/assets/textures/tile/fern.png new file mode 100644 index 000000000..67e5cb1b8 Binary files /dev/null and b/src/client/resources/assets/textures/tile/fern.png differ diff --git a/src/client/resources/assets/textures/tile/fir.png b/src/client/resources/assets/textures/tile/fir.png new file mode 100644 index 000000000..db594a536 Binary files /dev/null and b/src/client/resources/assets/textures/tile/fir.png differ diff --git a/src/client/resources/assets/textures/tile/fir_full.png b/src/client/resources/assets/textures/tile/fir_full.png new file mode 100644 index 000000000..fb1ce243a Binary files /dev/null and b/src/client/resources/assets/textures/tile/fir_full.png differ diff --git a/src/client/resources/assets/textures/tile/heavenly_berries_stage0.png b/src/client/resources/assets/textures/tile/heavenly_berries_stage0.png new file mode 100644 index 000000000..acfde05ba Binary files /dev/null and b/src/client/resources/assets/textures/tile/heavenly_berries_stage0.png differ diff --git a/src/client/resources/assets/textures/tile/heavenly_berries_stage1.png b/src/client/resources/assets/textures/tile/heavenly_berries_stage1.png new file mode 100644 index 000000000..451d6308b Binary files /dev/null and b/src/client/resources/assets/textures/tile/heavenly_berries_stage1.png differ diff --git a/src/client/resources/assets/textures/tile/heavenly_berries_stage2.png b/src/client/resources/assets/textures/tile/heavenly_berries_stage2.png new file mode 100644 index 000000000..630098f8b Binary files /dev/null and b/src/client/resources/assets/textures/tile/heavenly_berries_stage2.png differ diff --git a/src/client/resources/assets/textures/tile/heavenly_berries_stage3.png b/src/client/resources/assets/textures/tile/heavenly_berries_stage3.png new file mode 100644 index 000000000..ad0d0ae99 Binary files /dev/null and b/src/client/resources/assets/textures/tile/heavenly_berries_stage3.png differ diff --git a/src/client/resources/assets/textures/tile/hellish_berries_stage0.png b/src/client/resources/assets/textures/tile/hellish_berries_stage0.png new file mode 100644 index 000000000..3a7271992 Binary files /dev/null and b/src/client/resources/assets/textures/tile/hellish_berries_stage0.png differ diff --git a/src/client/resources/assets/textures/tile/hellish_berries_stage1.png b/src/client/resources/assets/textures/tile/hellish_berries_stage1.png new file mode 100644 index 000000000..25af95129 Binary files /dev/null and b/src/client/resources/assets/textures/tile/hellish_berries_stage1.png differ diff --git a/src/client/resources/assets/textures/tile/hellish_berries_stage2.png b/src/client/resources/assets/textures/tile/hellish_berries_stage2.png new file mode 100644 index 000000000..e75593447 Binary files /dev/null and b/src/client/resources/assets/textures/tile/hellish_berries_stage2.png differ diff --git a/src/client/resources/assets/textures/tile/hellish_berries_stage3.png b/src/client/resources/assets/textures/tile/hellish_berries_stage3.png new file mode 100644 index 000000000..379d2eea0 Binary files /dev/null and b/src/client/resources/assets/textures/tile/hellish_berries_stage3.png differ diff --git a/src/client/resources/assets/textures/tile/large_fern.png b/src/client/resources/assets/textures/tile/large_fern.png new file mode 100644 index 000000000..f5edb4c5c Binary files /dev/null and b/src/client/resources/assets/textures/tile/large_fern.png differ diff --git a/src/client/resources/assets/textures/tile/tree.png b/src/client/resources/assets/textures/tile/oak.png similarity index 100% rename from src/client/resources/assets/textures/tile/tree.png rename to src/client/resources/assets/textures/tile/oak.png diff --git a/src/client/resources/assets/textures/tile/tree_full.png b/src/client/resources/assets/textures/tile/oak_full.png similarity index 100% rename from src/client/resources/assets/textures/tile/tree_full.png rename to src/client/resources/assets/textures/tile/oak_full.png diff --git a/src/client/resources/assets/textures/tile/obsidian_door_border.png b/src/client/resources/assets/textures/tile/obsidian_door_border.png deleted file mode 100644 index 0fdcbe69f..000000000 Binary files a/src/client/resources/assets/textures/tile/obsidian_door_border.png and /dev/null differ diff --git a/src/client/resources/assets/textures/tile/obsidian_fence.png b/src/client/resources/assets/textures/tile/obsidian_fence.png new file mode 100644 index 000000000..726623712 Binary files /dev/null and b/src/client/resources/assets/textures/tile/obsidian_fence.png differ diff --git a/src/client/resources/assets/textures/tile/obsidian_fence_bottom.png b/src/client/resources/assets/textures/tile/obsidian_fence_bottom.png new file mode 100644 index 000000000..1c98de36a Binary files /dev/null and b/src/client/resources/assets/textures/tile/obsidian_fence_bottom.png differ diff --git a/src/client/resources/assets/textures/tile/obsidian_fence_left.png b/src/client/resources/assets/textures/tile/obsidian_fence_left.png new file mode 100644 index 000000000..03b15107e Binary files /dev/null and b/src/client/resources/assets/textures/tile/obsidian_fence_left.png differ diff --git a/src/client/resources/assets/textures/tile/obsidian_fence_right.png b/src/client/resources/assets/textures/tile/obsidian_fence_right.png new file mode 100644 index 000000000..eca4910d0 Binary files /dev/null and b/src/client/resources/assets/textures/tile/obsidian_fence_right.png differ diff --git a/src/client/resources/assets/textures/tile/obsidian_fence_top.png b/src/client/resources/assets/textures/tile/obsidian_fence_top.png new file mode 100644 index 000000000..de2aa9d97 Binary files /dev/null and b/src/client/resources/assets/textures/tile/obsidian_fence_top.png differ diff --git a/src/client/resources/assets/textures/tile/obsidian_wall.png b/src/client/resources/assets/textures/tile/obsidian_wall.png index 4eecbb56c..97bd8314d 100644 Binary files a/src/client/resources/assets/textures/tile/obsidian_wall.png and b/src/client/resources/assets/textures/tile/obsidian_wall.png differ diff --git a/src/client/resources/assets/textures/tile/obsidian_wall_border.png b/src/client/resources/assets/textures/tile/obsidian_wall_border.png index fee9436b4..f5945b9ff 100644 Binary files a/src/client/resources/assets/textures/tile/obsidian_wall_border.png and b/src/client/resources/assets/textures/tile/obsidian_wall_border.png differ diff --git a/src/client/resources/assets/textures/tile/ornate_wood.png b/src/client/resources/assets/textures/tile/ornate_wood.png new file mode 100644 index 000000000..8e5780f3e Binary files /dev/null and b/src/client/resources/assets/textures/tile/ornate_wood.png differ diff --git a/src/client/resources/assets/textures/tile/sign.png b/src/client/resources/assets/textures/tile/sign.png new file mode 100644 index 000000000..c62cdc442 Binary files /dev/null and b/src/client/resources/assets/textures/tile/sign.png differ diff --git a/src/client/resources/assets/textures/tile/spruce.png b/src/client/resources/assets/textures/tile/spruce.png new file mode 100644 index 000000000..e51fbb524 Binary files /dev/null and b/src/client/resources/assets/textures/tile/spruce.png differ diff --git a/src/client/resources/assets/textures/tile/spruce_full.png b/src/client/resources/assets/textures/tile/spruce_full.png new file mode 100644 index 000000000..d3ea3dbf0 Binary files /dev/null and b/src/client/resources/assets/textures/tile/spruce_full.png differ diff --git a/src/client/resources/assets/textures/tile/stone_fence.png b/src/client/resources/assets/textures/tile/stone_fence.png new file mode 100644 index 000000000..9df752393 Binary files /dev/null and b/src/client/resources/assets/textures/tile/stone_fence.png differ diff --git a/src/client/resources/assets/textures/tile/stone_fence_bottom.png b/src/client/resources/assets/textures/tile/stone_fence_bottom.png new file mode 100644 index 000000000..5091f520e Binary files /dev/null and b/src/client/resources/assets/textures/tile/stone_fence_bottom.png differ diff --git a/src/client/resources/assets/textures/tile/stone_fence_left.png b/src/client/resources/assets/textures/tile/stone_fence_left.png new file mode 100644 index 000000000..2c52b3695 Binary files /dev/null and b/src/client/resources/assets/textures/tile/stone_fence_left.png differ diff --git a/src/client/resources/assets/textures/tile/stone_fence_right.png b/src/client/resources/assets/textures/tile/stone_fence_right.png new file mode 100644 index 000000000..0fa689d4a Binary files /dev/null and b/src/client/resources/assets/textures/tile/stone_fence_right.png differ diff --git a/src/client/resources/assets/textures/tile/stone_fence_top.png b/src/client/resources/assets/textures/tile/stone_fence_top.png new file mode 100644 index 000000000..725f6a6de Binary files /dev/null and b/src/client/resources/assets/textures/tile/stone_fence_top.png differ diff --git a/src/client/resources/assets/textures/tile/stone_wall.png b/src/client/resources/assets/textures/tile/stone_wall.png index 576fc30f4..9b58dd288 100644 Binary files a/src/client/resources/assets/textures/tile/stone_wall.png and b/src/client/resources/assets/textures/tile/stone_wall.png differ diff --git a/src/client/resources/assets/textures/tile/stone_wall_border.png b/src/client/resources/assets/textures/tile/stone_wall_border.png index 575105751..6162560f0 100644 Binary files a/src/client/resources/assets/textures/tile/stone_wall_border.png and b/src/client/resources/assets/textures/tile/stone_wall_border.png differ diff --git a/src/client/resources/assets/textures/tile/tomato_stage0.png b/src/client/resources/assets/textures/tile/tomato_stage0.png new file mode 100644 index 000000000..1ceea3e4d Binary files /dev/null and b/src/client/resources/assets/textures/tile/tomato_stage0.png differ diff --git a/src/client/resources/assets/textures/tile/tomato_stage1.png b/src/client/resources/assets/textures/tile/tomato_stage1.png new file mode 100644 index 000000000..0cd3ff91b Binary files /dev/null and b/src/client/resources/assets/textures/tile/tomato_stage1.png differ diff --git a/src/client/resources/assets/textures/tile/tomato_stage2.png b/src/client/resources/assets/textures/tile/tomato_stage2.png new file mode 100644 index 000000000..24e990449 Binary files /dev/null and b/src/client/resources/assets/textures/tile/tomato_stage2.png differ diff --git a/src/client/resources/assets/textures/tile/tomato_stage3.png b/src/client/resources/assets/textures/tile/tomato_stage3.png new file mode 100644 index 000000000..80fbf4c2b Binary files /dev/null and b/src/client/resources/assets/textures/tile/tomato_stage3.png differ diff --git a/src/client/resources/assets/textures/tile/willow.png b/src/client/resources/assets/textures/tile/willow.png new file mode 100644 index 000000000..88f43ce2a Binary files /dev/null and b/src/client/resources/assets/textures/tile/willow.png differ diff --git a/src/client/resources/assets/textures/tile/willow_full.png b/src/client/resources/assets/textures/tile/willow_full.png new file mode 100644 index 000000000..ef7ad2e03 Binary files /dev/null and b/src/client/resources/assets/textures/tile/willow_full.png differ diff --git a/src/client/resources/assets/textures/tile/wood_fence.png b/src/client/resources/assets/textures/tile/wood_fence.png new file mode 100644 index 000000000..2375def5e Binary files /dev/null and b/src/client/resources/assets/textures/tile/wood_fence.png differ diff --git a/src/client/resources/assets/textures/tile/wood_fence_bottom.png b/src/client/resources/assets/textures/tile/wood_fence_bottom.png new file mode 100644 index 000000000..72e208983 Binary files /dev/null and b/src/client/resources/assets/textures/tile/wood_fence_bottom.png differ diff --git a/src/client/resources/assets/textures/tile/wood_fence_left.png b/src/client/resources/assets/textures/tile/wood_fence_left.png new file mode 100644 index 000000000..3acdf8fdc Binary files /dev/null and b/src/client/resources/assets/textures/tile/wood_fence_left.png differ diff --git a/src/client/resources/assets/textures/tile/wood_fence_right.png b/src/client/resources/assets/textures/tile/wood_fence_right.png new file mode 100644 index 000000000..0996a466e Binary files /dev/null and b/src/client/resources/assets/textures/tile/wood_fence_right.png differ diff --git a/src/client/resources/assets/textures/tile/wood_fence_top.png b/src/client/resources/assets/textures/tile/wood_fence_top.png new file mode 100644 index 000000000..961c68c8e Binary files /dev/null and b/src/client/resources/assets/textures/tile/wood_fence_top.png differ diff --git a/src/client/resources/assets/textures/tile/wood_wall.png b/src/client/resources/assets/textures/tile/wood_wall.png index d92577d85..621da38a2 100644 Binary files a/src/client/resources/assets/textures/tile/wood_wall.png and b/src/client/resources/assets/textures/tile/wood_wall.png differ diff --git a/src/client/resources/assets/textures/tile/wood_wall_border.png b/src/client/resources/assets/textures/tile/wood_wall_border.png index 4c8560766..789aa0c6f 100644 Binary files a/src/client/resources/assets/textures/tile/wood_wall_border.png and b/src/client/resources/assets/textures/tile/wood_wall_border.png differ diff --git a/src/client/resources/resources/achievements.json b/src/client/resources/resources/achievements.json index 307f8a20b..99fbc9027 100644 --- a/src/client/resources/resources/achievements.json +++ b/src/client/resources/resources/achievements.json @@ -78,5 +78,10 @@ "id": "minicraft.achievement.skin", "desc": "minicraft.achievement.skin.desc", "score": 10 + }, + { + "id": "minicraft.achievement.plant_seed", + "desc": "minicraft.achievement.plant_seed.desc", + "score": 20 } ] diff --git a/src/client/resources/resources/recipes.json b/src/client/resources/resources/recipes.json index 335f7e8c2..f627cefbe 100644 --- a/src/client/resources/resources/recipes.json +++ b/src/client/resources/resources/recipes.json @@ -1,70 +1,178 @@ { - "minicraft.advancements.recipes.workbench": { + "minicraft.advancements.recipes.gem_fishing_rod": { + "requirements": [ + [ + "has_gem", + "has_string" + ] + ], "criteria": { - "has_wood": { + "has_gem": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "wood" + "Gem" + ] + } + ] + } + }, + "has_string": { + "trigger": "inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "String" ] } ] } } }, + "rewards": { + "recipes": { + "Gem Fishing Rod_1": [ + "String_3", + "Gem_10" + ] + } + } + }, + "minicraft.advancements.recipes.health_potion": { "requirements": [ [ - "has_wood" + "has_leather_armor", + "has_gunpowder", + "has_awkward_potion" ] ], + "criteria": { + "has_leather_armor": { + "trigger": "inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "Leather Armor" + ] + } + ] + } + }, + "has_gunpowder": { + "trigger": "inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "Gunpowder" + ] + } + ] + } + }, + "has_awkward_potion": { + "trigger": "inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "Awkward Potion" + ] + } + ] + } + } + }, "rewards": { "recipes": { - "Workbench_1": ["Wood_10"] + "Health Potion_1": [ + "Awkward Potion_1", + "Gunpowder_2", + "Leather Armor_1" + ] } } }, - "minicraft.advancements.recipes.torch": { + "minicraft.advancements.recipes.green_wool": { + "requirements": [ + [ + "has_cactus", + "has_wool" + ] + ], "criteria": { - "has_wood": { + "has_cactus": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "wood" + "Cactus" ] } ] } }, - "has_coal": { + "has_wool": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "coal" + "Wool" ] } ] } } }, + "rewards": { + "recipes": { + "Green Wool_1": [ + "Cactus_1", + "Wool_1" + ] + } + } + }, + "minicraft.advancements.recipes.obsidian_brick": { "requirements": [ [ - "has_wood", - "has_coal" + "has_raw_obsidian" ] ], + "criteria": { + "has_raw_obsidian": { + "trigger": "inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "Raw Obsidian" + ] + } + ] + } + } + }, "rewards": { "recipes": { - "Torch_2": ["Wood_1", "coal_1"] + "Obsidian Brick_1": [ + "Raw Obsidian_2" + ] } } }, "minicraft.advancements.recipes.plank": { + "requirements": [ + [ + "has_wood" + ] + ], "criteria": { "has_wood": { "trigger": "inventory_changed", @@ -72,77 +180,98 @@ "items": [ { "items": [ - "wood" + "Wood" ] } ] } } }, - "requirements": [ - [ - "has_wood" - ] - ], "rewards": { "recipes": { - "plank_2": ["Wood_1"] + "Plank_2": [ + "Wood_1" + ] } } }, - "minicraft.advancements.recipes.plank_wall": { + "minicraft.advancements.recipes.leather_armor": { + "requirements": [ + [ + "has_leather" + ] + ], "criteria": { - "has_plank": { + "has_leather": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "plank" + "Leather" ] } ] } } }, - "requirements": [ - [ - "has_plank" - ] - ], "rewards": { "recipes": { - "Plank Wall_1": ["plank_3"] + "Leather Armor_1": [ + "Leather_10" + ] } } }, - "minicraft.advancements.recipes.wood_door": { + "minicraft.advancements.recipes.lava_potion": { + "requirements": [ + [ + "has_awkward_potion", + "has_lava_bucket" + ] + ], "criteria": { - "has_plank": { + "has_awkward_potion": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "plank" + "Awkward Potion" + ] + } + ] + } + }, + "has_lava_bucket": { + "trigger": "inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "Lava Bucket" ] } ] } } }, - "requirements": [ - [ - "has_plank" - ] - ], "rewards": { "recipes": { - "Wood Door_1": ["plank_5"] + "Lava Potion_1": [ + "Awkward Potion_1", + "Lava Bucket_1" + ] } } }, - "minicraft.advancements.recipes.lantern": { + "minicraft.advancements.recipes.iron_axe": { + "requirements": [ + [ + "has_wood", + "has_iron" + ] + ], "criteria": { "has_wood": { "trigger": "inventory_changed", @@ -150,285 +279,392 @@ "items": [ { "items": [ - "wood" + "Wood" ] } ] } }, - "has_slime": { + "has_iron": { + "trigger": "inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "Iron" + ] + } + ] + } + } + }, + "rewards": { + "recipes": { + "Iron Axe_1": [ + "Wood_5", + "Iron_5" + ] + } + } + }, + "minicraft.advancements.recipes.black_wool": { + "requirements": [ + [ + "has_coal", + "has_wool" + ] + ], + "criteria": { + "has_coal": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "slime" + "Coal" ] } ] } }, - "has_glass": { + "has_wool": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "glass" + "Wool" ] } ] } } }, - "requirements": [ - [ - "has_wood", - "has_slime", - "has_glass" - ] - ], "rewards": { "recipes": { - "Lantern_1": ["Wood_8", "slime_4", "glass_3"] + "Black Wool_1": [ + "Coal_1", + "Wool_1" + ] } } }, - "minicraft.advancements.recipes.stone_brick": { + "minicraft.advancements.recipes.cooked_pork": { + "requirements": [ + [ + "has_coal", + "has_raw_pork" + ] + ], "criteria": { - "has_stone": { + "has_coal": { + "trigger": "inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "Coal" + ] + } + ] + } + }, + "has_raw_pork": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "stone" + "Raw Pork" ] } ] } } }, - "requirements": [ - [ - "has_stone" - ] - ], "rewards": { "recipes": { - "Stone Brick_1": ["Stone_2"] + "Cooked Pork_1": [ + "Coal_1", + "Raw Pork_1" + ] } } }, - "minicraft.advancements.recipes.ornate_stone": { + "minicraft.advancements.recipes.wooden_hoe": { + "requirements": [ + [ + "has_wood" + ] + ], "criteria": { - "has_stone": { + "has_wood": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "stone" + "Wood" ] } ] } } }, - "requirements": [ - [ - "has_stone" - ] - ], "rewards": { "recipes": { - "Stone Brick_1": ["Stone_2"] + "Wood Hoe_1": [ + "Wood_5" + ] } } }, - "minicraft.advancements.recipes.stone_wall": { + "minicraft.advancements.recipes.stone_sword": { + "requirements": [ + [ + "has_stone", + "has_wood" + ] + ], "criteria": { - "has_stone_brick": { + "has_stone": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "stone brick" + "Stone" + ] + } + ] + } + }, + "has_wood": { + "trigger": "inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "Wood" ] } ] } } }, - "requirements": [ - [ - "has_stone_brick" - ] - ], "rewards": { "recipes": { - "Stone Wall_1": ["Stone Brick_3"] + "Rock Sword_1": [ + "Stone_5", + "Wood_5" + ] } } }, - "minicraft.advancements.recipes.stone_door": { + "minicraft.advancements.recipes.snake_armor": { + "requirements": [ + [ + "has_scale" + ] + ], "criteria": { - "has_stone_brick": { + "has_scale": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "stone brick" + "Scale" ] } ] } } }, - "requirements": [ - [ - "has_stone_brick" - ] - ], "rewards": { "recipes": { - "Stone Door_1": ["Stone Brick_5"] + "Snake Armor_1": [ + "Scale_15" + ] } } }, - "minicraft.advancements.recipes.obsidian_brick": { + "minicraft.advancements.recipes.shears": { + "requirements": [ + [ + "has_iron" + ] + ], "criteria": { - "has_raw_obsidian": { + "has_iron": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "raw obsidian" + "Iron" ] } ] } } }, - "requirements": [ - [ - "has_raw_obsidian" - ] - ], "rewards": { "recipes": { - "Obsidian Brick_1": ["Raw Obsidian_2"] + "Shears_1": [ + "Iron_4" + ] } } }, - "minicraft.advancements.recipes.ornate_obsidian": { + "minicraft.advancements.recipes.wood_door": { + "requirements": [ + [ + "has_plank" + ] + ], "criteria": { - "has_raw_obsidian": { + "has_plank": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "raw obsidian" + "Plank" ] } ] } } }, - "requirements": [ - [ - "has_raw_obsidian" - ] - ], "rewards": { "recipes": { - "Ornate Obsidian_1": ["Raw Obsidian_2"] + "Wood Door_1": [ + "Plank_5" + ] } } }, - "minicraft.advancements.recipes.obsidian_wall": { + "minicraft.advancements.recipes.stone_fence": { + "requirements": [ + [ + "has_stone_brick" + ] + ], "criteria": { - "has_obsidian_brick": { + "has_stone_brick": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "obsidian brick" + "Stone Brick" ] } ] } } }, - "requirements": [ - [ - "has_obsidian_brick" - ] - ], "rewards": { "recipes": { - "Obsidian Wall_1": ["Obsidian Brick_3"] + "Stone Fence_1": [ + "Stone Brick_3" + ] } } }, - "minicraft.advancements.recipes.obsidian_door": { + "minicraft.advancements.recipes.green_clothes": { + "requirements": [ + [ + "has_cactus", + "has_cloth" + ] + ], "criteria": { - "has_obsidian_brick": { + "has_cactus": { + "trigger": "inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "Cactus" + ] + } + ] + } + }, + "has_cloth": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "obsidian brick" + "Cloth" ] } ] } } }, - "requirements": [ - [ - "has_obsidian_brick" - ] - ], "rewards": { "recipes": { - "Obsidian Door_1": ["Obsidian Brick_5"] + "Green Clothes_1": [ + "Cactus_1", + "Cloth_5" + ] } } }, - "minicraft.advancements.recipes.oven": { + "minicraft.advancements.recipes.red_wool": { + "requirements": [ + [ + "has_rose", + "has_wool" + ] + ], "criteria": { - "has_stone": { + "has_rose": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "stone" + "Rose" + ] + } + ] + } + }, + "has_wool": { + "trigger": "inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "Wool" ] } ] } } }, - "requirements": [ - [ - "has_stone" - ] - ], "rewards": { "recipes": { - "Oven_1": ["Stone_15"] + "Red Wool_1": [ + "Rose_1", + "Wool_1" + ] } } }, - "minicraft.advancements.recipes.furnace": { + "minicraft.advancements.recipes.stone_bow": { + "requirements": [ + [ + "has_stone", + "has_wood", + "has_string" + ] + ], "criteria": { "has_stone": { "trigger": "inventory_changed", @@ -436,25 +672,55 @@ "items": [ { "items": [ - "stone" + "Stone" + ] + } + ] + } + }, + "has_wood": { + "trigger": "inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "Wood" + ] + } + ] + } + }, + "has_string": { + "trigger": "inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "String" ] } ] } } }, - "requirements": [ - [ - "has_stone" - ] - ], "rewards": { "recipes": { - "Furnace_1": ["Stone_20"] + "Rock Bow_1": [ + "String_2", + "Stone_5", + "Wood_5" + ] } } }, - "minicraft.advancements.recipes.enchanter": { + "minicraft.advancements.recipes.gem_bow": { + "requirements": [ + [ + "has_wood", + "has_gem", + "has_string" + ] + ], "criteria": { "has_wood": { "trigger": "inventory_changed", @@ -462,51 +728,109 @@ "items": [ { "items": [ - "wood" + "Wood" ] } ] } }, - "has_string": { + "has_gem": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "string" + "Gem" ] } ] } }, - "has_lapis": { + "has_string": { + "trigger": "inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "String" + ] + } + ] + } + } + }, + "rewards": { + "recipes": { + "Gem Bow_1": [ + "String_2", + "Wood_5", + "Gem_50" + ] + } + } + }, + "minicraft.advancements.recipes.wooden_axe": { + "requirements": [ + [ + "has_wood" + ] + ], + "criteria": { + "has_wood": { + "trigger": "inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "Wood" + ] + } + ] + } + } + }, + "rewards": { + "recipes": { + "Wood Axe_1": [ + "Wood_5" + ] + } + } + }, + "minicraft.advancements.recipes.stone_brick": { + "requirements": [ + [ + "has_stone" + ] + ], + "criteria": { + "has_stone": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "lapis" + "Stone" ] } ] } } }, - "requirements": [ - [ - "has_wood", - "has_string", - "has_lapis" - ] - ], "rewards": { "recipes": { - "Enchanter_1": ["Wood_5", "String_2", "Lapis_10"] + "Stone Brick_1": [ + "Stone_2" + ] } } }, - "minicraft.advancements.recipes.chest": { + "minicraft.advancements.recipes.workbench": { + "requirements": [ + [ + "has_wood" + ] + ], "criteria": { "has_wood": { "trigger": "inventory_changed", @@ -514,254 +838,260 @@ "items": [ { "items": [ - "wood" + "Wood" ] } ] } } }, - "requirements": [ - [ - "has_wood" - ] - ], "rewards": { "recipes": { - "Chest_1": ["Wood_20"] + "Workbench_1": [ + "Wood_10" + ] } } }, - "minicraft.advancements.recipes.anvil": { + "minicraft.advancements.recipes.lantern": { + "requirements": [ + [ + "has_glass", + "has_wood", + "has_slime" + ] + ], "criteria": { - "has_iron": { + "has_glass": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "iron" + "Glass" ] } ] } - } - }, - "requirements": [ - [ - "has_iron" - ] - ], - "rewards": { - "recipes": { - "Anvil_1": ["iron_5"] - } - } - }, - "minicraft.advancements.recipes.tnt": { - "criteria": { - "has_gunpowder": { + }, + "has_wood": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "gunpowder" + "Wood" ] } ] } }, - "has_sand": { + "has_slime": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "sand" + "Slime" ] } ] } } }, - "requirements": [ - [ - "has_gunpowder", - "has_sand" - ] - ], "rewards": { "recipes": { - "Tnt_1": ["Gunpowder_10", "Sand_8"] + "Lantern_1": [ + "Glass_3", + "Slime_4", + "Wood_8" + ] } } }, - "minicraft.advancements.recipes.loom": { + "minicraft.advancements.recipes.gold_armor": { + "requirements": [ + [ + "has_gold" + ] + ], "criteria": { - "has_wood": { - "trigger": "inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "wood" - ] - } - ] - } - }, - "has_wool": { + "has_gold": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "wool" + "Gold" ] } ] } } }, - "requirements": [ - [ - "has_wood", - "has_wool" - ] - ], "rewards": { "recipes": { - "Loom_1": ["Wood_10", "Wool_5"] + "Gold Armor_1": [ + "Gold_10" + ] } } }, - "minicraft.advancements.recipes.wood_fishing_rod": { + "minicraft.advancements.recipes.yellow_clothes": { + "requirements": [ + [ + "has_cloth", + "has_flower" + ] + ], "criteria": { - "has_wood": { + "has_cloth": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "wood" + "Cloth" ] } ] } }, - "has_string": { + "has_flower": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "string" + "Flower" ] } ] } } }, - "requirements": [ - [ - "has_wood", - "has_string" - ] - ], "rewards": { "recipes": { - "Wood Fishing Rod_1": ["Wood_10", "String_3"] + "Yellow Clothes_1": [ + "Flower_1", + "Cloth_5" + ] } } }, - "minicraft.advancements.recipes.iron_fishing_rod": { + "minicraft.advancements.recipes.glass_bottle": { + "requirements": [ + [ + "has_glass" + ] + ], "criteria": { - "has_iron": { - "trigger": "inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "iron" - ] - } - ] - } - }, - "has_string": { + "has_glass": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "string" + "Glass" ] } ] } } }, - "requirements": [ - [ - "has_iron", - "has_string" - ] - ], "rewards": { "recipes": { - "Iron Fishing Rod_1": ["Iron_10", "String_3"] + "Glass Bottle_1": [ + "Glass_3" + ] } } }, - "minicraft.advancements.recipes.gold_fishing_rod": { + "minicraft.advancements.recipes.gem_claymore": { + "requirements": [ + [ + "has_shard", + "has_gem_sword" + ] + ], "criteria": { - "has_gold": { + "has_shard": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "gold" + "Shard" ] } ] } }, - "has_string": { + "has_gem_sword": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "string" + "Gem Sword" ] } ] } } }, + "rewards": { + "recipes": { + "Gem Claymore_1": [ + "Gem Sword_1", + "Shard_15" + ] + } + } + }, + "minicraft.advancements.recipes.wood_fence": { "requirements": [ [ - "has_gold", - "has_string" + "has_plank" ] ], + "criteria": { + "has_plank": { + "trigger": "inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "Plank" + ] + } + ] + } + } + }, "rewards": { "recipes": { - "Gold Fishing Rod_1": ["Gold_10", "String_3"] + "Wood Fence_1": [ + "Plank_3" + ] } } }, - "minicraft.advancements.recipes.gem_fishing_rod": { + "minicraft.advancements.recipes.wood_fishing_rod": { + "requirements": [ + [ + "has_wood", + "has_string" + ] + ], "criteria": { - "has_gem": { + "has_wood": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "gem" + "Wood" ] } ] @@ -773,273 +1103,239 @@ "items": [ { "items": [ - "string" + "String" ] } ] } } }, - "requirements": [ - [ - "has_gem", - "has_string" - ] - ], "rewards": { "recipes": { - "Gem Fishing Rod_1": ["Gem_10", "String_3"] + "Wood Fishing Rod_1": [ + "String_3", + "Wood_10" + ] } } }, - "minicraft.advancements.recipes.wooden_sword": { + "minicraft.advancements.recipes.gold_fishing_rod": { + "requirements": [ + [ + "has_string", + "has_gold" + ] + ], "criteria": { - "has_wood": { + "has_string": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "wood" + "String" ] } ] } - } - }, - "requirements": [ - [ - "has_wood" - ] - ], - "rewards": { - "recipes": { - "Wood Sword_1": ["Wood_5"] - } - } - }, - "minicraft.advancements.recipes.wooden_axe": { - "criteria": { - "has_wood": { + }, + "has_gold": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "wood" + "Gold" ] } ] } } }, - "requirements": [ - [ - "has_wood" - ] - ], "rewards": { "recipes": { - "Wood Axe_1": ["Wood_5"] + "Gold Fishing Rod_1": [ + "Gold_10", + "String_3" + ] } } }, - "minicraft.advancements.recipes.wooden_hoe": { + "minicraft.advancements.recipes.purple_clothes": { + "requirements": [ + [ + "has_rose", + "has_lapis", + "has_cloth" + ] + ], "criteria": { - "has_wood": { + "has_rose": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "wood" + "Rose" ] } ] } - } - }, - "requirements": [ - [ - "has_wood" - ] - ], - "rewards": { - "recipes": { - "Wood Hoe_1": ["Wood_5"] - } - } - }, - "minicraft.advancements.recipes.wooden_pickaxe": { - "criteria": { - "has_wood": { + }, + "has_lapis": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "wood" + "Lapis" ] } ] } - } - }, - "requirements": [ - [ - "has_wood" - ] - ], - "rewards": { - "recipes": { - "Wood Pickaxe_1": ["Wood_5"] - } - } - }, - "minicraft.advancements.recipes.wooden_shovel": { - "criteria": { - "has_wood": { + }, + "has_cloth": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "wood" + "Cloth" ] } ] } } }, - "requirements": [ - [ - "has_wood" - ] - ], "rewards": { "recipes": { - "Wood Shovel_1": ["Wood_5"] + "Purple Clothes_1": [ + "Lapis_1", + "Cloth_5", + "Rose_1" + ] } } }, - "minicraft.advancements.recipes.wooden_bow": { + "minicraft.advancements.recipes.stone_pickaxe": { + "requirements": [ + [ + "has_stone", + "has_wood" + ] + ], "criteria": { - "has_wood": { + "has_stone": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "wood" + "Stone" ] } ] } }, - "has_string": { + "has_wood": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "string" + "Wood" ] } ] } } }, - "requirements": [ - [ - "has_wood", - "has_string" - ] - ], "rewards": { "recipes": { - "Wood Bow_1": ["Wood_5", "string_2"] + "Rock Pickaxe_1": [ + "Stone_5", + "Wood_5" + ] } } }, - "minicraft.advancements.recipes.rock_sword": { + "minicraft.advancements.recipes.blue_clothes": { + "requirements": [ + [ + "has_lapis", + "has_cloth" + ] + ], "criteria": { - "has_wood": { + "has_lapis": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "wood" + "Lapis" ] } ] } }, - "has_stone": { + "has_cloth": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "stone" + "Cloth" ] } ] } } }, - "requirements": [ - [ - "has_wood", - "has_stone" - ] - ], "rewards": { "recipes": { - "Rock Sword_1": ["Wood_5", "Stone_5"] + "Blue Clothes_1": [ + "Lapis_1", + "Cloth_5" + ] } } }, - "minicraft.advancements.recipes.rock_axe": { + "minicraft.advancements.recipes.watering_can": { + "requirements": [ + [ + "has_iron" + ] + ], "criteria": { - "has_wood": { - "trigger": "inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "wood" - ] - } - ] - } - }, - "has_stone": { + "has_iron": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "stone" + "Iron" ] } ] } } }, - "requirements": [ - [ - "has_wood", - "has_stone" - ] - ], "rewards": { "recipes": { - "Rock Sword_1": ["Wood_5", "Stone_5"] + "Watering Can_1": [ + "Iron_3" + ] } } }, - "minicraft.advancements.recipes.rock_hoe": { + "minicraft.advancements.recipes.gem_sword": { + "requirements": [ + [ + "has_wood", + "has_gem" + ] + ], "criteria": { "has_wood": { "trigger": "inventory_changed", @@ -1047,38 +1343,41 @@ "items": [ { "items": [ - "wood" + "Wood" ] } ] } }, - "has_stone": { + "has_gem": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "stone" + "Gem" ] } ] } } }, - "requirements": [ - [ - "has_wood", - "has_stone" - ] - ], "rewards": { "recipes": { - "Rock Axe_1": ["Wood_5", "Stone_5"] + "Gem Sword_1": [ + "Wood_5", + "Gem_50" + ] } } }, - "minicraft.advancements.recipes.rock_pickaxe": { + "minicraft.advancements.recipes.bed": { + "requirements": [ + [ + "has_wood", + "has_wool" + ] + ], "criteria": { "has_wood": { "trigger": "inventory_changed", @@ -1086,129 +1385,125 @@ "items": [ { "items": [ - "wood" + "Wood" ] } ] } }, - "has_stone": { + "has_wool": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "stone" + "Wool" ] } ] } } }, - "requirements": [ - [ - "has_wood", - "has_stone" - ] - ], "rewards": { "recipes": { - "Rock Pickaxe_1": ["Wood_5", "Stone_5"] + "Bed_1": [ + "Wood_5", + "Wool_3" + ] } } }, - "minicraft.advancements.recipes.rock_shovel": { + "minicraft.advancements.recipes.swim_potion": { + "requirements": [ + [ + "has_raw_fish", + "has_awkward_potion" + ] + ], "criteria": { - "has_wood": { + "has_raw_fish": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "wood" + "Raw Fish" ] } ] } }, - "has_stone": { + "has_awkward_potion": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "stone" + "Awkward Potion" ] } ] } } }, - "requirements": [ - [ - "has_wood", - "has_stone" - ] - ], "rewards": { "recipes": { - "Rock Shovel_1": ["Wood_5", "Stone_5"] + "Swim Potion_1": [ + "Awkward Potion_1", + "Raw Fish_5" + ] } } }, - "minicraft.advancements.recipes.rock_bow": { + "minicraft.advancements.recipes.steak": { + "requirements": [ + [ + "has_coal", + "has_raw_beef" + ] + ], "criteria": { - "has_wood": { - "trigger": "inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "wood" - ] - } - ] - } - }, - "has_stone": { + "has_coal": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "stone" + "Coal" ] } ] } }, - "has_string": { + "has_raw_beef": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "string" + "Raw Beef" ] } ] } } }, - "requirements": [ - [ - "has_wood", - "has_stone", - "has_string" - ] - ], "rewards": { "recipes": { - "Rock Bow_1": ["Wood_5", "Stone_5", "string_2"] + "Steak_1": [ + "Coal_1", + "Raw Beef_1" + ] } } }, - "minicraft.advancements.recipes.arrow": { + "minicraft.advancements.recipes.gem_pickaxe": { + "requirements": [ + [ + "has_wood", + "has_gem" + ] + ], "criteria": { "has_wood": { "trigger": "inventory_changed", @@ -1216,241 +1511,244 @@ "items": [ { "items": [ - "wood" + "Wood" ] } ] } }, - "has_stone": { + "has_gem": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "stone" + "Gem" ] } ] } } }, - "requirements": [ - [ - "has_wood", - "has_stone" - ] - ], "rewards": { "recipes": { - "arrow_3": ["Wood_2", "Stone_2"] + "Gem Pickaxe_1": [ + "Wood_5", + "Gem_50" + ] } } }, - "minicraft.advancements.recipes.leather_armor": { + "minicraft.advancements.recipes.obsidian_fence": { + "requirements": [ + [ + "has_obsidian_brick" + ] + ], "criteria": { - "has_leather": { + "has_obsidian_brick": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "leather" + "Obsidian Brick" ] } ] } } }, - "requirements": [ - [ - "has_leather" - ] - ], "rewards": { "recipes": { - "Leather Armor_1": ["leather_10"] + "Obsidian Fence_1": [ + "Obsidian Brick_3" + ] } } }, - "minicraft.advancements.recipes.snake_armor": { + "minicraft.advancements.recipes.iron_hoe": { + "requirements": [ + [ + "has_wood", + "has_iron" + ] + ], "criteria": { - "has_scale": { + "has_wood": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "scale" + "Wood" ] } ] } - } - }, - "requirements": [ - [ - "has_scale" - ] - ], - "rewards": { - "recipes": { - "Snake Armor_1": ["scale_15"] - } - } - }, - "minicraft.advancements.recipes.string": { - "criteria": { - "has_wool": { + }, + "has_iron": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "wool" + "Iron" ] } ] } } }, - "requirements": [ - [ - "has_wool" - ] - ], "rewards": { "recipes": { - "String_2": ["Wool_1"] + "Iron Hoe_1": [ + "Wood_5", + "Iron_5" + ] } } }, - "minicraft.advancements.recipes.red_wool": { + "minicraft.advancements.recipes.iron_claymore": { + "requirements": [ + [ + "has_shard", + "has_iron_sword" + ] + ], "criteria": { - "has_wool": { + "has_shard": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "wool" + "Shard" ] } ] } }, - "has_rose": { + "has_iron_sword": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "rose" + "Iron Sword" ] } ] } } }, - "requirements": [ - [ - "has_wool", - "has_rose" - ] - ], "rewards": { "recipes": { - "red wool_1": ["Wool_1", "rose_1"] + "Iron Claymore_1": [ + "Iron Sword_1", + "Shard_15" + ] } } }, - "minicraft.advancements.recipes.blue_wool": { + "minicraft.advancements.recipes.wooden_pickaxe": { + "requirements": [ + [ + "has_wood" + ] + ], "criteria": { - "has_wool": { - "trigger": "inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "wool" - ] - } - ] - } - }, - "has_lapis": { + "has_wood": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "lapis" + "Wood" ] } ] } } }, - "requirements": [ - [ - "has_wool", - "has_lapis" - ] - ], "rewards": { "recipes": { - "blue wool_1": ["Wool_1", "Lapis_1"] + "Wood Pickaxe_1": [ + "Wood_5" + ] } } }, - "minicraft.advancements.recipes.green_wool": { + "minicraft.advancements.recipes.stone_axe": { + "requirements": [ + [ + "has_stone", + "has_wood" + ] + ], "criteria": { - "has_wool": { + "has_stone": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "wool" + "Stone" ] } ] } }, - "has_cactus": { + "has_wood": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "cactus" + "Wood" ] } ] } } }, - "requirements": [ - [ - "has_wool", - "has_cactus" - ] - ], "rewards": { "recipes": { - "green wool_1": ["Wool_1", "Cactus_1"] + "Rock Axe_1": [ + "Stone_5", + "Wood_5" + ] } } }, - "minicraft.advancements.recipes.yellow_wool": { + "minicraft.advancements.recipes.orange_clothes": { + "requirements": [ + [ + "has_rose", + "has_cloth", + "has_flower" + ] + ], "criteria": { - "has_wool": { + "has_rose": { + "trigger": "inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "Rose" + ] + } + ] + } + }, + "has_cloth": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "wool" + "Cloth" ] } ] @@ -1462,65 +1760,72 @@ "items": [ { "items": [ - "flower" + "Flower" ] } ] } } }, - "requirements": [ - [ - "has_wool", - "has_flower" - ] - ], "rewards": { "recipes": { - "yellow wool_1": ["Wool_1", "Flower_1"] + "Orange Clothes_1": [ + "Cloth_5", + "Rose_1", + "Flower_1" + ] } } }, - "minicraft.advancements.recipes.black_wool": { + "minicraft.advancements.recipes.iron_fishing_rod": { + "requirements": [ + [ + "has_string", + "has_iron" + ] + ], "criteria": { - "has_wool": { + "has_string": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "wool" + "String" ] } ] } }, - "has_coal": { + "has_iron": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "coal" + "Iron" ] } ] } } }, - "requirements": [ - [ - "has_wool", - "has_coal" - ] - ], "rewards": { "recipes": { - "black wool_1": ["Wool_1", "coal_1"] + "Iron Fishing Rod_1": [ + "String_3", + "Iron_10" + ] } } }, - "minicraft.advancements.recipes.bed": { + "minicraft.advancements.recipes.iron_pickaxe": { + "requirements": [ + [ + "has_wood", + "has_iron" + ] + ], "criteria": { "has_wood": { "trigger": "inventory_changed", @@ -1528,46 +1833,49 @@ "items": [ { "items": [ - "wood" + "Wood" ] } ] } }, - "has_wool": { + "has_iron": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "wool" + "Iron" ] } ] } } }, - "requirements": [ - [ - "has_wood", - "has_wool" - ] - ], "rewards": { "recipes": { - "Bed_1": ["Wood_5", "Wool_3"] + "Iron Pickaxe_1": [ + "Wood_5", + "Iron_5" + ] } } }, - "minicraft.advancements.recipes.blue_clothes": { + "minicraft.advancements.recipes.arcane_fertilizer": { + "requirements": [ + [ + "has_bone", + "has_lapis" + ] + ], "criteria": { - "has_cloth": { + "has_bone": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "cloth" + "Bone" ] } ] @@ -1579,767 +1887,758 @@ "items": [ { "items": [ - "lapis" + "Lapis" ] } ] } } }, - "requirements": [ - [ - "has_cloth", - "has_lapis" - ] - ], "rewards": { "recipes": { - "blue clothes_1": ["cloth_5", "Lapis_1"] + "ARCANE FERTILIZER_3": [ + "Lapis_6", + "Bone_2" + ] } } }, - "minicraft.advancements.recipes.green_clothes": { + "minicraft.advancements.recipes.ornate_stone": { + "requirements": [ + [ + "has_stone" + ] + ], "criteria": { - "has_cloth": { - "trigger": "inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "cloth" - ] - } - ] - } - }, - "has_cactus": { + "has_stone": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "cactus" + "Stone" ] } ] } } }, - "requirements": [ - [ - "has_cloth", - "has_cactus" - ] - ], "rewards": { "recipes": { - "green clothes_1": ["cloth_5", "Cactus_1"] + "Ornate Stone_1": [ + "Stone_2" + ] } } }, - "minicraft.advancements.recipes.yellow_clothes": { + "minicraft.advancements.recipes.wooden_bow": { + "requirements": [ + [ + "has_wood", + "has_string" + ] + ], "criteria": { - "has_cloth": { + "has_wood": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "cloth" + "Wood" ] } ] } }, - "has_flower": { + "has_string": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "flower" + "String" ] } ] } } }, - "requirements": [ - [ - "has_cloth", - "has_flower" - ] - ], "rewards": { "recipes": { - "yellow clothes_1": ["cloth_5", "Flower_1"] + "Wood Bow_1": [ + "String_2", + "Wood_5" + ] } } }, - "minicraft.advancements.recipes.black_clothes": { + "minicraft.advancements.recipes.gold_pickaxe": { + "requirements": [ + [ + "has_wood", + "has_gold" + ] + ], "criteria": { - "has_cloth": { + "has_wood": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "cloth" + "Wood" ] } ] } }, - "has_coal": { + "has_gold": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "coal" + "Gold" ] } ] } } }, - "requirements": [ - [ - "has_cloth", - "has_coal" - ] - ], "rewards": { "recipes": { - "black clothes_1": ["cloth_5", "coal_1"] + "Gold Pickaxe_1": [ + "Gold_5", + "Wood_5" + ] } } }, - "minicraft.advancements.recipes.orange_clothes": { + "minicraft.advancements.recipes.gold": { + "requirements": [ + [ + "has_coal", + "has_gold_ore" + ] + ], "criteria": { - "has_cloth": { - "trigger": "inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "cloth" - ] - } - ] - } - }, - "has_rose": { + "has_coal": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "rose" + "Coal" ] } ] } }, - "has_flower": { + "has_gold_ore": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "flower" + "Gold Ore" ] } ] } } }, - "requirements": [ - [ - "has_cloth", - "has_rose", - "has_flower" - ] - ], "rewards": { "recipes": { - "orange clothes_1": ["cloth_5", "rose_1", "Flower_1"] + "Gold_1": [ + "Coal_1", + "Gold Ore_3" + ] } } }, - "minicraft.advancements.recipes.purple_clothes": { + "minicraft.advancements.recipes.cooked_fish": { + "requirements": [ + [ + "has_coal", + "has_raw_fish" + ] + ], "criteria": { - "has_cloth": { - "trigger": "inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "cloth" - ] - } - ] - } - }, - "has_lapis": { + "has_coal": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "lapis" + "Coal" ] } ] } }, - "has_rose": { + "has_raw_fish": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "rose" + "Raw Fish" ] } ] } } }, - "requirements": [ - [ - "has_cloth", - "has_lapis", - "has_rose" - ] - ], "rewards": { "recipes": { - "purple clothes_1": ["cloth_5", "Lapis_1", "rose_1"] + "Cooked Fish_1": [ + "Coal_1", + "Raw Fish_1" + ] } } }, - "minicraft.advancements.recipes.cyan_clothes": { + "minicraft.advancements.recipes.light_potion": { + "requirements": [ + [ + "has_slime", + "has_awkward_potion" + ] + ], "criteria": { - "has_cloth": { - "trigger": "inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "cloth" - ] - } - ] - } - }, - "has_lapis": { + "has_slime": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "lapis" + "Slime" ] } ] } }, - "has_cactus": { + "has_awkward_potion": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "cactus" + "Awkward Potion" ] } ] } } }, - "requirements": [ - [ - "has_cloth", - "has_lapis", - "has_cactus" - ] - ], "rewards": { "recipes": { - "cyan clothes_1": ["cloth_5", "Lapis_1", "Cactus_1"] + "Light Potion_1": [ + "Slime_5", + "Awkward Potion_1" + ] } } }, - "minicraft.advancements.recipes.reg_clothes": { + "minicraft.advancements.recipes.gold_sword": { + "requirements": [ + [ + "has_wood", + "has_gold" + ] + ], "criteria": { - "has_cloth": { + "has_wood": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "cloth" + "Wood" ] } ] } - } - }, - "requirements": [ - [ - "has_cloth" - ] - ], - "rewards": { - "recipes": { - "reg clothes_1": ["cloth_5"] - } - } - }, - "minicraft.advancements.recipes.iron_armor": { - "criteria": { - "has_iron": { + }, + "has_gold": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "iron" + "Gold" ] } ] } } }, - "requirements": [ - [ - "has_iron" - ] - ], "rewards": { "recipes": { - "Iron Armor_1": ["iron_10"] + "Gold Sword_1": [ + "Gold_5", + "Wood_5" + ] } } }, - "minicraft.advancements.recipes.gold_armor": { + "minicraft.advancements.recipes.gold_shovel": { + "requirements": [ + [ + "has_wood", + "has_gold" + ] + ], "criteria": { - "has_gold": { + "has_wood": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "gold" + "Wood" ] } ] } - } - }, - "requirements": [ - [ - "has_gold" - ] - ], - "rewards": { - "recipes": { - "Gold Armor_1": ["gold_10"] - } - } - }, - "minicraft.advancements.recipes.gem_armor": { - "criteria": { - "has_gem": { + }, + "has_gold": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "gem" + "Gold" ] } ] } } }, - "requirements": [ - [ - "has_gem" - ] - ], "rewards": { "recipes": { - "Gem Armor_1": ["gem_65"] + "Gold Shovel_1": [ + "Gold_5", + "Wood_5" + ] } } }, - "minicraft.advancements.recipes.empty_bucket": { + "minicraft.advancements.recipes.stone_shovel": { + "requirements": [ + [ + "has_stone", + "has_wood" + ] + ], "criteria": { - "has_iron": { + "has_stone": { + "trigger": "inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "Stone" + ] + } + ] + } + }, + "has_wood": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "iron" + "Wood" ] } ] } } }, - "requirements": [ - [ - "has_iron" - ] - ], "rewards": { "recipes": { - "Empty Bucket_1": ["iron_5"] + "Rock Shovel_1": [ + "Stone_5", + "Wood_5" + ] } } }, - "minicraft.advancements.recipes.iron_lantern": { + "minicraft.advancements.recipes.escape_potion": { + "requirements": [ + [ + "has_lapis", + "has_gunpowder", + "has_awkward_potion" + ] + ], "criteria": { - "has_iron": { + "has_lapis": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "iron" + "Lapis" ] } ] } }, - "has_slime": { + "has_gunpowder": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "slime" + "Gunpowder" ] } ] } }, - "has_glass": { + "has_awkward_potion": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "glass" + "Awkward Potion" ] } ] } } }, + "rewards": { + "recipes": { + "Escape Potion_1": [ + "Lapis_7", + "Awkward Potion_1", + "Gunpowder_3" + ] + } + } + }, + "minicraft.advancements.recipes.obsidian_wall": { "requirements": [ [ - "has_iron", - "has_slime", - "has_glass" + "has_obsidian_brick" ] ], + "criteria": { + "has_obsidian_brick": { + "trigger": "inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "Obsidian Brick" + ] + } + ] + } + } + }, "rewards": { "recipes": { - "Iron Lantern_1": ["iron_8", "slime_5", "glass_4"] + "Obsidian Wall_1": [ + "Obsidian Brick_3" + ] } } }, - "minicraft.advancements.recipes.gold_lantern": { + "minicraft.advancements.recipes.cyan_clothes": { + "requirements": [ + [ + "has_cactus", + "has_lapis", + "has_cloth" + ] + ], "criteria": { - "has_gold": { + "has_cactus": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "gold" + "Cactus" ] } ] } }, - "has_slime": { + "has_lapis": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "slime" + "Lapis" ] } ] } }, - "has_glass": { + "has_cloth": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "glass" + "Cloth" ] } ] } } }, - "requirements": [ - [ - "has_gold", - "has_slime", - "has_glass" - ] - ], "rewards": { "recipes": { - "Gold Lantern_1": ["gold_10", "slime_5", "glass_4"] + "Cyan Clothes_1": [ + "Lapis_1", + "Cloth_5", + "Cactus_1" + ] } } }, - "minicraft.advancements.recipes.iron_sword": { + "minicraft.advancements.recipes.gem_armor": { + "requirements": [ + [ + "has_gem" + ] + ], "criteria": { - "has_wood": { - "trigger": "inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "wood" - ] - } - ] - } - }, - "has_iron": { + "has_gem": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "iron" + "Gem" ] } ] } } }, - "requirements": [ - [ - "has_wood", - "has_iron" - ] - ], "rewards": { "recipes": { - "Iron Sword_1": ["Wood_5", "iron_5"] + "Gem Armor_1": [ + "Gem_65" + ] } } }, - "minicraft.advancements.recipes.iron_claymore": { + "minicraft.advancements.recipes.golden_apple": { + "requirements": [ + [ + "has_apple", + "has_gold" + ] + ], "criteria": { - "has_sword": { + "has_apple": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "iron sword" + "Apple" ] } ] } }, - "has_shard": { + "has_gold": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "shard" + "Gold" ] } ] } } }, - "requirements": [ - [ - "has_sword", - "has_shard" - ] - ], "rewards": { "recipes": { - "Iron Claymore_1": ["Iron Sword_1", "shard_15"] + "Gold Apple_1": [ + "Gold_8", + "Apple_1" + ] } } }, - "minicraft.advancements.recipes.iron_axe": { + "minicraft.advancements.recipes.arrow": { + "requirements": [ + [ + "has_stone", + "has_wood" + ] + ], "criteria": { - "has_wood": { + "has_stone": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "wood" + "Stone" ] } ] } }, - "has_iron": { + "has_wood": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "iron" + "Wood" ] } ] } } }, - "requirements": [ - [ - "has_wood", - "has_iron" - ] - ], "rewards": { "recipes": { - "Iron Axe_1": ["Wood_5", "iron_5"] + "Arrow_3": [ + "Stone_2", + "Wood_2" + ] } } }, - "minicraft.advancements.recipes.iron_hoe": { + "minicraft.advancements.recipes.stone_wall": { + "requirements": [ + [ + "has_stone_brick" + ] + ], "criteria": { - "has_wood": { - "trigger": "inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "wood" - ] - } - ] - } - }, - "has_iron": { + "has_stone_brick": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "iron" + "Stone Brick" ] } ] } } }, - "requirements": [ - [ - "has_wood", - "has_iron" - ] - ], "rewards": { "recipes": { - "Iron Hoe_1": ["Wood_5", "iron_5"] + "Stone Wall_1": [ + "Stone Brick_3" + ] } } }, - "minicraft.advancements.recipes.iron_pickaxe": { + "minicraft.advancements.recipes.glass": { + "requirements": [ + [ + "has_coal", + "has_sand" + ] + ], "criteria": { - "has_wood": { + "has_coal": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "wood" + "Coal" ] } ] } }, - "has_iron": { + "has_sand": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "iron" + "Sand" ] } ] } } }, - "requirements": [ - [ - "has_wood", - "has_iron" - ] - ], "rewards": { "recipes": { - "Iron Pickaxe_1": ["Wood_5", "iron_5"] + "Glass_1": [ + "Coal_1", + "Sand_4" + ] } } }, - "minicraft.advancements.recipes.iron_shovel": { + "minicraft.advancements.recipes.speed_potion": { + "requirements": [ + [ + "has_cactus", + "has_awkward_potion" + ] + ], "criteria": { - "has_wood": { + "has_cactus": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "wood" + "Cactus" ] } ] } }, - "has_iron": { + "has_awkward_potion": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "iron" + "Awkward Potion" ] } ] } } }, - "requirements": [ - [ - "has_wood", - "has_iron" - ] - ], "rewards": { "recipes": { - "Iron Shovel_1": ["Wood_5", "iron_5"] + "Speed Potion_1": [ + "Cactus_5", + "Awkward Potion_1" + ] } } }, - "minicraft.advancements.recipes.iron_bow": { + "minicraft.advancements.recipes.gold_bow": { + "requirements": [ + [ + "has_wood", + "has_string", + "has_gold" + ] + ], "criteria": { "has_wood": { "trigger": "inventory_changed", @@ -2347,59 +2646,63 @@ "items": [ { "items": [ - "wood" + "Wood" ] } ] } }, - "has_iron": { + "has_string": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "iron" + "String" ] } ] } }, - "has_string": { + "has_gold": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "string" + "Gold" ] } ] } } }, - "requirements": [ - [ - "has_wood", - "has_iron", - "has_string" - ] - ], "rewards": { "recipes": { - "Iron Bow_1": ["Wood_5", "iron_5", "string_2"] + "Gold Bow_1": [ + "Gold_5", + "String_2", + "Wood_5" + ] } } }, - "minicraft.advancements.recipes.gold_sword": { + "minicraft.advancements.recipes.gold_lantern": { + "requirements": [ + [ + "has_glass", + "has_gold", + "has_slime" + ] + ], "criteria": { - "has_wood": { + "has_glass": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "wood" + "Glass" ] } ] @@ -2411,104 +2714,98 @@ "items": [ { "items": [ - "gold" - ] - } - ] - } - } - }, - "requirements": [ - [ - "has_wood", - "has_gold" - ] - ], - "rewards": { - "recipes": { - "Gold Sword_1": ["Wood_5", "gold_5"] - } - } - }, - "minicraft.advancements.recipes.gold_claymore": { - "criteria": { - "has_sword": { - "trigger": "inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "gold sword" + "Gold" ] } ] } }, - "has_shard": { + "has_slime": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "shard" + "Slime" ] } ] } } }, - "requirements": [ - [ - "has_sword", - "has_shard" - ] - ], "rewards": { "recipes": { - "Gold Claymore_1": ["Gold Sword_1", "shard_15"] + "Gold Lantern_1": [ + "Glass_4", + "Gold_10", + "Slime_5" + ] } } }, - "minicraft.advancements.recipes.gold_axe": { + "minicraft.advancements.recipes.plank_wall": { + "requirements": [ + [ + "has_plank" + ] + ], "criteria": { - "has_wood": { + "has_plank": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "wood" + "Plank" ] } ] } - }, - "has_gold": { + } + }, + "rewards": { + "recipes": { + "Plank Wall_1": [ + "Plank_3" + ] + } + } + }, + "minicraft.advancements.recipes.iron_armor": { + "requirements": [ + [ + "has_iron" + ] + ], + "criteria": { + "has_iron": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "gold" + "Iron" ] } ] } } }, - "requirements": [ - [ - "has_wood", - "has_gold" - ] - ], "rewards": { "recipes": { - "Gold Axe_1": ["Wood_5", "gold_5"] + "Iron Armor_1": [ + "Iron_10" + ] } } }, - "minicraft.advancements.recipes.gold_hoe": { + "minicraft.advancements.recipes.iron_shovel": { + "requirements": [ + [ + "has_wood", + "has_iron" + ] + ], "criteria": { "has_wood": { "trigger": "inventory_changed", @@ -2516,168 +2813,181 @@ "items": [ { "items": [ - "wood" + "Wood" ] } ] } }, - "has_gold": { + "has_iron": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "gold" + "Iron" ] } ] } } }, - "requirements": [ - [ - "has_wood", - "has_gold" - ] - ], "rewards": { "recipes": { - "Gold Hoe_1": ["Wood_5", "gold_5"] + "Iron Shovel_1": [ + "Wood_5", + "Iron_5" + ] } } }, - "minicraft.advancements.recipes.gold_pickaxe": { + "minicraft.advancements.recipes.yellow_wool": { + "requirements": [ + [ + "has_wool", + "has_flower" + ] + ], "criteria": { - "has_wood": { + "has_wool": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "wood" + "Wool" ] } ] } }, - "has_gold": { + "has_flower": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "gold" + "Flower" ] } ] } } }, - "requirements": [ - [ - "has_wood", - "has_gold" - ] - ], "rewards": { "recipes": { - "Gold Pickaxe_1": ["Wood_5", "gold_5"] + "Yellow Wool_1": [ + "Flower_1", + "Wool_1" + ] } } }, - "minicraft.advancements.recipes.gold_shovel": { + "minicraft.advancements.recipes.obsidian_door": { + "requirements": [ + [ + "has_obsidian_brick" + ] + ], "criteria": { - "has_wood": { - "trigger": "inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "wood" - ] - } - ] - } - }, - "has_gold": { + "has_obsidian_brick": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "gold" + "Obsidian Brick" ] } ] } } }, - "requirements": [ - [ - "has_wood", - "has_gold" - ] - ], "rewards": { "recipes": { - "Gold Shovel_1": ["Wood_5", "gold_5"] + "Obsidian Door_1": [ + "Obsidian Brick_5" + ] } } }, - "minicraft.advancements.recipes.gold_bow": { + "minicraft.advancements.recipes.stone_hoe": { + "requirements": [ + [ + "has_stone", + "has_wood" + ] + ], "criteria": { - "has_wood": { + "has_stone": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "wood" + "Stone" ] } ] } }, - "has_gold": { + "has_wood": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "gold" + "Wood" ] } ] } - }, - "has_string": { + } + }, + "rewards": { + "recipes": { + "Rock Hoe_1": [ + "Stone_5", + "Wood_5" + ] + } + } + }, + "minicraft.advancements.recipes.chest": { + "requirements": [ + [ + "has_wood" + ] + ], + "criteria": { + "has_wood": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "string" + "Wood" ] } ] } } }, - "requirements": [ - [ - "has_wood", - "has_gold", - "has_string" - ] - ], "rewards": { "recipes": { - "Gold Bow_1": ["Wood_5", "gold_5", "string_2"] + "Chest_1": [ + "Wood_20" + ] } } }, - "minicraft.advancements.recipes.gem_sword": { + "minicraft.advancements.recipes.gem_hoe": { + "requirements": [ + [ + "has_wood", + "has_gem" + ] + ], "criteria": { "has_wood": { "trigger": "inventory_changed", @@ -2685,7 +2995,7 @@ "items": [ { "items": [ - "wood" + "Wood" ] } ] @@ -2697,143 +3007,170 @@ "items": [ { "items": [ - "gem" + "Gem" ] } ] } } }, - "requirements": [ - [ - "has_wood", - "has_gem" - ] - ], "rewards": { "recipes": { - "Gem Sword_1": ["Wood_5", "gem_50"] + "Gem Hoe_1": [ + "Wood_5", + "Gem_50" + ] } } }, - "minicraft.advancements.recipes.gem_claymore": { + "minicraft.advancements.recipes.awkward_potion": { + "requirements": [ + [ + "has_lapis", + "has_glass_bottle" + ] + ], "criteria": { - "has_sword": { + "has_lapis": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "gem sword" + "Lapis" ] } ] } }, - "has_shard": { + "has_glass_bottle": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "shard" + "Glass Bottle" ] } ] } } }, + "rewards": { + "recipes": { + "Awkward Potion_1": [ + "Lapis_3", + "Glass Bottle_1" + ] + } + } + }, + "minicraft.advancements.recipes.reg_clothes": { "requirements": [ [ - "has_sword", - "has_shard" + "has_cloth" ] ], + "criteria": { + "has_cloth": { + "trigger": "inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "Cloth" + ] + } + ] + } + } + }, "rewards": { "recipes": { - "Gem Claymore_1": ["Gem Sword_1", "shard_15"] + "Reg Clothes_1": [ + "Cloth_5" + ] } } }, - "minicraft.advancements.recipes.gem_axe": { + "minicraft.advancements.recipes.totem_of_air": { + "requirements": [ + [ + "has_gem", + "has_cloud_ore", + "has_lapis", + "has_gold" + ] + ], "criteria": { - "has_wood": { + "has_gem": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "wood" + "Gem" ] } ] } }, - "has_gem": { + "has_cloud_ore": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "gem" + "Cloud Ore" ] } ] } - } - }, - "requirements": [ - [ - "has_wood", - "has_gem" - ] - ], - "rewards": { - "recipes": { - "Gem Axe_1": ["Wood_5", "gem_50"] - } - } - }, - "minicraft.advancements.recipes.gem_hoe": { - "criteria": { - "has_wood": { + }, + "has_lapis": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "wood" + "Lapis" ] } ] } }, - "has_gem": { + "has_gold": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "gem" + "Gold" ] } ] } } }, - "requirements": [ - [ - "has_wood", - "has_gem" - ] - ], "rewards": { "recipes": { - "Gem Hoe_1": ["Wood_5", "gem_50"] + "Totem of Air_1": [ + "Lapis_5", + "Gold_10", + "Gem_10", + "Cloud Ore_5" + ] } } }, - "minicraft.advancements.recipes.gem_pickaxe": { + "minicraft.advancements.recipes.iron_bow": { + "requirements": [ + [ + "has_wood", + "has_string", + "has_iron" + ] + ], "criteria": { "has_wood": { "trigger": "inventory_changed", @@ -2841,38 +3178,53 @@ "items": [ { "items": [ - "wood" + "Wood" ] } ] } }, - "has_gem": { + "has_string": { + "trigger": "inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "String" + ] + } + ] + } + }, + "has_iron": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "gem" + "Iron" ] } ] } } }, - "requirements": [ - [ - "has_wood", - "has_gem" - ] - ], "rewards": { "recipes": { - "Gem Pickaxe_1": ["Wood_5", "gem_50"] + "Iron Bow_1": [ + "String_2", + "Iron_5", + "Wood_5" + ] } } }, - "minicraft.advancements.recipes.gem_shovel": { + "minicraft.advancements.recipes.wooden_shovel": { + "requirements": [ + [ + "has_wood" + ] + ], "criteria": { "has_wood": { "trigger": "inventory_changed", @@ -2880,38 +3232,56 @@ "items": [ { "items": [ - "wood" + "Wood" ] } ] } - }, - "has_gem": { + } + }, + "rewards": { + "recipes": { + "Wood Shovel_1": [ + "Wood_5" + ] + } + } + }, + "minicraft.advancements.recipes.string": { + "requirements": [ + [ + "has_wool" + ] + ], + "criteria": { + "has_wool": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "gem" + "Wool" ] } ] } } }, - "requirements": [ - [ - "has_wood", - "has_gem" - ] - ], "rewards": { "recipes": { - "Gem Shovel_1": ["Wood_5", "gem_50"] + "String_2": [ + "Wool_1" + ] } } }, - "minicraft.advancements.recipes.gem_bow": { + "minicraft.advancements.recipes.loom": { + "requirements": [ + [ + "has_wood", + "has_wool" + ] + ], "criteria": { "has_wood": { "trigger": "inventory_changed", @@ -2919,51 +3289,68 @@ "items": [ { "items": [ - "wood" + "Wood" ] } ] } }, - "has_gem": { + "has_wool": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "gem" + "Wool" ] } ] } - }, - "has_string": { + } + }, + "rewards": { + "recipes": { + "Loom_1": [ + "Wood_10", + "Wool_5" + ] + } + } + }, + "minicraft.advancements.recipes.bread": { + "requirements": [ + [ + "has_wheat" + ] + ], + "criteria": { + "has_wheat": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "string" + "Wheat" ] } ] } } }, - "requirements": [ - [ - "has_wood", - "has_gem", - "has_string" - ] - ], "rewards": { "recipes": { - "Gem Bow_1": ["Wood_5", "gem_50", "string_2"] + "Bread_1": [ + "Wheat_4" + ] } } }, - "minicraft.advancements.recipes.shears": { + "minicraft.advancements.recipes.anvil": { + "requirements": [ + [ + "has_iron" + ] + ], "criteria": { "has_iron": { "trigger": "inventory_changed", @@ -2971,631 +3358,694 @@ "items": [ { "items": [ - "iron" + "Iron" ] } ] } } }, - "requirements": [ - [ - "has_iron" - ] - ], "rewards": { "recipes": { - "Shears_1": ["Iron_4"] + "Anvil_1": [ + "Iron_5" + ] } } }, - "minicraft.advancements.recipes.iron": { + "minicraft.advancements.recipes.torch": { + "requirements": [ + [ + "has_coal", + "has_wood" + ] + ], "criteria": { - "has_ore": { + "has_coal": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "iron ore" + "Coal" ] } ] } }, - "has_coal": { + "has_wood": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "coal" + "Wood" ] } ] } } }, - "requirements": [ - [ - "has_ore", - "has_coal" - ] - ], "rewards": { "recipes": { - "iron_1": ["iron Ore_4", "coal_1"] + "Torch_2": [ + "Coal_1", + "Wood_1" + ] } } }, - "minicraft.advancements.recipes.gold": { + "minicraft.advancements.recipes.gold_axe": { + "requirements": [ + [ + "has_wood", + "has_gold" + ] + ], "criteria": { - "has_ore": { + "has_wood": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "gold ore" + "Wood" ] } ] } }, - "has_coal": { + "has_gold": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "coal" + "Gold" ] } ] } } }, - "requirements": [ - [ - "has_ore", - "has_coal" - ] - ], "rewards": { "recipes": { - "gold_1": ["gold Ore_4", "coal_1"] + "Gold Axe_1": [ + "Gold_5", + "Wood_5" + ] } } }, - "minicraft.advancements.recipes.glass": { + "minicraft.advancements.recipes.iron_lantern": { + "requirements": [ + [ + "has_glass", + "has_slime", + "has_iron" + ] + ], "criteria": { - "has_sand": { + "has_glass": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "sand" + "Glass" ] } ] } }, - "has_coal": { + "has_slime": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "coal" + "Slime" ] } ] } - } - }, - "requirements": [ - [ - "has_sand", - "has_coal" - ] - ], - "rewards": { - "recipes": { - "glass_1": ["sand_4", "coal_1"] - } - } - }, - "minicraft.advancements.recipes.glass_bottle": { - "criteria": { - "has_glass": { + }, + "has_iron": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "glass" + "Iron" ] } ] } } }, - "requirements": [ - [ - "has_glass" - ] - ], "rewards": { "recipes": { - "glass bottle_1": ["glass_3"] + "Iron Lantern_1": [ + "Glass_4", + "Iron_8", + "Slime_5" + ] } } }, - "minicraft.advancements.recipes.cooked_pork": { + "minicraft.advancements.recipes.enchanter": { + "requirements": [ + [ + "has_wood", + "has_string", + "has_lapis" + ] + ], "criteria": { - "has_pork": { + "has_wood": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "raw pork" + "Wood" ] } ] } }, - "has_coal": { + "has_string": { + "trigger": "inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "String" + ] + } + ] + } + }, + "has_lapis": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "coal" + "Lapis" ] } ] } } }, - "requirements": [ - [ - "has_pork", - "has_coal" - ] - ], "rewards": { "recipes": { - "cooked pork_1": ["raw pork_1", "coal_1"] + "Enchanter_1": [ + "Lapis_10", + "String_2", + "Wood_5" + ] } } }, - "minicraft.advancements.recipes.steak": { + "minicraft.advancements.recipes.gold_claymore": { + "requirements": [ + [ + "has_shard", + "has_gold_sword" + ] + ], "criteria": { - "has_beef": { + "has_shard": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "raw beef" + "Shard" ] } ] } }, - "has_coal": { + "has_gold_sword": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "coal" + "Gold Sword" ] } ] } } }, - "requirements": [ - [ - "has_beef", - "has_coal" - ] - ], "rewards": { "recipes": { - "steak_1": ["raw beef_1", "coal_1"] + "Gold Claymore_1": [ + "Shard_15", + "Gold Sword_1" + ] } } }, - "minicraft.advancements.recipes.cooked_fish": { + "minicraft.advancements.recipes.baked_potato": { + "requirements": [ + [ + "has_potato" + ] + ], "criteria": { - "has_fish": { + "has_potato": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "raw fish" + "Potato" ] } ] } - }, - "has_coal": { + } + }, + "rewards": { + "recipes": { + "Baked Potato_1": [ + "Potato_1" + ] + } + } + }, + "minicraft.advancements.recipes.empty_bucket": { + "requirements": [ + [ + "has_iron" + ] + ], + "criteria": { + "has_iron": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "coal" + "Iron" ] } ] } } }, - "requirements": [ - [ - "has_fish", - "has_coal" - ] - ], "rewards": { "recipes": { - "cooked fish_1": ["raw fish_1", "coal_1"] + "Empty Bucket_1": [ + "Iron_5" + ] } } }, - "minicraft.advancements.recipes.bread": { + "minicraft.advancements.recipes.gold_hoe": { + "requirements": [ + [ + "has_wood", + "has_gold" + ] + ], "criteria": { - "has_wheat": { + "has_wood": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "wheat" + "Wood" ] } ] } - } - }, - "requirements": [ - [ - "has_wheat" - ] - ], - "rewards": { - "recipes": { - "bread_1": ["wheat_4"] - } - } - }, - "minicraft.advancements.recipes.baked_potato": { - "criteria": { - "has_potato": { + }, + "has_gold": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "potato" + "Gold" ] } ] } } }, - "requirements": [ - [ - "has_potato" - ] - ], "rewards": { "recipes": { - "Baked Potato_1": ["Potato_1"] + "Gold Hoe_1": [ + "Gold_5", + "Wood_5" + ] } } }, - "minicraft.advancements.recipes.golden_apple": { + "minicraft.advancements.recipes.iron": { + "requirements": [ + [ + "has_coal", + "has_iron_ore" + ] + ], "criteria": { - "has_apple": { + "has_coal": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "apple" + "Coal" ] } ] } }, - "has_gold": { + "has_iron_ore": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "gold" + "Iron Ore" ] } ] } } }, + "rewards": { + "recipes": { + "Iron_1": [ + "Coal_1", + "Iron Ore_3" + ] + } + } + }, + "minicraft.advancements.recipes.stone_door": { "requirements": [ [ - "has_apple", - "has_gold" + "has_stone_brick" ] ], + "criteria": { + "has_stone_brick": { + "trigger": "inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "Stone Brick" + ] + } + ] + } + } + }, "rewards": { "recipes": { - "Gold Apple_1": ["apple_1", "gold_8"] + "Stone Door_1": [ + "Stone Brick_5" + ] } } }, - "minicraft.advancements.recipes.awkward_potion": { + "minicraft.advancements.recipes.obsidian_poppet": { + "requirements": [ + [ + "has_shard", + "has_gem", + "has_lapis", + "has_gold" + ] + ], "criteria": { - "has_bottle": { + "has_shard": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "glass bottle" + "Shard" ] } ] } }, - "has_lapis": { + "has_gem": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "lapis" + "Gem" ] } ] } - } - }, - "requirements": [ - [ - "has_bottle", - "has_lapis" - ] - ], - "rewards": { - "recipes": { - "awkward potion_1": ["glass bottle_1", "Lapis_3"] - } - } - }, - "minicraft.advancements.recipes.speed_potion": { - "criteria": { - "has_awkward": { + }, + "has_lapis": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "awkward potion" + "Lapis" ] } ] } }, - "has_cactus": { + "has_gold": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "cactus" + "Gold" ] } ] } } }, - "requirements": [ - [ - "has_awkward", - "has_cactus" - ] - ], "rewards": { "recipes": { - "speed potion_1": ["awkward potion_1", "Cactus_5"] + "Obsidian Poppet_1": [ + "Lapis_5", + "Gold_10", + "Shard_15", + "Gem_10" + ] } } }, - "minicraft.advancements.recipes.light_potion": { + "minicraft.advancements.recipes.gem_axe": { + "requirements": [ + [ + "has_wood", + "has_gem" + ] + ], "criteria": { - "has_awkward": { + "has_wood": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "awkward potion" + "Wood" ] } ] } }, - "has_slime": { + "has_gem": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "slime" + "Gem" ] } ] } } }, - "requirements": [ - [ - "has_awkward", - "has_slime" - ] - ], "rewards": { "recipes": { - "light potion_1": ["awkward potion_1", "slime_5"] + "Gem Axe_1": [ + "Wood_5", + "Gem_50" + ] } } }, - "minicraft.advancements.recipes.swim_potion": { + "minicraft.advancements.recipes.tnt": { + "requirements": [ + [ + "has_sand", + "has_gunpowder" + ] + ], "criteria": { - "has_awkward": { + "has_sand": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "awkward potion" + "Sand" ] } ] } }, - "has_fish": { + "has_gunpowder": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "raw fish" + "Gunpowder" ] } ] } } }, - "requirements": [ - [ - "has_awkward", - "has_fish" - ] - ], "rewards": { "recipes": { - "swim potion_1": ["awkward potion_1", "raw fish_5"] + "Tnt_1": [ + "Sand_8", + "Gunpowder_10" + ] } } }, - "minicraft.advancements.recipes.haste_potion": { + "minicraft.advancements.recipes.iron_sword": { + "requirements": [ + [ + "has_wood", + "has_iron" + ] + ], "criteria": { - "has_awkward": { - "trigger": "inventory_changed", - "conditions": { - "items": [ - { - "items": [ - "awkward potion" - ] - } - ] - } - }, "has_wood": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "wood" + "Wood" ] } ] } }, - "has_stone": { + "has_iron": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "stone" + "Iron" ] } ] } } }, - "requirements": [ - [ - "has_awkward", - "has_wood", - "has_stone" - ] - ], "rewards": { "recipes": { - "haste potion_1": ["awkward potion_1", "Wood_5", "Stone_5"] + "Iron Sword_1": [ + "Wood_5", + "Iron_5" + ] } } }, - "minicraft.advancements.recipes.lava_potion": { + "minicraft.advancements.recipes.wooden_sword": { + "requirements": [ + [ + "has_wood" + ] + ], "criteria": { - "has_awkward": { + "has_wood": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "awkward potion" + "Wood" ] } ] } - }, - "has_lava_bucket": { + } + }, + "rewards": { + "recipes": { + "Wood Sword_1": [ + "Wood_5" + ] + } + } + }, + "minicraft.advancements.recipes.furnace": { + "requirements": [ + [ + "has_stone" + ] + ], + "criteria": { + "has_stone": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "lava bucket" + "Stone" ] } ] } } }, - "requirements": [ - [ - "has_awkward", - "has_lava_bucket" - ] - ], "rewards": { "recipes": { - "lava potion_1": ["awkward potion_1", "Lava Bucket_1"] + "Furnace_1": [ + "Stone_20" + ] } } }, - "minicraft.advancements.recipes.energy_potion": { + "minicraft.advancements.recipes.gem_shovel": { + "requirements": [ + [ + "has_wood", + "has_gem" + ] + ], "criteria": { - "has_awkward": { + "has_wood": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "awkward potion" + "Wood" ] } ] @@ -3607,230 +4057,299 @@ "items": [ { "items": [ - "gem" + "Gem" ] } ] } } }, - "requirements": [ - [ - "has_awkward", - "has_gem" - ] - ], "rewards": { "recipes": { - "energy potion_1": ["awkward potion_1", "gem_25"] + "Gem Shovel_1": [ + "Wood_5", + "Gem_50" + ] } } }, - "minicraft.advancements.recipes.regen_potion": { + "minicraft.advancements.recipes.black_clothes": { + "requirements": [ + [ + "has_coal", + "has_cloth" + ] + ], "criteria": { - "has_awkward": { + "has_coal": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "awkward potion" + "Coal" ] } ] } }, - "has_golden_apple": { + "has_cloth": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "gold apple" + "Cloth" ] } ] } } }, - "requirements": [ - [ - "has_awkward", - "has_golden_apple" - ] - ], "rewards": { "recipes": { - "regen potion_1": ["awkward potion_1", "Gold Apple_1"] + "Black Clothes_1": [ + "Coal_1", + "Cloth_5" + ] } } }, - "minicraft.advancements.recipes.health_potion": { + "minicraft.advancements.recipes.haste_potion": { + "requirements": [ + [ + "has_stone", + "has_wood", + "has_awkward_potion" + ] + ], "criteria": { - "has_awkward": { + "has_stone": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "awkward potion" + "Stone" ] } ] } }, - "has_gunpowder": { + "has_wood": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "gunpowder" + "Wood" ] } ] } }, - "has_leather_armor": { + "has_awkward_potion": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "leather armor" + "Awkward Potion" ] } ] } } }, - "requirements": [ - [ - "has_awkward", - "has_gunpowder", - "has_leather_armor" - ] - ], "rewards": { "recipes": { - "Health potion_1": ["awkward potion_1", "GunPowder_2", "Leather Armor_1"] + "Haste Potion_1": [ + "Awkward Potion_1", + "Stone_5", + "Wood_5" + ] } } }, - "minicraft.advancements.recipes.escape_potion": { + "minicraft.advancements.recipes.blue_wool": { + "requirements": [ + [ + "has_lapis", + "has_wool" + ] + ], "criteria": { - "has_awkward": { + "has_lapis": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "awkward potion" + "Lapis" ] } ] } }, - "has_gunpowder": { + "has_wool": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "gunpowder" + "Wool" ] } ] } - }, - "has_lapis": { + } + }, + "rewards": { + "recipes": { + "Blue Wool_1": [ + "Lapis_1", + "Wool_1" + ] + } + } + }, + "minicraft.advancements.recipes.ornate_obsidian": { + "requirements": [ + [ + "has_raw_obsidian" + ] + ], + "criteria": { + "has_raw_obsidian": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "lapis" + "Raw Obsidian" ] } ] } } }, - "requirements": [ - [ - "has_awkward", - "has_gunpowder", - "has_lapis" - ] - ], "rewards": { "recipes": { - "Escape potion_1": ["awkward potion_1", "GunPowder_3", "Lapis_7"] + "Ornate Obsidian_1": [ + "Raw Obsidian_2" + ] } } }, - "minicraft.advancements.recipes.totem_of_air": { + "minicraft.advancements.recipes.energy_potion": { + "requirements": [ + [ + "has_gem", + "has_awkward_potion" + ] + ], "criteria": { - "has_gold": { + "has_gem": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "gold potion" + "Gem" ] } ] } }, - "has_gem": { + "has_awkward_potion": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "gem" + "Awkward Potion" ] } ] } - }, - "has_lapis": { + } + }, + "rewards": { + "recipes": { + "Energy Potion_1": [ + "Awkward Potion_1", + "Gem_25" + ] + } + } + }, + "minicraft.advancements.recipes.oven": { + "requirements": [ + [ + "has_stone" + ] + ], + "criteria": { + "has_stone": { + "trigger": "inventory_changed", + "conditions": { + "items": [ + { + "items": [ + "Stone" + ] + } + ] + } + } + }, + "rewards": { + "recipes": { + "Oven_1": [ + "Stone_15" + ] + } + } + }, + "minicraft.advancements.recipes.regen_potion": { + "requirements": [ + [ + "has_golden_apple", + "has_awkward_potion" + ] + ], + "criteria": { + "has_golden_apple": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "lapis" + "Gold Apple" ] } ] } }, - "has_cloud_ore": { + "has_awkward_potion": { "trigger": "inventory_changed", "conditions": { "items": [ { "items": [ - "cloud ore" + "Awkward Potion" ] } ] } } }, - "requirements": [ - [ - "has_gold", - "has_gem", - "has_lapis", - "has_cloud_ore" - ] - ], "rewards": { "recipes": { - "Totem of Air_1": ["gold_10", "gem_10", "Lapis_5","Cloud Ore_5"] + "Regen Potion_1": [ + "Gold Apple_1", + "Awkward Potion_1" + ] } } } diff --git a/src/client/resources/tinylog.properties b/src/client/resources/tinylog.properties index 0db23bc41..f303f6b62 100644 --- a/src/client/resources/tinylog.properties +++ b/src/client/resources/tinylog.properties @@ -1,33 +1,27 @@ # suppress inspection "UnusedProperty" for whole file # If there is any modification in this file, # minicraft.util.TinylogLoggingProvider and/or minicraft.util.TinylogLoggingConfiguration might also need to be modified. - # Note: # "@" in writer.tag is not implemented as an extra parameter here. - -provider = minicraft.util.TinylogLoggingProvider -writingthread = true # This is always true. - +provider=minicraft.util.TinylogLoggingProvider +writingthread=true # This is always true. # Logging to console # All console writers are generated directly by minicraft.util.TinylogLoggingConfiguration. - # Log file -writer2 = file -writer2.level = trace -writer2.file = logs/log.txt -writer2.charset = UTF-8 -writer2.format = {date: HH:mm:ss.SSS} [{tag}] {level}: {message} - -writer2Full = file -writer2Full.level = trace -writer2Full.file = logs/log.txt -writer2Full.charset = UTF-8 -writer2Full.format = {date: yyyy-MM-dd HH:mm:ss.SSSSSSSSS} [{thread-id}/{thread}] [{tag}] {level}: {message} - +writer2=file +writer2.level=trace +writer2.file=logs/log.txt +writer2.charset=UTF-8 +writer2.format={date: HH:mm:ss.SSS} [{tag}] {level}: {message} +writer2Full=file +writer2Full.level=trace +writer2Full.file=logs/log.txt +writer2Full.charset=UTF-8 +writer2Full.format={date: yyyy-MM-dd HH:mm:ss.SSSSSSSSS} [{thread-id}/{thread}] [{tag}] {level}: {message} # Localization message file -writer3 = file -writer3.level = trace -writer3.file = logs/unlocalized.txt -writer3.charset = UTF-8 -writer3.format = [{file}#L{line}] [{class}#{method}]: {message-only} -writer3.tag = LOC +writer3=file +writer3.level=trace +writer3.file=logs/unlocalized.txt +writer3.charset=UTF-8 +writer3.format=[{file}#L{line}] [{class}#{method}]: {message-only} +writer3.tag=LOC