From 3fb8f624cc2d0a5c3f6b9ba9c7ea448a778d3940 Mon Sep 17 00:00:00 2001 From: tartaric_acid Date: Tue, 22 Oct 2024 21:34:36 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90=201.20=20=E7=9A=84=E5=90=8C?= =?UTF-8?q?=E6=AD=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + .../advancement/base/build_altar.json | 35 + .../advancement/base/change_chair_model.json | 30 + .../advancement/base/change_maid_model.json | 30 + .../advancement/base/change_maid_sound.json | 30 + .../advancement/base/craft_chair.json | 30 + .../advancement/base/craft_gohei.json | 39 + .../advancement/base/kill_maid_fairy.json | 38 + .../advancement/base/pickup_power_point.json | 30 + .../advancement/base/spawn_maid.json | 38 + .../advancement/base/tamed_maid.json | 31 + .../challenge/all_netherite_equipment.json | 34 + .../advancement/challenge/any_equipment.json | 29 + .../challenge/eat_enchanted_golden_apple.json | 30 + .../advancement/challenge/kill_100.json | 34 + .../advancement/challenge/kill_dragon.json | 31 + .../advancement/challenge/kill_slime_300.json | 34 + .../advancement/challenge/kill_wither.json | 31 + .../advancement/challenge/lightning_bolt.json | 33 + .../challenge/maid_100_healthy.json | 31 + .../favorability/favorability_increased.json | 30 + .../favorability_increased_max.json | 31 + .../favorability/maid_picnic_eat.json | 30 + .../favorability/maid_sit_joy.json | 32 + .../advancement/favorability/maid_sleep.json | 30 + .../advancement/favorability/win_cchess.json | 31 + .../advancement/favorability/win_gomoku.json | 31 + .../advancement/favorability/win_wchess.json | 31 + .../advancement/maid_base/chisel_statue.json | 30 + .../maid_base/clear_maid_effects.json | 30 + .../advancement/maid_base/maid_backpack.json | 30 + .../advancement/maid_base/maid_farm.json | 31 + .../maid_base/maid_feed_animal.json | 30 + .../maid_base/maid_feed_player.json | 30 + .../advancement/maid_base/maid_fishing.json | 30 + .../advancement/maid_base/maid_kill_mob.json | 31 + .../advancement/maid_base/photo_maid.json | 30 + .../maid_base/pickup_garage_kit.json | 32 + .../advancement/maid_base/pickup_maid.json | 30 + .../advancement/maid_base/reborn_maid.json | 33 + .../maid_base/shrine_reborn_maid.json | 31 + .../maid_base/switch_schedule.json | 30 + .../advancement/maid_base/switch_task.json | 29 + .../advancement/maid_base/take_maid_xp.json | 30 + .../maid_base/use_item_magnet_bauble.json | 30 + .../maid_base/use_nimble_fabric.json | 30 + .../maid_base/use_protect_bauble.json | 30 + .../maid_base/use_red_fox_scroll.json | 30 + .../maid_base/use_servant_bell.json | 30 + .../advancement/maid_base/use_trumpet.json | 30 + .../maid_base/use_undead_bauble.json | 31 + .../maid_base/use_white_fox_scroll.json | 30 + .../maid_base/use_wireless_io.json | 30 + .../loot_table/advancement/cake.json | 16 + .../loot_table/advancement/power_point.json | 16 + .../advancements/altar/AltarCraftTrigger.java | 40 + .../{ => altar}/package-info.java | 12 +- .../advancements/maid/MaidEventTrigger.java | 38 + .../advancements/maid/TriggerType.java | 65 + .../advancements/maid/package-info.java | 7 + .../GivePatchouliBookConfigTrigger.java | 2 +- .../GiveSmartSlabConfigTrigger.java | 68 +- .../advancements/rewards/package-info.java | 7 + .../touhoulittlemaid/api/ILittleMaid.java | 9 + .../api/block/IBoardGameBlock.java | 13 + .../api/block/IBoardGameEntityBlock.java | 10 + .../api/entity/ai/IExtraMaidBrain.java | 25 + .../api/game/chess/Evaluate.java | 411 ++ .../api/game/chess/Position.java | 1188 +++++ .../api/game/chess/Search.java | 399 ++ .../touhoulittlemaid/api/game/chess/Util.java | 129 + .../api/game/xqwlight/Position.java | 1122 ++++ .../api/game/xqwlight/Search.java | 456 ++ .../api/game/xqwlight/Util.java | 129 + .../touhoulittlemaid/block/BlockAltar.java | 10 +- .../touhoulittlemaid/block/BlockCChess.java | 349 ++ .../touhoulittlemaid/block/BlockGomoku.java | 12 +- .../touhoulittlemaid/block/BlockShrine.java | 6 + .../touhoulittlemaid/block/BlockWChess.java | 353 ++ .../client/entity/GeckoMaidEntity.java | 12 +- .../client/event/MaidSoundFreqEvent.java | 9 +- .../entity/maid/AbstractMaidContainerGui.java | 4 +- .../entity/maid/MaidConfigContainerGui.java | 92 - .../client/gui/entity/maid/MaidSideTabs.java | 21 +- .../client/gui/entity/maid/MaidTabs.java | 20 +- .../maid/config/MaidConfigContainerGui.java | 137 + .../maid/{ => other}/CheckSchedulePosGui.java | 3 +- ...Gui.java => DefaultMaidTaskConfigGui.java} | 4 +- .../entity/maid/task/MaidTaskConfigGui.java | 11 - .../gui/item/PicnicBasketContainerScreen.java | 2 +- .../gui/item/WirelessIOContainerGui.java | 2 +- .../gui/widget/button/MaidConfigButton.java | 89 + .../widget/button/MaidSoundFreqButton.java | 27 - .../gui/widget/button/MaidTabButton.java | 27 +- .../client/init/ClientSetupEvent.java | 2 - .../client/init/InitContainerGui.java | 6 +- .../client/init/InitEntitiesRender.java | 5 + .../client/model/CChessModel.java | 45 + .../client/model/CChessPiecesModel.java | 65 + .../client/model/WChessModel.java | 39 + .../client/model/WChessPiecesModel.java | 87 + .../client/model/bedrock/BedrockModel.java | 4 + .../renderer/entity/EntityMaidRenderer.java | 3 +- .../geckolayer/GeckoLayerMaidBackItem.java | 9 +- .../geckolayer/GeckoLayerMaidBackpack.java | 4 +- .../geckolayer/GeckoLayerMaidBanner.java | 7 +- .../entity/layer/LayerMaidBackItem.java | 11 +- .../entity/layer/LayerMaidBackpack.java | 3 +- .../entity/layer/LayerMaidBanner.java | 7 +- .../tileentity/TileEntityCChessRenderer.java | 164 + .../tileentity/TileEntityWChessRenderer.java | 164 + .../entity/AquacultureFishingHook.java | 1 + .../config/subconfig/InGameMaidConfig.java | 84 - .../datagen/AdvancementDataGen.java | 17 +- .../datagen/LootTableGenerator.java | 11 + .../datagen/advancement/BaseAdvancement.java | 118 + .../advancement/ChallengeAdvancement.java | 123 + .../advancement/FavorabilityAdvancement.java | 85 + .../advancement/MaidBaseAdvancement.java | 187 + .../ai/brain/ExtraMaidBrainManager.java | 23 + .../entity/ai/brain/MaidBrain.java | 11 +- ...GomokuTask.java => MaidBoardGameTask.java} | 34 +- .../ai/brain/task/MaidFarmPlantTask.java | 9 + .../ai/brain/task/MaidFeedAnimalTask.java | 6 + .../ai/brain/task/MaidFeedOwnerTask.java | 6 + .../ai/brain/task/MaidHomeMealTask.java | 6 + .../ai/brain/task/MaidInteractWithDoor.java | 12 +- .../entity/ai/brain/task/MaidJoyTask.java | 6 + .../ai/navigation/MaidNodeEvaluator.java | 26 +- .../favorability/FavorabilityManager.java | 12 + .../entity/favorability/Type.java | 2 + .../entity/item/EntityPowerPoint.java | 5 + .../entity/passive/EntityMaid.java | 180 +- .../entity/passive/MaidConfigManager.java | 310 ++ .../entity/passive/MaidKillRecordManager.java | 73 + .../entity/passive/PickType.java | 43 + .../entity/passive/SideTab.java | 6 +- .../entity/passive/TabIndex.java | 3 +- .../entity/poi/MaidPoiManager.java | 3 +- .../entity/projectile/MaidFishingHook.java | 16 + .../entity/task/TaskBoardGames.java | 6 +- .../event/EntityDeathEvent.java | 18 + .../event/maid/ApplyGoldenAppleEvent.java | 6 + .../event/maid/ApplyPotionEffectEvent.java | 6 + .../event/maid/GetExpBottleEvent.java | 6 + .../event/maid/HandleBackpackEvent.java | 6 + .../event/maid/SaddleMaidEvent.java | 6 + .../geckolib3/core/AnimatableEntity.java | 8 +- .../geckolib3/util/RenderUtils.java | 11 - .../touhoulittlemaid/init/InitBlocks.java | 4 + .../touhoulittlemaid/init/InitContainer.java | 6 +- .../init/InitCreativeTabs.java | 2 + .../touhoulittlemaid/init/InitItems.java | 11 + .../touhoulittlemaid/init/InitTrigger.java | 8 +- .../init/registry/CommonRegistry.java | 2 + .../{ => config}/MaidConfigContainer.java | 3 +- .../{ => other}/PicnicBasketContainer.java | 2 +- .../{ => other}/WirelessIOContainer.java | 224 +- .../item/ItemAdvancementIcon.java | 25 + .../touhoulittlemaid/item/ItemCamera.java | 10 +- .../touhoulittlemaid/item/ItemChisel.java | 6 + .../item/ItemEntityPlaceholder.java | 4 +- .../touhoulittlemaid/item/ItemFoxScroll.java | 11 +- .../item/ItemHakureiGohei.java | 6 + .../item/ItemPicnicBasket.java | 2 +- .../item/ItemServantBell.java | 6 + .../touhoulittlemaid/item/ItemTrumpet.java | 6 + .../touhoulittlemaid/item/ItemWirelessIO.java | 2 +- .../item/bauble/DrownProtectBauble.java | 6 + .../item/bauble/ExplosionProtectBauble.java | 6 + .../item/bauble/ExtraLifeBauble.java | 6 + .../item/bauble/FallProtectBauble.java | 6 + .../item/bauble/FireProtectBauble.java | 6 + .../item/bauble/ItemMagnetBauble.java | 6 + .../item/bauble/MagicProtectBauble.java | 6 + .../item/bauble/NimbleFabricBauble.java | 6 + .../item/bauble/ProjectileProtectBauble.java | 6 + .../item/bauble/UndyingTotemBauble.java | 6 + .../item/bauble/WirelessIOBauble.java | 6 + .../mixin/client/RenderSystemMixin.java | 21 - .../network/NetworkHandler.java | 10 +- .../message/CChessToClientPackage.java | 77 + .../message/CChessToServerPackage.java | 45 + .../network/message/ChairModelPackage.java | 3 + .../message/CheckSchedulePosPacket.java | 2 +- ...tPackage.java => GomokuClientPackage.java} | 26 +- ...rPackage.java => GomokuServerPackage.java} | 14 +- .../network/message/MaidConfigPackage.java | 5 + .../network/message/MaidModelPackage.java | 3 + .../network/message/MaidSubConfigPackage.java | 52 + .../network/message/MaidTaskPackage.java | 11 + .../message/SetMaidSoundIdPackage.java | 3 + .../network/message/ToggleSideTabPackage.java | 47 - .../message/WChessToClientPackage.java | 77 + .../message/WChessToServerPackage.java | 45 + .../tileentity/TileEntityCChess.java | 122 + .../tileentity/TileEntityGomoku.java | 3 +- .../tileentity/TileEntityWChess.java | 122 + .../touhoulittlemaid/util/CChessUtil.java | 67 + .../touhoulittlemaid/util/WChessUtil.java | 60 + .../blockstates/cchess.json | 7 + .../blockstates/wchess.json | 7 + .../touhou_little_maid/book/cchess/BOOK.DAT | Bin 0 -> 96648 bytes .../touhou_little_maid/book/wchess/BOOK.DAT | Bin 0 -> 124216 bytes .../assets/touhou_little_maid/lang/en_us.json | 134 +- .../assets/touhou_little_maid/lang/zh_cn.json | 240 +- .../models/block/cchess.json | 5 + .../models/block/wchess.json | 5 + .../models/entity/cchess_pieces.json | 4564 +++++++++++++++++ .../models/item/all_netherite_equipment.json | 6 + .../models/item/cchess.json | 6 + .../models/item/change_chair_model.json | 6 + .../models/item/change_maid_model.json | 6 + .../models/item/kill_dragon.json | 6 + .../models/item/kill_slime_300.json | 6 + .../models/item/kill_wither.json | 6 + .../models/item/maid_100_healthy.json | 6 + .../models/item/wchess.json | 6 + .../advancements/backgrounds/stone.png | Bin 0 -> 427 bytes .../textures/entity/cchess.png | Bin 0 -> 66708 bytes .../textures/entity/cchess_pieces.png | Bin 0 -> 3011 bytes .../textures/entity/wchess.png | Bin 0 -> 680 bytes .../textures/entity/wchess_pieces.png | Bin 0 -> 16931 bytes .../textures/gui/maid_gui_button.png | Bin 7013 -> 7282 bytes .../textures/gui/maid_gui_config.png | Bin 1212 -> 1552 bytes .../textures/gui/maid_gui_side.png | Bin 5172 -> 5059 bytes .../textures/item/all_netherite_equipment.png | Bin 0 -> 304 bytes .../textures/item/cchess.png | Bin 0 -> 278 bytes .../textures/item/change_chair_model.png | Bin 0 -> 228 bytes .../textures/item/change_maid_model.png | Bin 0 -> 307 bytes .../textures/item/kill_dragon.png | Bin 0 -> 291 bytes .../textures/item/kill_slime_300.png | Bin 0 -> 287 bytes .../textures/item/kill_wither.png | Bin 0 -> 282 bytes .../textures/item/maid_100_healthy.png | Bin 0 -> 311 bytes .../textures/item/wchess.png | Bin 0 -> 253 bytes src/main/resources/licenses/chess | 339 ++ src/main/resources/licenses/xqwlight | 339 ++ .../resources/touhou_little_maid.mixins.json | 2 +- 238 files changed, 15297 insertions(+), 711 deletions(-) create mode 100644 src/generated/resources/data/touhou_little_maid/advancement/base/build_altar.json create mode 100644 src/generated/resources/data/touhou_little_maid/advancement/base/change_chair_model.json create mode 100644 src/generated/resources/data/touhou_little_maid/advancement/base/change_maid_model.json create mode 100644 src/generated/resources/data/touhou_little_maid/advancement/base/change_maid_sound.json create mode 100644 src/generated/resources/data/touhou_little_maid/advancement/base/craft_chair.json create mode 100644 src/generated/resources/data/touhou_little_maid/advancement/base/craft_gohei.json create mode 100644 src/generated/resources/data/touhou_little_maid/advancement/base/kill_maid_fairy.json create mode 100644 src/generated/resources/data/touhou_little_maid/advancement/base/pickup_power_point.json create mode 100644 src/generated/resources/data/touhou_little_maid/advancement/base/spawn_maid.json create mode 100644 src/generated/resources/data/touhou_little_maid/advancement/base/tamed_maid.json create mode 100644 src/generated/resources/data/touhou_little_maid/advancement/challenge/all_netherite_equipment.json create mode 100644 src/generated/resources/data/touhou_little_maid/advancement/challenge/any_equipment.json create mode 100644 src/generated/resources/data/touhou_little_maid/advancement/challenge/eat_enchanted_golden_apple.json create mode 100644 src/generated/resources/data/touhou_little_maid/advancement/challenge/kill_100.json create mode 100644 src/generated/resources/data/touhou_little_maid/advancement/challenge/kill_dragon.json create mode 100644 src/generated/resources/data/touhou_little_maid/advancement/challenge/kill_slime_300.json create mode 100644 src/generated/resources/data/touhou_little_maid/advancement/challenge/kill_wither.json create mode 100644 src/generated/resources/data/touhou_little_maid/advancement/challenge/lightning_bolt.json create mode 100644 src/generated/resources/data/touhou_little_maid/advancement/challenge/maid_100_healthy.json create mode 100644 src/generated/resources/data/touhou_little_maid/advancement/favorability/favorability_increased.json create mode 100644 src/generated/resources/data/touhou_little_maid/advancement/favorability/favorability_increased_max.json create mode 100644 src/generated/resources/data/touhou_little_maid/advancement/favorability/maid_picnic_eat.json create mode 100644 src/generated/resources/data/touhou_little_maid/advancement/favorability/maid_sit_joy.json create mode 100644 src/generated/resources/data/touhou_little_maid/advancement/favorability/maid_sleep.json create mode 100644 src/generated/resources/data/touhou_little_maid/advancement/favorability/win_cchess.json create mode 100644 src/generated/resources/data/touhou_little_maid/advancement/favorability/win_gomoku.json create mode 100644 src/generated/resources/data/touhou_little_maid/advancement/favorability/win_wchess.json create mode 100644 src/generated/resources/data/touhou_little_maid/advancement/maid_base/chisel_statue.json create mode 100644 src/generated/resources/data/touhou_little_maid/advancement/maid_base/clear_maid_effects.json create mode 100644 src/generated/resources/data/touhou_little_maid/advancement/maid_base/maid_backpack.json create mode 100644 src/generated/resources/data/touhou_little_maid/advancement/maid_base/maid_farm.json create mode 100644 src/generated/resources/data/touhou_little_maid/advancement/maid_base/maid_feed_animal.json create mode 100644 src/generated/resources/data/touhou_little_maid/advancement/maid_base/maid_feed_player.json create mode 100644 src/generated/resources/data/touhou_little_maid/advancement/maid_base/maid_fishing.json create mode 100644 src/generated/resources/data/touhou_little_maid/advancement/maid_base/maid_kill_mob.json create mode 100644 src/generated/resources/data/touhou_little_maid/advancement/maid_base/photo_maid.json create mode 100644 src/generated/resources/data/touhou_little_maid/advancement/maid_base/pickup_garage_kit.json create mode 100644 src/generated/resources/data/touhou_little_maid/advancement/maid_base/pickup_maid.json create mode 100644 src/generated/resources/data/touhou_little_maid/advancement/maid_base/reborn_maid.json create mode 100644 src/generated/resources/data/touhou_little_maid/advancement/maid_base/shrine_reborn_maid.json create mode 100644 src/generated/resources/data/touhou_little_maid/advancement/maid_base/switch_schedule.json create mode 100644 src/generated/resources/data/touhou_little_maid/advancement/maid_base/switch_task.json create mode 100644 src/generated/resources/data/touhou_little_maid/advancement/maid_base/take_maid_xp.json create mode 100644 src/generated/resources/data/touhou_little_maid/advancement/maid_base/use_item_magnet_bauble.json create mode 100644 src/generated/resources/data/touhou_little_maid/advancement/maid_base/use_nimble_fabric.json create mode 100644 src/generated/resources/data/touhou_little_maid/advancement/maid_base/use_protect_bauble.json create mode 100644 src/generated/resources/data/touhou_little_maid/advancement/maid_base/use_red_fox_scroll.json create mode 100644 src/generated/resources/data/touhou_little_maid/advancement/maid_base/use_servant_bell.json create mode 100644 src/generated/resources/data/touhou_little_maid/advancement/maid_base/use_trumpet.json create mode 100644 src/generated/resources/data/touhou_little_maid/advancement/maid_base/use_undead_bauble.json create mode 100644 src/generated/resources/data/touhou_little_maid/advancement/maid_base/use_white_fox_scroll.json create mode 100644 src/generated/resources/data/touhou_little_maid/advancement/maid_base/use_wireless_io.json create mode 100644 src/generated/resources/data/touhou_little_maid/loot_table/advancement/cake.json create mode 100644 src/generated/resources/data/touhou_little_maid/loot_table/advancement/power_point.json create mode 100644 src/main/java/com/github/tartaricacid/touhoulittlemaid/advancements/altar/AltarCraftTrigger.java rename src/main/java/com/github/tartaricacid/touhoulittlemaid/advancements/{ => altar}/package-info.java (71%) create mode 100644 src/main/java/com/github/tartaricacid/touhoulittlemaid/advancements/maid/MaidEventTrigger.java create mode 100644 src/main/java/com/github/tartaricacid/touhoulittlemaid/advancements/maid/TriggerType.java create mode 100644 src/main/java/com/github/tartaricacid/touhoulittlemaid/advancements/maid/package-info.java rename src/main/java/com/github/tartaricacid/touhoulittlemaid/advancements/{ => rewards}/GivePatchouliBookConfigTrigger.java (95%) rename src/main/java/com/github/tartaricacid/touhoulittlemaid/advancements/{ => rewards}/GiveSmartSlabConfigTrigger.java (86%) create mode 100644 src/main/java/com/github/tartaricacid/touhoulittlemaid/advancements/rewards/package-info.java create mode 100644 src/main/java/com/github/tartaricacid/touhoulittlemaid/api/block/IBoardGameBlock.java create mode 100644 src/main/java/com/github/tartaricacid/touhoulittlemaid/api/block/IBoardGameEntityBlock.java create mode 100644 src/main/java/com/github/tartaricacid/touhoulittlemaid/api/entity/ai/IExtraMaidBrain.java create mode 100644 src/main/java/com/github/tartaricacid/touhoulittlemaid/api/game/chess/Evaluate.java create mode 100644 src/main/java/com/github/tartaricacid/touhoulittlemaid/api/game/chess/Position.java create mode 100644 src/main/java/com/github/tartaricacid/touhoulittlemaid/api/game/chess/Search.java create mode 100644 src/main/java/com/github/tartaricacid/touhoulittlemaid/api/game/chess/Util.java create mode 100644 src/main/java/com/github/tartaricacid/touhoulittlemaid/api/game/xqwlight/Position.java create mode 100644 src/main/java/com/github/tartaricacid/touhoulittlemaid/api/game/xqwlight/Search.java create mode 100644 src/main/java/com/github/tartaricacid/touhoulittlemaid/api/game/xqwlight/Util.java create mode 100644 src/main/java/com/github/tartaricacid/touhoulittlemaid/block/BlockCChess.java create mode 100644 src/main/java/com/github/tartaricacid/touhoulittlemaid/block/BlockWChess.java delete mode 100644 src/main/java/com/github/tartaricacid/touhoulittlemaid/client/gui/entity/maid/MaidConfigContainerGui.java create mode 100644 src/main/java/com/github/tartaricacid/touhoulittlemaid/client/gui/entity/maid/config/MaidConfigContainerGui.java rename src/main/java/com/github/tartaricacid/touhoulittlemaid/client/gui/entity/maid/{ => other}/CheckSchedulePosGui.java (94%) rename src/main/java/com/github/tartaricacid/touhoulittlemaid/client/gui/entity/maid/task/{DefaultMaidTaskConfigContainerGui.java => DefaultMaidTaskConfigGui.java} (79%) create mode 100644 src/main/java/com/github/tartaricacid/touhoulittlemaid/client/gui/widget/button/MaidConfigButton.java delete mode 100644 src/main/java/com/github/tartaricacid/touhoulittlemaid/client/gui/widget/button/MaidSoundFreqButton.java create mode 100644 src/main/java/com/github/tartaricacid/touhoulittlemaid/client/model/CChessModel.java create mode 100644 src/main/java/com/github/tartaricacid/touhoulittlemaid/client/model/CChessPiecesModel.java create mode 100644 src/main/java/com/github/tartaricacid/touhoulittlemaid/client/model/WChessModel.java create mode 100644 src/main/java/com/github/tartaricacid/touhoulittlemaid/client/model/WChessPiecesModel.java create mode 100644 src/main/java/com/github/tartaricacid/touhoulittlemaid/client/renderer/tileentity/TileEntityCChessRenderer.java create mode 100644 src/main/java/com/github/tartaricacid/touhoulittlemaid/client/renderer/tileentity/TileEntityWChessRenderer.java delete mode 100644 src/main/java/com/github/tartaricacid/touhoulittlemaid/config/subconfig/InGameMaidConfig.java create mode 100644 src/main/java/com/github/tartaricacid/touhoulittlemaid/datagen/advancement/BaseAdvancement.java create mode 100644 src/main/java/com/github/tartaricacid/touhoulittlemaid/datagen/advancement/ChallengeAdvancement.java create mode 100644 src/main/java/com/github/tartaricacid/touhoulittlemaid/datagen/advancement/FavorabilityAdvancement.java create mode 100644 src/main/java/com/github/tartaricacid/touhoulittlemaid/datagen/advancement/MaidBaseAdvancement.java create mode 100644 src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/ai/brain/ExtraMaidBrainManager.java rename src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/ai/brain/task/{MaidGomokuTask.java => MaidBoardGameTask.java} (69%) create mode 100644 src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/passive/MaidConfigManager.java create mode 100644 src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/passive/MaidKillRecordManager.java create mode 100644 src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/passive/PickType.java create mode 100644 src/main/java/com/github/tartaricacid/touhoulittlemaid/event/EntityDeathEvent.java rename src/main/java/com/github/tartaricacid/touhoulittlemaid/inventory/container/{ => config}/MaidConfigContainer.java (95%) rename src/main/java/com/github/tartaricacid/touhoulittlemaid/inventory/container/{ => other}/PicnicBasketContainer.java (99%) rename src/main/java/com/github/tartaricacid/touhoulittlemaid/inventory/container/{ => other}/WirelessIOContainer.java (97%) create mode 100644 src/main/java/com/github/tartaricacid/touhoulittlemaid/item/ItemAdvancementIcon.java delete mode 100644 src/main/java/com/github/tartaricacid/touhoulittlemaid/mixin/client/RenderSystemMixin.java create mode 100644 src/main/java/com/github/tartaricacid/touhoulittlemaid/network/message/CChessToClientPackage.java create mode 100644 src/main/java/com/github/tartaricacid/touhoulittlemaid/network/message/CChessToServerPackage.java rename src/main/java/com/github/tartaricacid/touhoulittlemaid/network/message/{ChessDataClientPackage.java => GomokuClientPackage.java} (68%) rename src/main/java/com/github/tartaricacid/touhoulittlemaid/network/message/{ChessDataServerPackage.java => GomokuServerPackage.java} (83%) create mode 100644 src/main/java/com/github/tartaricacid/touhoulittlemaid/network/message/MaidSubConfigPackage.java delete mode 100644 src/main/java/com/github/tartaricacid/touhoulittlemaid/network/message/ToggleSideTabPackage.java create mode 100644 src/main/java/com/github/tartaricacid/touhoulittlemaid/network/message/WChessToClientPackage.java create mode 100644 src/main/java/com/github/tartaricacid/touhoulittlemaid/network/message/WChessToServerPackage.java create mode 100644 src/main/java/com/github/tartaricacid/touhoulittlemaid/tileentity/TileEntityCChess.java create mode 100644 src/main/java/com/github/tartaricacid/touhoulittlemaid/tileentity/TileEntityWChess.java create mode 100644 src/main/java/com/github/tartaricacid/touhoulittlemaid/util/CChessUtil.java create mode 100644 src/main/java/com/github/tartaricacid/touhoulittlemaid/util/WChessUtil.java create mode 100644 src/main/resources/assets/touhou_little_maid/blockstates/cchess.json create mode 100644 src/main/resources/assets/touhou_little_maid/blockstates/wchess.json create mode 100644 src/main/resources/assets/touhou_little_maid/book/cchess/BOOK.DAT create mode 100644 src/main/resources/assets/touhou_little_maid/book/wchess/BOOK.DAT create mode 100644 src/main/resources/assets/touhou_little_maid/models/block/cchess.json create mode 100644 src/main/resources/assets/touhou_little_maid/models/block/wchess.json create mode 100644 src/main/resources/assets/touhou_little_maid/models/entity/cchess_pieces.json create mode 100644 src/main/resources/assets/touhou_little_maid/models/item/all_netherite_equipment.json create mode 100644 src/main/resources/assets/touhou_little_maid/models/item/cchess.json create mode 100644 src/main/resources/assets/touhou_little_maid/models/item/change_chair_model.json create mode 100644 src/main/resources/assets/touhou_little_maid/models/item/change_maid_model.json create mode 100644 src/main/resources/assets/touhou_little_maid/models/item/kill_dragon.json create mode 100644 src/main/resources/assets/touhou_little_maid/models/item/kill_slime_300.json create mode 100644 src/main/resources/assets/touhou_little_maid/models/item/kill_wither.json create mode 100644 src/main/resources/assets/touhou_little_maid/models/item/maid_100_healthy.json create mode 100644 src/main/resources/assets/touhou_little_maid/models/item/wchess.json create mode 100644 src/main/resources/assets/touhou_little_maid/textures/advancements/backgrounds/stone.png create mode 100644 src/main/resources/assets/touhou_little_maid/textures/entity/cchess.png create mode 100644 src/main/resources/assets/touhou_little_maid/textures/entity/cchess_pieces.png create mode 100644 src/main/resources/assets/touhou_little_maid/textures/entity/wchess.png create mode 100644 src/main/resources/assets/touhou_little_maid/textures/entity/wchess_pieces.png create mode 100644 src/main/resources/assets/touhou_little_maid/textures/item/all_netherite_equipment.png create mode 100644 src/main/resources/assets/touhou_little_maid/textures/item/cchess.png create mode 100644 src/main/resources/assets/touhou_little_maid/textures/item/change_chair_model.png create mode 100644 src/main/resources/assets/touhou_little_maid/textures/item/change_maid_model.png create mode 100644 src/main/resources/assets/touhou_little_maid/textures/item/kill_dragon.png create mode 100644 src/main/resources/assets/touhou_little_maid/textures/item/kill_slime_300.png create mode 100644 src/main/resources/assets/touhou_little_maid/textures/item/kill_wither.png create mode 100644 src/main/resources/assets/touhou_little_maid/textures/item/maid_100_healthy.png create mode 100644 src/main/resources/assets/touhou_little_maid/textures/item/wchess.png create mode 100644 src/main/resources/licenses/chess create mode 100644 src/main/resources/licenses/xqwlight diff --git a/.gitignore b/.gitignore index 0ca762e42..d040b35a4 100644 --- a/.gitignore +++ b/.gitignore @@ -29,3 +29,4 @@ src/test # Files from Forge MDK forge*changelog.txt +/src/generated/resources/.cache/ diff --git a/src/generated/resources/data/touhou_little_maid/advancement/base/build_altar.json b/src/generated/resources/data/touhou_little_maid/advancement/base/build_altar.json new file mode 100644 index 000000000..7d5873413 --- /dev/null +++ b/src/generated/resources/data/touhou_little_maid/advancement/base/build_altar.json @@ -0,0 +1,35 @@ +{ + "parent": "touhou_little_maid:base/craft_gohei", + "criteria": { + "maid_event": { + "conditions": { + "event": "build_altar" + }, + "trigger": "touhou_little_maid:maid_event" + } + }, + "display": { + "background": "touhou_little_maid:textures/advancements/backgrounds/stone.png", + "description": { + "translate": "advancements.touhou_little_maid.base.build_altar.description" + }, + "icon": { + "count": 1, + "id": "minecraft:red_wool" + }, + "title": { + "translate": "advancements.touhou_little_maid.base.build_altar.title" + } + }, + "requirements": [ + [ + "maid_event" + ] + ], + "rewards": { + "loot": [ + "touhou_little_maid:advancement/power_point" + ] + }, + "sends_telemetry_event": true +} \ No newline at end of file diff --git a/src/generated/resources/data/touhou_little_maid/advancement/base/change_chair_model.json b/src/generated/resources/data/touhou_little_maid/advancement/base/change_chair_model.json new file mode 100644 index 000000000..1681ddeff --- /dev/null +++ b/src/generated/resources/data/touhou_little_maid/advancement/base/change_chair_model.json @@ -0,0 +1,30 @@ +{ + "parent": "touhou_little_maid:base/craft_chair", + "criteria": { + "maid_event": { + "conditions": { + "event": "change_chair_model" + }, + "trigger": "touhou_little_maid:maid_event" + } + }, + "display": { + "background": "touhou_little_maid:textures/advancements/backgrounds/stone.png", + "description": { + "translate": "advancements.touhou_little_maid.base.change_chair_model.description" + }, + "icon": { + "count": 1, + "id": "touhou_little_maid:change_chair_model" + }, + "title": { + "translate": "advancements.touhou_little_maid.base.change_chair_model.title" + } + }, + "requirements": [ + [ + "maid_event" + ] + ], + "sends_telemetry_event": true +} \ No newline at end of file diff --git a/src/generated/resources/data/touhou_little_maid/advancement/base/change_maid_model.json b/src/generated/resources/data/touhou_little_maid/advancement/base/change_maid_model.json new file mode 100644 index 000000000..e4864029a --- /dev/null +++ b/src/generated/resources/data/touhou_little_maid/advancement/base/change_maid_model.json @@ -0,0 +1,30 @@ +{ + "parent": "touhou_little_maid:base/spawn_maid", + "criteria": { + "maid_event": { + "conditions": { + "event": "change_maid_model" + }, + "trigger": "touhou_little_maid:maid_event" + } + }, + "display": { + "background": "touhou_little_maid:textures/advancements/backgrounds/stone.png", + "description": { + "translate": "advancements.touhou_little_maid.base.change_maid_model.description" + }, + "icon": { + "count": 1, + "id": "touhou_little_maid:change_maid_model" + }, + "title": { + "translate": "advancements.touhou_little_maid.base.change_maid_model.title" + } + }, + "requirements": [ + [ + "maid_event" + ] + ], + "sends_telemetry_event": true +} \ No newline at end of file diff --git a/src/generated/resources/data/touhou_little_maid/advancement/base/change_maid_sound.json b/src/generated/resources/data/touhou_little_maid/advancement/base/change_maid_sound.json new file mode 100644 index 000000000..fa90210eb --- /dev/null +++ b/src/generated/resources/data/touhou_little_maid/advancement/base/change_maid_sound.json @@ -0,0 +1,30 @@ +{ + "parent": "touhou_little_maid:base/spawn_maid", + "criteria": { + "maid_event": { + "conditions": { + "event": "change_maid_sound" + }, + "trigger": "touhou_little_maid:maid_event" + } + }, + "display": { + "background": "touhou_little_maid:textures/advancements/backgrounds/stone.png", + "description": { + "translate": "advancements.touhou_little_maid.base.change_maid_sound.description" + }, + "icon": { + "count": 1, + "id": "minecraft:jukebox" + }, + "title": { + "translate": "advancements.touhou_little_maid.base.change_maid_sound.title" + } + }, + "requirements": [ + [ + "maid_event" + ] + ], + "sends_telemetry_event": true +} \ No newline at end of file diff --git a/src/generated/resources/data/touhou_little_maid/advancement/base/craft_chair.json b/src/generated/resources/data/touhou_little_maid/advancement/base/craft_chair.json new file mode 100644 index 000000000..4c6485452 --- /dev/null +++ b/src/generated/resources/data/touhou_little_maid/advancement/base/craft_chair.json @@ -0,0 +1,30 @@ +{ + "parent": "touhou_little_maid:base/craft_gohei", + "criteria": { + "craft_chair": { + "conditions": { + "recipe_id": "touhou_little_maid:chair" + }, + "trigger": "minecraft:recipe_crafted" + } + }, + "display": { + "background": "touhou_little_maid:textures/advancements/backgrounds/stone.png", + "description": { + "translate": "advancements.touhou_little_maid.base.craft_chair.description" + }, + "icon": { + "count": 1, + "id": "touhou_little_maid:chair" + }, + "title": { + "translate": "advancements.touhou_little_maid.base.craft_chair.title" + } + }, + "requirements": [ + [ + "craft_chair" + ] + ], + "sends_telemetry_event": true +} \ No newline at end of file diff --git a/src/generated/resources/data/touhou_little_maid/advancement/base/craft_gohei.json b/src/generated/resources/data/touhou_little_maid/advancement/base/craft_gohei.json new file mode 100644 index 000000000..48a5448fb --- /dev/null +++ b/src/generated/resources/data/touhou_little_maid/advancement/base/craft_gohei.json @@ -0,0 +1,39 @@ +{ + "criteria": { + "craft_hakurei_gohei": { + "conditions": { + "recipe_id": "touhou_little_maid:hakurei_gohei" + }, + "trigger": "minecraft:recipe_crafted" + }, + "craft_sanae_gohei": { + "conditions": { + "recipe_id": "touhou_little_maid:sanae_gohei" + }, + "trigger": "minecraft:recipe_crafted" + } + }, + "display": { + "background": "touhou_little_maid:textures/advancements/backgrounds/stone.png", + "description": { + "translate": "advancements.touhou_little_maid.base.craft_gohei.description" + }, + "icon": { + "count": 1, + "id": "touhou_little_maid:hakurei_gohei" + }, + "title": { + "translate": "advancements.touhou_little_maid.base.craft_gohei.title" + } + }, + "requirements": [ + [ + "craft_hakurei_gohei", + "craft_sanae_gohei" + ] + ], + "rewards": { + "experience": 50 + }, + "sends_telemetry_event": true +} \ No newline at end of file diff --git a/src/generated/resources/data/touhou_little_maid/advancement/base/kill_maid_fairy.json b/src/generated/resources/data/touhou_little_maid/advancement/base/kill_maid_fairy.json new file mode 100644 index 000000000..95df13d56 --- /dev/null +++ b/src/generated/resources/data/touhou_little_maid/advancement/base/kill_maid_fairy.json @@ -0,0 +1,38 @@ +{ + "parent": "touhou_little_maid:base/build_altar", + "criteria": { + "killed_entity": { + "conditions": { + "entity": [ + { + "condition": "minecraft:entity_properties", + "entity": "this", + "predicate": { + "type": "touhou_little_maid:fairy" + } + } + ] + }, + "trigger": "minecraft:player_killed_entity" + } + }, + "display": { + "background": "touhou_little_maid:textures/advancements/backgrounds/stone.png", + "description": { + "translate": "advancements.touhou_little_maid.base.kill_maid_fairy.description" + }, + "icon": { + "count": 1, + "id": "touhou_little_maid:fairy_spawn_egg" + }, + "title": { + "translate": "advancements.touhou_little_maid.base.kill_maid_fairy.title" + } + }, + "requirements": [ + [ + "killed_entity" + ] + ], + "sends_telemetry_event": true +} \ No newline at end of file diff --git a/src/generated/resources/data/touhou_little_maid/advancement/base/pickup_power_point.json b/src/generated/resources/data/touhou_little_maid/advancement/base/pickup_power_point.json new file mode 100644 index 000000000..53500121d --- /dev/null +++ b/src/generated/resources/data/touhou_little_maid/advancement/base/pickup_power_point.json @@ -0,0 +1,30 @@ +{ + "parent": "touhou_little_maid:base/build_altar", + "criteria": { + "maid_event": { + "conditions": { + "event": "pickup_power_point" + }, + "trigger": "touhou_little_maid:maid_event" + } + }, + "display": { + "background": "touhou_little_maid:textures/advancements/backgrounds/stone.png", + "description": { + "translate": "advancements.touhou_little_maid.base.pickup_power_point.description" + }, + "icon": { + "count": 1, + "id": "touhou_little_maid:power_point" + }, + "title": { + "translate": "advancements.touhou_little_maid.base.pickup_power_point.title" + } + }, + "requirements": [ + [ + "maid_event" + ] + ], + "sends_telemetry_event": true +} \ No newline at end of file diff --git a/src/generated/resources/data/touhou_little_maid/advancement/base/spawn_maid.json b/src/generated/resources/data/touhou_little_maid/advancement/base/spawn_maid.json new file mode 100644 index 000000000..b3524507e --- /dev/null +++ b/src/generated/resources/data/touhou_little_maid/advancement/base/spawn_maid.json @@ -0,0 +1,38 @@ +{ + "parent": "touhou_little_maid:base/craft_gohei", + "criteria": { + "altar_craft": { + "conditions": { + "recipe_id": "touhou_little_maid:altar_recipe/spawn_box" + }, + "trigger": "touhou_little_maid:altar_craft" + } + }, + "display": { + "background": "touhou_little_maid:textures/advancements/backgrounds/stone.png", + "description": { + "translate": "advancements.touhou_little_maid.base.spawn_maid.description" + }, + "icon": { + "components": { + "touhou_little_maid:recipe_id": "spawn_box" + }, + "count": 1, + "id": "touhou_little_maid:entity_placeholder" + }, + "title": { + "translate": "advancements.touhou_little_maid.base.spawn_maid.title" + } + }, + "requirements": [ + [ + "altar_craft" + ] + ], + "rewards": { + "loot": [ + "touhou_little_maid:advancement/cake" + ] + }, + "sends_telemetry_event": true +} \ No newline at end of file diff --git a/src/generated/resources/data/touhou_little_maid/advancement/base/tamed_maid.json b/src/generated/resources/data/touhou_little_maid/advancement/base/tamed_maid.json new file mode 100644 index 000000000..3e9e9916e --- /dev/null +++ b/src/generated/resources/data/touhou_little_maid/advancement/base/tamed_maid.json @@ -0,0 +1,31 @@ +{ + "parent": "touhou_little_maid:base/spawn_maid", + "criteria": { + "maid_event": { + "conditions": { + "event": "tamed_maid" + }, + "trigger": "touhou_little_maid:maid_event" + } + }, + "display": { + "background": "touhou_little_maid:textures/advancements/backgrounds/stone.png", + "description": { + "translate": "advancements.touhou_little_maid.base.tamed_maid.description" + }, + "frame": "goal", + "icon": { + "count": 1, + "id": "minecraft:cake" + }, + "title": { + "translate": "advancements.touhou_little_maid.base.tamed_maid.title" + } + }, + "requirements": [ + [ + "maid_event" + ] + ], + "sends_telemetry_event": true +} \ No newline at end of file diff --git a/src/generated/resources/data/touhou_little_maid/advancement/challenge/all_netherite_equipment.json b/src/generated/resources/data/touhou_little_maid/advancement/challenge/all_netherite_equipment.json new file mode 100644 index 000000000..b7dcfd8fa --- /dev/null +++ b/src/generated/resources/data/touhou_little_maid/advancement/challenge/all_netherite_equipment.json @@ -0,0 +1,34 @@ +{ + "parent": "touhou_little_maid:challenge/eat_enchanted_golden_apple", + "criteria": { + "maid_event": { + "conditions": { + "event": "all_netherite_equipment" + }, + "trigger": "touhou_little_maid:maid_event" + } + }, + "display": { + "background": "touhou_little_maid:textures/advancements/backgrounds/stone.png", + "description": { + "translate": "advancements.touhou_little_maid.challenge.all_netherite_equipment.description" + }, + "frame": "challenge", + "icon": { + "count": 1, + "id": "touhou_little_maid:all_netherite_equipment" + }, + "title": { + "translate": "advancements.touhou_little_maid.challenge.all_netherite_equipment.title" + } + }, + "requirements": [ + [ + "maid_event" + ] + ], + "rewards": { + "experience": 50 + }, + "sends_telemetry_event": true +} \ No newline at end of file diff --git a/src/generated/resources/data/touhou_little_maid/advancement/challenge/any_equipment.json b/src/generated/resources/data/touhou_little_maid/advancement/challenge/any_equipment.json new file mode 100644 index 000000000..67728401f --- /dev/null +++ b/src/generated/resources/data/touhou_little_maid/advancement/challenge/any_equipment.json @@ -0,0 +1,29 @@ +{ + "criteria": { + "maid_event": { + "conditions": { + "event": "any_equipment" + }, + "trigger": "touhou_little_maid:maid_event" + } + }, + "display": { + "background": "touhou_little_maid:textures/advancements/backgrounds/stone.png", + "description": { + "translate": "advancements.touhou_little_maid.challenge.any_equipment.description" + }, + "icon": { + "count": 1, + "id": "minecraft:iron_helmet" + }, + "title": { + "translate": "advancements.touhou_little_maid.challenge.any_equipment.title" + } + }, + "requirements": [ + [ + "maid_event" + ] + ], + "sends_telemetry_event": true +} \ No newline at end of file diff --git a/src/generated/resources/data/touhou_little_maid/advancement/challenge/eat_enchanted_golden_apple.json b/src/generated/resources/data/touhou_little_maid/advancement/challenge/eat_enchanted_golden_apple.json new file mode 100644 index 000000000..3ba05c4be --- /dev/null +++ b/src/generated/resources/data/touhou_little_maid/advancement/challenge/eat_enchanted_golden_apple.json @@ -0,0 +1,30 @@ +{ + "parent": "touhou_little_maid:challenge/any_equipment", + "criteria": { + "maid_event": { + "conditions": { + "event": "eat_enchanted_golden_apple" + }, + "trigger": "touhou_little_maid:maid_event" + } + }, + "display": { + "background": "touhou_little_maid:textures/advancements/backgrounds/stone.png", + "description": { + "translate": "advancements.touhou_little_maid.challenge.eat_enchanted_golden_apple.description" + }, + "icon": { + "count": 1, + "id": "minecraft:enchanted_golden_apple" + }, + "title": { + "translate": "advancements.touhou_little_maid.challenge.eat_enchanted_golden_apple.title" + } + }, + "requirements": [ + [ + "maid_event" + ] + ], + "sends_telemetry_event": true +} \ No newline at end of file diff --git a/src/generated/resources/data/touhou_little_maid/advancement/challenge/kill_100.json b/src/generated/resources/data/touhou_little_maid/advancement/challenge/kill_100.json new file mode 100644 index 000000000..811d6d1fe --- /dev/null +++ b/src/generated/resources/data/touhou_little_maid/advancement/challenge/kill_100.json @@ -0,0 +1,34 @@ +{ + "parent": "touhou_little_maid:challenge/any_equipment", + "criteria": { + "maid_event": { + "conditions": { + "event": "kill_100" + }, + "trigger": "touhou_little_maid:maid_event" + } + }, + "display": { + "background": "touhou_little_maid:textures/advancements/backgrounds/stone.png", + "description": { + "translate": "advancements.touhou_little_maid.challenge.kill_100.description" + }, + "frame": "goal", + "icon": { + "count": 1, + "id": "minecraft:diamond_sword" + }, + "title": { + "translate": "advancements.touhou_little_maid.challenge.kill_100.title" + } + }, + "requirements": [ + [ + "maid_event" + ] + ], + "rewards": { + "experience": 50 + }, + "sends_telemetry_event": true +} \ No newline at end of file diff --git a/src/generated/resources/data/touhou_little_maid/advancement/challenge/kill_dragon.json b/src/generated/resources/data/touhou_little_maid/advancement/challenge/kill_dragon.json new file mode 100644 index 000000000..df57765fe --- /dev/null +++ b/src/generated/resources/data/touhou_little_maid/advancement/challenge/kill_dragon.json @@ -0,0 +1,31 @@ +{ + "parent": "touhou_little_maid:challenge/kill_wither", + "criteria": { + "maid_event": { + "conditions": { + "event": "kill_dragon" + }, + "trigger": "touhou_little_maid:maid_event" + } + }, + "display": { + "background": "touhou_little_maid:textures/advancements/backgrounds/stone.png", + "description": { + "translate": "advancements.touhou_little_maid.challenge.kill_dragon.description" + }, + "frame": "challenge", + "icon": { + "count": 1, + "id": "touhou_little_maid:kill_dragon" + }, + "title": { + "translate": "advancements.touhou_little_maid.challenge.kill_dragon.title" + } + }, + "requirements": [ + [ + "maid_event" + ] + ], + "sends_telemetry_event": true +} \ No newline at end of file diff --git a/src/generated/resources/data/touhou_little_maid/advancement/challenge/kill_slime_300.json b/src/generated/resources/data/touhou_little_maid/advancement/challenge/kill_slime_300.json new file mode 100644 index 000000000..ce4cf2020 --- /dev/null +++ b/src/generated/resources/data/touhou_little_maid/advancement/challenge/kill_slime_300.json @@ -0,0 +1,34 @@ +{ + "parent": "touhou_little_maid:challenge/kill_100", + "criteria": { + "maid_event": { + "conditions": { + "event": "kill_slime_300" + }, + "trigger": "touhou_little_maid:maid_event" + } + }, + "display": { + "background": "touhou_little_maid:textures/advancements/backgrounds/stone.png", + "description": { + "translate": "advancements.touhou_little_maid.challenge.kill_slime_300.description" + }, + "frame": "challenge", + "icon": { + "count": 1, + "id": "touhou_little_maid:kill_slime_300" + }, + "title": { + "translate": "advancements.touhou_little_maid.challenge.kill_slime_300.title" + } + }, + "requirements": [ + [ + "maid_event" + ] + ], + "rewards": { + "experience": 50 + }, + "sends_telemetry_event": true +} \ No newline at end of file diff --git a/src/generated/resources/data/touhou_little_maid/advancement/challenge/kill_wither.json b/src/generated/resources/data/touhou_little_maid/advancement/challenge/kill_wither.json new file mode 100644 index 000000000..211d4990c --- /dev/null +++ b/src/generated/resources/data/touhou_little_maid/advancement/challenge/kill_wither.json @@ -0,0 +1,31 @@ +{ + "parent": "touhou_little_maid:challenge/kill_100", + "criteria": { + "maid_event": { + "conditions": { + "event": "kill_wither" + }, + "trigger": "touhou_little_maid:maid_event" + } + }, + "display": { + "background": "touhou_little_maid:textures/advancements/backgrounds/stone.png", + "description": { + "translate": "advancements.touhou_little_maid.challenge.kill_wither.description" + }, + "frame": "challenge", + "icon": { + "count": 1, + "id": "touhou_little_maid:kill_wither" + }, + "title": { + "translate": "advancements.touhou_little_maid.challenge.kill_wither.title" + } + }, + "requirements": [ + [ + "maid_event" + ] + ], + "sends_telemetry_event": true +} \ No newline at end of file diff --git a/src/generated/resources/data/touhou_little_maid/advancement/challenge/lightning_bolt.json b/src/generated/resources/data/touhou_little_maid/advancement/challenge/lightning_bolt.json new file mode 100644 index 000000000..9fc3132c2 --- /dev/null +++ b/src/generated/resources/data/touhou_little_maid/advancement/challenge/lightning_bolt.json @@ -0,0 +1,33 @@ +{ + "parent": "touhou_little_maid:challenge/eat_enchanted_golden_apple", + "criteria": { + "maid_event": { + "conditions": { + "event": "lightning_bolt" + }, + "trigger": "touhou_little_maid:maid_event" + } + }, + "display": { + "background": "touhou_little_maid:textures/advancements/backgrounds/stone.png", + "description": { + "translate": "advancements.touhou_little_maid.challenge.lightning_bolt.description" + }, + "icon": { + "components": { + "touhou_little_maid:recipe_id": "spawn_lightning_bolt" + }, + "count": 1, + "id": "touhou_little_maid:entity_placeholder" + }, + "title": { + "translate": "advancements.touhou_little_maid.challenge.lightning_bolt.title" + } + }, + "requirements": [ + [ + "maid_event" + ] + ], + "sends_telemetry_event": true +} \ No newline at end of file diff --git a/src/generated/resources/data/touhou_little_maid/advancement/challenge/maid_100_healthy.json b/src/generated/resources/data/touhou_little_maid/advancement/challenge/maid_100_healthy.json new file mode 100644 index 000000000..06ae9ad2a --- /dev/null +++ b/src/generated/resources/data/touhou_little_maid/advancement/challenge/maid_100_healthy.json @@ -0,0 +1,31 @@ +{ + "parent": "touhou_little_maid:challenge/lightning_bolt", + "criteria": { + "maid_event": { + "conditions": { + "event": "maid_100_healthy" + }, + "trigger": "touhou_little_maid:maid_event" + } + }, + "display": { + "background": "touhou_little_maid:textures/advancements/backgrounds/stone.png", + "description": { + "translate": "advancements.touhou_little_maid.challenge.maid_100_healthy.description" + }, + "frame": "goal", + "icon": { + "count": 1, + "id": "touhou_little_maid:maid_100_healthy" + }, + "title": { + "translate": "advancements.touhou_little_maid.challenge.maid_100_healthy.title" + } + }, + "requirements": [ + [ + "maid_event" + ] + ], + "sends_telemetry_event": true +} \ No newline at end of file diff --git a/src/generated/resources/data/touhou_little_maid/advancement/favorability/favorability_increased.json b/src/generated/resources/data/touhou_little_maid/advancement/favorability/favorability_increased.json new file mode 100644 index 000000000..3eba4ac7f --- /dev/null +++ b/src/generated/resources/data/touhou_little_maid/advancement/favorability/favorability_increased.json @@ -0,0 +1,30 @@ +{ + "parent": "touhou_little_maid:favorability/maid_sit_joy", + "criteria": { + "maid_event": { + "conditions": { + "event": "favorability_increased" + }, + "trigger": "touhou_little_maid:maid_event" + } + }, + "display": { + "background": "touhou_little_maid:textures/advancements/backgrounds/stone.png", + "description": { + "translate": "advancements.touhou_little_maid.favorability.favorability_increased.description" + }, + "icon": { + "count": 1, + "id": "touhou_little_maid:favorability_tool_add" + }, + "title": { + "translate": "advancements.touhou_little_maid.favorability.favorability_increased.title" + } + }, + "requirements": [ + [ + "maid_event" + ] + ], + "sends_telemetry_event": true +} \ No newline at end of file diff --git a/src/generated/resources/data/touhou_little_maid/advancement/favorability/favorability_increased_max.json b/src/generated/resources/data/touhou_little_maid/advancement/favorability/favorability_increased_max.json new file mode 100644 index 000000000..e79c3e2f6 --- /dev/null +++ b/src/generated/resources/data/touhou_little_maid/advancement/favorability/favorability_increased_max.json @@ -0,0 +1,31 @@ +{ + "parent": "touhou_little_maid:favorability/favorability_increased", + "criteria": { + "maid_event": { + "conditions": { + "event": "favorability_increased_max" + }, + "trigger": "touhou_little_maid:maid_event" + } + }, + "display": { + "background": "touhou_little_maid:textures/advancements/backgrounds/stone.png", + "description": { + "translate": "advancements.touhou_little_maid.favorability.favorability_increased_max.description" + }, + "frame": "goal", + "icon": { + "count": 1, + "id": "touhou_little_maid:favorability_tool_full" + }, + "title": { + "translate": "advancements.touhou_little_maid.favorability.favorability_increased_max.title" + } + }, + "requirements": [ + [ + "maid_event" + ] + ], + "sends_telemetry_event": true +} \ No newline at end of file diff --git a/src/generated/resources/data/touhou_little_maid/advancement/favorability/maid_picnic_eat.json b/src/generated/resources/data/touhou_little_maid/advancement/favorability/maid_picnic_eat.json new file mode 100644 index 000000000..78c382f87 --- /dev/null +++ b/src/generated/resources/data/touhou_little_maid/advancement/favorability/maid_picnic_eat.json @@ -0,0 +1,30 @@ +{ + "parent": "touhou_little_maid:favorability/maid_sit_joy", + "criteria": { + "maid_event": { + "conditions": { + "event": "maid_picnic_eat" + }, + "trigger": "touhou_little_maid:maid_event" + } + }, + "display": { + "background": "touhou_little_maid:textures/advancements/backgrounds/stone.png", + "description": { + "translate": "advancements.touhou_little_maid.favorability.maid_picnic_eat.description" + }, + "icon": { + "count": 1, + "id": "touhou_little_maid:picnic_basket" + }, + "title": { + "translate": "advancements.touhou_little_maid.favorability.maid_picnic_eat.title" + } + }, + "requirements": [ + [ + "maid_event" + ] + ], + "sends_telemetry_event": true +} \ No newline at end of file diff --git a/src/generated/resources/data/touhou_little_maid/advancement/favorability/maid_sit_joy.json b/src/generated/resources/data/touhou_little_maid/advancement/favorability/maid_sit_joy.json new file mode 100644 index 000000000..f6c09a184 --- /dev/null +++ b/src/generated/resources/data/touhou_little_maid/advancement/favorability/maid_sit_joy.json @@ -0,0 +1,32 @@ +{ + "criteria": { + "maid_event": { + "conditions": { + "event": "maid_sit_joy" + }, + "trigger": "touhou_little_maid:maid_event" + } + }, + "display": { + "background": "touhou_little_maid:textures/advancements/backgrounds/stone.png", + "description": { + "translate": "advancements.touhou_little_maid.favorability.maid_sit_joy.description" + }, + "icon": { + "count": 1, + "id": "touhou_little_maid:bookshelf" + }, + "title": { + "translate": "advancements.touhou_little_maid.favorability.maid_sit_joy.title" + } + }, + "requirements": [ + [ + "maid_event" + ] + ], + "rewards": { + "experience": 50 + }, + "sends_telemetry_event": true +} \ No newline at end of file diff --git a/src/generated/resources/data/touhou_little_maid/advancement/favorability/maid_sleep.json b/src/generated/resources/data/touhou_little_maid/advancement/favorability/maid_sleep.json new file mode 100644 index 000000000..1a0ca1bf7 --- /dev/null +++ b/src/generated/resources/data/touhou_little_maid/advancement/favorability/maid_sleep.json @@ -0,0 +1,30 @@ +{ + "parent": "touhou_little_maid:favorability/maid_picnic_eat", + "criteria": { + "maid_event": { + "conditions": { + "event": "maid_sleep" + }, + "trigger": "touhou_little_maid:maid_event" + } + }, + "display": { + "background": "touhou_little_maid:textures/advancements/backgrounds/stone.png", + "description": { + "translate": "advancements.touhou_little_maid.favorability.maid_sleep.description" + }, + "icon": { + "count": 1, + "id": "touhou_little_maid:maid_bed" + }, + "title": { + "translate": "advancements.touhou_little_maid.favorability.maid_sleep.title" + } + }, + "requirements": [ + [ + "maid_event" + ] + ], + "sends_telemetry_event": true +} \ No newline at end of file diff --git a/src/generated/resources/data/touhou_little_maid/advancement/favorability/win_cchess.json b/src/generated/resources/data/touhou_little_maid/advancement/favorability/win_cchess.json new file mode 100644 index 000000000..ae698cf1f --- /dev/null +++ b/src/generated/resources/data/touhou_little_maid/advancement/favorability/win_cchess.json @@ -0,0 +1,31 @@ +{ + "parent": "touhou_little_maid:favorability/win_gomoku", + "criteria": { + "maid_event": { + "conditions": { + "event": "win_cchess" + }, + "trigger": "touhou_little_maid:maid_event" + } + }, + "display": { + "background": "touhou_little_maid:textures/advancements/backgrounds/stone.png", + "description": { + "translate": "advancements.touhou_little_maid.favorability.win_cchess.description" + }, + "frame": "goal", + "icon": { + "count": 1, + "id": "touhou_little_maid:cchess" + }, + "title": { + "translate": "advancements.touhou_little_maid.favorability.win_cchess.title" + } + }, + "requirements": [ + [ + "maid_event" + ] + ], + "sends_telemetry_event": true +} \ No newline at end of file diff --git a/src/generated/resources/data/touhou_little_maid/advancement/favorability/win_gomoku.json b/src/generated/resources/data/touhou_little_maid/advancement/favorability/win_gomoku.json new file mode 100644 index 000000000..68d073d48 --- /dev/null +++ b/src/generated/resources/data/touhou_little_maid/advancement/favorability/win_gomoku.json @@ -0,0 +1,31 @@ +{ + "parent": "touhou_little_maid:favorability/maid_picnic_eat", + "criteria": { + "maid_event": { + "conditions": { + "event": "win_gomoku" + }, + "trigger": "touhou_little_maid:maid_event" + } + }, + "display": { + "background": "touhou_little_maid:textures/advancements/backgrounds/stone.png", + "description": { + "translate": "advancements.touhou_little_maid.favorability.win_gomoku.description" + }, + "frame": "goal", + "icon": { + "count": 1, + "id": "touhou_little_maid:gomoku" + }, + "title": { + "translate": "advancements.touhou_little_maid.favorability.win_gomoku.title" + } + }, + "requirements": [ + [ + "maid_event" + ] + ], + "sends_telemetry_event": true +} \ No newline at end of file diff --git a/src/generated/resources/data/touhou_little_maid/advancement/favorability/win_wchess.json b/src/generated/resources/data/touhou_little_maid/advancement/favorability/win_wchess.json new file mode 100644 index 000000000..3c69978fd --- /dev/null +++ b/src/generated/resources/data/touhou_little_maid/advancement/favorability/win_wchess.json @@ -0,0 +1,31 @@ +{ + "parent": "touhou_little_maid:favorability/win_cchess", + "criteria": { + "maid_event": { + "conditions": { + "event": "win_wchess" + }, + "trigger": "touhou_little_maid:maid_event" + } + }, + "display": { + "background": "touhou_little_maid:textures/advancements/backgrounds/stone.png", + "description": { + "translate": "advancements.touhou_little_maid.favorability.win_wchess.description" + }, + "frame": "goal", + "icon": { + "count": 1, + "id": "touhou_little_maid:wchess" + }, + "title": { + "translate": "advancements.touhou_little_maid.favorability.win_wchess.title" + } + }, + "requirements": [ + [ + "maid_event" + ] + ], + "sends_telemetry_event": true +} \ No newline at end of file diff --git a/src/generated/resources/data/touhou_little_maid/advancement/maid_base/chisel_statue.json b/src/generated/resources/data/touhou_little_maid/advancement/maid_base/chisel_statue.json new file mode 100644 index 000000000..06c1b0ed4 --- /dev/null +++ b/src/generated/resources/data/touhou_little_maid/advancement/maid_base/chisel_statue.json @@ -0,0 +1,30 @@ +{ + "parent": "touhou_little_maid:maid_base/photo_maid", + "criteria": { + "maid_event": { + "conditions": { + "event": "chisel_statue" + }, + "trigger": "touhou_little_maid:maid_event" + } + }, + "display": { + "background": "touhou_little_maid:textures/advancements/backgrounds/stone.png", + "description": { + "translate": "advancements.touhou_little_maid.maid_base.chisel_statue.description" + }, + "icon": { + "count": 1, + "id": "touhou_little_maid:chisel" + }, + "title": { + "translate": "advancements.touhou_little_maid.maid_base.chisel_statue.title" + } + }, + "requirements": [ + [ + "maid_event" + ] + ], + "sends_telemetry_event": true +} \ No newline at end of file diff --git a/src/generated/resources/data/touhou_little_maid/advancement/maid_base/clear_maid_effects.json b/src/generated/resources/data/touhou_little_maid/advancement/maid_base/clear_maid_effects.json new file mode 100644 index 000000000..bc74befb6 --- /dev/null +++ b/src/generated/resources/data/touhou_little_maid/advancement/maid_base/clear_maid_effects.json @@ -0,0 +1,30 @@ +{ + "parent": "touhou_little_maid:maid_base/pickup_maid", + "criteria": { + "maid_event": { + "conditions": { + "event": "clear_maid_effects" + }, + "trigger": "touhou_little_maid:maid_event" + } + }, + "display": { + "background": "touhou_little_maid:textures/advancements/backgrounds/stone.png", + "description": { + "translate": "advancements.touhou_little_maid.maid_base.clear_maid_effects.description" + }, + "icon": { + "count": 1, + "id": "minecraft:milk_bucket" + }, + "title": { + "translate": "advancements.touhou_little_maid.maid_base.clear_maid_effects.title" + } + }, + "requirements": [ + [ + "maid_event" + ] + ], + "sends_telemetry_event": true +} \ No newline at end of file diff --git a/src/generated/resources/data/touhou_little_maid/advancement/maid_base/maid_backpack.json b/src/generated/resources/data/touhou_little_maid/advancement/maid_base/maid_backpack.json new file mode 100644 index 000000000..71fa36050 --- /dev/null +++ b/src/generated/resources/data/touhou_little_maid/advancement/maid_base/maid_backpack.json @@ -0,0 +1,30 @@ +{ + "parent": "touhou_little_maid:maid_base/switch_schedule", + "criteria": { + "maid_event": { + "conditions": { + "event": "maid_backpack" + }, + "trigger": "touhou_little_maid:maid_event" + } + }, + "display": { + "background": "touhou_little_maid:textures/advancements/backgrounds/stone.png", + "description": { + "translate": "advancements.touhou_little_maid.maid_base.maid_backpack.description" + }, + "icon": { + "count": 1, + "id": "touhou_little_maid:maid_backpack_big" + }, + "title": { + "translate": "advancements.touhou_little_maid.maid_base.maid_backpack.title" + } + }, + "requirements": [ + [ + "maid_event" + ] + ], + "sends_telemetry_event": true +} \ No newline at end of file diff --git a/src/generated/resources/data/touhou_little_maid/advancement/maid_base/maid_farm.json b/src/generated/resources/data/touhou_little_maid/advancement/maid_base/maid_farm.json new file mode 100644 index 000000000..c646af43d --- /dev/null +++ b/src/generated/resources/data/touhou_little_maid/advancement/maid_base/maid_farm.json @@ -0,0 +1,31 @@ +{ + "parent": "touhou_little_maid:maid_base/switch_schedule", + "criteria": { + "maid_event": { + "conditions": { + "event": "maid_farm" + }, + "trigger": "touhou_little_maid:maid_event" + } + }, + "display": { + "background": "touhou_little_maid:textures/advancements/backgrounds/stone.png", + "description": { + "translate": "advancements.touhou_little_maid.maid_base.maid_farm.description" + }, + "frame": "goal", + "icon": { + "count": 1, + "id": "minecraft:iron_hoe" + }, + "title": { + "translate": "advancements.touhou_little_maid.maid_base.maid_farm.title" + } + }, + "requirements": [ + [ + "maid_event" + ] + ], + "sends_telemetry_event": true +} \ No newline at end of file diff --git a/src/generated/resources/data/touhou_little_maid/advancement/maid_base/maid_feed_animal.json b/src/generated/resources/data/touhou_little_maid/advancement/maid_base/maid_feed_animal.json new file mode 100644 index 000000000..3eca19fb0 --- /dev/null +++ b/src/generated/resources/data/touhou_little_maid/advancement/maid_base/maid_feed_animal.json @@ -0,0 +1,30 @@ +{ + "parent": "touhou_little_maid:maid_base/maid_farm", + "criteria": { + "maid_event": { + "conditions": { + "event": "maid_feed_animal" + }, + "trigger": "touhou_little_maid:maid_event" + } + }, + "display": { + "background": "touhou_little_maid:textures/advancements/backgrounds/stone.png", + "description": { + "translate": "advancements.touhou_little_maid.maid_base.maid_feed_animal.description" + }, + "icon": { + "count": 1, + "id": "minecraft:wheat" + }, + "title": { + "translate": "advancements.touhou_little_maid.maid_base.maid_feed_animal.title" + } + }, + "requirements": [ + [ + "maid_event" + ] + ], + "sends_telemetry_event": true +} \ No newline at end of file diff --git a/src/generated/resources/data/touhou_little_maid/advancement/maid_base/maid_feed_player.json b/src/generated/resources/data/touhou_little_maid/advancement/maid_base/maid_feed_player.json new file mode 100644 index 000000000..eb4778911 --- /dev/null +++ b/src/generated/resources/data/touhou_little_maid/advancement/maid_base/maid_feed_player.json @@ -0,0 +1,30 @@ +{ + "parent": "touhou_little_maid:maid_base/maid_feed_animal", + "criteria": { + "maid_event": { + "conditions": { + "event": "maid_feed_player" + }, + "trigger": "touhou_little_maid:maid_event" + } + }, + "display": { + "background": "touhou_little_maid:textures/advancements/backgrounds/stone.png", + "description": { + "translate": "advancements.touhou_little_maid.maid_base.maid_feed_player.description" + }, + "icon": { + "count": 1, + "id": "minecraft:cooked_beef" + }, + "title": { + "translate": "advancements.touhou_little_maid.maid_base.maid_feed_player.title" + } + }, + "requirements": [ + [ + "maid_event" + ] + ], + "sends_telemetry_event": true +} \ No newline at end of file diff --git a/src/generated/resources/data/touhou_little_maid/advancement/maid_base/maid_fishing.json b/src/generated/resources/data/touhou_little_maid/advancement/maid_base/maid_fishing.json new file mode 100644 index 000000000..c4262d4db --- /dev/null +++ b/src/generated/resources/data/touhou_little_maid/advancement/maid_base/maid_fishing.json @@ -0,0 +1,30 @@ +{ + "parent": "touhou_little_maid:maid_base/maid_backpack", + "criteria": { + "maid_event": { + "conditions": { + "event": "maid_fishing" + }, + "trigger": "touhou_little_maid:maid_event" + } + }, + "display": { + "background": "touhou_little_maid:textures/advancements/backgrounds/stone.png", + "description": { + "translate": "advancements.touhou_little_maid.maid_base.maid_fishing.description" + }, + "icon": { + "count": 1, + "id": "minecraft:fishing_rod" + }, + "title": { + "translate": "advancements.touhou_little_maid.maid_base.maid_fishing.title" + } + }, + "requirements": [ + [ + "maid_event" + ] + ], + "sends_telemetry_event": true +} \ No newline at end of file diff --git a/src/generated/resources/data/touhou_little_maid/advancement/maid_base/maid_kill_mob.json b/src/generated/resources/data/touhou_little_maid/advancement/maid_base/maid_kill_mob.json new file mode 100644 index 000000000..aa6059b1c --- /dev/null +++ b/src/generated/resources/data/touhou_little_maid/advancement/maid_base/maid_kill_mob.json @@ -0,0 +1,31 @@ +{ + "parent": "touhou_little_maid:maid_base/maid_backpack", + "criteria": { + "maid_event": { + "conditions": { + "event": "maid_kill_mob" + }, + "trigger": "touhou_little_maid:maid_event" + } + }, + "display": { + "background": "touhou_little_maid:textures/advancements/backgrounds/stone.png", + "description": { + "translate": "advancements.touhou_little_maid.maid_base.maid_kill_mob.description" + }, + "frame": "goal", + "icon": { + "count": 1, + "id": "minecraft:diamond_sword" + }, + "title": { + "translate": "advancements.touhou_little_maid.maid_base.maid_kill_mob.title" + } + }, + "requirements": [ + [ + "maid_event" + ] + ], + "sends_telemetry_event": true +} \ No newline at end of file diff --git a/src/generated/resources/data/touhou_little_maid/advancement/maid_base/photo_maid.json b/src/generated/resources/data/touhou_little_maid/advancement/maid_base/photo_maid.json new file mode 100644 index 000000000..6495dfd7d --- /dev/null +++ b/src/generated/resources/data/touhou_little_maid/advancement/maid_base/photo_maid.json @@ -0,0 +1,30 @@ +{ + "parent": "touhou_little_maid:maid_base/switch_task", + "criteria": { + "maid_event": { + "conditions": { + "event": "photo_maid" + }, + "trigger": "touhou_little_maid:maid_event" + } + }, + "display": { + "background": "touhou_little_maid:textures/advancements/backgrounds/stone.png", + "description": { + "translate": "advancements.touhou_little_maid.maid_base.photo_maid.description" + }, + "icon": { + "count": 1, + "id": "touhou_little_maid:camera" + }, + "title": { + "translate": "advancements.touhou_little_maid.maid_base.photo_maid.title" + } + }, + "requirements": [ + [ + "maid_event" + ] + ], + "sends_telemetry_event": true +} \ No newline at end of file diff --git a/src/generated/resources/data/touhou_little_maid/advancement/maid_base/pickup_garage_kit.json b/src/generated/resources/data/touhou_little_maid/advancement/maid_base/pickup_garage_kit.json new file mode 100644 index 000000000..96fe70a32 --- /dev/null +++ b/src/generated/resources/data/touhou_little_maid/advancement/maid_base/pickup_garage_kit.json @@ -0,0 +1,32 @@ +{ + "parent": "touhou_little_maid:maid_base/chisel_statue", + "criteria": { + "pickup_item": { + "conditions": { + "item": { + "items": "touhou_little_maid:garage_kit" + } + }, + "trigger": "minecraft:thrown_item_picked_up_by_player" + } + }, + "display": { + "background": "touhou_little_maid:textures/advancements/backgrounds/stone.png", + "description": { + "translate": "advancements.touhou_little_maid.maid_base.pickup_garage_kit.description" + }, + "icon": { + "count": 1, + "id": "touhou_little_maid:garage_kit" + }, + "title": { + "translate": "advancements.touhou_little_maid.maid_base.pickup_garage_kit.title" + } + }, + "requirements": [ + [ + "pickup_item" + ] + ], + "sends_telemetry_event": true +} \ No newline at end of file diff --git a/src/generated/resources/data/touhou_little_maid/advancement/maid_base/pickup_maid.json b/src/generated/resources/data/touhou_little_maid/advancement/maid_base/pickup_maid.json new file mode 100644 index 000000000..a7f9333d9 --- /dev/null +++ b/src/generated/resources/data/touhou_little_maid/advancement/maid_base/pickup_maid.json @@ -0,0 +1,30 @@ +{ + "parent": "touhou_little_maid:maid_base/switch_task", + "criteria": { + "maid_event": { + "conditions": { + "event": "pickup_maid" + }, + "trigger": "touhou_little_maid:maid_event" + } + }, + "display": { + "background": "touhou_little_maid:textures/advancements/backgrounds/stone.png", + "description": { + "translate": "advancements.touhou_little_maid.maid_base.pickup_maid.description" + }, + "icon": { + "count": 1, + "id": "minecraft:saddle" + }, + "title": { + "translate": "advancements.touhou_little_maid.maid_base.pickup_maid.title" + } + }, + "requirements": [ + [ + "maid_event" + ] + ], + "sends_telemetry_event": true +} \ No newline at end of file diff --git a/src/generated/resources/data/touhou_little_maid/advancement/maid_base/reborn_maid.json b/src/generated/resources/data/touhou_little_maid/advancement/maid_base/reborn_maid.json new file mode 100644 index 000000000..a5484e058 --- /dev/null +++ b/src/generated/resources/data/touhou_little_maid/advancement/maid_base/reborn_maid.json @@ -0,0 +1,33 @@ +{ + "parent": "touhou_little_maid:maid_base/switch_task", + "criteria": { + "altar_craft": { + "conditions": { + "recipe_id": "touhou_little_maid:altar_recipe/reborn_maid" + }, + "trigger": "touhou_little_maid:altar_craft" + } + }, + "display": { + "background": "touhou_little_maid:textures/advancements/backgrounds/stone.png", + "description": { + "translate": "advancements.touhou_little_maid.maid_base.reborn_maid.description" + }, + "icon": { + "components": { + "touhou_little_maid:recipe_id": "reborn_maid" + }, + "count": 1, + "id": "touhou_little_maid:entity_placeholder" + }, + "title": { + "translate": "advancements.touhou_little_maid.maid_base.reborn_maid.title" + } + }, + "requirements": [ + [ + "altar_craft" + ] + ], + "sends_telemetry_event": true +} \ No newline at end of file diff --git a/src/generated/resources/data/touhou_little_maid/advancement/maid_base/shrine_reborn_maid.json b/src/generated/resources/data/touhou_little_maid/advancement/maid_base/shrine_reborn_maid.json new file mode 100644 index 000000000..3c47c58da --- /dev/null +++ b/src/generated/resources/data/touhou_little_maid/advancement/maid_base/shrine_reborn_maid.json @@ -0,0 +1,31 @@ +{ + "parent": "touhou_little_maid:maid_base/reborn_maid", + "criteria": { + "maid_event": { + "conditions": { + "event": "shrine_reborn_maid" + }, + "trigger": "touhou_little_maid:maid_event" + } + }, + "display": { + "background": "touhou_little_maid:textures/advancements/backgrounds/stone.png", + "description": { + "translate": "advancements.touhou_little_maid.maid_base.shrine_reborn_maid.description" + }, + "frame": "goal", + "icon": { + "count": 1, + "id": "touhou_little_maid:shrine" + }, + "title": { + "translate": "advancements.touhou_little_maid.maid_base.shrine_reborn_maid.title" + } + }, + "requirements": [ + [ + "maid_event" + ] + ], + "sends_telemetry_event": true +} \ No newline at end of file diff --git a/src/generated/resources/data/touhou_little_maid/advancement/maid_base/switch_schedule.json b/src/generated/resources/data/touhou_little_maid/advancement/maid_base/switch_schedule.json new file mode 100644 index 000000000..92abbb57a --- /dev/null +++ b/src/generated/resources/data/touhou_little_maid/advancement/maid_base/switch_schedule.json @@ -0,0 +1,30 @@ +{ + "parent": "touhou_little_maid:maid_base/switch_task", + "criteria": { + "maid_event": { + "conditions": { + "event": "switch_schedule" + }, + "trigger": "touhou_little_maid:maid_event" + } + }, + "display": { + "background": "touhou_little_maid:textures/advancements/backgrounds/stone.png", + "description": { + "translate": "advancements.touhou_little_maid.maid_base.switch_schedule.description" + }, + "icon": { + "count": 1, + "id": "minecraft:clock" + }, + "title": { + "translate": "advancements.touhou_little_maid.maid_base.switch_schedule.title" + } + }, + "requirements": [ + [ + "maid_event" + ] + ], + "sends_telemetry_event": true +} \ No newline at end of file diff --git a/src/generated/resources/data/touhou_little_maid/advancement/maid_base/switch_task.json b/src/generated/resources/data/touhou_little_maid/advancement/maid_base/switch_task.json new file mode 100644 index 000000000..d09aacc43 --- /dev/null +++ b/src/generated/resources/data/touhou_little_maid/advancement/maid_base/switch_task.json @@ -0,0 +1,29 @@ +{ + "criteria": { + "maid_event": { + "conditions": { + "event": "switch_task" + }, + "trigger": "touhou_little_maid:maid_event" + } + }, + "display": { + "background": "touhou_little_maid:textures/advancements/backgrounds/stone.png", + "description": { + "translate": "advancements.touhou_little_maid.maid_base.switch_task.description" + }, + "icon": { + "count": 1, + "id": "touhou_little_maid:hakurei_gohei" + }, + "title": { + "translate": "advancements.touhou_little_maid.maid_base.switch_task.title" + } + }, + "requirements": [ + [ + "maid_event" + ] + ], + "sends_telemetry_event": true +} \ No newline at end of file diff --git a/src/generated/resources/data/touhou_little_maid/advancement/maid_base/take_maid_xp.json b/src/generated/resources/data/touhou_little_maid/advancement/maid_base/take_maid_xp.json new file mode 100644 index 000000000..c94d26542 --- /dev/null +++ b/src/generated/resources/data/touhou_little_maid/advancement/maid_base/take_maid_xp.json @@ -0,0 +1,30 @@ +{ + "parent": "touhou_little_maid:maid_base/pickup_maid", + "criteria": { + "maid_event": { + "conditions": { + "event": "take_maid_xp" + }, + "trigger": "touhou_little_maid:maid_event" + } + }, + "display": { + "background": "touhou_little_maid:textures/advancements/backgrounds/stone.png", + "description": { + "translate": "advancements.touhou_little_maid.maid_base.take_maid_xp.description" + }, + "icon": { + "count": 1, + "id": "minecraft:experience_bottle" + }, + "title": { + "translate": "advancements.touhou_little_maid.maid_base.take_maid_xp.title" + } + }, + "requirements": [ + [ + "maid_event" + ] + ], + "sends_telemetry_event": true +} \ No newline at end of file diff --git a/src/generated/resources/data/touhou_little_maid/advancement/maid_base/use_item_magnet_bauble.json b/src/generated/resources/data/touhou_little_maid/advancement/maid_base/use_item_magnet_bauble.json new file mode 100644 index 000000000..4adebd2e7 --- /dev/null +++ b/src/generated/resources/data/touhou_little_maid/advancement/maid_base/use_item_magnet_bauble.json @@ -0,0 +1,30 @@ +{ + "parent": "touhou_little_maid:maid_base/use_protect_bauble", + "criteria": { + "maid_event": { + "conditions": { + "event": "use_item_magnet_bauble" + }, + "trigger": "touhou_little_maid:maid_event" + } + }, + "display": { + "background": "touhou_little_maid:textures/advancements/backgrounds/stone.png", + "description": { + "translate": "advancements.touhou_little_maid.maid_base.use_item_magnet_bauble.description" + }, + "icon": { + "count": 1, + "id": "touhou_little_maid:item_magnet_bauble" + }, + "title": { + "translate": "advancements.touhou_little_maid.maid_base.use_item_magnet_bauble.title" + } + }, + "requirements": [ + [ + "maid_event" + ] + ], + "sends_telemetry_event": true +} \ No newline at end of file diff --git a/src/generated/resources/data/touhou_little_maid/advancement/maid_base/use_nimble_fabric.json b/src/generated/resources/data/touhou_little_maid/advancement/maid_base/use_nimble_fabric.json new file mode 100644 index 000000000..46307d819 --- /dev/null +++ b/src/generated/resources/data/touhou_little_maid/advancement/maid_base/use_nimble_fabric.json @@ -0,0 +1,30 @@ +{ + "parent": "touhou_little_maid:maid_base/use_protect_bauble", + "criteria": { + "maid_event": { + "conditions": { + "event": "use_nimble_fabric" + }, + "trigger": "touhou_little_maid:maid_event" + } + }, + "display": { + "background": "touhou_little_maid:textures/advancements/backgrounds/stone.png", + "description": { + "translate": "advancements.touhou_little_maid.maid_base.use_nimble_fabric.description" + }, + "icon": { + "count": 1, + "id": "touhou_little_maid:nimble_fabric" + }, + "title": { + "translate": "advancements.touhou_little_maid.maid_base.use_nimble_fabric.title" + } + }, + "requirements": [ + [ + "maid_event" + ] + ], + "sends_telemetry_event": true +} \ No newline at end of file diff --git a/src/generated/resources/data/touhou_little_maid/advancement/maid_base/use_protect_bauble.json b/src/generated/resources/data/touhou_little_maid/advancement/maid_base/use_protect_bauble.json new file mode 100644 index 000000000..e2ba57462 --- /dev/null +++ b/src/generated/resources/data/touhou_little_maid/advancement/maid_base/use_protect_bauble.json @@ -0,0 +1,30 @@ +{ + "parent": "touhou_little_maid:maid_base/switch_task", + "criteria": { + "maid_event": { + "conditions": { + "event": "use_protect_bauble" + }, + "trigger": "touhou_little_maid:maid_event" + } + }, + "display": { + "background": "touhou_little_maid:textures/advancements/backgrounds/stone.png", + "description": { + "translate": "advancements.touhou_little_maid.maid_base.use_protect_bauble.description" + }, + "icon": { + "count": 1, + "id": "touhou_little_maid:fire_protect_bauble" + }, + "title": { + "translate": "advancements.touhou_little_maid.maid_base.use_protect_bauble.title" + } + }, + "requirements": [ + [ + "maid_event" + ] + ], + "sends_telemetry_event": true +} \ No newline at end of file diff --git a/src/generated/resources/data/touhou_little_maid/advancement/maid_base/use_red_fox_scroll.json b/src/generated/resources/data/touhou_little_maid/advancement/maid_base/use_red_fox_scroll.json new file mode 100644 index 000000000..613be962f --- /dev/null +++ b/src/generated/resources/data/touhou_little_maid/advancement/maid_base/use_red_fox_scroll.json @@ -0,0 +1,30 @@ +{ + "parent": "touhou_little_maid:maid_base/use_servant_bell", + "criteria": { + "maid_event": { + "conditions": { + "event": "use_red_fox_scroll" + }, + "trigger": "touhou_little_maid:maid_event" + } + }, + "display": { + "background": "touhou_little_maid:textures/advancements/backgrounds/stone.png", + "description": { + "translate": "advancements.touhou_little_maid.maid_base.use_red_fox_scroll.description" + }, + "icon": { + "count": 1, + "id": "touhou_little_maid:red_fox_scroll" + }, + "title": { + "translate": "advancements.touhou_little_maid.maid_base.use_red_fox_scroll.title" + } + }, + "requirements": [ + [ + "maid_event" + ] + ], + "sends_telemetry_event": true +} \ No newline at end of file diff --git a/src/generated/resources/data/touhou_little_maid/advancement/maid_base/use_servant_bell.json b/src/generated/resources/data/touhou_little_maid/advancement/maid_base/use_servant_bell.json new file mode 100644 index 000000000..543b0f8fe --- /dev/null +++ b/src/generated/resources/data/touhou_little_maid/advancement/maid_base/use_servant_bell.json @@ -0,0 +1,30 @@ +{ + "parent": "touhou_little_maid:maid_base/switch_task", + "criteria": { + "maid_event": { + "conditions": { + "event": "use_servant_bell" + }, + "trigger": "touhou_little_maid:maid_event" + } + }, + "display": { + "background": "touhou_little_maid:textures/advancements/backgrounds/stone.png", + "description": { + "translate": "advancements.touhou_little_maid.maid_base.use_servant_bell.description" + }, + "icon": { + "count": 1, + "id": "touhou_little_maid:servant_bell" + }, + "title": { + "translate": "advancements.touhou_little_maid.maid_base.use_servant_bell.title" + } + }, + "requirements": [ + [ + "maid_event" + ] + ], + "sends_telemetry_event": true +} \ No newline at end of file diff --git a/src/generated/resources/data/touhou_little_maid/advancement/maid_base/use_trumpet.json b/src/generated/resources/data/touhou_little_maid/advancement/maid_base/use_trumpet.json new file mode 100644 index 000000000..930fae8ea --- /dev/null +++ b/src/generated/resources/data/touhou_little_maid/advancement/maid_base/use_trumpet.json @@ -0,0 +1,30 @@ +{ + "parent": "touhou_little_maid:maid_base/use_servant_bell", + "criteria": { + "maid_event": { + "conditions": { + "event": "use_trumpet" + }, + "trigger": "touhou_little_maid:maid_event" + } + }, + "display": { + "background": "touhou_little_maid:textures/advancements/backgrounds/stone.png", + "description": { + "translate": "advancements.touhou_little_maid.maid_base.use_trumpet.description" + }, + "icon": { + "count": 1, + "id": "touhou_little_maid:trumpet" + }, + "title": { + "translate": "advancements.touhou_little_maid.maid_base.use_trumpet.title" + } + }, + "requirements": [ + [ + "maid_event" + ] + ], + "sends_telemetry_event": true +} \ No newline at end of file diff --git a/src/generated/resources/data/touhou_little_maid/advancement/maid_base/use_undead_bauble.json b/src/generated/resources/data/touhou_little_maid/advancement/maid_base/use_undead_bauble.json new file mode 100644 index 000000000..65ad4065e --- /dev/null +++ b/src/generated/resources/data/touhou_little_maid/advancement/maid_base/use_undead_bauble.json @@ -0,0 +1,31 @@ +{ + "parent": "touhou_little_maid:maid_base/use_nimble_fabric", + "criteria": { + "maid_event": { + "conditions": { + "event": "use_undead_bauble" + }, + "trigger": "touhou_little_maid:maid_event" + } + }, + "display": { + "background": "touhou_little_maid:textures/advancements/backgrounds/stone.png", + "description": { + "translate": "advancements.touhou_little_maid.maid_base.use_undead_bauble.description" + }, + "frame": "goal", + "icon": { + "count": 1, + "id": "touhou_little_maid:ultramarine_orb_elixir" + }, + "title": { + "translate": "advancements.touhou_little_maid.maid_base.use_undead_bauble.title" + } + }, + "requirements": [ + [ + "maid_event" + ] + ], + "sends_telemetry_event": true +} \ No newline at end of file diff --git a/src/generated/resources/data/touhou_little_maid/advancement/maid_base/use_white_fox_scroll.json b/src/generated/resources/data/touhou_little_maid/advancement/maid_base/use_white_fox_scroll.json new file mode 100644 index 000000000..9cfc356a3 --- /dev/null +++ b/src/generated/resources/data/touhou_little_maid/advancement/maid_base/use_white_fox_scroll.json @@ -0,0 +1,30 @@ +{ + "parent": "touhou_little_maid:maid_base/use_red_fox_scroll", + "criteria": { + "maid_event": { + "conditions": { + "event": "use_white_fox_scroll" + }, + "trigger": "touhou_little_maid:maid_event" + } + }, + "display": { + "background": "touhou_little_maid:textures/advancements/backgrounds/stone.png", + "description": { + "translate": "advancements.touhou_little_maid.maid_base.use_white_fox_scroll.description" + }, + "icon": { + "count": 1, + "id": "touhou_little_maid:white_fox_scroll" + }, + "title": { + "translate": "advancements.touhou_little_maid.maid_base.use_white_fox_scroll.title" + } + }, + "requirements": [ + [ + "maid_event" + ] + ], + "sends_telemetry_event": true +} \ No newline at end of file diff --git a/src/generated/resources/data/touhou_little_maid/advancement/maid_base/use_wireless_io.json b/src/generated/resources/data/touhou_little_maid/advancement/maid_base/use_wireless_io.json new file mode 100644 index 000000000..4f67983a5 --- /dev/null +++ b/src/generated/resources/data/touhou_little_maid/advancement/maid_base/use_wireless_io.json @@ -0,0 +1,30 @@ +{ + "parent": "touhou_little_maid:maid_base/use_item_magnet_bauble", + "criteria": { + "maid_event": { + "conditions": { + "event": "use_wireless_io" + }, + "trigger": "touhou_little_maid:maid_event" + } + }, + "display": { + "background": "touhou_little_maid:textures/advancements/backgrounds/stone.png", + "description": { + "translate": "advancements.touhou_little_maid.maid_base.use_wireless_io.description" + }, + "icon": { + "count": 1, + "id": "touhou_little_maid:wireless_io" + }, + "title": { + "translate": "advancements.touhou_little_maid.maid_base.use_wireless_io.title" + } + }, + "requirements": [ + [ + "maid_event" + ] + ], + "sends_telemetry_event": true +} \ No newline at end of file diff --git a/src/generated/resources/data/touhou_little_maid/loot_table/advancement/cake.json b/src/generated/resources/data/touhou_little_maid/loot_table/advancement/cake.json new file mode 100644 index 000000000..a2508693d --- /dev/null +++ b/src/generated/resources/data/touhou_little_maid/loot_table/advancement/cake.json @@ -0,0 +1,16 @@ +{ + "type": "minecraft:advancement_reward", + "pools": [ + { + "bonus_rolls": 0.0, + "entries": [ + { + "type": "minecraft:item", + "name": "minecraft:cake" + } + ], + "rolls": 1.0 + } + ], + "random_sequence": "touhou_little_maid:advancement/cake" +} \ No newline at end of file diff --git a/src/generated/resources/data/touhou_little_maid/loot_table/advancement/power_point.json b/src/generated/resources/data/touhou_little_maid/loot_table/advancement/power_point.json new file mode 100644 index 000000000..ea1fd480c --- /dev/null +++ b/src/generated/resources/data/touhou_little_maid/loot_table/advancement/power_point.json @@ -0,0 +1,16 @@ +{ + "type": "minecraft:advancement_reward", + "pools": [ + { + "bonus_rolls": 0.0, + "entries": [ + { + "type": "minecraft:item", + "name": "touhou_little_maid:power_point" + } + ], + "rolls": 5.0 + } + ], + "random_sequence": "touhou_little_maid:advancement/power_point" +} \ No newline at end of file diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/advancements/altar/AltarCraftTrigger.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/advancements/altar/AltarCraftTrigger.java new file mode 100644 index 000000000..bf8523204 --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/advancements/altar/AltarCraftTrigger.java @@ -0,0 +1,40 @@ +package com.github.tartaricacid.touhoulittlemaid.advancements.altar; + +import com.github.tartaricacid.touhoulittlemaid.init.InitTrigger; +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import net.minecraft.advancements.Criterion; +import net.minecraft.advancements.critereon.ContextAwarePredicate; +import net.minecraft.advancements.critereon.EntityPredicate; +import net.minecraft.advancements.critereon.SimpleCriterionTrigger; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerPlayer; + +import java.util.Optional; + +public class AltarCraftTrigger extends SimpleCriterionTrigger { + public void trigger(ServerPlayer serverPlayer, ResourceLocation recipeId) { + super.trigger(serverPlayer, instance -> instance.matches(recipeId)); + } + + @Override + public Codec codec() { + return AltarCraftTrigger.Instance.CODEC; + } + + public record Instance(Optional player, + ResourceLocation recipeId) implements SimpleInstance { + public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( + EntityPredicate.ADVANCEMENT_CODEC.optionalFieldOf("player").forGetter(AltarCraftTrigger.Instance::player), + ResourceLocation.CODEC.fieldOf("recipe_id").forGetter(AltarCraftTrigger.Instance::recipeId)) + .apply(instance, AltarCraftTrigger.Instance::new)); + + public boolean matches(ResourceLocation recipeIdIn) { + return this.recipeId.equals(recipeIdIn); + } + + public static Criterion recipe(ResourceLocation recipeId) { + return InitTrigger.ALTAR_CRAFT.get().createCriterion(new AltarCraftTrigger.Instance(Optional.empty(), recipeId)); + } + } +} diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/advancements/package-info.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/advancements/altar/package-info.java similarity index 71% rename from src/main/java/com/github/tartaricacid/touhoulittlemaid/advancements/package-info.java rename to src/main/java/com/github/tartaricacid/touhoulittlemaid/advancements/altar/package-info.java index 139b8a0fe..aae8396b7 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/advancements/package-info.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/advancements/altar/package-info.java @@ -1,7 +1,7 @@ -@ParametersAreNonnullByDefault -@MethodsReturnNonnullByDefault -package com.github.tartaricacid.touhoulittlemaid.advancements; - -import net.minecraft.MethodsReturnNonnullByDefault; - +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +package com.github.tartaricacid.touhoulittlemaid.advancements.altar; + +import net.minecraft.MethodsReturnNonnullByDefault; + import javax.annotation.ParametersAreNonnullByDefault; \ No newline at end of file diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/advancements/maid/MaidEventTrigger.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/advancements/maid/MaidEventTrigger.java new file mode 100644 index 000000000..2e0756282 --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/advancements/maid/MaidEventTrigger.java @@ -0,0 +1,38 @@ +package com.github.tartaricacid.touhoulittlemaid.advancements.maid; + +import com.github.tartaricacid.touhoulittlemaid.init.InitTrigger; +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import net.minecraft.advancements.Criterion; +import net.minecraft.advancements.critereon.ContextAwarePredicate; +import net.minecraft.advancements.critereon.EntityPredicate; +import net.minecraft.advancements.critereon.SimpleCriterionTrigger; +import net.minecraft.server.level.ServerPlayer; + +import java.util.Optional; + +public class MaidEventTrigger extends SimpleCriterionTrigger { + public static Criterion create(String eventName) { + return InitTrigger.MAID_EVENT.get().createCriterion(new MaidEventTrigger.Instance(Optional.empty(), eventName)); + } + + public void trigger(ServerPlayer serverPlayer, String eventName) { + super.trigger(serverPlayer, instance -> instance.matches(eventName)); + } + + @Override + public Codec codec() { + return MaidEventTrigger.Instance.CODEC; + } + + public record Instance(Optional player, String eventName) implements SimpleInstance { + public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( + EntityPredicate.ADVANCEMENT_CODEC.optionalFieldOf("player").forGetter(MaidEventTrigger.Instance::player), + Codec.STRING.fieldOf("event").forGetter(MaidEventTrigger.Instance::eventName)) + .apply(instance, MaidEventTrigger.Instance::new)); + + public boolean matches(String eventNameIn) { + return this.eventName.equals(eventNameIn); + } + } +} diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/advancements/maid/TriggerType.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/advancements/maid/TriggerType.java new file mode 100644 index 000000000..8a743b9c7 --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/advancements/maid/TriggerType.java @@ -0,0 +1,65 @@ +package com.github.tartaricacid.touhoulittlemaid.advancements.maid; + +public final class TriggerType { + // 基础部分 + public static final String BUILD_ALTAR = "build_altar"; + public static final String TAMED_MAID = "tamed_maid"; + public static final String PICKUP_POWER_POINT = "pickup_power_point"; + public static final String CHANGE_MAID_MODEL = "change_maid_model"; + public static final String CHANGE_MAID_SOUND = "change_maid_sound"; + public static final String CHANGE_CHAIR_MODEL = "change_chair_model"; + + // 女仆基础 + public static final String SWITCH_TASK = "switch_task"; + public static final String SWITCH_SCHEDULE = "switch_schedule"; + public static final String MAID_BACKPACK = "maid_backpack"; + public static final String MAID_FARM = "maid_farm"; + public static final String MAID_FEED_ANIMAL = "maid_feed_animal"; + public static final String MAID_FEED_PLAYER = "maid_feed_player"; + public static final String MAID_KILL_MOB = "maid_kill_mob"; + public static final String MAID_FISHING = "maid_fishing"; + + public static final String PICKUP_MAID = "pickup_maid"; + public static final String TAKE_MAID_XP = "take_maid_xp"; + public static final String CLEAR_MAID_EFFECTS = "clear_maid_effects"; + + public static final String USE_PROTECT_BAUBLE = "use_protect_bauble"; + public static final String USE_NIMBLE_FABRIC = "use_nimble_fabric"; + public static final String USE_ITEM_MAGNET_BAUBLE = "use_item_magnet_bauble"; + public static final String USE_UNDEAD_BAUBLE = "use_undead_bauble"; + public static final String USE_WIRELESS_IO = "use_wireless_io"; + + public static final String PHOTO_MAID = "photo_maid"; + public static final String CHISEL_STATUE = "chisel_statue"; + public static final String SHRINE_REBORN_MAID = "shrine_reborn_maid"; + + public static final String USE_SERVANT_BELL = "use_servant_bell"; + public static final String USE_TRUMPET = "use_trumpet"; + public static final String USE_RED_FOX_SCROLL = "use_red_fox_scroll"; + public static final String USE_WHITE_FOX_SCROLL = "use_white_fox_scroll"; + + // 女仆好感度 + public static final String FAVORABILITY_INCREASED = "favorability_increased"; + public static final String FAVORABILITY_INCREASED_MAX = "favorability_increased_max"; + + public static final String MAID_SIT_JOY = "maid_sit_joy"; + public static final String MAID_PICNIC_EAT = "maid_picnic_eat"; + public static final String WIN_GOMOKU = "win_gomoku"; + public static final String WIN_CCHESS = "win_cchess"; + public static final String WIN_WCHESS = "win_wchess"; + public static final String MAID_SLEEP = "maid_sleep"; + + // 女仆挑战 + public static final String ANY_EQUIPMENT = "any_equipment"; + public static final String EAT_ENCHANTED_GOLDEN_APPLE = "eat_enchanted_golden_apple"; + public static final String ALL_NETHERITE_EQUIPMENT = "all_netherite_equipment"; + public static final String LIGHTNING_BOLT = "lightning_bolt"; + public static final String MAID_100_HEALTHY = "maid_100_healthy"; + + public static final String KILL_100 = "kill_100"; + public static final String KILL_SLIME_300 = "kill_slime_300"; + public static final String MAID_FISHING_ENCHANTED_BOOK = "maid_fishing_enchanted_book"; + public static final String TAMED_MAID_FROM_STRUCTURE = "tamed_maid_from_structure"; + public static final String KILL_WITHER = "kill_wither"; + public static final String KILL_DRAGON = "kill_dragon"; +} \ No newline at end of file diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/advancements/maid/package-info.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/advancements/maid/package-info.java new file mode 100644 index 000000000..7c8b0d1c7 --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/advancements/maid/package-info.java @@ -0,0 +1,7 @@ +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +package com.github.tartaricacid.touhoulittlemaid.advancements.maid; + +import net.minecraft.MethodsReturnNonnullByDefault; + +import javax.annotation.ParametersAreNonnullByDefault; \ No newline at end of file diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/advancements/GivePatchouliBookConfigTrigger.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/advancements/rewards/GivePatchouliBookConfigTrigger.java similarity index 95% rename from src/main/java/com/github/tartaricacid/touhoulittlemaid/advancements/GivePatchouliBookConfigTrigger.java rename to src/main/java/com/github/tartaricacid/touhoulittlemaid/advancements/rewards/GivePatchouliBookConfigTrigger.java index dbb9d4efb..3804ffbc2 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/advancements/GivePatchouliBookConfigTrigger.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/advancements/rewards/GivePatchouliBookConfigTrigger.java @@ -1,4 +1,4 @@ -package com.github.tartaricacid.touhoulittlemaid.advancements; +package com.github.tartaricacid.touhoulittlemaid.advancements.rewards; import com.github.tartaricacid.touhoulittlemaid.config.subconfig.MiscConfig; import com.github.tartaricacid.touhoulittlemaid.init.InitTrigger; diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/advancements/GiveSmartSlabConfigTrigger.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/advancements/rewards/GiveSmartSlabConfigTrigger.java similarity index 86% rename from src/main/java/com/github/tartaricacid/touhoulittlemaid/advancements/GiveSmartSlabConfigTrigger.java rename to src/main/java/com/github/tartaricacid/touhoulittlemaid/advancements/rewards/GiveSmartSlabConfigTrigger.java index c102b8747..0e3bd573a 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/advancements/GiveSmartSlabConfigTrigger.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/advancements/rewards/GiveSmartSlabConfigTrigger.java @@ -1,34 +1,34 @@ -package com.github.tartaricacid.touhoulittlemaid.advancements; - -import com.github.tartaricacid.touhoulittlemaid.config.subconfig.MiscConfig; -import com.github.tartaricacid.touhoulittlemaid.init.InitTrigger; -import com.mojang.serialization.Codec; -import com.mojang.serialization.codecs.RecordCodecBuilder; -import net.minecraft.advancements.Criterion; -import net.minecraft.advancements.critereon.ContextAwarePredicate; -import net.minecraft.advancements.critereon.EntityPredicate; -import net.minecraft.advancements.critereon.SimpleCriterionTrigger; -import net.minecraft.server.level.ServerPlayer; - -import java.util.Optional; - -public class GiveSmartSlabConfigTrigger extends SimpleCriterionTrigger { - public void trigger(ServerPlayer serverPlayer) { - super.trigger(serverPlayer, instance -> MiscConfig.GIVE_SMART_SLAB.get()); - } - - @Override - public Codec codec() { - return Instance.CODEC; - } - - public record Instance(Optional player) implements SimpleInstance { - public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( - EntityPredicate.ADVANCEMENT_CODEC.optionalFieldOf("player").forGetter(GiveSmartSlabConfigTrigger.Instance::player)) - .apply(instance, GiveSmartSlabConfigTrigger.Instance::new)); - - public static Criterion instance() { - return InitTrigger.GIVE_SMART_SLAB_CONFIG.get().createCriterion(new GiveSmartSlabConfigTrigger.Instance(Optional.empty())); - } - } -} +package com.github.tartaricacid.touhoulittlemaid.advancements.rewards; + +import com.github.tartaricacid.touhoulittlemaid.config.subconfig.MiscConfig; +import com.github.tartaricacid.touhoulittlemaid.init.InitTrigger; +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import net.minecraft.advancements.Criterion; +import net.minecraft.advancements.critereon.ContextAwarePredicate; +import net.minecraft.advancements.critereon.EntityPredicate; +import net.minecraft.advancements.critereon.SimpleCriterionTrigger; +import net.minecraft.server.level.ServerPlayer; + +import java.util.Optional; + +public class GiveSmartSlabConfigTrigger extends SimpleCriterionTrigger { + public void trigger(ServerPlayer serverPlayer) { + super.trigger(serverPlayer, instance -> MiscConfig.GIVE_SMART_SLAB.get()); + } + + @Override + public Codec codec() { + return Instance.CODEC; + } + + public record Instance(Optional player) implements SimpleInstance { + public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( + EntityPredicate.ADVANCEMENT_CODEC.optionalFieldOf("player").forGetter(GiveSmartSlabConfigTrigger.Instance::player)) + .apply(instance, GiveSmartSlabConfigTrigger.Instance::new)); + + public static Criterion instance() { + return InitTrigger.GIVE_SMART_SLAB_CONFIG.get().createCriterion(new GiveSmartSlabConfigTrigger.Instance(Optional.empty())); + } + } +} diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/advancements/rewards/package-info.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/advancements/rewards/package-info.java new file mode 100644 index 000000000..78bad0ae2 --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/advancements/rewards/package-info.java @@ -0,0 +1,7 @@ +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +package com.github.tartaricacid.touhoulittlemaid.advancements.rewards; + +import net.minecraft.MethodsReturnNonnullByDefault; + +import javax.annotation.ParametersAreNonnullByDefault; \ No newline at end of file diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/api/ILittleMaid.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/api/ILittleMaid.java index 12a9fbd1a..43eb4d3ce 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/api/ILittleMaid.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/api/ILittleMaid.java @@ -4,6 +4,7 @@ import com.github.tartaricacid.touhoulittlemaid.client.overlay.MaidTipsOverlay; import com.github.tartaricacid.touhoulittlemaid.client.renderer.entity.EntityMaidRenderer; import com.github.tartaricacid.touhoulittlemaid.client.renderer.entity.GeckoEntityMaidRenderer; +import com.github.tartaricacid.touhoulittlemaid.entity.ai.brain.ExtraMaidBrainManager; import com.github.tartaricacid.touhoulittlemaid.entity.backpack.BackpackManager; import com.github.tartaricacid.touhoulittlemaid.entity.data.TaskDataRegister; import com.github.tartaricacid.touhoulittlemaid.entity.task.TaskManager; @@ -72,6 +73,14 @@ default void addMaidMeal(MaidMealManager manager) { default void registerTaskData(TaskDataRegister register) { } + /** + * 给女仆添加额外的 AI 数据,比如 MemoryModuleType 或者 SensorType + * + * @param manager 注册器 + */ + default void addExtraMaidBrain(ExtraMaidBrainManager manager) { + } + /** * 添加女仆相关提示 *

diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/api/block/IBoardGameBlock.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/api/block/IBoardGameBlock.java new file mode 100644 index 000000000..814afe4e8 --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/api/block/IBoardGameBlock.java @@ -0,0 +1,13 @@ +package com.github.tartaricacid.touhoulittlemaid.api.block; + +import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; + +public interface IBoardGameBlock { + /** + * 女仆尝试游玩坐在棋盘旁边 + */ + void startMaidSit(EntityMaid maid, BlockState state, Level worldIn, BlockPos pos); +} \ No newline at end of file diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/api/block/IBoardGameEntityBlock.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/api/block/IBoardGameEntityBlock.java new file mode 100644 index 000000000..64b2d9a13 --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/api/block/IBoardGameEntityBlock.java @@ -0,0 +1,10 @@ +package com.github.tartaricacid.touhoulittlemaid.api.block; + +import java.util.UUID; + +public interface IBoardGameEntityBlock { + /** + * 棋盘生成的座位实体的 UUID + */ + UUID getSitId(); +} diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/api/entity/ai/IExtraMaidBrain.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/api/entity/ai/IExtraMaidBrain.java new file mode 100644 index 000000000..9944d3047 --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/api/entity/ai/IExtraMaidBrain.java @@ -0,0 +1,25 @@ +package com.github.tartaricacid.touhoulittlemaid.api.entity.ai; + +import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid; +import net.minecraft.world.entity.ai.memory.MemoryModuleType; +import net.minecraft.world.entity.ai.sensing.Sensor; +import net.minecraft.world.entity.ai.sensing.SensorType; + +import java.util.Collections; +import java.util.List; + +public interface IExtraMaidBrain { + /** + * 为女仆 AI 添加新的 MemoryModuleType + */ + default List> getExtraMemoryTypes() { + return Collections.emptyList(); + } + + /** + * 为女仆 AI 添加新的 SensorType + */ + default List>> getExtraSensorTypes() { + return Collections.emptyList(); + } +} diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/api/game/chess/Evaluate.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/api/game/chess/Evaluate.java new file mode 100644 index 000000000..c5d7e31cc --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/api/game/chess/Evaluate.java @@ -0,0 +1,411 @@ +/* +Evaluate.java - Source Code for Mobile Chess, Part VII + +Mobile Chess - a Chess Program for Java ME +Designed by Morning Yellow, Version: 1.01, Last Modified: Feb. 2008 +Copyright (C) 2008 mobilechess.sourceforge.net + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +package com.github.tartaricacid.touhoulittlemaid.api.game.chess; + +// This part is ported from Owl Chess Sample in Borland C++ 5.0 +@SuppressWarnings("all") +public class Evaluate { + public static final int PIECE_KING = Position.PIECE_KING; + public static final int PIECE_QUEEN = Position.PIECE_QUEEN; + public static final int PIECE_ROOK = Position.PIECE_ROOK; + public static final int PIECE_BISHOP = Position.PIECE_BISHOP; + public static final int PIECE_KNIGHT = Position.PIECE_KNIGHT; + public static final int PIECE_PAWN = Position.PIECE_PAWN; + + public static final int FULL_BIT_RANK = 0x0ff0; + public static final int LAZY_MARGIN = 100; + public static final int ISOLATED_PENALTY = 10; + public static final int DOUBLE_PENALTY = 4; + + public static final int[] PIECE_VALUE = {0, 9, 5, 3, 3, 1}; + + public static final int[] PASS_PAWN = {0, 35, 30, 20, 10, 5, 0, 0}; + + public static final byte[] DISTANCE = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 7, 6, 7, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 7, 6, 5, 6, 7, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 7, 6, 5, 4, 5, 6, 7, 0, 0, 0, 0, 0, + 0, 0, 0, 7, 6, 5, 4, 3, 4, 5, 6, 7, 0, 0, 0, 0, + 0, 0, 7, 6, 5, 4, 3, 2, 3, 4, 5, 6, 7, 0, 0, 0, + 0, 7, 6, 5, 4, 3, 2, 1, 2, 3, 4, 5, 6, 7, 0, 0, + 7, 6, 5, 4, 3, 2, 1, 0, 1, 2, 3, 4, 5, 6, 7, 0, + 0, 7, 6, 5, 4, 3, 2, 1, 2, 3, 4, 5, 6, 7, 0, 0, + 0, 0, 7, 6, 5, 4, 3, 2, 3, 4, 5, 6, 7, 0, 0, 0, + 0, 0, 0, 7, 6, 5, 4, 3, 4, 5, 6, 7, 0, 0, 0, 0, + 0, 0, 0, 0, 7, 6, 5, 4, 5, 6, 7, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 7, 6, 5, 6, 7, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 7, 6, 7, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + }; + + public static final byte[] ENDGAME_EDGE = { + 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, + }; + + public static final byte[] ENDGAME_BOTTOM = { + 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, + }; + + public static final byte[] ENDGAME_KING_PENALTY = { + 0, 0, 0, 0, 25, 22, 19, 16, 16, 19, 22, 25, 0, 0, 0, 0, + 0, 0, 0, 0, 17, 14, 11, 8, 8, 11, 14, 17, 0, 0, 0, 0, + 0, 0, 0, 0, 13, 10, 7, 4, 4, 7, 10, 13, 0, 0, 0, 0, + 0, 0, 0, 0, 9, 6, 3, 0, 0, 3, 6, 9, 0, 0, 0, 0, + 0, 0, 0, 0, 9, 6, 3, 0, 0, 3, 6, 9, 0, 0, 0, 0, + 0, 0, 0, 0, 13, 10, 7, 4, 4, 7, 10, 13, 0, 0, 0, 0, + 0, 0, 0, 0, 17, 14, 11, 8, 8, 11, 14, 17, 0, 0, 0, 0, + 0, 0, 0, 0, 25, 22, 19, 16, 16, 19, 22, 25, 0, 0, 0, 0, + }; + + public static final byte[] EDGE_PENALTY = { + 0, 0, 0, 0, 6, 5, 4, 3, 3, 4, 5, 6, 0, 0, 0, 0, + 0, 0, 0, 0, 5, 4, 3, 2, 2, 3, 4, 5, 0, 0, 0, 0, + 0, 0, 0, 0, 4, 3, 2, 1, 1, 2, 3, 4, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 2, 1, 0, 0, 1, 2, 3, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 2, 1, 0, 0, 1, 2, 3, 0, 0, 0, 0, + 0, 0, 0, 0, 4, 3, 2, 1, 1, 2, 3, 4, 0, 0, 0, 0, + 0, 0, 0, 0, 5, 4, 3, 2, 2, 3, 4, 5, 0, 0, 0, 0, + 0, 0, 0, 0, 6, 5, 4, 3, 3, 4, 5, 6, 0, 0, 0, 0, + }; + + public static final byte[] PAWN_VALUE = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 30, 30, 46, 70, 78, 46, 30, 30, 0, 0, 0, 0, + 0, 0, 0, 0, 8, 8, 22, 43, 50, 22, 8, 8, 0, 0, 0, 0, + 0, 0, 0, 0, 4, 4, 16, 34, 40, 16, 4, 4, 0, 0, 0, 0, + 0, 0, 0, 0, 2, 2, 12, 27, 32, 12, 2, 2, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 8, 20, 24, 8, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 6, 15, 18, 6, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }; + + public static final byte[] CENTER_IMPORTANCE = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 2, 5, 5, 2, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 2, 5, 8, 8, 5, 2, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 2, 5, 8, 8, 5, 2, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 2, 5, 5, 2, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }; + + public static final byte[] RANK_IMPORTANCE = { + 0, 0, 0, 0, 12, 12, 12, 12, 12, 12, 12, 12, 0, 0, 0, 0, + 0, 0, 0, 0, 12, 12, 12, 12, 12, 12, 12, 12, 0, 0, 0, 0, + 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }; + + public static boolean IN_BOARD(int sq) { + return Position.IN_BOARD(sq); + } + + public static int SQUARE_FLIP(int sq) { + return Position.SQUARE_FLIP(sq); + } + + public static int losingKingValue(int sq) { + return -ENDGAME_KING_PENALTY[sq] * 2 - ENDGAME_BOTTOM[sq] * 8; + } + + public static int winningKingValue(int sq, int sqOppKing) { + return -DISTANCE[sqOppKing - sq + 128] * 2 - ENDGAME_EDGE[sq] * 8; + } + + public static int calcRookControl(Position pos, int sqSrc, short[] attack) { + return calcSlideControl(pos, sqSrc, attack, true); + } + + public static int calcBishopControl(Position pos, int sqSrc, short[] attack) { + return calcSlideControl(pos, sqSrc, attack, false); + } + + public static int calcSlideControl(Position pos, int sqSrc, short[] attack, boolean isRook) { + int control = 0; + for (int i = 0; i < 4; i++) { + int delta = (isRook ? Position.ROOK_DELTA[i] : Position.BISHOP_DELTA[i]); + int sqDst = sqSrc + delta; + boolean direct = true; + while (IN_BOARD(sqDst)) { + control += (direct ? attack[sqDst] : attack[sqDst] / 2); + if (pos.squares[sqDst] > 0) { + int pieceType = Position.PIECE_TYPE(pos.squares[sqDst]); + if (pieceType == PIECE_PAWN) { + break; + } else if (pieceType == PIECE_KING || pieceType == PIECE_KNIGHT || + pieceType == (isRook ? PIECE_BISHOP : PIECE_ROOK)) { + direct = false; + } + } + sqDst += delta; + } + } + return control; + } + + public static void preEval(Position pos) { + // 1. Calculate Simple Materials for Both Sides + int vlWhite = 0, vlBlack = 0, sqWhiteKing = 0, sqBlackKing = 0; + for (int sq = 0; sq < 128; sq++) { + int pc = pos.squares[sq]; + if (pc == 0) { + continue; + } + if (pc < 16) { + vlWhite += PIECE_VALUE[pc - 8]; + if (pc == 8) { + sqWhiteKing = sq; + } + } else { + vlBlack += PIECE_VALUE[pc - 16]; + if (pc == 16) { + sqBlackKing = sq; + } + } + } + boolean inEndgame = Math.min(vlWhite, vlBlack) <= 6 && Math.abs(vlWhite - vlBlack) >= 2; + // 2. Calculate Attacking Values for Each Squares (Both Sides) + short[] whiteAttack = new short[128], blackAttack = new short[128]; + for (int sq = 0; sq < 128; sq++) { + whiteAttack[sq] = blackAttack[SQUARE_FLIP(sq)] = (short) + (RANK_IMPORTANCE[sq] * Math.max(vlWhite + vlBlack - 24, 8) / 32 + CENTER_IMPORTANCE[sq]); + } + for (int i = 0; i < 8; i++) { + int importance = 12 * Math.max(vlWhite + vlBlack - 24, 8) / 32; + int sq = sqWhiteKing + Position.KING_DELTA[i]; + if (IN_BOARD(sq)) { + blackAttack[sq] += importance; + } + sq = sqBlackKing + Position.KING_DELTA[i]; + if (IN_BOARD(sq)) { + whiteAttack[sq] += importance; + } + } + // 3. Calculate Control Table for Each Squares + short[] whiteRookControl = new short[128], whiteBishopControl = new short[128]; + short[] blackRookControl = new short[128], blackBishopControl = new short[128]; + for (int sq = 0; sq < 128; sq++) { + if (IN_BOARD(sq)) { + whiteRookControl[sq] = (short) calcRookControl(pos, sq, whiteAttack); + blackRookControl[sq] = (short) calcRookControl(pos, sq, blackAttack); + whiteBishopControl[sq] = (short) calcBishopControl(pos, sq, whiteAttack); + blackBishopControl[sq] = (short) calcBishopControl(pos, sq, blackAttack); + } + } + // 4. Calculate Piece Value Table for Each Squares and Each Piece-Types + for (int sq = 0; sq < 128; sq++) { + if (!IN_BOARD(sq)) { + continue; + } + int edgePenalty = EDGE_PENALTY[sq]; + if (inEndgame) { + if (vlWhite < vlBlack) { + // 4.1. In Endgames, the Losing King should be Close to Center and Distant to Bottom + pos.vlWhitePiecePos[PIECE_KING][sq] = (short) losingKingValue(sq); + // 4.2. In Endgames, the Winning King should be Close to the Losing King and Distant to Border + pos.vlBlackPiecePos[PIECE_KING][sq] = (short) winningKingValue(sq, sqWhiteKing); + } else { + // 4.1. ... + pos.vlBlackPiecePos[PIECE_KING][sq] = (short) losingKingValue(sq); + // 4.2. ... + pos.vlWhitePiecePos[PIECE_KING][sq] = (short) winningKingValue(sq, sqBlackKing); + } + // 4.3. In Endgames, Other Pieces are independent to their Positions + for (int i = PIECE_QUEEN; i <= PIECE_KNIGHT; i++) { + pos.vlWhitePiecePos[i][sq] = pos.vlBlackPiecePos[i][sq] = + (short) (PIECE_VALUE[i] * 100); + } + } else { + // 4.4. King should be Close to Center in Midgames or Endgames + if (vlWhite + vlBlack <= 32) { + pos.vlWhitePiecePos[PIECE_KING][sq] = + pos.vlBlackPiecePos[PIECE_KING][sq] = (short) -edgePenalty; + } else { + pos.vlWhitePiecePos[PIECE_KING][sq] = + pos.vlBlackPiecePos[PIECE_KING][sq] = 0; + } + // 4.5. Queen, Rook, Bishop should Favor their Control Values + pos.vlWhitePiecePos[PIECE_QUEEN][sq] = (short) + (PIECE_VALUE[PIECE_QUEEN] * 100 + (whiteRookControl[sq] + whiteBishopControl[sq]) / 8); + pos.vlBlackPiecePos[PIECE_QUEEN][sq] = (short) + (PIECE_VALUE[PIECE_QUEEN] * 100 + (blackRookControl[sq] + blackBishopControl[sq]) / 8); + pos.vlWhitePiecePos[PIECE_ROOK][sq] = (short) + (PIECE_VALUE[PIECE_ROOK] * 100 + whiteRookControl[sq] / 2); + pos.vlBlackPiecePos[PIECE_ROOK][sq] = (short) + (PIECE_VALUE[PIECE_ROOK] * 100 + blackRookControl[sq] / 2); + pos.vlWhitePiecePos[PIECE_BISHOP][sq] = (short) + (PIECE_VALUE[PIECE_BISHOP] * 100 + whiteBishopControl[sq] / 2); + pos.vlBlackPiecePos[PIECE_BISHOP][sq] = (short) + (PIECE_VALUE[PIECE_BISHOP] * 100 + blackBishopControl[sq] / 2); + // 4.6. Knight should Favor its Attack Value + int whiteKnightAttack = 0, blackKnightAttack = 0; + for (int i = 0; i < 8; i++) { + int sqDst = sq + Position.KNIGHT_DELTA[i]; + if (IN_BOARD(sqDst)) { + whiteKnightAttack += whiteAttack[sqDst]; + blackKnightAttack += blackAttack[sqDst]; + } + } + pos.vlWhitePiecePos[PIECE_KNIGHT][sq] = (short) + (PIECE_VALUE[PIECE_KNIGHT] * 100 + whiteKnightAttack / 4 - edgePenalty * 3 / 2); + pos.vlBlackPiecePos[PIECE_KNIGHT][sq] = (short) + (PIECE_VALUE[PIECE_KNIGHT] * 100 + blackKnightAttack / 4 - edgePenalty * 3 / 2); + } + // 4.7. Pawn should Favor its Position Value + pos.vlWhitePiecePos[PIECE_PAWN][sq] = pos.vlBlackPiecePos[PIECE_PAWN][SQUARE_FLIP(sq)] = + (short) (PIECE_VALUE[PIECE_PAWN] * 100 + PAWN_VALUE[sq] / 2 - 6); + } + /* 5. Calculate Piece Value Table for Pawn Structure + * + * Self: + * x P x - P = brForward, x = brLeftCover/brRightCover + * ^ x P x - P = brSelf, x = brSide + * | x P x - P = brSelf(Last), x = brChain + * + * Opponent: + * . . . + * ^ . x . - x = brOppPass, or BehindOppPass if a Pawn in Front + * | o o o - o = ~brSelf/brSide(Last) + */ + for (int sd = 0; sd < 2; sd++) { + int brSelf = 0, brSide = 0, brBehindOppPass = 0; + int brOppPass = FULL_BIT_RANK; + for (int i = 1; i <= 6; i++) { + int y = (sd == 0 ? 7 - i : i); + int brOpp = (sd == 0 ? pos.brBlackPawn[y] : pos.brWhitePawn[y]); + brOppPass &= ~(brSelf | brSide); + brBehindOppPass |= (brOppPass & brOpp); + int brChain = brSide; + brSelf = (sd == 0 ? pos.brWhitePawn[y] : pos.brBlackPawn[y]); + brSide = ((brSelf >> 1) | (brSelf << 1)) & FULL_BIT_RANK; + int brForward = (sd == 0 ? pos.brWhitePawn[y + 1] : pos.brBlackPawn[y + 1]); + int brLeftCover = (brForward >> 1) & FULL_BIT_RANK; + int brRightCover = (brForward << 1) & FULL_BIT_RANK; + for (int x = Position.FILE_LEFT; x <= Position.FILE_RIGHT; x++) { + int sq = Position.COORD_XY(x, y); + int brSquare = 1 << x; + // 5.1. Bonus for Parallel and Protected Pawns + int value = ((brSide & brSquare) != 0 ? 3 : 0) + ((brChain & brSquare) != 0 ? 2 : 0); + // 5.2. Bonus for the Pawn which can Protect Other Pawns + value += ((brLeftCover & brSquare) != 0 ? 2 : 0) + ((brRightCover & brSquare) != 0 ? 2 : 0); + // 5.3. Bonus for Self (Penalty for Moving) + value += ((brSelf & brSquare) != 0 ? 1 : 0); + if (sd == 0) { + pos.vlWhitePiecePos[PIECE_PAWN][sq] += value; + } else { + pos.vlBlackPiecePos[PIECE_PAWN][sq] += value; + } + if (vlWhite + vlBlack <= 32) { + // 5.4. Bonus for Passed Pawn + if ((brOppPass & brSquare) != 0) { + if (sd == 0) { + pos.vlBlackPiecePos[PIECE_PAWN][sq] += PASS_PAWN[i]; + } else { + pos.vlWhitePiecePos[PIECE_PAWN][sq] += PASS_PAWN[i]; + } + } + // 5.5. Bonus for Rook (Both Sides) Behind Pawn + if ((brBehindOppPass & brSquare) != 0) { + pos.vlWhitePiecePos[PIECE_ROOK][sq] += 8; + pos.vlBlackPiecePos[PIECE_ROOK][sq] += 8; + if (i == 6) { + int sqBottom = sq + Position.FORWARD_DELTA(sd); + pos.vlWhitePiecePos[PIECE_ROOK][sqBottom] += 8; + pos.vlBlackPiecePos[PIECE_ROOK][sqBottom] += 8; + } + } + } + } + } + } + // 6. Calculate Penalty for Blocking Center Pawns with a Bishop + for (int sq = 0x67; sq <= 0x68; sq++) { + if (pos.squares[sq] == 8 + PIECE_PAWN) { + pos.vlWhitePiecePos[PIECE_BISHOP][sq - 16] -= 10; + } + } + for (int sq = 0x17; sq <= 0x18; sq++) { + if (pos.squares[sq] == 16 + PIECE_PAWN) { + pos.vlBlackPiecePos[PIECE_BISHOP][sq + 16] -= 10; + } + } + // 7. Update "vlWhite" and "vlBlack" in "pos" + pos.vlWhite = pos.vlBlack = 0; + for (int sq = 0; sq < 128; sq++) { + int pc = pos.squares[sq]; + if (pc > 0) { + if (pc < 16) { + pos.vlWhite += pos.vlWhitePiecePos[pc - 8][sq]; + } else { + pos.vlBlack += pos.vlBlackPiecePos[pc - 16][sq]; + } + } + } + } + + public static int evaluate(Position pos, int vlAlpha, int vlBeta) { + // 1. Material (with Position) Value + int vl = pos.material(); + if (vl + LAZY_MARGIN <= vlAlpha) { + return vl + LAZY_MARGIN; + } else if (vl - LAZY_MARGIN >= vlBeta) { + return vl - LAZY_MARGIN; + } + // 2. Pawn Structure Value + for (int sd = 0; sd < 2; sd++) { + int brSingle = 0, brDouble = 0; + int[] brs = (sd == 0 ? pos.brWhitePawn : pos.brBlackPawn); + for (int i = 1; i <= 6; i++) { + brDouble |= brSingle & brs[i]; + brSingle |= brs[i]; + } + int brIsolated = brSingle & ~((brSingle << 1) | (brSingle >> 1)); + int penalty = Util.POP_COUNT_16(brDouble) * DOUBLE_PENALTY + + Util.POP_COUNT_16(brIsolated) * ISOLATED_PENALTY + + Util.POP_COUNT_16(brIsolated & brDouble) * ISOLATED_PENALTY * 2; + vl += (pos.sdPlayer == sd ? -penalty : penalty); + } + return vl; + } +} \ No newline at end of file diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/api/game/chess/Position.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/api/game/chess/Position.java new file mode 100644 index 000000000..098e55b2e --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/api/game/chess/Position.java @@ -0,0 +1,1188 @@ +/* +Position.java - Source Code for Mobile Chess, Part I + +Mobile Chess - a Chess Program for Java ME +Designed by Morning Yellow, Version: 1.05, Last Modified: Mar. 2008 +Copyright (C) 2008 mobilechess.sourceforge.net + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +package com.github.tartaricacid.touhoulittlemaid.api.game.chess; + +import java.io.InputStream; +import java.io.PrintStream; +import java.util.Random; + +@SuppressWarnings("all") +public class Position { + public static final int MATE_VALUE = 10000; + public static final int WIN_VALUE = MATE_VALUE - 100; + public static final int NULL_SAFE_MARGIN = 1000; + public static final int NULL_OKAY_MARGIN = 500; + public static final int DRAW_VALUE = 50; + public static final int ADVANCED_VALUE = 10; + + public static final int MAX_MOVE_NUM = 256; + public static final int MAX_GEN_MOVES = 128; + public static final int MAX_BOOK_SIZE = 16384; + + public static final int PIECE_KING = 0; + public static final int PIECE_QUEEN = 1; + public static final int PIECE_ROOK = 2; + public static final int PIECE_BISHOP = 3; + public static final int PIECE_KNIGHT = 4; + public static final int PIECE_PAWN = 5; + + public static final int DIFF_LINE = 0; + public static final int SAME_RANK = 1; + public static final int SAME_FILE = 2; + public static final int SAME_DIAG_A1H8 = 3; + public static final int SAME_DIAG_A8H1 = 4; + + public static final int RANK_TOP = 0; + public static final int RANK_BOTTOM = 7; + public static final int FILE_LEFT = 4; + public static final int FILE_RIGHT = 11; + + public static final byte[] LEGAL_SPAN = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 2, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 2, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + }; + + public static final byte[] SAME_LINE = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 4, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 3, 0, + 0, 4, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 3, 0, 0, + 0, 0, 4, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, + 0, 0, 0, 4, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, + 0, 0, 0, 0, 4, 0, 0, 2, 0, 0, 3, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 4, 0, 2, 0, 3, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 4, 2, 3, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, 0, 3, 2, 4, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 3, 0, 2, 0, 4, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3, 0, 0, 2, 0, 0, 4, 0, 0, 0, 0, 0, + 0, 0, 0, 3, 0, 0, 0, 2, 0, 0, 0, 4, 0, 0, 0, 0, + 0, 0, 3, 0, 0, 0, 0, 2, 0, 0, 0, 0, 4, 0, 0, 0, + 0, 3, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 4, 0, 0, + 3, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 4, 0, + 0, 0, 0, 0, 0, 0, 0, + }; + + public static final byte[] PAWN_LINE = { + 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, + 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, + 0, 0, 0, 0, 5, 5, 5, 5, 5, 5, 5, 5, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 6, 6, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, + }; + + public static final int[] KING_DELTA = {-17, -16, -15, -1, 1, 15, 16, 17}; + public static final int[] ROOK_DELTA = {-16, -1, 1, 16}; + public static final int[] BISHOP_DELTA = {-17, -15, 15, 17}; + public static final int[] KNIGHT_DELTA = {-33, -31, -18, -14, 14, 18, 31, 33}; + public static final int[] MMV_VALUE = {0, 900, 500, 300, 300, 100}; + public static final int[] CASTLING_DIRECTION = {1, -1, 1, -1}; + public static final int[] CASTLING_KING_SRC = {0x78, 0x78, 0x08, 0x08}; + public static final int[] CASTLING_ROOK_DST = {0x79, 0x77, 0x09, 0x07}; + public static final int[] CASTLING_KING_DST = {0x7a, 0x76, 0x0a, 0x06}; + public static final int[] CASTLING_ROOK_SRC = {0x7b, 0x74, 0x0b, 0x04}; + + public static final String PIECE_STRING = "KQRBNP"; + + public static final String[] STARTUP_FEN = { + "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1", + "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/R1BQKBNR w KQkq - 0 1", + "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/1NBQKBNR w KQkq - 0 1", + "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNB1KBNR w KQkq - 0 1", + }; + + public static boolean IN_BOARD(int sq) { + return ((sq - 4) & 0x88) == 0; + } + + public static int RANK_Y(int sq) { + return sq >> 4; + } + + public static int FILE_X(int sq) { + return sq & 15; + } + + public static int COORD_XY(int x, int y) { + return x + (y << 4); + } + + public static int SQUARE_FLIP(int sq) { + return 127 - sq; + } + + public static int SQUARE_FORWARD(int sq, int sd) { + return sq - 16 + (sd << 5); + } + + public static int FORWARD_DELTA(int sd) { + return (sd << 5) - 16; + } + + public static boolean PAWN_INIT(int sq, int sd) { + return PAWN_LINE[sq] == sd + 1; + } + + public static boolean PAWN_PROMOTION(int sq, int sd) { + return PAWN_LINE[sq] == sd + 3; + } + + public static boolean PAWN_EN_PASSANT(int sq, int sd) { + return PAWN_LINE[sq] == sd + 5; + } + + public static boolean KING_SPAN(int sqSrc, int sqDst) { + return LEGAL_SPAN[sqDst - sqSrc + 128] == 1; + } + + public static boolean KNIGHT_SPAN(int sqSrc, int sqDst) { + return LEGAL_SPAN[sqDst - sqSrc + 128] == 2; + } + + public static int SAME_LINE(int sqSrc, int sqDst) { + return SAME_LINE[sqDst - sqSrc + 128]; + } + + public static int CASTLING_TYPE(int sd, int sqSrc, int sqDst) { + return (sd << 1) + (sqDst > sqSrc ? 0 : 1); + } + + public static int SIDE_TAG(int sd) { + return 8 + (sd << 3); + } + + public static int OPP_SIDE_TAG(int sd) { + return 16 - (sd << 3); + } + + public static int SRC(int mv) { + return mv & 127; + } + + public static int DST(int mv) { + return mv >> 7; + } + + public static int MOVE(int sqSrc, int sqDst) { + return sqSrc + (sqDst << 7); + } + + public static int PIECE_TYPE(int pc) { + return pc & 7; + } + + public static int MVV_LVA(int pc, int lva) { + return MMV_VALUE[PIECE_TYPE(pc)] - lva; + } + + public static int PARSE_COORD(String str, int index) { + int sq = 0; + if (index == str.length()) { + return 0; + } + int c = str.charAt(index); + if (c >= 'a' && c <= 'h') { + if (index + 1 == str.length()) { + return 0; + } + char c2 = str.charAt(index + 1); + if (c2 >= '1' && c2 <= '8') { + sq = COORD_XY(c - 'a' + FILE_LEFT, '8' - c2 + RANK_TOP); + } + } + return sq; + } + + public static int PARSE_MOVE(String str) { + return PARSE_MOVE(str, 0); + } + + public static int PARSE_MOVE(String str, int index) { + return MOVE(PARSE_COORD(str, index), PARSE_COORD(str, index + 2)); + } + + public static String SQUARE_STR(int sq) { + return "" + (char) ('a' + FILE_X(sq) - FILE_LEFT) + (char) ('8' - RANK_Y(sq) + RANK_TOP); + } + + public static String MOVE_STR(int mv) { + return SQUARE_STR(SRC(mv)) + SQUARE_STR(DST(mv)); + } + + public static int PreGen_zobristKeyPlayer; + public static int PreGen_zobristLockPlayer; + public static int[][] PreGen_zobristKeyTable = new int[12][128]; + public static int[][] PreGen_zobristLockTable = new int[12][128]; + + public static Random random = new Random(); + + public static int bookSize = 0; + public static int[] bookLock = new int[MAX_BOOK_SIZE]; + public static short[] bookMove = new short[MAX_BOOK_SIZE]; + public static short[] bookValue = new short[MAX_BOOK_SIZE]; + + static { + Util.RC4 rc4 = new Util.RC4(new byte[]{0}); + PreGen_zobristKeyPlayer = rc4.nextLong(); + rc4.nextLong(); // Skip ZobristLock0 + PreGen_zobristLockPlayer = rc4.nextLong(); + for (int i = 0; i < 12; i++) { + for (int j = 0; j < 128; j++) { + PreGen_zobristKeyTable[i][j] = rc4.nextLong(); + rc4.nextLong(); // Skip ZobristLock0 + PreGen_zobristLockTable[i][j] = rc4.nextLong(); + } + } + + InputStream in = rc4.getClass().getResourceAsStream("/assets/touhou_little_maid/book/wchess/BOOK.DAT"); + if (in != null) { + try { + while (bookSize < MAX_BOOK_SIZE) { + bookLock[bookSize] = Util.readInt(in) >>> 1; + bookMove[bookSize] = (short) Util.readShort(in); + bookValue[bookSize] = (short) Util.readShort(in); + bookSize++; + } + } catch (Exception e) { + // Exit "while" when IOException occurs + } + try { + in.close(); + } catch (Exception e) { + throw new RuntimeException(e.getMessage()); + } + } + } + + public int sdPlayer; + public byte[] squares = new byte[128]; + + public int zobristKey; + public int zobristLock; + public int vlWhite, vlBlack; + public int moveNum, distance; + + public int[] mvList = new int[MAX_MOVE_NUM]; + public int[] pcList = new int[MAX_MOVE_NUM]; + public int[] keyList = new int[MAX_MOVE_NUM]; + public boolean[] chkList = new boolean[MAX_MOVE_NUM]; + public boolean[] specialMoveList = new boolean[MAX_MOVE_NUM]; + public int[] castlingBitsList = new int[MAX_MOVE_NUM]; + public int[] sqEnPassantList = new int[MAX_MOVE_NUM]; + + public int[] brWhitePawn = new int[8]; // br = Bit-Rank + public int[] brBlackPawn = new int[8]; // br = Bit-Rank + public short[][] vlWhitePiecePos = new short[6][128]; + public short[][] vlBlackPiecePos = new short[6][128]; + + public void clearBoard() { + sdPlayer = 0; + for (int sq = 0; sq < 128; sq++) { + squares[sq] = 0; + } + for (int i = 0; i < 8; i++) { + brWhitePawn[i] = brBlackPawn[i] = 0; + } + zobristKey = zobristLock = 0; + vlWhite = vlBlack = 0; + } + + public boolean captured() { + return pcList[moveNum - 1] > 0; + } + + public boolean inCheck() { + return chkList[moveNum - 1]; + } + + public boolean specialMove() { + return specialMoveList[moveNum - 1]; + } + + public int castlingBits() { + return castlingBitsList[moveNum - 1]; + } + + public int enPassantSquare() { + return sqEnPassantList[moveNum - 1]; + } + + public boolean canCastling(int castling) { + if (!inCheck() && (castlingBits() & (1 << castling)) != 0) { + int delta = CASTLING_DIRECTION[castling]; + int sqSrc = CASTLING_KING_SRC[castling] + delta; + int sqDst = CASTLING_ROOK_SRC[castling]; + while (sqSrc != sqDst) { + if (squares[sqSrc] > 0) { + return false; + } + sqSrc += delta; + } + return !checked(CASTLING_ROOK_DST[castling]); + } + return false; + } + + public void setIrrev() { + setIrrev(castlingBits(), enPassantSquare()); + } + + public void setIrrev(int castlingBits, int sqEnPassant) { + mvList[0] = pcList[0] = 0; + castlingBitsList[0] = castlingBits; + sqEnPassantList[0] = sqEnPassant; + chkList[0] = checked(); + moveNum = 1; + distance = 0; + } + + public void addPiece(int sq, int pc, boolean del) { + int pcAdjust; + squares[sq] = (byte) (del ? 0 : pc); + if (pc < 16) { + if (pc == 8 + PIECE_PAWN) { + brWhitePawn[RANK_Y(sq)] ^= 1 << FILE_X(sq); + } + pcAdjust = pc - 8; + vlWhite += del ? -vlWhitePiecePos[pcAdjust][sq] : vlWhitePiecePos[pcAdjust][sq]; + } else { + if (pc == 16 + PIECE_PAWN) { + brBlackPawn[RANK_Y(sq)] ^= 1 << FILE_X(sq); + } + pcAdjust = pc - 16; + vlBlack += del ? -vlBlackPiecePos[pcAdjust][sq] : vlBlackPiecePos[pcAdjust][sq]; + pcAdjust += 6; + } + zobristKey ^= PreGen_zobristKeyTable[pcAdjust][sq]; + zobristLock ^= PreGen_zobristLockTable[pcAdjust][sq]; + } + + public void addPiece(int sq, int pc) { + addPiece(sq, pc, false); + } + + public void delPiece(int sq, int pc) { + addPiece(sq, pc, true); + } + + /* A - Take out Captured Piece (Different in En-Passant, see A-EP) + * B - Remove Source + * C - Add into Destination (Different in Promotion, see C-P) + * D - for Castling only + */ + public void movePiece() { + int sqSrc = SRC(mvList[moveNum]); + int sqDst = DST(mvList[moveNum]); + int pcCaptured = squares[sqDst]; + if (pcCaptured > 0) { + delPiece(sqDst, pcCaptured); // A + } + int pc = squares[sqSrc]; + // __ASSERT((pcCaptured & SIDE_TAG(sdPlayer)) == 0); + // __ASSERT((pc & SIDE_TAG(sdPlayer)) != 0); + delPiece(sqSrc, pc); // B + addPiece(sqDst, pc); // C + pcList[moveNum] = pcCaptured; + specialMoveList[moveNum] = false; + castlingBitsList[moveNum] = castlingBits(); + sqEnPassantList[moveNum] = 0; + // CASTLING -> Set Castling Bits for Rook's Capture + if (PIECE_TYPE(pcCaptured) == PIECE_ROOK) { + int castling = (1 - sdPlayer) << 1; + if (sqDst == CASTLING_ROOK_SRC[castling]) { + castlingBitsList[moveNum] &= ~(1 << castling); + } else if (sqDst == CASTLING_ROOK_SRC[castling + 1]) { + castlingBitsList[moveNum] &= ~(1 << (castling + 1)); + } + } + if (PIECE_TYPE(pc) == PIECE_KING) { + // CASTLING -> Move both King and Rook + if (!KING_SPAN(sqSrc, sqDst)) { + int castling = CASTLING_TYPE(sdPlayer, sqSrc, sqDst); + delPiece(CASTLING_ROOK_SRC[castling], pc - PIECE_KING + PIECE_ROOK); // D + addPiece(CASTLING_ROOK_DST[castling], pc - PIECE_KING + PIECE_ROOK); // D + specialMoveList[moveNum] = true; + } + // CASTLING -> Set Castling Bits for King's Move + castlingBitsList[moveNum] &= ~(3 << (sdPlayer << 1)); + } else if (PIECE_TYPE(pc) == PIECE_PAWN) { + if (PAWN_PROMOTION(sqDst, sdPlayer)) { + // PROMOTION -> Add a Queen instead of a Pawn + delPiece(sqDst, pc); // C-P + addPiece(sqDst, pc - PIECE_PAWN + PIECE_QUEEN); // C-P + specialMoveList[moveNum] = true; + } else if (sqDst == enPassantSquare()) { + // EN-PASSANT -> Reset the Captured Piece for En-Passant Move + int sqCaptured = sqDst - FORWARD_DELTA(sdPlayer); + pcCaptured = squares[sqCaptured]; + // __ASSERT(sqSrc == sqCaptured + 1 || sqSrc == sqCaptured - 1); + // __ASSERT(pcCaptured == OPP_SIDE_TAG(sdPlayer) + PIECE_PAWN); + delPiece(sqCaptured, pcCaptured); // A-EP + pcList[moveNum] = pcCaptured; + specialMoveList[moveNum] = true; + } else { + // EN-PASSANT -> Set En-Passant Square for Pawn's Double-Move + int delta = FORWARD_DELTA(sdPlayer); + if (sqDst == sqSrc + (delta << 1)) { + sqEnPassantList[moveNum] = sqSrc + delta; + } + } + } else if (PIECE_TYPE(pc) == PIECE_ROOK) { + // CASTLING -> Set Castling Bits for Rook's Move + int castling = sdPlayer << 1; + if (sqSrc == CASTLING_ROOK_SRC[castling]) { + castlingBitsList[moveNum] &= ~(1 << castling); + } else if (sqSrc == CASTLING_ROOK_SRC[castling + 1]) { + castlingBitsList[moveNum] &= ~(1 << (castling + 1)); + } + } + } + + /* A - Return Captured Piece (Different in En-Passant, see A-EP) + * B - Add into Source (Different in Promotion, see B-P) + * C - Remove Destination + * D - for Castling only + */ + public void undoMovePiece() { + int sqSrc = SRC(mvList[moveNum]); + int sqDst = DST(mvList[moveNum]); + int pc = squares[sqDst]; + // __ASSERT((pcList[moveNum] & SIDE_TAG(sdPlayer)) == 0); + // __ASSERT((pc & SIDE_TAG(sdPlayer)) != 0); + delPiece(sqDst, pc); // C + addPiece(sqSrc, pc); // B + if (pcList[moveNum] > 0) { + addPiece(sqDst, pcList[moveNum]); // A + } + if (specialMoveList[moveNum]) { + if (PIECE_TYPE(pc) == PIECE_KING) { + // CASTLING -> Move both King and Rook + int castling = CASTLING_TYPE(sdPlayer, sqSrc, sqDst); + // __ASSERT((castlingBits() & (1 << castling)) != 0); + // __ASSERT(squares[CASTLING_ROOK_DST[castling]] == SIDE_TAG(sdPlayer) + PIECE_ROOK); + // __ASSERT(squares[CASTLING_ROOK_SRC[castling]] == 0); + delPiece(CASTLING_ROOK_DST[castling], pc - PIECE_KING + PIECE_ROOK); // D + addPiece(CASTLING_ROOK_SRC[castling], pc - PIECE_KING + PIECE_ROOK); // D + } else if (PAWN_PROMOTION(sqDst, sdPlayer)) { + // PROMOTION -> Add a Pawn instead of a Queen + // __ASSERT(pc == SIDE_TAG(sdPlayer) + PIECE_QUEEN); + delPiece(sqSrc, pc); // B-P + addPiece(sqSrc, pc - PIECE_QUEEN + PIECE_PAWN); // B-P + } else { + // __ASSERT(sqDst == enPassantSquare()); + // EN-PASSANT -> Adjust the Captured Pawn + // __ASSERT(pcList[moveNum] == OPP_SIDE_TAG(sdPlayer) + PIECE_PAWN); + delPiece(sqDst, pcList[moveNum]); // A-EP + addPiece(sqDst - FORWARD_DELTA(sdPlayer), pcList[moveNum]); // A-EP + } + } + } + + public void changeSide() { + sdPlayer = 1 - sdPlayer; + zobristKey ^= PreGen_zobristKeyPlayer; + zobristLock ^= PreGen_zobristLockPlayer; + } + + public boolean makeMove(int mv) { + keyList[moveNum] = zobristKey; + mvList[moveNum] = mv; + movePiece(); + if (checked()) { + undoMovePiece(); + return false; + } + changeSide(); + chkList[moveNum] = checked(); + moveNum++; + distance++; + return true; + } + + public void undoMakeMove() { + moveNum--; + distance--; + changeSide(); + undoMovePiece(); + } + + public void nullMove() { + keyList[moveNum] = zobristKey; + changeSide(); + mvList[moveNum] = pcList[moveNum] = sqEnPassantList[moveNum] = 0; + chkList[moveNum] = specialMoveList[moveNum] = false; + castlingBitsList[moveNum] = castlingBits(); + moveNum++; + distance++; + } + + public void undoNullMove() { + moveNum--; + distance--; + changeSide(); + } + + public int fenPiece(char c) { + switch (c) { + case 'K': + return PIECE_KING; + case 'Q': + return PIECE_QUEEN; + case 'R': + return PIECE_ROOK; + case 'B': + return PIECE_BISHOP; + case 'N': + return PIECE_KNIGHT; + case 'P': + return PIECE_PAWN; + default: + return -1; + } + } + + public void fromFen(String fen) { + clearBoard(); + int y = RANK_TOP; + int x = FILE_LEFT; + int index = 0; + if (index == fen.length()) { + setIrrev(0, 0); + return; + } + char c = fen.charAt(index); + while (c != ' ') { + if (c == '/') { + x = FILE_LEFT; + y++; + if (y > RANK_BOTTOM) { + break; + } + } else if (c >= '1' && c <= '8') { + x += (c - '0'); + } else if (c >= 'A' && c <= 'Z') { + if (x <= FILE_RIGHT) { + if (c != 'P' || (y != RANK_TOP && y != RANK_BOTTOM)) { + int pt = fenPiece(c); + if (pt >= 0) { + addPiece(COORD_XY(x, y), pt + 8); + } + } + x++; + } + } else if (c >= 'a' && c <= 'z') { + if (x <= FILE_RIGHT) { + if (c != 'p' || (y != RANK_TOP && y != RANK_BOTTOM)) { + int pt = fenPiece((char) (c + 'A' - 'a')); + if (pt >= 0) { + addPiece(COORD_XY(x, y), pt + 16); + } + } + x++; + } + } + index++; + if (index == fen.length()) { + setIrrev(0, 0); + return; + } + c = fen.charAt(index); + } + index++; + if (index == fen.length()) { + setIrrev(0, 0); + return; + } + if (sdPlayer == (fen.charAt(index) == 'b' ? 0 : 1)) { + changeSide(); + } + index++; // Skip a ' ' + if (index == fen.length()) { + setIrrev(0, 0); + return; + } + int castlingBits = 0; + index++; + if (index == fen.length()) { + setIrrev(0, 0); + return; + } + c = fen.charAt(index); + while (c != ' ') { + switch (c) { + case 'K': + if (squares[0x78] == 8 && squares[0x7b] == 10) { + castlingBits += 1; + } + break; + case 'Q': + if (squares[0x78] == 8 && squares[0x74] == 10) { + castlingBits += 2; + } + break; + case 'k': + if (squares[0x08] == 16 && squares[0x0b] == 18) { + castlingBits += 4; + } + break; + case 'q': + if (squares[0x08] == 16 && squares[0x04] == 18) { + castlingBits += 8; + } + break; + } + index++; + if (index == fen.length()) { + setIrrev(castlingBits, 0); + return; + } + c = fen.charAt(index); + } + int sqEnPassant = PARSE_COORD(fen, index + 1); + if (sqEnPassant > 0 && PAWN_EN_PASSANT(sqEnPassant, sdPlayer) && + squares[sqEnPassant - FORWARD_DELTA(sdPlayer)] > 0) { + setIrrev(castlingBits, sqEnPassant); + } else { + setIrrev(castlingBits, 0); + } + } + + public static final String FEN_PIECE = " KQRBNP kqrbnp "; + public static final String CASTLING_CHAR = "KQkq"; + + public String toFen() { + StringBuffer fen = new StringBuffer(); + for (int y = RANK_TOP; y <= RANK_BOTTOM; y++) { + int k = 0; + for (int x = FILE_LEFT; x <= FILE_RIGHT; x++) { + int pc = squares[COORD_XY(x, y)]; + if (pc > 0) { + if (k > 0) { + fen.append((char) ('0' + k)); + k = 0; + } + fen.append(FEN_PIECE.charAt(pc)); + } else { + k++; + } + } + if (k > 0) { + fen.append((char) ('0' + k)); + } + fen.append('/'); + } + fen.setCharAt(fen.length() - 1, ' '); + fen.append(sdPlayer == 0 ? 'w' : 'b'); + fen.append(' '); + int castlingBits = castlingBits(); + if (castlingBits == 0) { + fen.append('-'); + } else { + for (int castling = 0; castling < 4; castling++) { + if ((castlingBits & (1 << castling)) != 0) { + fen.append(CASTLING_CHAR.charAt(castling)); + } + } + } + fen.append(' '); + fen.append(enPassantSquare() > 0 ? SQUARE_STR(enPassantSquare()) : "-"); + return fen.toString(); + } + + public int generateAllMoves(int[] mvs) { + return generateMoves(mvs, null); + } + + public int generateMoves(int[] mvs, int[] vls) { + int moves = 0; + int pcSelfSide = SIDE_TAG(sdPlayer); + int pcOppSide = OPP_SIDE_TAG(sdPlayer); + // CASTLING -> Begin Generating Castling Moves + if (vls == null) { + for (int i = 0; i < 2; i++) { + int castling = (sdPlayer << 1) + i; + if (canCastling(castling)) { + mvs[moves] = MOVE(CASTLING_KING_SRC[castling], CASTLING_KING_DST[castling]); + moves++; + } + } + } + // CASTLING -> End Generating Castling Moves + for (int sqSrc = 0; sqSrc < 128; sqSrc++) { + int pcSrc = squares[sqSrc]; + if ((pcSrc & pcSelfSide) == 0) { + continue; + } + switch (pcSrc - pcSelfSide) { + case PIECE_KING: + for (int i = 0; i < 8; i++) { + int sqDst = sqSrc + KING_DELTA[i]; + if (!IN_BOARD(sqDst)) { + continue; + } + int pcDst = squares[sqDst]; + if (vls == null) { + if ((pcDst & pcSelfSide) == 0) { + mvs[moves] = MOVE(sqSrc, sqDst); + moves++; + } + } else if ((pcDst & pcOppSide) != 0) { + mvs[moves] = MOVE(sqSrc, sqDst); + vls[moves] = MVV_LVA(pcDst, 99); + moves++; + } + } + break; + case PIECE_QUEEN: + for (int i = 0; i < 8; i++) { + int delta = KING_DELTA[i]; + int sqDst = sqSrc + delta; + while (IN_BOARD(sqDst)) { + int pcDst = squares[sqDst]; + if (pcDst == 0) { + if (vls == null) { + mvs[moves] = MOVE(sqSrc, sqDst); + moves++; + } + } else { + if ((pcDst & pcOppSide) != 0) { + mvs[moves] = MOVE(sqSrc, sqDst); + if (vls != null) { + vls[moves] = MVV_LVA(pcDst, 9); + } + moves++; + } + break; + } + sqDst += delta; + } + } + break; + case PIECE_ROOK: + for (int i = 0; i < 4; i++) { + int delta = ROOK_DELTA[i]; + int sqDst = sqSrc + delta; + while (IN_BOARD(sqDst)) { + int pcDst = squares[sqDst]; + if (pcDst == 0) { + if (vls == null) { + mvs[moves] = MOVE(sqSrc, sqDst); + moves++; + } + } else { + if ((pcDst & pcOppSide) != 0) { + mvs[moves] = MOVE(sqSrc, sqDst); + if (vls != null) { + vls[moves] = MVV_LVA(pcDst, 5); + } + moves++; + } + break; + } + sqDst += delta; + } + } + break; + case PIECE_BISHOP: + for (int i = 0; i < 4; i++) { + int delta = BISHOP_DELTA[i]; + int sqDst = sqSrc + delta; + while (IN_BOARD(sqDst)) { + int pcDst = squares[sqDst]; + if (pcDst == 0) { + if (vls == null) { + mvs[moves] = MOVE(sqSrc, sqDst); + moves++; + } + } else { + if ((pcDst & pcOppSide) != 0) { + mvs[moves] = MOVE(sqSrc, sqDst); + if (vls != null) { + vls[moves] = MVV_LVA(pcDst, 3); + } + moves++; + } + break; + } + sqDst += delta; + } + } + break; + case PIECE_KNIGHT: + for (int i = 0; i < 8; i++) { + int sqDst = sqSrc + KNIGHT_DELTA[i]; + if (!IN_BOARD(sqDst)) { + continue; + } + int pcDst = squares[sqDst]; + if (vls == null) { + if ((pcDst & pcSelfSide) == 0) { + mvs[moves] = MOVE(sqSrc, sqDst); + moves++; + } + } else if ((pcDst & pcOppSide) != 0) { + mvs[moves] = MOVE(sqSrc, sqDst); + vls[moves] = MVV_LVA(pcDst, 3); + moves++; + } + } + break; + case PIECE_PAWN: + int delta = FORWARD_DELTA(sdPlayer); + int sqDst = sqSrc + delta; + if (vls == null) { + if (IN_BOARD(sqDst) && squares[sqDst] == 0) { + mvs[moves] = MOVE(sqSrc, sqDst); + moves++; + if (PAWN_INIT(sqSrc, sdPlayer)) { + sqDst += delta; + if (squares[sqDst] == 0) { + mvs[moves] = MOVE(sqSrc, sqDst); + moves++; + } + } + } + } else { + // PROMOTION -> Promotions are regarded as Capture Moves + if (PAWN_PROMOTION(sqDst, sdPlayer) && squares[sqDst] == 0) { + mvs[moves] = MOVE(sqSrc, sqDst); + vls[moves] = MVV_LVA(PIECE_QUEEN, 1); + moves++; + } + } + int sqTmp = sqSrc + delta; + for (int i = -1; i <= 1; i += 2) { + sqDst = sqTmp + i; + if (!IN_BOARD(sqDst)) { + continue; + } + int pcDst = squares[sqDst]; + // EN-PASSANT -> En-passant considered + if (sqDst == enPassantSquare()) { + pcDst = squares[sqDst - delta]; + } + if ((pcDst & pcOppSide) != 0) { + mvs[moves] = MOVE(sqSrc, sqDst); + if (vls != null) { + vls[moves] = MVV_LVA(pcDst, 1); + } + moves++; + } + } + break; + } + } + return moves; + } + + public boolean legalMove(int mv) { + int sqSrc = SRC(mv); + int pcSrc = squares[sqSrc]; + int pcSelfSide = SIDE_TAG(sdPlayer); + if ((pcSrc & pcSelfSide) == 0) { + return false; + } + int sqDst = DST(mv); + int pcDst = squares[sqDst]; + if ((pcDst & pcSelfSide) != 0) { + return false; + } + int pieceType = pcSrc - pcSelfSide; + switch (pieceType) { + case PIECE_KING: + if (KING_SPAN(sqSrc, sqDst)) { + return true; + } + // CASTLING -> Castling considered + int castling = CASTLING_TYPE(sdPlayer, sqSrc, sqDst); + return (CASTLING_KING_DST[castling] == sqDst && canCastling(castling)); + case PIECE_KNIGHT: + return KNIGHT_SPAN(sqSrc, sqDst); + case PIECE_QUEEN: + case PIECE_ROOK: + case PIECE_BISHOP: + int delta; + switch (SAME_LINE(sqSrc, sqDst)) { + case DIFF_LINE: + return false; + case SAME_RANK: + if (pieceType == PIECE_BISHOP) { + return false; + } + delta = (sqDst < sqSrc ? -1 : 1); + break; + case SAME_FILE: + if (pieceType == PIECE_BISHOP) { + return false; + } + delta = (sqDst < sqSrc ? -16 : 16); + break; + case SAME_DIAG_A1H8: + if (pieceType == PIECE_ROOK) { + return false; + } + delta = (sqDst < sqSrc ? -15 : 15); + break; + case SAME_DIAG_A8H1: + if (pieceType == PIECE_ROOK) { + return false; + } + delta = (sqDst < sqSrc ? -17 : 17); + break; + default: // Never Occurs + throw new RuntimeException(); + } + int sqTmp = sqSrc + delta; + while (sqTmp != sqDst) { + if (squares[sqTmp] > 0) { + return false; + } + sqTmp += delta; + } + return true; + case PIECE_PAWN: + delta = FORWARD_DELTA(sdPlayer); + sqTmp = sqSrc + delta; + // EN-PASSANT -> En-passant is a capture move but "pcDst != 0" + if (pcDst != 0 || sqDst == enPassantSquare()) { + return (sqDst == sqTmp - 1 || sqDst == sqTmp + 1); + } + return (sqDst == sqTmp || (sqDst == sqTmp + delta && + PAWN_INIT(sqSrc, sdPlayer) && squares[sqTmp] == 0)); + default: + return false; + } + } + + public boolean checked() { + int pcSelfSide = SIDE_TAG(sdPlayer); + for (int sqSrc = 0; sqSrc < 128; sqSrc++) { + if (squares[sqSrc] == pcSelfSide + PIECE_KING) { + return checked(sqSrc); + } + } + return false; + } + + public boolean checked(int sqSrc) { + int pcOppSide = OPP_SIDE_TAG(sdPlayer); + int sqTmp = sqSrc + FORWARD_DELTA(sdPlayer); + for (int i = -1; i <= 1; i += 2) { + int sqDst = sqTmp + i; + if (IN_BOARD(sqDst) && squares[sqDst] == pcOppSide + PIECE_PAWN) { + return true; + } + } + for (int i = 0; i < 8; i++) { + int sqDst = sqSrc + KING_DELTA[i]; + if (IN_BOARD(sqDst) && squares[sqDst] == pcOppSide + PIECE_KING) { + return true; + } + } + for (int i = 0; i < 8; i++) { + int sqDst = sqSrc + KNIGHT_DELTA[i]; + if (IN_BOARD(sqDst) && squares[sqDst] == pcOppSide + PIECE_KNIGHT) { + return true; + } + } + for (int i = 0; i < 4; i++) { + int delta = BISHOP_DELTA[i]; + int sqDst = sqSrc + delta; + while (IN_BOARD(sqDst)) { + int pcDst = squares[sqDst]; + if (pcDst > 0) { + if (pcDst == pcOppSide + PIECE_BISHOP || pcDst == pcOppSide + PIECE_QUEEN) { + return true; + } + break; + } + sqDst += delta; + } + } + for (int i = 0; i < 4; i++) { + int delta = ROOK_DELTA[i]; + int sqDst = sqSrc + delta; + while (IN_BOARD(sqDst)) { + int pcDst = squares[sqDst]; + if (pcDst > 0) { + if (pcDst == pcOppSide + PIECE_ROOK || pcDst == pcOppSide + PIECE_QUEEN) { + return true; + } + break; + } + sqDst += delta; + } + } + return false; + } + + public boolean isMate() { + int[] mvs = new int[MAX_GEN_MOVES]; + int moves = generateAllMoves(mvs); + for (int i = 0; i < moves; i++) { + if (makeMove(mvs[i])) { + undoMakeMove(); + return false; + } + } + return true; + } + + public int drawValue() { + return (distance & 1) == 0 ? -DRAW_VALUE : DRAW_VALUE; + } + + public int checkmateValue() { + return distance - MATE_VALUE; + } + + public int mateValue() { + return inCheck() ? checkmateValue() : drawValue(); + } + + public int material() { + return (sdPlayer == 0 ? vlWhite - vlBlack : vlBlack - vlWhite) + ADVANCED_VALUE; + } + + public boolean nullOkay() { + return (sdPlayer == 0 ? vlWhite : vlBlack) > NULL_OKAY_MARGIN; + } + + public boolean nullSafe() { + return (sdPlayer == 0 ? vlWhite : vlBlack) > NULL_SAFE_MARGIN; + } + + public boolean isRep() { + return isRep(1); + } + + public boolean isRep(int recur_) { + int recur = recur_; + boolean selfSide = false; + int index = moveNum - 1; + while (mvList[index] > 0 && pcList[index] == 0) { + if (selfSide) { + if (keyList[index] == zobristKey) { + recur--; + if (recur == 0) { + return true; + } + } + } + selfSide = !selfSide; + index--; + } + return false; + } + + public int bookMove() { + if (bookSize == 0) { + return 0; + } + int lock = zobristLock >>> 1; // Convert into Unsigned + int index = Util.binarySearch(lock, bookLock, 0, bookSize); + if (index < 0) { + return 0; + } + index--; + while (index >= 0 && bookLock[index] == lock) { + index--; + } + int[] mvs = new int[MAX_GEN_MOVES]; + int[] vls = new int[MAX_GEN_MOVES]; + int value = 0; + int moves = 0; + index++; + while (index < bookSize && bookLock[index] == lock) { + int mv = 0xffff & bookMove[index]; + if (legalMove(mv)) { + mvs[moves] = mv; + vls[moves] = bookValue[index]; + value += vls[moves]; + moves++; + if (moves == MAX_GEN_MOVES) { + break; + } + } + index++; + } + if (value == 0) { + return 0; + } + value = Math.abs(random.nextInt()) % value; + for (index = 0; index < moves; index++) { + value -= vls[index]; + if (value < 0) { + break; + } + } + return mvs[index]; + } + + public int historyIndex(int mv) { + return ((squares[SRC(mv)] - 8) << 7) + DST(mv); + } + + public void printBoard() { + printBoard(System.out); + } + + public void printBoard(PrintStream out) { + for (int y = Position.RANK_TOP; y <= Position.RANK_BOTTOM; y++) { + out.print((char) ('8' - y)); + out.print('|'); + for (int x = Position.FILE_LEFT; x <= Position.FILE_RIGHT; x++) { + int pc = squares[Position.COORD_XY(x, y)]; + if (pc > 0) { + if (pc < 16) { + out.print(PIECE_STRING.charAt(pc - 8)); + } else { + out.print((char) (PIECE_STRING.charAt(pc - 16) - 'A' + 'a')); + } + } else { + out.print('.'); + } + out.print(' '); + } + out.println(); + } + out.println(" +----------------"); + out.println(" a b c d e f g h"); + } +} \ No newline at end of file diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/api/game/chess/Search.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/api/game/chess/Search.java new file mode 100644 index 000000000..dbd10bbc8 --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/api/game/chess/Search.java @@ -0,0 +1,399 @@ +/* +Search.java - Source Code for Mobile Chess, Part II + +Mobile Chess - a Chess Program for Java ME +Designed by Morning Yellow, Version: 1.20, Last Modified: Mar. 2013 +Copyright (C) 2008-2013 www.chess-wizard.com + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +package com.github.tartaricacid.touhoulittlemaid.api.game.chess; + +@SuppressWarnings("all") +public class Search { + private static final int HASH_ALPHA = 1; + private static final int HASH_BETA = 2; + private static final int HASH_PV = 3; + private static final int LIMIT_DEPTH = 64; + private static final int NULL_DEPTH = 2; + private static final int RANDOM_MASK = 7; + private static final int MAX_GEN_MOVES = Position.MAX_GEN_MOVES; + private static final int MATE_VALUE = Position.MATE_VALUE; + private static final int WIN_VALUE = Position.WIN_VALUE; + + private int hashMask, mvResult, allNodes, allMillis; + private HashItem[] hashTable; + Position pos; + int[] historyTable = new int[2048]; + int[][] mvKiller = new int[LIMIT_DEPTH][2]; + + public Search(Position pos, int hashLevel) { + this.pos = pos; + hashMask = (1 << hashLevel) - 1; + hashTable = new HashItem[hashMask + 1]; + for (int i = 0; i <= hashMask; i++) { + hashTable[i] = new HashItem(); + } + } + + private HashItem getHashItem() { + return hashTable[pos.zobristKey & hashMask]; + } + + private int probeHash(int vlAlpha, int vlBeta, int depth, int[] mv) { + HashItem hash = getHashItem(); + if (hash.zobristLock != pos.zobristLock) { + mv[0] = 0; + return -MATE_VALUE; + } + mv[0] = hash.mv; + boolean mate = false; + if (hash.vl > WIN_VALUE) { + hash.vl -= pos.distance; + mate = true; + } else if (hash.vl < -WIN_VALUE) { + hash.vl += pos.distance; + mate = true; + } + if (hash.depth >= depth || mate) { + if (hash.flag == HASH_BETA) { + return (hash.vl >= vlBeta ? hash.vl : -MATE_VALUE); + } else if (hash.flag == HASH_ALPHA) { + return (hash.vl <= vlAlpha ? hash.vl : -MATE_VALUE); + } + return hash.vl; + } + return -MATE_VALUE; + } + + private void recordHash(int flag, int vl, int depth, int mv) { + HashItem hash = getHashItem(); + if (hash.depth > depth) { + return; + } + hash.flag = (byte) flag; + hash.depth = (byte) depth; + if (vl > WIN_VALUE) { + hash.vl = (short) (vl + pos.distance); + } else if (vl < -WIN_VALUE) { + hash.vl = (short) (vl - pos.distance); + } else { + hash.vl = (short) vl; + } + hash.mv = mv; + hash.zobristLock = pos.zobristLock; + } + + private class SortItem { + private static final int PHASE_HASH = 0; + private static final int PHASE_KILLER_1 = 1; + private static final int PHASE_KILLER_2 = 2; + private static final int PHASE_GEN_MOVES = 3; + private static final int PHASE_REST = 4; + + private int index, moves, phase; + private int mvHash, mvKiller1, mvKiller2; + private int[] mvs, vls; + + SortItem(int mvHash) { + phase = PHASE_HASH; + this.mvHash = mvHash; + mvKiller1 = mvKiller[pos.distance][0]; + mvKiller2 = mvKiller[pos.distance][1]; + } + + int next() { + if (phase == PHASE_HASH) { + phase = PHASE_KILLER_1; + // WARNING: pos.legalMove(mvHash) is not always true!!! + // (En-Passant Square and Castling Bits are not considered in Zobrist) + if (mvHash > 0 && pos.legalMove(mvHash)) { + return mvHash; + } + } + if (phase == PHASE_KILLER_1) { + phase = PHASE_KILLER_2; + if (mvKiller1 != mvHash && mvKiller1 > 0 && pos.legalMove(mvKiller1)) { + return mvKiller1; + } + } + if (phase == PHASE_KILLER_2) { + phase = PHASE_GEN_MOVES; + if (mvKiller2 != mvHash && mvKiller2 > 0 && pos.legalMove(mvKiller2)) { + return mvKiller2; + } + } + if (phase == PHASE_GEN_MOVES) { + phase = PHASE_REST; + mvs = new int[MAX_GEN_MOVES]; + vls = new int[MAX_GEN_MOVES]; + moves = pos.generateAllMoves(mvs); + for (int i = 0; i < moves; i++) { + vls[i] = historyTable[pos.historyIndex(mvs[i])]; + } + Util.shellSort(mvs, vls, 0, moves); + index = 0; + } + while (index < moves) { + int mv = mvs[index]; + index++; + if (mv != mvHash && mv != mvKiller1 && mv != mvKiller2) { + return mv; + } + } + return 0; + } + } + + public void setBestMove(int mv, int depth) { + historyTable[pos.historyIndex(mv)] += depth * depth; + int[] killers = mvKiller[pos.distance]; + if (killers[0] != mv) { + killers[1] = killers[0]; + killers[0] = mv; + } + } + + public int searchQuiesc(int vlAlpha_, int vlBeta) { + int vlAlpha = vlAlpha_; + allNodes++; + int vl = pos.checkmateValue(); + if (vl >= vlBeta) { + return vl; + } + if (pos.isRep()) { + return pos.drawValue(); + } + if (pos.distance == LIMIT_DEPTH) { + return Evaluate.evaluate(pos, vlAlpha, vlBeta); + } + int vlBest = -MATE_VALUE; + int genMoves; + int[] mvs = new int[MAX_GEN_MOVES]; + int[] vls = new int[MAX_GEN_MOVES]; + if (pos.inCheck()) { + genMoves = pos.generateAllMoves(mvs); + for (int i = 0; i < genMoves; i++) { + vls[i] = historyTable[pos.historyIndex(mvs[i])]; + } + } else { + vl = Evaluate.evaluate(pos, vlAlpha, vlBeta); + if (vl > vlBest) { + if (vl >= vlBeta) { + return vl; + } + vlBest = vl; + vlAlpha = Math.max(vl, vlAlpha); + } + genMoves = pos.generateMoves(mvs, vls); + } + Util.shellSort(mvs, vls, 0, genMoves); + for (int i = 0; i < genMoves; i++) { + if (!pos.makeMove(mvs[i])) { + continue; + } + vl = -searchQuiesc(-vlBeta, -vlAlpha); + pos.undoMakeMove(); + if (vl > vlBest) { + if (vl >= vlBeta) { + return vl; + } + vlBest = vl; + vlAlpha = Math.max(vl, vlAlpha); + } + } + return vlBest == -MATE_VALUE ? pos.mateValue() : vlBest; + } + + public int searchNoNull(int vlAlpha, int vlBeta, int depth) { + return searchFull(vlAlpha, vlBeta, depth, true); + } + + public int searchFull(int vlAlpha, int vlBeta, int depth) { + return searchFull(vlAlpha, vlBeta, depth, false); + } + + public int searchFull(int vlAlpha_, int vlBeta, int depth, boolean noNull) { + int vlAlpha = vlAlpha_; + int vl; + if (depth <= 0) { + return searchQuiesc(vlAlpha, vlBeta); + } + allNodes++; + vl = pos.checkmateValue(); + if (vl >= vlBeta) { + return vl; + } + if (pos.isRep()) { + return pos.drawValue(); + } + int[] mvHash = new int[1]; + vl = probeHash(vlAlpha, vlBeta, depth, mvHash); + if (vl > -MATE_VALUE) { + return vl; + } + if (pos.distance == LIMIT_DEPTH) { + return Evaluate.evaluate(pos, vlAlpha, vlBeta); + } + if (!noNull && !pos.inCheck() && pos.nullOkay()) { + pos.nullMove(); + vl = -searchNoNull(-vlBeta, 1 - vlBeta, depth - NULL_DEPTH - 1); + pos.undoNullMove(); + if (vl >= vlBeta && (pos.nullSafe() || searchNoNull(vlAlpha, vlBeta, depth - NULL_DEPTH) >= vlBeta)) { + return vl; + } + } + int hashFlag = HASH_ALPHA; + int vlBest = -MATE_VALUE; + int mvBest = 0; + SortItem sort = new SortItem(mvHash[0]); + int mv; + while ((mv = sort.next()) > 0) { + if (!pos.makeMove(mv)) { + continue; + } + int newDepth = pos.inCheck() ? depth : depth - 1; + if (vlBest == -MATE_VALUE) { + vl = -searchFull(-vlBeta, -vlAlpha, newDepth); + } else { + vl = -searchFull(-vlAlpha - 1, -vlAlpha, newDepth); + if (vl > vlAlpha && vl < vlBeta) { + vl = -searchFull(-vlBeta, -vlAlpha, newDepth); + } + } + pos.undoMakeMove(); + if (vl > vlBest) { + vlBest = vl; + if (vl >= vlBeta) { + hashFlag = HASH_BETA; + mvBest = mv; + break; + } + if (vl > vlAlpha) { + vlAlpha = vl; + hashFlag = HASH_PV; + mvBest = mv; + } + } + } + if (vlBest == -MATE_VALUE) { + return pos.mateValue(); + } + recordHash(hashFlag, vlBest, depth, mvBest); + if (mvBest > 0) { + setBestMove(mvBest, depth); + } + return vlBest; + } + + public int searchRoot(int depth) { + int vlBest = -MATE_VALUE; + SortItem sort = new SortItem(mvResult); + int mv; + while ((mv = sort.next()) > 0) { + if (!pos.makeMove(mv)) { + continue; + } + int newDepth = pos.inCheck() ? depth : depth - 1; + int vl; + if (vlBest == -MATE_VALUE) { + vl = -searchNoNull(-MATE_VALUE, MATE_VALUE, newDepth); + } else { + vl = -searchFull(-vlBest - 1, -vlBest, newDepth); + if (vl > vlBest) { + vl = -searchNoNull(-MATE_VALUE, -vlBest, newDepth); + } + } + pos.undoMakeMove(); + if (vl > vlBest) { + vlBest = vl; + mvResult = mv; + if (vlBest > -WIN_VALUE && vlBest < WIN_VALUE) { + vlBest += (Position.random.nextInt() & RANDOM_MASK) - + (Position.random.nextInt() & RANDOM_MASK); + } + } + } + setBestMove(mvResult, depth); + return vlBest; + } + + public int searchMain(int millis) { + return searchMain(LIMIT_DEPTH, millis); + } + + public int searchMain(int depth, int millis) { + mvResult = pos.bookMove(); + if (mvResult > 0) { + pos.makeMove(mvResult); + if (!pos.isRep(2)) { + pos.undoMakeMove(); + return mvResult; + } + pos.undoMakeMove(); + } + int vl = 0; + int[] mvs = new int[MAX_GEN_MOVES]; + int genMoves = pos.generateAllMoves(mvs); + for (int i = 0; i < genMoves; i++) { + if (pos.makeMove(mvs[i])) { + pos.undoMakeMove(); + mvResult = mvs[i]; + vl++; + } + } + if (vl == 1) { + return mvResult; + } + for (int i = 0; i <= hashMask; i++) { + HashItem hash = hashTable[i]; + hash.depth = hash.flag = 0; + hash.vl = 0; + hash.mv = hash.zobristLock = 0; + } + for (int i = 0; i < LIMIT_DEPTH; i++) { + mvKiller[i][0] = mvKiller[i][1] = 0; + } + for (int i = 0; i < 2048; i++) { + historyTable[i] = 0; + } + mvResult = 0; + allNodes = 0; + pos.distance = 0; + Evaluate.preEval(pos); + long t = System.currentTimeMillis(); + for (int i = 1; i <= depth; i++) { + vl = searchRoot(i); + if (vl > WIN_VALUE || vl < -WIN_VALUE) { + break; + } + allMillis = (int) (System.currentTimeMillis() - t); + if (allMillis > millis) { + break; + } + } + return mvResult; + } + + public int getKNPS() { + return allNodes / allMillis; + } + + class HashItem { + byte depth, flag; + short vl; + int mv, zobristLock; + } +} \ No newline at end of file diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/api/game/chess/Util.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/api/game/chess/Util.java new file mode 100644 index 000000000..2ba555690 --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/api/game/chess/Util.java @@ -0,0 +1,129 @@ +package com.github.tartaricacid.touhoulittlemaid.api.game.chess; + +import java.io.IOException; +import java.io.InputStream; + +@SuppressWarnings("all") +public class Util { + public static int MIN_MAX(int min, int mid, int max) { + return mid < min ? min : mid > max ? max : mid; + } + + private static byte[] POP_COUNT_16 = new byte[65536]; + + static { + for (int i = 0; i < 65536; i++) { + int n = ((i >> 1) & 0x5555) + (i & 0x5555); + n = ((n >> 2) & 0x3333) + (n & 0x3333); + n = ((n >> 4) & 0x0f0f) + (n & 0x0f0f); + POP_COUNT_16[i] = (byte) ((n >> 8) + (n & 0x00ff)); + } + } + + public static int POP_COUNT_16(int data) { + return POP_COUNT_16[data]; + } + + public static int readShort(InputStream in) throws IOException { + int b0 = in.read(); + int b1 = in.read(); + if (b0 == -1 || b1 == -1) { + throw new IOException(); + } + return b0 | (b1 << 8); + } + + public static int readInt(InputStream in) throws IOException { + int b0 = in.read(); + int b1 = in.read(); + int b2 = in.read(); + int b3 = in.read(); + if (b0 == -1 || b1 == -1 || b2 == -1 || b3 == -1) { + throw new IOException(); + } + return b0 | (b1 << 8) | (b2 << 16) | (b3 << 24); + } + + public static class RC4 { + public int[] state = new int[256]; + public int x, y; + + public void swap(int i, int j) { + int t = state[i]; + state[i] = state[j]; + state[j] = t; + } + + public RC4(byte[] key) { + x = 0; + y = 0; + for (int i = 0; i < 256; i++) { + state[i] = i; + } + int j = 0; + for (int i = 0; i < 256; i++) { + j = (j + state[i] + key[i % key.length]) & 0xff; + swap(i, j); + } + } + + public int nextByte() { + x = (x + 1) & 0xff; + y = (y + state[x]) & 0xff; + swap(x, y); + int t = (state[x] + state[y]) & 0xff; + return state[t]; + } + + public int nextLong() { + int n0, n1, n2, n3; + n0 = nextByte(); + n1 = nextByte(); + n2 = nextByte(); + n3 = nextByte(); + return n0 + (n1 << 8) + (n2 << 16) + (n3 << 24); + } + } + + public static int binarySearch(int vl, int[] vls, int from, int to) { + int low = from; + int high = to - 1; + while (low <= high) { + int mid = (low + high) / 2; + if (vls[mid] < vl) { + low = mid + 1; + } else if (vls[mid] > vl) { + high = mid - 1; + } else { + return mid; + } + } + return -1; + } + + private static final int[] SHELL_STEP = {0, 1, 4, 13, 40, 121, 364, 1093}; + + public static void shellSort(int[] mvs, int[] vls, int from, int to) { + int stepLevel = 1; + while (SHELL_STEP[stepLevel] < to - from) { + stepLevel++; + } + stepLevel--; + while (stepLevel > 0) { + int step = SHELL_STEP[stepLevel]; + for (int i = from + step; i < to; i++) { + int mvBest = mvs[i]; + int vlBest = vls[i]; + int j = i - step; + while (j >= from && vlBest > vls[j]) { + mvs[j + step] = mvs[j]; + vls[j + step] = vls[j]; + j -= step; + } + mvs[j + step] = mvBest; + vls[j + step] = vlBest; + } + stepLevel--; + } + } +} \ No newline at end of file diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/api/game/xqwlight/Position.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/api/game/xqwlight/Position.java new file mode 100644 index 000000000..f1a4e9cff --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/api/game/xqwlight/Position.java @@ -0,0 +1,1122 @@ +/* +Position.java - Source Code for XiangQi Wizard Light, Part I + +XiangQi Wizard Light - a Chinese Chess Program for Java ME +Designed by Morning Yellow, Version: 1.25, Last Modified: Mar. 2008 +Copyright (C) 2004-2008 www.elephantbase.net + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +package com.github.tartaricacid.touhoulittlemaid.api.game.xqwlight; + +import java.io.InputStream; +import java.util.Random; + +@SuppressWarnings("all") +public class Position { + public static final int MATE_VALUE = 10000; + public static final int BAN_VALUE = MATE_VALUE - 100; + public static final int WIN_VALUE = MATE_VALUE - 200; + public static final int NULL_SAFE_MARGIN = 400; + public static final int NULL_OKAY_MARGIN = 200; + public static final int DRAW_VALUE = 20; + public static final int ADVANCED_VALUE = 3; + + public static final int MAX_MOVE_NUM = 256; + public static final int MAX_GEN_MOVES = 128; + public static final int MAX_BOOK_SIZE = 16384; + + public static final int PIECE_KING = 0; + public static final int PIECE_ADVISOR = 1; + public static final int PIECE_BISHOP = 2; + public static final int PIECE_KNIGHT = 3; + public static final int PIECE_ROOK = 4; + public static final int PIECE_CANNON = 5; + public static final int PIECE_PAWN = 6; + + public static final int RANK_TOP = 3; + public static final int RANK_BOTTOM = 12; + public static final int FILE_LEFT = 3; + public static final int FILE_RIGHT = 11; + + public static final byte[] IN_BOARD = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }; + + public static final byte[] IN_FORT = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }; + + public static final byte[] LEGAL_SPAN = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 2, 1, 2, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 2, 1, 2, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + }; + + public static final byte[] KNIGHT_PIN = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, -16, 0, -16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, -1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, -1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 16, 0, 16, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0 + }; + + public static final int[] KING_DELTA = {-16, -1, 1, 16}; + public static final int[] ADVISOR_DELTA = {-17, -15, 15, 17}; + public static final int[][] KNIGHT_DELTA = {{-33, -31}, {-18, 14}, {-14, 18}, {31, 33}}; + public static final int[][] KNIGHT_CHECK_DELTA = {{-33, -18}, {-31, -14}, {14, 31}, {18, 33}}; + public static final int[] MVV_VALUE = {50, 10, 10, 30, 40, 30, 20, 0}; + + public static final short[][] PIECE_VALUE = { + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 9, 9, 9, 11, 13, 11, 9, 9, 9, 0, 0, 0, 0, + 0, 0, 0, 19, 24, 34, 42, 44, 42, 34, 24, 19, 0, 0, 0, 0, + 0, 0, 0, 19, 24, 32, 37, 37, 37, 32, 24, 19, 0, 0, 0, 0, + 0, 0, 0, 19, 23, 27, 29, 30, 29, 27, 23, 19, 0, 0, 0, 0, + 0, 0, 0, 14, 18, 20, 27, 29, 27, 20, 18, 14, 0, 0, 0, 0, + 0, 0, 0, 7, 0, 13, 0, 16, 0, 13, 0, 7, 0, 0, 0, 0, + 0, 0, 0, 7, 0, 7, 0, 15, 0, 7, 0, 7, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 11, 15, 11, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }, { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 20, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 18, 0, 0, 20, 23, 20, 0, 0, 18, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 20, 20, 0, 20, 20, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }, { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 20, 0, 0, 0, 20, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 18, 0, 0, 20, 23, 20, 0, 0, 18, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 20, 20, 0, 20, 20, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }, { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 90, 90, 90, 96, 90, 96, 90, 90, 90, 0, 0, 0, 0, + 0, 0, 0, 90, 96, 103, 97, 94, 97, 103, 96, 90, 0, 0, 0, 0, + 0, 0, 0, 92, 98, 99, 103, 99, 103, 99, 98, 92, 0, 0, 0, 0, + 0, 0, 0, 93, 108, 100, 107, 100, 107, 100, 108, 93, 0, 0, 0, 0, + 0, 0, 0, 90, 100, 99, 103, 104, 103, 99, 100, 90, 0, 0, 0, 0, + 0, 0, 0, 90, 98, 101, 102, 103, 102, 101, 98, 90, 0, 0, 0, 0, + 0, 0, 0, 92, 94, 98, 95, 98, 95, 98, 94, 92, 0, 0, 0, 0, + 0, 0, 0, 93, 92, 94, 95, 92, 95, 94, 92, 93, 0, 0, 0, 0, + 0, 0, 0, 85, 90, 92, 93, 78, 93, 92, 90, 85, 0, 0, 0, 0, + 0, 0, 0, 88, 85, 90, 88, 90, 88, 90, 85, 88, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }, { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 206, 208, 207, 213, 214, 213, 207, 208, 206, 0, 0, 0, 0, + 0, 0, 0, 206, 212, 209, 216, 233, 216, 209, 212, 206, 0, 0, 0, 0, + 0, 0, 0, 206, 208, 207, 214, 216, 214, 207, 208, 206, 0, 0, 0, 0, + 0, 0, 0, 206, 213, 213, 216, 216, 216, 213, 213, 206, 0, 0, 0, 0, + 0, 0, 0, 208, 211, 211, 214, 215, 214, 211, 211, 208, 0, 0, 0, 0, + 0, 0, 0, 208, 212, 212, 214, 215, 214, 212, 212, 208, 0, 0, 0, 0, + 0, 0, 0, 204, 209, 204, 212, 214, 212, 204, 209, 204, 0, 0, 0, 0, + 0, 0, 0, 198, 208, 204, 212, 212, 212, 204, 208, 198, 0, 0, 0, 0, + 0, 0, 0, 200, 208, 206, 212, 200, 212, 206, 208, 200, 0, 0, 0, 0, + 0, 0, 0, 194, 206, 204, 212, 200, 212, 204, 206, 194, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }, { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 100, 100, 96, 91, 90, 91, 96, 100, 100, 0, 0, 0, 0, + 0, 0, 0, 98, 98, 96, 92, 89, 92, 96, 98, 98, 0, 0, 0, 0, + 0, 0, 0, 97, 97, 96, 91, 92, 91, 96, 97, 97, 0, 0, 0, 0, + 0, 0, 0, 96, 99, 99, 98, 100, 98, 99, 99, 96, 0, 0, 0, 0, + 0, 0, 0, 96, 96, 96, 96, 100, 96, 96, 96, 96, 0, 0, 0, 0, + 0, 0, 0, 95, 96, 99, 96, 100, 96, 99, 96, 95, 0, 0, 0, 0, + 0, 0, 0, 96, 96, 96, 96, 96, 96, 96, 96, 96, 0, 0, 0, 0, + 0, 0, 0, 97, 96, 100, 99, 101, 99, 100, 96, 97, 0, 0, 0, 0, + 0, 0, 0, 96, 97, 98, 98, 98, 98, 98, 97, 96, 0, 0, 0, 0, + 0, 0, 0, 96, 96, 97, 99, 99, 99, 97, 96, 96, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }, { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 9, 9, 9, 11, 13, 11, 9, 9, 9, 0, 0, 0, 0, + 0, 0, 0, 19, 24, 34, 42, 44, 42, 34, 24, 19, 0, 0, 0, 0, + 0, 0, 0, 19, 24, 32, 37, 37, 37, 32, 24, 19, 0, 0, 0, 0, + 0, 0, 0, 19, 23, 27, 29, 30, 29, 27, 23, 19, 0, 0, 0, 0, + 0, 0, 0, 14, 18, 20, 27, 29, 27, 20, 18, 14, 0, 0, 0, 0, + 0, 0, 0, 7, 0, 13, 0, 16, 0, 13, 0, 7, 0, 0, 0, 0, + 0, 0, 0, 7, 0, 7, 0, 15, 0, 7, 0, 7, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 11, 15, 11, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }, + }; + + public static final String[] STARTUP_FEN = { + "rnbakabnr/9/1c5c1/p1p1p1p1p/9/9/P1P1P1P1P/1C5C1/9/RNBAKABNR w - - 0 1", + "rnbakabnr/9/1c5c1/p1p1p1p1p/9/9/P1P1P1P1P/1C5C1/9/R1BAKABNR w - - 0 1", + "rnbakabnr/9/1c5c1/p1p1p1p1p/9/9/P1P1P1P1P/1C5C1/9/R1BAKAB1R w - - 0 1", + "rnbakabnr/9/1c5c1/p1p1p1p1p/9/9/9/1C5C1/9/RN2K2NR w - - 0 1", + }; + + public static boolean IN_BOARD(int sq) { + return IN_BOARD[sq] != 0; + } + + public static boolean IN_FORT(int sq) { + return IN_FORT[sq] != 0; + } + + public static int RANK_Y(int sq) { + return sq >> 4; + } + + public static int FILE_X(int sq) { + return sq & 15; + } + + public static int COORD_XY(int x, int y) { + return x + (y << 4); + } + + public static int SQUARE_FLIP(int sq) { + return 254 - sq; + } + + public static int FILE_FLIP(int x) { + return 14 - x; + } + + public static int RANK_FLIP(int y) { + return 15 - y; + } + + public static int MIRROR_SQUARE(int sq) { + return COORD_XY(FILE_FLIP(FILE_X(sq)), RANK_Y(sq)); + } + + public static int SQUARE_FORWARD(int sq, int sd) { + return sq - 16 + (sd << 5); + } + + public static boolean KING_SPAN(int sqSrc, int sqDst) { + return LEGAL_SPAN[sqDst - sqSrc + 256] == 1; + } + + public static boolean ADVISOR_SPAN(int sqSrc, int sqDst) { + return LEGAL_SPAN[sqDst - sqSrc + 256] == 2; + } + + public static boolean BISHOP_SPAN(int sqSrc, int sqDst) { + return LEGAL_SPAN[sqDst - sqSrc + 256] == 3; + } + + public static int BISHOP_PIN(int sqSrc, int sqDst) { + return (sqSrc + sqDst) >> 1; + } + + public static int KNIGHT_PIN(int sqSrc, int sqDst) { + return sqSrc + KNIGHT_PIN[sqDst - sqSrc + 256]; + } + + public static boolean HOME_HALF(int sq, int sd) { + return (sq & 0x80) != (sd << 7); + } + + public static boolean AWAY_HALF(int sq, int sd) { + return (sq & 0x80) == (sd << 7); + } + + public static boolean SAME_HALF(int sqSrc, int sqDst) { + return ((sqSrc ^ sqDst) & 0x80) == 0; + } + + public static boolean SAME_RANK(int sqSrc, int sqDst) { + return ((sqSrc ^ sqDst) & 0xf0) == 0; + } + + public static boolean SAME_FILE(int sqSrc, int sqDst) { + return ((sqSrc ^ sqDst) & 0x0f) == 0; + } + + public static int SIDE_TAG(int sd) { + return 8 + (sd << 3); + } + + public static int OPP_SIDE_TAG(int sd) { + return 16 - (sd << 3); + } + + public static int SRC(int mv) { + return mv & 255; + } + + public static int DST(int mv) { + return mv >> 8; + } + + public static int MOVE(int sqSrc, int sqDst) { + return sqSrc + (sqDst << 8); + } + + public static int MIRROR_MOVE(int mv) { + return MOVE(MIRROR_SQUARE(SRC(mv)), MIRROR_SQUARE(DST(mv))); + } + + public static int MVV_LVA(int pc, int lva) { + return MVV_VALUE[pc & 7] - lva; + } + + public static final String FEN_PIECE = " KABNRCP kabnrcp "; + + public static int CHAR_TO_PIECE(char c) { + return switch (c) { + case 'K' -> PIECE_KING; + case 'A' -> PIECE_ADVISOR; + case 'B', 'E' -> PIECE_BISHOP; + case 'H', 'N' -> PIECE_KNIGHT; + case 'R' -> PIECE_ROOK; + case 'C' -> PIECE_CANNON; + case 'P' -> PIECE_PAWN; + default -> -1; + }; + } + + public static int PreGen_zobristKeyPlayer; + public static int PreGen_zobristLockPlayer; + public static int[][] PreGen_zobristKeyTable = new int[14][256]; + public static int[][] PreGen_zobristLockTable = new int[14][256]; + + public static Random random = new Random(); + + public static int bookSize = 0; + public static int[] bookLock = new int[MAX_BOOK_SIZE]; + public static short[] bookMove = new short[MAX_BOOK_SIZE]; + public static short[] bookValue = new short[MAX_BOOK_SIZE]; + + static { + Util.RC4 rc4 = new Util.RC4(new byte[]{0}); + PreGen_zobristKeyPlayer = rc4.nextLong(); + rc4.nextLong(); // Skip ZobristLock0 + PreGen_zobristLockPlayer = rc4.nextLong(); + for (int i = 0; i < 14; i++) { + for (int j = 0; j < 256; j++) { + PreGen_zobristKeyTable[i][j] = rc4.nextLong(); + rc4.nextLong(); // Skip ZobristLock0 + PreGen_zobristLockTable[i][j] = rc4.nextLong(); + } + } + + InputStream in = rc4.getClass().getResourceAsStream("/assets/touhou_little_maid/book/cchess/BOOK.DAT"); + if (in != null) { + try { + while (bookSize < MAX_BOOK_SIZE) { + bookLock[bookSize] = Util.readInt(in) >>> 1; + bookMove[bookSize] = (short) Util.readShort(in); + bookValue[bookSize] = (short) Util.readShort(in); + bookSize++; + } + } catch (Exception e) { + // Exit "while" when IOException occurs + } + try { + in.close(); + } catch (Exception e) { + // Ignored + } + } + } + + public int sdPlayer; + public byte[] squares = new byte[256]; + + public int zobristKey; + public int zobristLock; + public int vlWhite, vlBlack; + public int moveNum, distance; + + public int[] mvList = new int[MAX_MOVE_NUM]; + public int[] pcList = new int[MAX_MOVE_NUM]; + public int[] keyList = new int[MAX_MOVE_NUM]; + public boolean[] chkList = new boolean[MAX_MOVE_NUM]; + + public void clearBoard() { + sdPlayer = 0; + for (int sq = 0; sq < 256; sq++) { + squares[sq] = 0; + } + zobristKey = zobristLock = 0; + vlWhite = vlBlack = 0; + } + + public void setIrrev() { + mvList[0] = pcList[0] = 0; + chkList[0] = checked(); + moveNum = 1; + distance = 0; + } + + public void addPiece(int sq, int pc, boolean del) { + int pcAdjust; + squares[sq] = (byte) (del ? 0 : pc); + if (pc < 16) { + pcAdjust = pc - 8; + vlWhite += del ? -PIECE_VALUE[pcAdjust][sq] : PIECE_VALUE[pcAdjust][sq]; + } else { + pcAdjust = pc - 16; + vlBlack += del ? -PIECE_VALUE[pcAdjust][SQUARE_FLIP(sq)] : + PIECE_VALUE[pcAdjust][SQUARE_FLIP(sq)]; + pcAdjust += 7; + } + zobristKey ^= PreGen_zobristKeyTable[pcAdjust][sq]; + zobristLock ^= PreGen_zobristLockTable[pcAdjust][sq]; + } + + public void addPiece(int sq, int pc) { + addPiece(sq, pc, false); + } + + public void delPiece(int sq, int pc) { + addPiece(sq, pc, true); + } + + public void movePiece() { + int sqSrc = SRC(mvList[moveNum]); + int sqDst = DST(mvList[moveNum]); + pcList[moveNum] = squares[sqDst]; + if (pcList[moveNum] > 0) { + delPiece(sqDst, pcList[moveNum]); + } + int pc = squares[sqSrc]; + delPiece(sqSrc, pc); + addPiece(sqDst, pc); + } + + public void undoMovePiece() { + int sqSrc = SRC(mvList[moveNum]); + int sqDst = DST(mvList[moveNum]); + int pc = squares[sqDst]; + delPiece(sqDst, pc); + addPiece(sqSrc, pc); + if (pcList[moveNum] > 0) { + addPiece(sqDst, pcList[moveNum]); + } + } + + public void changeSide() { + sdPlayer = 1 - sdPlayer; + zobristKey ^= PreGen_zobristKeyPlayer; + zobristLock ^= PreGen_zobristLockPlayer; + } + + public boolean makeMove(int mv) { + keyList[moveNum] = zobristKey; + mvList[moveNum] = mv; + movePiece(); + if (checked()) { + undoMovePiece(); + return false; + } + changeSide(); + chkList[moveNum] = checked(); + moveNum++; + distance++; + return true; + } + + public void undoMakeMove() { + moveNum--; + distance--; + changeSide(); + undoMovePiece(); + } + + public void nullMove() { + keyList[moveNum] = zobristKey; + changeSide(); + mvList[moveNum] = pcList[moveNum] = 0; + chkList[moveNum] = false; + moveNum++; + distance++; + } + + public void undoNullMove() { + moveNum--; + distance--; + changeSide(); + } + + public void fromFen(String fen) { + clearBoard(); + int y = RANK_TOP; + int x = FILE_LEFT; + int index = 0; + if (index == fen.length()) { + setIrrev(); + return; + } + char c = fen.charAt(index); + while (c != ' ') { + if (c == '/') { + x = FILE_LEFT; + y++; + if (y > RANK_BOTTOM) { + break; + } + } else if (c >= '1' && c <= '9') { + x += (c - '0'); + } else if (c >= 'A' && c <= 'Z') { + if (x <= FILE_RIGHT) { + int pt = CHAR_TO_PIECE(c); + if (pt >= 0) { + addPiece(COORD_XY(x, y), pt + 8); + } + x++; + } + } else if (c >= 'a' && c <= 'z') { + if (x <= FILE_RIGHT) { + int pt = CHAR_TO_PIECE((char) (c + 'A' - 'a')); + if (pt >= 0) { + addPiece(COORD_XY(x, y), pt + 16); + } + x++; + } + } + index++; + if (index == fen.length()) { + setIrrev(); + return; + } + c = fen.charAt(index); + } + index++; + if (index == fen.length()) { + setIrrev(); + return; + } + if (sdPlayer == (fen.charAt(index) == 'b' ? 0 : 1)) { + changeSide(); + } + setIrrev(); + } + + public String toFen() { + StringBuilder fen = new StringBuilder(); + for (int y = RANK_TOP; y <= RANK_BOTTOM; y++) { + int k = 0; + for (int x = FILE_LEFT; x <= FILE_RIGHT; x++) { + int pc = squares[COORD_XY(x, y)]; + if (pc > 0) { + if (k > 0) { + fen.append((char) ('0' + k)); + k = 0; + } + fen.append(FEN_PIECE.charAt(pc)); + } else { + k++; + } + } + if (k > 0) { + fen.append((char) ('0' + k)); + } + fen.append('/'); + } + fen.setCharAt(fen.length() - 1, ' '); + fen.append(sdPlayer == 0 ? 'w' : 'b'); + return fen.toString(); + } + + public int generateAllMoves(int[] mvs) { + return generateMoves(mvs, null); + } + + public int generateMoves(int[] mvs, int[] vls) { + int moves = 0; + int pcSelfSide = SIDE_TAG(sdPlayer); + int pcOppSide = OPP_SIDE_TAG(sdPlayer); + for (int sqSrc = 0; sqSrc < 256; sqSrc++) { + int pcSrc = squares[sqSrc]; + if ((pcSrc & pcSelfSide) == 0) { + continue; + } + switch (pcSrc - pcSelfSide) { + case PIECE_KING: + for (int i = 0; i < 4; i++) { + int sqDst = sqSrc + KING_DELTA[i]; + if (!IN_FORT(sqDst)) { + continue; + } + int pcDst = squares[sqDst]; + if (vls == null) { + if ((pcDst & pcSelfSide) == 0) { + mvs[moves] = MOVE(sqSrc, sqDst); + moves++; + } + } else if ((pcDst & pcOppSide) != 0) { + mvs[moves] = MOVE(sqSrc, sqDst); + vls[moves] = MVV_LVA(pcDst, 5); + moves++; + } + } + break; + case PIECE_ADVISOR: + for (int i = 0; i < 4; i++) { + int sqDst = sqSrc + ADVISOR_DELTA[i]; + if (!IN_FORT(sqDst)) { + continue; + } + int pcDst = squares[sqDst]; + if (vls == null) { + if ((pcDst & pcSelfSide) == 0) { + mvs[moves] = MOVE(sqSrc, sqDst); + moves++; + } + } else if ((pcDst & pcOppSide) != 0) { + mvs[moves] = MOVE(sqSrc, sqDst); + vls[moves] = MVV_LVA(pcDst, 1); + moves++; + } + } + break; + case PIECE_BISHOP: + for (int i = 0; i < 4; i++) { + int sqDst = sqSrc + ADVISOR_DELTA[i]; + if (!(IN_BOARD(sqDst) && HOME_HALF(sqDst, sdPlayer) && squares[sqDst] == 0)) { + continue; + } + sqDst += ADVISOR_DELTA[i]; + int pcDst = squares[sqDst]; + if (vls == null) { + if ((pcDst & pcSelfSide) == 0) { + mvs[moves] = MOVE(sqSrc, sqDst); + moves++; + } + } else if ((pcDst & pcOppSide) != 0) { + mvs[moves] = MOVE(sqSrc, sqDst); + vls[moves] = MVV_LVA(pcDst, 1); + moves++; + } + } + break; + case PIECE_KNIGHT: + for (int i = 0; i < 4; i++) { + int sqDst = sqSrc + KING_DELTA[i]; + if (squares[sqDst] > 0) { + continue; + } + for (int j = 0; j < 2; j++) { + sqDst = sqSrc + KNIGHT_DELTA[i][j]; + if (!IN_BOARD(sqDst)) { + continue; + } + int pcDst = squares[sqDst]; + if (vls == null) { + if ((pcDst & pcSelfSide) == 0) { + mvs[moves] = MOVE(sqSrc, sqDst); + moves++; + } + } else if ((pcDst & pcOppSide) != 0) { + mvs[moves] = MOVE(sqSrc, sqDst); + vls[moves] = MVV_LVA(pcDst, 1); + moves++; + } + } + } + break; + case PIECE_ROOK: + for (int i = 0; i < 4; i++) { + int delta = KING_DELTA[i]; + int sqDst = sqSrc + delta; + while (IN_BOARD(sqDst)) { + int pcDst = squares[sqDst]; + if (pcDst == 0) { + if (vls == null) { + mvs[moves] = MOVE(sqSrc, sqDst); + moves++; + } + } else { + if ((pcDst & pcOppSide) != 0) { + mvs[moves] = MOVE(sqSrc, sqDst); + if (vls != null) { + vls[moves] = MVV_LVA(pcDst, 4); + } + moves++; + } + break; + } + sqDst += delta; + } + } + break; + case PIECE_CANNON: + for (int i = 0; i < 4; i++) { + int delta = KING_DELTA[i]; + int sqDst = sqSrc + delta; + while (IN_BOARD(sqDst)) { + int pcDst = squares[sqDst]; + if (pcDst == 0) { + if (vls == null) { + mvs[moves] = MOVE(sqSrc, sqDst); + moves++; + } + } else { + break; + } + sqDst += delta; + } + sqDst += delta; + while (IN_BOARD(sqDst)) { + int pcDst = squares[sqDst]; + if (pcDst > 0) { + if ((pcDst & pcOppSide) != 0) { + mvs[moves] = MOVE(sqSrc, sqDst); + if (vls != null) { + vls[moves] = MVV_LVA(pcDst, 4); + } + moves++; + } + break; + } + sqDst += delta; + } + } + break; + case PIECE_PAWN: + int sqDst = SQUARE_FORWARD(sqSrc, sdPlayer); + if (IN_BOARD(sqDst)) { + int pcDst = squares[sqDst]; + if (vls == null) { + if ((pcDst & pcSelfSide) == 0) { + mvs[moves] = MOVE(sqSrc, sqDst); + moves++; + } + } else if ((pcDst & pcOppSide) != 0) { + mvs[moves] = MOVE(sqSrc, sqDst); + vls[moves] = MVV_LVA(pcDst, 2); + moves++; + } + } + if (AWAY_HALF(sqSrc, sdPlayer)) { + for (int delta = -1; delta <= 1; delta += 2) { + sqDst = sqSrc + delta; + if (IN_BOARD(sqDst)) { + int pcDst = squares[sqDst]; + if (vls == null) { + if ((pcDst & pcSelfSide) == 0) { + mvs[moves] = MOVE(sqSrc, sqDst); + moves++; + } + } else if ((pcDst & pcOppSide) != 0) { + mvs[moves] = MOVE(sqSrc, sqDst); + vls[moves] = MVV_LVA(pcDst, 2); + moves++; + } + } + } + } + break; + } + } + return moves; + } + + public boolean legalMove(int mv) { + int sqSrc = SRC(mv); + int pcSrc = squares[sqSrc]; + int pcSelfSide = SIDE_TAG(sdPlayer); + if ((pcSrc & pcSelfSide) == 0) { + return false; + } + + int sqDst = DST(mv); + int pcDst = squares[sqDst]; + if ((pcDst & pcSelfSide) != 0) { + return false; + } + + switch (pcSrc - pcSelfSide) { + case PIECE_KING: + return IN_FORT(sqDst) && KING_SPAN(sqSrc, sqDst); + case PIECE_ADVISOR: + return IN_FORT(sqDst) && ADVISOR_SPAN(sqSrc, sqDst); + case PIECE_BISHOP: + return SAME_HALF(sqSrc, sqDst) && BISHOP_SPAN(sqSrc, sqDst) && + squares[BISHOP_PIN(sqSrc, sqDst)] == 0; + case PIECE_KNIGHT: + int sqPin = KNIGHT_PIN(sqSrc, sqDst); + return sqPin != sqSrc && squares[sqPin] == 0; + case PIECE_ROOK: + case PIECE_CANNON: + int delta; + if (SAME_RANK(sqSrc, sqDst)) { + delta = (sqDst < sqSrc ? -1 : 1); + } else if (SAME_FILE(sqSrc, sqDst)) { + delta = (sqDst < sqSrc ? -16 : 16); + } else { + return false; + } + sqPin = sqSrc + delta; + while (sqPin != sqDst && squares[sqPin] == 0) { + sqPin += delta; + } + if (sqPin == sqDst) { + return pcDst == 0 || pcSrc - pcSelfSide == PIECE_ROOK; + } + if (pcDst == 0 || pcSrc - pcSelfSide == PIECE_ROOK) { + return false; + } + do { + sqPin += delta; + } while (sqPin != sqDst && squares[sqPin] == 0); + return sqPin == sqDst; + case PIECE_PAWN: + if (AWAY_HALF(sqDst, sdPlayer) && (sqDst == sqSrc - 1 || sqDst == sqSrc + 1)) { + return true; + } + return sqDst == SQUARE_FORWARD(sqSrc, sdPlayer); + default: + return false; + } + } + + public boolean checked() { + int pcSelfSide = SIDE_TAG(sdPlayer); + int pcOppSide = OPP_SIDE_TAG(sdPlayer); + for (int sqSrc = 0; sqSrc < 256; sqSrc++) { + if (squares[sqSrc] != pcSelfSide + PIECE_KING) { + continue; + } + if (squares[SQUARE_FORWARD(sqSrc, sdPlayer)] == pcOppSide + PIECE_PAWN) { + return true; + } + for (int delta = -1; delta <= 1; delta += 2) { + if (squares[sqSrc + delta] == pcOppSide + PIECE_PAWN) { + return true; + } + } + for (int i = 0; i < 4; i++) { + if (squares[sqSrc + ADVISOR_DELTA[i]] != 0) { + continue; + } + for (int j = 0; j < 2; j++) { + int pcDst = squares[sqSrc + KNIGHT_CHECK_DELTA[i][j]]; + if (pcDst == pcOppSide + PIECE_KNIGHT) { + return true; + } + } + } + for (int i = 0; i < 4; i++) { + int delta = KING_DELTA[i]; + int sqDst = sqSrc + delta; + while (IN_BOARD(sqDst)) { + int pcDst = squares[sqDst]; + if (pcDst > 0) { + if (pcDst == pcOppSide + PIECE_ROOK || pcDst == pcOppSide + PIECE_KING) { + return true; + } + break; + } + sqDst += delta; + } + sqDst += delta; + while (IN_BOARD(sqDst)) { + int pcDst = squares[sqDst]; + if (pcDst > 0) { + if (pcDst == pcOppSide + PIECE_CANNON) { + return true; + } + break; + } + sqDst += delta; + } + } + return false; + } + return false; + } + + public boolean isMate() { + int[] mvs = new int[MAX_GEN_MOVES]; + int moves = generateAllMoves(mvs); + for (int i = 0; i < moves; i++) { + if (makeMove(mvs[i])) { + undoMakeMove(); + return false; + } + } + return true; + } + + public int mateValue() { + return distance - MATE_VALUE; + } + + public int banValue() { + return distance - BAN_VALUE; + } + + public int drawValue() { + return (distance & 1) == 0 ? -DRAW_VALUE : DRAW_VALUE; + } + + public int evaluate() { + int vl = (sdPlayer == 0 ? vlWhite - vlBlack : vlBlack - vlWhite) + ADVANCED_VALUE; + return vl == drawValue() ? vl - 1 : vl; + } + + public boolean nullOkay() { + return (sdPlayer == 0 ? vlWhite : vlBlack) > NULL_OKAY_MARGIN; + } + + public boolean nullSafe() { + return (sdPlayer == 0 ? vlWhite : vlBlack) > NULL_SAFE_MARGIN; + } + + public boolean inCheck() { + return chkList[moveNum - 1]; + } + + public boolean captured() { + return pcList[moveNum - 1] > 0; + } + + public int repValue(int vlRep) { + int vlReturn = ((vlRep & 2) == 0 ? 0 : banValue()) + ((vlRep & 4) == 0 ? 0 : -banValue()); + return vlReturn == 0 ? drawValue() : vlReturn; + } + + public int repStatus() { + return repStatus(1); + } + + public int repStatus(int recur_) { + int recur = recur_; + boolean selfSide = false; + boolean perpCheck = true; + boolean oppPerpCheck = true; + int index = moveNum - 1; + while (mvList[index] > 0 && pcList[index] == 0) { + if (selfSide) { + perpCheck = perpCheck && chkList[index]; + if (keyList[index] == zobristKey) { + recur--; + if (recur == 0) { + return 1 + (perpCheck ? 2 : 0) + (oppPerpCheck ? 4 : 0); + } + } + } else { + oppPerpCheck = oppPerpCheck && chkList[index]; + } + selfSide = !selfSide; + index--; + } + return 0; + } + + public Position mirror() { + Position pos = new Position(); + pos.clearBoard(); + for (int sq = 0; sq < 256; sq++) { + int pc = squares[sq]; + if (pc > 0) { + pos.addPiece(MIRROR_SQUARE(sq), pc); + } + } + if (sdPlayer == 1) { + pos.changeSide(); + } + return pos; + } + + public int bookMove() { + if (bookSize == 0) { + return 0; + } + boolean mirror = false; + int lock = zobristLock >>> 1; // Convert into Unsigned + int index = Util.binarySearch(lock, bookLock, 0, bookSize); + if (index < 0) { + mirror = true; + lock = mirror().zobristLock >>> 1; // Convert into Unsigned + index = Util.binarySearch(lock, bookLock, 0, bookSize); + } + if (index < 0) { + return 0; + } + do { + index--; + } while (index >= 0 && bookLock[index] == lock); + int[] mvs = new int[MAX_GEN_MOVES]; + int[] vls = new int[MAX_GEN_MOVES]; + int value = 0; + int moves = 0; + index++; + while (index < bookSize && bookLock[index] == lock) { + int mv = 0xffff & bookMove[index]; + mv = (mirror ? MIRROR_MOVE(mv) : mv); + if (legalMove(mv)) { + mvs[moves] = mv; + vls[moves] = bookValue[index]; + value += vls[moves]; + moves++; + if (moves == MAX_GEN_MOVES) { + break; + } + } + index++; + } + if (value == 0) { + return 0; + } + value = Math.abs(random.nextInt()) % value; + for (index = 0; index < moves; index++) { + value -= vls[index]; + if (value < 0) { + break; + } + } + return mvs[index]; + } + + public int historyIndex(int mv) { + return ((squares[SRC(mv)] - 8) << 8) + DST(mv); + } +} \ No newline at end of file diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/api/game/xqwlight/Search.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/api/game/xqwlight/Search.java new file mode 100644 index 000000000..281df679f --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/api/game/xqwlight/Search.java @@ -0,0 +1,456 @@ +/* +Search.java - Source Code for XiangQi Wizard Light, Part II + +XiangQi Wizard Light - a Chinese Chess Program for Java ME +Designed by Morning Yellow, Version: 1.70, Last Modified: Mar. 2013 +Copyright (C) 2004-2013 www.xqbase.com + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +package com.github.tartaricacid.touhoulittlemaid.api.game.xqwlight; + +@SuppressWarnings("all") +public class Search { + private static final int HASH_ALPHA = 1; + private static final int HASH_BETA = 2; + private static final int HASH_PV = 3; + private static final int LIMIT_DEPTH = 64; + private static final int NULL_DEPTH = 2; + private static final int RANDOM_MASK = 7; + private static final int MAX_GEN_MOVES = Position.MAX_GEN_MOVES; + private static final int MATE_VALUE = Position.MATE_VALUE; + private static final int BAN_VALUE = Position.BAN_VALUE; + private static final int WIN_VALUE = Position.WIN_VALUE; + + private int hashMask, mvResult, allNodes, allMillis; + private HashItem[] hashTable; + Position pos; + int[] historyTable = new int[4096]; + int[][] mvKiller = new int[LIMIT_DEPTH][2]; + + public Search(Position pos, int hashLevel) { + this.pos = pos; + hashMask = (1 << hashLevel) - 1; + hashTable = new HashItem[hashMask + 1]; + for (int i = 0; i <= hashMask; i++) { + hashTable[i] = new HashItem(); + } + } + + private HashItem getHashItem() { + return hashTable[pos.zobristKey & hashMask]; + } + + private int probeHash(int vlAlpha, int vlBeta, int depth, int[] mv) { + HashItem hash = getHashItem(); + if (hash.zobristLock != pos.zobristLock) { + mv[0] = 0; + return -MATE_VALUE; + } + mv[0] = hash.mv; + boolean mate = false; + if (hash.vl > WIN_VALUE) { + if (hash.vl <= BAN_VALUE) { + return -MATE_VALUE; + } + hash.vl -= (short) pos.distance; + mate = true; + } else if (hash.vl < -WIN_VALUE) { + if (hash.vl >= -BAN_VALUE) { + return -MATE_VALUE; + } + hash.vl += (short) pos.distance; + mate = true; + } else if (hash.vl == pos.drawValue()) { + return -MATE_VALUE; + } + if (hash.depth >= depth || mate) { + if (hash.flag == HASH_BETA) { + return (hash.vl >= vlBeta ? hash.vl : -MATE_VALUE); + } else if (hash.flag == HASH_ALPHA) { + return (hash.vl <= vlAlpha ? hash.vl : -MATE_VALUE); + } + return hash.vl; + } + return -MATE_VALUE; + } + + private void recordHash(int flag, int vl, int depth, int mv) { + HashItem hash = getHashItem(); + if (hash.depth > depth) { + return; + } + hash.flag = (byte) flag; + hash.depth = (byte) depth; + if (vl > WIN_VALUE) { + if (mv == 0 && vl <= BAN_VALUE) { + return; + } + hash.vl = (short) (vl + pos.distance); + } else if (vl < -WIN_VALUE) { + if (mv == 0 && vl >= -BAN_VALUE) { + return; + } + hash.vl = (short) (vl - pos.distance); + } else if (vl == pos.drawValue() && mv == 0) { + return; + } else { + hash.vl = (short) vl; + } + hash.mv = mv; + hash.zobristLock = pos.zobristLock; + } + + private class SortItem { + private static final int PHASE_HASH = 0; + private static final int PHASE_KILLER_1 = 1; + private static final int PHASE_KILLER_2 = 2; + private static final int PHASE_GEN_MOVES = 3; + private static final int PHASE_REST = 4; + + private int index, moves, phase; + private int mvHash, mvKiller1, mvKiller2; + private int[] mvs, vls; + + boolean singleReply = false; + + SortItem(int mvHash) { + if (!pos.inCheck()) { + phase = PHASE_HASH; + this.mvHash = mvHash; + mvKiller1 = mvKiller[pos.distance][0]; + mvKiller2 = mvKiller[pos.distance][1]; + return; + } + phase = PHASE_REST; + this.mvHash = mvKiller1 = mvKiller2 = 0; + mvs = new int[MAX_GEN_MOVES]; + vls = new int[MAX_GEN_MOVES]; + moves = 0; + int[] mvsAll = new int[MAX_GEN_MOVES]; + int numAll = pos.generateAllMoves(mvsAll); + for (int i = 0; i < numAll; i++) { + int mv = mvsAll[i]; + if (!pos.makeMove(mv)) { + continue; + } + pos.undoMakeMove(); + mvs[moves] = mv; + vls[moves] = mv == mvHash ? Integer.MAX_VALUE : historyTable[pos.historyIndex(mv)]; + moves++; + } + Util.shellSort(mvs, vls, 0, moves); + index = 0; + singleReply = moves == 1; + } + + int next() { + if (phase == PHASE_HASH) { + phase = PHASE_KILLER_1; + if (mvHash > 0) { + return mvHash; + } + } + if (phase == PHASE_KILLER_1) { + phase = PHASE_KILLER_2; + if (mvKiller1 != mvHash && mvKiller1 > 0 && pos.legalMove(mvKiller1)) { + return mvKiller1; + } + } + if (phase == PHASE_KILLER_2) { + phase = PHASE_GEN_MOVES; + if (mvKiller2 != mvHash && mvKiller2 > 0 && pos.legalMove(mvKiller2)) { + return mvKiller2; + } + } + if (phase == PHASE_GEN_MOVES) { + phase = PHASE_REST; + mvs = new int[MAX_GEN_MOVES]; + vls = new int[MAX_GEN_MOVES]; + moves = pos.generateAllMoves(mvs); + for (int i = 0; i < moves; i++) { + vls[i] = historyTable[pos.historyIndex(mvs[i])]; + } + Util.shellSort(mvs, vls, 0, moves); + index = 0; + } + while (index < moves) { + int mv = mvs[index]; + index++; + if (mv != mvHash && mv != mvKiller1 && mv != mvKiller2) { + return mv; + } + } + return 0; + } + } + + private void setBestMove(int mv, int depth) { + historyTable[pos.historyIndex(mv)] += depth * depth; + int[] killers = mvKiller[pos.distance]; + if (killers[0] != mv) { + killers[1] = killers[0]; + killers[0] = mv; + } + } + + private int searchQuiesc(int vlAlpha_, int vlBeta) { + int vlAlpha = vlAlpha_; + allNodes++; + int vl = pos.mateValue(); + if (vl >= vlBeta) { + return vl; + } + int vlRep = pos.repStatus(); + if (vlRep > 0) { + return pos.repValue(vlRep); + } + if (pos.distance == LIMIT_DEPTH) { + return pos.evaluate(); + } + int vlBest = -MATE_VALUE; + int genMoves; + int[] mvs = new int[MAX_GEN_MOVES]; + if (pos.inCheck()) { + genMoves = pos.generateAllMoves(mvs); + int[] vls = new int[MAX_GEN_MOVES]; + for (int i = 0; i < genMoves; i++) { + vls[i] = historyTable[pos.historyIndex(mvs[i])]; + } + Util.shellSort(mvs, vls, 0, genMoves); + } else { + vl = pos.evaluate(); + if (vl > vlBest) { + if (vl >= vlBeta) { + return vl; + } + vlBest = vl; + vlAlpha = Math.max(vl, vlAlpha); + } + int[] vls = new int[MAX_GEN_MOVES]; + genMoves = pos.generateMoves(mvs, vls); + Util.shellSort(mvs, vls, 0, genMoves); + for (int i = 0; i < genMoves; i++) { + if (vls[i] < 10 || (vls[i] < 20 && Position.HOME_HALF(Position.DST(mvs[i]), pos.sdPlayer))) { + genMoves = i; + break; + } + } + } + for (int i = 0; i < genMoves; i++) { + if (!pos.makeMove(mvs[i])) { + continue; + } + vl = -searchQuiesc(-vlBeta, -vlAlpha); + pos.undoMakeMove(); + if (vl > vlBest) { + if (vl >= vlBeta) { + return vl; + } + vlBest = vl; + vlAlpha = Math.max(vl, vlAlpha); + } + } + return vlBest == -MATE_VALUE ? pos.mateValue() : vlBest; + } + + private int searchNoNull(int vlAlpha, int vlBeta, int depth) { + return searchFull(vlAlpha, vlBeta, depth, true); + } + + private int searchFull(int vlAlpha, int vlBeta, int depth) { + return searchFull(vlAlpha, vlBeta, depth, false); + } + + private int searchFull(int vlAlpha_, int vlBeta, int depth, boolean noNull) { + int vlAlpha = vlAlpha_; + int vl; + if (depth <= 0) { + return searchQuiesc(vlAlpha, vlBeta); + } + allNodes++; + vl = pos.mateValue(); + if (vl >= vlBeta) { + return vl; + } + int vlRep = pos.repStatus(); + if (vlRep > 0) { + return pos.repValue(vlRep); + } + int[] mvHash = new int[1]; + vl = probeHash(vlAlpha, vlBeta, depth, mvHash); + if (vl > -MATE_VALUE) { + return vl; + } + if (pos.distance == LIMIT_DEPTH) { + return pos.evaluate(); + } + if (!noNull && !pos.inCheck() && pos.nullOkay()) { + pos.nullMove(); + vl = -searchNoNull(-vlBeta, 1 - vlBeta, depth - NULL_DEPTH - 1); + pos.undoNullMove(); + if (vl >= vlBeta && (pos.nullSafe() || searchNoNull(vlAlpha, vlBeta, depth - NULL_DEPTH) >= vlBeta)) { + return vl; + } + } + int hashFlag = HASH_ALPHA; + int vlBest = -MATE_VALUE; + int mvBest = 0; + SortItem sort = new SortItem(mvHash[0]); + int mv; + while ((mv = sort.next()) > 0) { + if (!pos.makeMove(mv)) { + continue; + } + int newDepth = pos.inCheck() || sort.singleReply ? depth : depth - 1; + if (vlBest == -MATE_VALUE) { + vl = -searchFull(-vlBeta, -vlAlpha, newDepth); + } else { + vl = -searchFull(-vlAlpha - 1, -vlAlpha, newDepth); + if (vl > vlAlpha && vl < vlBeta) { + vl = -searchFull(-vlBeta, -vlAlpha, newDepth); + } + } + pos.undoMakeMove(); + if (vl > vlBest) { + vlBest = vl; + if (vl >= vlBeta) { + hashFlag = HASH_BETA; + mvBest = mv; + break; + } + if (vl > vlAlpha) { + vlAlpha = vl; + hashFlag = HASH_PV; + mvBest = mv; + } + } + } + if (vlBest == -MATE_VALUE) { + return pos.mateValue(); + } + recordHash(hashFlag, vlBest, depth, mvBest); + if (mvBest > 0) { + setBestMove(mvBest, depth); + } + return vlBest; + } + + private int searchRoot(int depth) { + int vlBest = -MATE_VALUE; + SortItem sort = new SortItem(mvResult); + int mv; + while ((mv = sort.next()) > 0) { + if (!pos.makeMove(mv)) { + continue; + } + int newDepth = pos.inCheck() ? depth : depth - 1; + int vl; + if (vlBest == -MATE_VALUE) { + vl = -searchNoNull(-MATE_VALUE, MATE_VALUE, newDepth); + } else { + vl = -searchFull(-vlBest - 1, -vlBest, newDepth); + if (vl > vlBest) { + vl = -searchNoNull(-MATE_VALUE, -vlBest, newDepth); + } + } + pos.undoMakeMove(); + if (vl > vlBest) { + vlBest = vl; + mvResult = mv; + if (vlBest > -WIN_VALUE && vlBest < WIN_VALUE) { + vlBest += (Position.random.nextInt() & RANDOM_MASK) - + (Position.random.nextInt() & RANDOM_MASK); + vlBest = (vlBest == pos.drawValue() ? vlBest - 1 : vlBest); + } + } + } + setBestMove(mvResult, depth); + return vlBest; + } + + public boolean searchUnique(int vlBeta, int depth) { + SortItem sort = new SortItem(mvResult); + sort.next(); + int mv; + while ((mv = sort.next()) > 0) { + if (!pos.makeMove(mv)) { + continue; + } + int vl = -searchFull(-vlBeta, 1 - vlBeta, pos.inCheck() ? depth : depth - 1); + pos.undoMakeMove(); + if (vl >= vlBeta) { + return false; + } + } + return true; + } + + public int searchMain(int millis) { + return searchMain(LIMIT_DEPTH, millis); + } + + public int searchMain(int depth, int millis) { + mvResult = pos.bookMove(); + if (mvResult > 0) { + pos.makeMove(mvResult); + if (pos.repStatus(3) == 0) { + pos.undoMakeMove(); + return mvResult; + } + pos.undoMakeMove(); + } + for (int i = 0; i <= hashMask; i++) { + HashItem hash = hashTable[i]; + hash.depth = hash.flag = 0; + hash.vl = 0; + hash.mv = hash.zobristLock = 0; + } + for (int i = 0; i < LIMIT_DEPTH; i++) { + mvKiller[i][0] = mvKiller[i][1] = 0; + } + for (int i = 0; i < 4096; i++) { + historyTable[i] = 0; + } + mvResult = 0; + allNodes = 0; + pos.distance = 0; + long t = System.currentTimeMillis(); + for (int i = 1; i <= depth; i++) { + int vl = searchRoot(i); + allMillis = (int) (System.currentTimeMillis() - t); + if (allMillis > millis) { + break; + } + if (vl > WIN_VALUE || vl < -WIN_VALUE) { + break; + } + if (searchUnique(1 - WIN_VALUE, i)) { + break; + } + } + return mvResult; + } + + public int getKNPS() { + return allNodes / allMillis; + } + + static class HashItem { + byte depth, flag; + short vl; + int mv, zobristLock; + } +} \ No newline at end of file diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/api/game/xqwlight/Util.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/api/game/xqwlight/Util.java new file mode 100644 index 000000000..f79923ac6 --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/api/game/xqwlight/Util.java @@ -0,0 +1,129 @@ +package com.github.tartaricacid.touhoulittlemaid.api.game.xqwlight; + +import java.io.IOException; +import java.io.InputStream; + +@SuppressWarnings("all") +public class Util { + public static int MIN_MAX(int min, int mid, int max) { + return mid < min ? min : Math.min(mid, max); + } + + private static byte[] POP_COUNT_16 = new byte[65536]; + + static { + for (int i = 0; i < 65536; i++) { + int n = ((i >> 1) & 0x5555) + (i & 0x5555); + n = ((n >> 2) & 0x3333) + (n & 0x3333); + n = ((n >> 4) & 0x0f0f) + (n & 0x0f0f); + POP_COUNT_16[i] = (byte) ((n >> 8) + (n & 0x00ff)); + } + } + + public static int POP_COUNT_16(int data) { + return POP_COUNT_16[data]; + } + + public static int readShort(InputStream in) throws IOException { + int b0 = in.read(); + int b1 = in.read(); + if (b0 == -1 || b1 == -1) { + throw new IOException(); + } + return b0 | (b1 << 8); + } + + public static int readInt(InputStream in) throws IOException { + int b0 = in.read(); + int b1 = in.read(); + int b2 = in.read(); + int b3 = in.read(); + if (b0 == -1 || b1 == -1 || b2 == -1 || b3 == -1) { + throw new IOException(); + } + return b0 | (b1 << 8) | (b2 << 16) | (b3 << 24); + } + + public static class RC4 { + public int[] state = new int[256]; + public int x, y; + + public void swap(int i, int j) { + int t = state[i]; + state[i] = state[j]; + state[j] = t; + } + + public RC4(byte[] key) { + x = 0; + y = 0; + for (int i = 0; i < 256; i++) { + state[i] = i; + } + int j = 0; + for (int i = 0; i < 256; i++) { + j = (j + state[i] + key[i % key.length]) & 0xff; + swap(i, j); + } + } + + public int nextByte() { + x = (x + 1) & 0xff; + y = (y + state[x]) & 0xff; + swap(x, y); + int t = (state[x] + state[y]) & 0xff; + return state[t]; + } + + public int nextLong() { + int n0, n1, n2, n3; + n0 = nextByte(); + n1 = nextByte(); + n2 = nextByte(); + n3 = nextByte(); + return n0 + (n1 << 8) + (n2 << 16) + (n3 << 24); + } + } + + public static int binarySearch(int vl, int[] vls, int from, int to) { + int low = from; + int high = to - 1; + while (low <= high) { + int mid = (low + high) / 2; + if (vls[mid] < vl) { + low = mid + 1; + } else if (vls[mid] > vl) { + high = mid - 1; + } else { + return mid; + } + } + return -1; + } + + private static final int[] SHELL_STEP = {0, 1, 4, 13, 40, 121, 364, 1093}; + + public static void shellSort(int[] mvs, int[] vls, int from, int to) { + int stepLevel = 1; + while (SHELL_STEP[stepLevel] < to - from) { + stepLevel++; + } + stepLevel--; + while (stepLevel > 0) { + int step = SHELL_STEP[stepLevel]; + for (int i = from + step; i < to; i++) { + int mvBest = mvs[i]; + int vlBest = vls[i]; + int j = i - step; + while (j >= from && vlBest > vls[j]) { + mvs[j + step] = mvs[j]; + vls[j + step] = vls[j]; + j -= step; + } + mvs[j + step] = mvBest; + vls[j + step] = vlBest; + } + stepLevel--; + } + } +} \ No newline at end of file diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/block/BlockAltar.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/block/BlockAltar.java index a1ffbaf05..0a04a09db 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/block/BlockAltar.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/block/BlockAltar.java @@ -5,6 +5,7 @@ import com.github.tartaricacid.touhoulittlemaid.init.InitDataAttachment; import com.github.tartaricacid.touhoulittlemaid.init.InitRecipes; import com.github.tartaricacid.touhoulittlemaid.init.InitSounds; +import com.github.tartaricacid.touhoulittlemaid.init.InitTrigger; import com.github.tartaricacid.touhoulittlemaid.tileentity.TileEntityAltar; import com.github.tartaricacid.touhoulittlemaid.util.PosListData; import net.minecraft.client.Minecraft; @@ -15,7 +16,9 @@ import net.minecraft.core.Direction; import net.minecraft.core.particles.ParticleTypes; import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.sounds.SoundSource; import net.minecraft.world.InteractionHand; import net.minecraft.world.ItemInteractionResult; @@ -239,7 +242,7 @@ private void altarCraft(Level world, TileEntityAltar altar, Player playerIn) { CraftingInput craftingInput = CraftingInput.of(6, 1, arrayList); PowerAttachment powerAttachment = playerIn.getData(InitDataAttachment.POWER_NUM); world.getRecipeManager().getRecipeFor(InitRecipes.ALTAR_CRAFTING.get(), craftingInput, world) - .ifPresent(recipe -> spawnResultEntity(world, playerIn, powerAttachment, recipe.value(), arrayList, altar)); + .ifPresent(recipe -> spawnResultEntity(world, playerIn, powerAttachment, recipe.id(), recipe.value(), arrayList, altar)); } private Optional getAltar(BlockGetter world, BlockPos pos) { @@ -250,7 +253,7 @@ private Optional getAltar(BlockGetter world, BlockPos pos) { return Optional.empty(); } - private void spawnResultEntity(Level world, Player playerIn, PowerAttachment power, + private void spawnResultEntity(Level world, Player playerIn, PowerAttachment power, ResourceLocation altarId, AltarRecipe altarRecipe, List inventory, TileEntityAltar altar) { if (power.get() >= altarRecipe.getPower()) { power.min(altarRecipe.getPower()); @@ -262,6 +265,9 @@ private void spawnResultEntity(Level world, Player playerIn, PowerAttachment pow removeAllAltarItem(world, altar); spawnParticleInCentre(world, centrePos); world.playSound(null, centrePos, InitSounds.ALTAR_CRAFT.get(), SoundSource.VOICE, 1.0f, 1.0f); + if (playerIn instanceof ServerPlayer serverPlayer) { + InitTrigger.ALTAR_CRAFT.get().trigger(serverPlayer, altarId); + } } else { if (!world.isClientSide) { playerIn.sendSystemMessage(Component.translatable("message.touhou_little_maid.altar.not_enough_power")); diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/block/BlockCChess.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/block/BlockCChess.java new file mode 100644 index 000000000..e3da075b7 --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/block/BlockCChess.java @@ -0,0 +1,349 @@ +package com.github.tartaricacid.touhoulittlemaid.block; + +import com.github.tartaricacid.touhoulittlemaid.advancements.maid.TriggerType; +import com.github.tartaricacid.touhoulittlemaid.api.block.IBoardGameBlock; +import com.github.tartaricacid.touhoulittlemaid.api.game.xqwlight.Position; +import com.github.tartaricacid.touhoulittlemaid.block.properties.GomokuPart; +import com.github.tartaricacid.touhoulittlemaid.config.subconfig.MaidConfig; +import com.github.tartaricacid.touhoulittlemaid.entity.favorability.Type; +import com.github.tartaricacid.touhoulittlemaid.entity.item.EntitySit; +import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid; +import com.github.tartaricacid.touhoulittlemaid.init.InitItems; +import com.github.tartaricacid.touhoulittlemaid.init.InitSounds; +import com.github.tartaricacid.touhoulittlemaid.init.InitTrigger; +import com.github.tartaricacid.touhoulittlemaid.network.message.CChessToClientPackage; +import com.github.tartaricacid.touhoulittlemaid.tileentity.TileEntityCChess; +import com.github.tartaricacid.touhoulittlemaid.tileentity.TileEntityJoy; +import com.github.tartaricacid.touhoulittlemaid.util.CChessUtil; +import com.mojang.serialization.MapCodec; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Vec3i; +import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +import net.minecraft.util.Mth; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.ItemInteractionResult; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Explosion; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.BaseEntityBlock; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.SoundType; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockBehaviour; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.StateDefinition; +import net.minecraft.world.level.block.state.properties.EnumProperty; +import net.minecraft.world.level.material.MapColor; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.Vec3; +import net.minecraft.world.phys.shapes.CollisionContext; +import net.minecraft.world.phys.shapes.VoxelShape; +import net.neoforged.neoforge.network.PacketDistributor; +import org.jetbrains.annotations.Nullable; + +import java.util.UUID; + +public class BlockCChess extends BlockJoy implements IBoardGameBlock { + public static final EnumProperty PART = EnumProperty.create("part", GomokuPart.class); + public static final VoxelShape AABB = Block.box(0, 0, 0, 16, 2, 16); + + public BlockCChess() { + super(BlockBehaviour.Properties.of().mapColor(MapColor.WOOD).sound(SoundType.WOOD).strength(2.0F, 3.0F).noOcclusion()); + this.registerDefaultState(this.stateDefinition.any().setValue(PART, GomokuPart.CENTER).setValue(FACING, Direction.NORTH)); + } + + private static void handleCChessRemove(Level world, BlockPos pos, BlockState state) { + if (!world.isClientSide) { + GomokuPart part = state.getValue(PART); + BlockPos centerPos = pos.subtract(new Vec3i(part.getPosX(), 0, part.getPosY())); + BlockEntity te = world.getBlockEntity(centerPos); + popResource(world, centerPos, InitItems.CCHESS.get().getDefaultInstance()); + if (te instanceof TileEntityCChess) { + for (int i = -1; i < 2; i++) { + for (int j = -1; j < 2; j++) { + world.setBlockAndUpdate(centerPos.offset(i, 0, j), Blocks.AIR.defaultBlockState()); + } + } + } + } + } + + public static void maidMove(ServerPlayer player, Level level, BlockPos pos, int move, boolean maidLost, boolean playerLost) { + if (level.getBlockEntity(pos) instanceof TileEntityCChess chess) { + if (chess.isPlayerTurn()) { + return; + } + + Position chessData = chess.getChessData(); + UUID sitId = chess.getSitId(); + // 女仆输,以防作弊,再检查一次 + if (maidLost && CChessUtil.isMaid(chessData) && chessData.isMate()) { + chess.setCheckmate(true); + chess.refresh(); + + if (level instanceof ServerLevel serverLevel && serverLevel.getEntity(sitId) instanceof EntitySit sit + && sit.getFirstPassenger() instanceof EntityMaid maid && maid.isOwnedBy(player)) { + // TODO: 暂时不加段位系统 + maid.getFavorabilityManager().apply(Type.CCHESS_WIN); + InitTrigger.MAID_EVENT.get().trigger(player, TriggerType.WIN_CCHESS); + } + + return; + } + + boolean notChecked = chessData.makeMove(move); + // 如果吃子了,那么重置计数器(该计数器用于判断自然限着和长将) + if (notChecked && chessData.captured()) { + chessData.setIrrev(); + } + chess.setSelectChessPoint(Position.DST(move)); + chess.setCheckmate(playerLost); + + // 如果玩家没输,那么检查其他和局情况 + if (!playerLost) { + if (CChessUtil.reachMoveLimit(chessData)) { + // 判断是否六十回自然限着 + chess.setMoveNumberLimit(true); + } else if (CChessUtil.isRepeat(chessData)) { + // 判断是否长打 + chess.setRepeat(true); + } + } + + if (level instanceof ServerLevel serverLevel && serverLevel.getEntity(sitId) instanceof EntitySit sit && sit.getFirstPassenger() instanceof EntityMaid maid) { + maid.swing(InteractionHand.MAIN_HAND); + } + level.playSound(null, pos, InitSounds.GOMOKU.get(), SoundSource.BLOCKS, 1.0f, 0.8F + level.random.nextFloat() * 0.4F); + chess.refresh(); + } + } + + @Override + public void startMaidSit(EntityMaid maid, BlockState state, Level worldIn, BlockPos pos) { + if (worldIn instanceof ServerLevel serverLevel && worldIn.getBlockEntity(pos) instanceof TileEntityJoy joy) { + Entity oldSitEntity = serverLevel.getEntity(joy.getSitId()); + if (oldSitEntity != null && oldSitEntity.isAlive()) { + return; + } + Direction face = state.getValue(FACING).getOpposite(); + Vec3 position = new Vec3(0.5 + face.getStepX() * 2, 0.1, 0.5 + face.getStepZ() * 2); + EntitySit newSitEntity = new EntitySit(worldIn, Vec3.atLowerCornerWithOffset(pos, position.x, position.y, position.z), this.getTypeName(), pos); + newSitEntity.setYRot(face.getOpposite().toYRot() + this.sitYRot()); + worldIn.addFreshEntity(newSitEntity); + joy.setSitId(newSitEntity.getUUID()); + joy.setChanged(); + maid.startRiding(newSitEntity); + } + } + + @Override + public BlockState playerWillDestroy(Level world, BlockPos pos, BlockState state, Player player) { + handleCChessRemove(world, pos, state); + return super.playerWillDestroy(world, pos, state, player); + } + + @Override + public void onBlockExploded(BlockState state, Level world, BlockPos pos, Explosion explosion) { + handleCChessRemove(world, pos, state); + super.onBlockExploded(state, world, pos, explosion); + } + + @Nullable + @Override + public BlockState getStateForPlacement(BlockPlaceContext context) { + BlockPos centerPos = context.getClickedPos(); + for (int i = -1; i < 2; i++) { + for (int j = -1; j < 2; j++) { + BlockPos searchPos = centerPos.offset(i, 0, j); + if (!context.getLevel().getBlockState(searchPos).canBeReplaced(context)) { + return null; + } + } + } + return this.defaultBlockState().setValue(FACING, context.getHorizontalDirection().getOpposite()); + } + + @Override + public void setPlacedBy(Level worldIn, BlockPos pos, BlockState state, @javax.annotation.Nullable LivingEntity placer, ItemStack stack) { + super.setPlacedBy(worldIn, pos, state, placer, stack); + if (worldIn.isClientSide) { + return; + } + for (int i = -1; i < 2; i++) { + for (int j = -1; j < 2; j++) { + BlockPos searchPos = pos.offset(i, 0, j); + GomokuPart part = GomokuPart.getPartByPos(i, j); + if (part != null && !part.isCenter()) { + worldIn.setBlock(searchPos, state.setValue(PART, part), Block.UPDATE_ALL); + } + } + } + } + + @Override + public ItemInteractionResult useItemOn(ItemStack itemStack, BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) { + if (level instanceof ServerLevel serverLevel && hand == InteractionHand.MAIN_HAND && player.getMainHandItem().isEmpty()) { + GomokuPart part = state.getValue(PART); + BlockPos centerPos = pos.subtract(new Vec3i(part.getPosX(), 0, part.getPosY())); + BlockEntity te = level.getBlockEntity(centerPos); + + if (!(te instanceof TileEntityCChess chess)) { + return ItemInteractionResult.FAIL; + } + if (!chess.isPlayerTurn() && !chess.isCheckmate()) { + return ItemInteractionResult.FAIL; + } + + // 检查女仆 + Entity sitEntity = serverLevel.getEntity(chess.getSitId()); + if (sitEntity == null || !sitEntity.isAlive() || !(sitEntity.getFirstPassenger() instanceof EntityMaid maid)) { + player.sendSystemMessage(Component.translatable("message.touhou_little_maid.gomoku.no_maid")); + return ItemInteractionResult.FAIL; + } + // 检查是不是自己的女仆 + if (MaidConfig.MAID_GOMOKU_OWNER_LIMIT.get() && !maid.isOwnedBy(player)) { + player.sendSystemMessage(Component.translatable("message.touhou_little_maid.gomoku.not_owner")); + return ItemInteractionResult.FAIL; + } + + // 点击坐标的转换 + Direction facing = state.getValue(FACING); + Vec3 clickPos = hit.getLocation() + .subtract(pos.getX(), pos.getY(), pos.getZ()) + .add(part.getPosX() - 0.5, 0, part.getPosY() - 0.5) + .yRot(facing.toYRot() * Mth.DEG_TO_RAD); + + // 重置棋盘 + boolean clickResetArea = CChessUtil.isClickResetArea(clickPos); + if (clickResetArea) { + chess.reset(); + chess.refresh(); + level.playSound(null, centerPos, InitSounds.GOMOKU_RESET.get(), SoundSource.BLOCKS, 1.0f, 1.0f); + } + + // 没有点击到棋盘上,返回 + int nowClick = CChessUtil.getClickPosition(clickPos); + if (nowClick < 0 || !Position.IN_BOARD(nowClick)) { + return ItemInteractionResult.SKIP_DEFAULT_BLOCK_INTERACTION; + } + + // 玩家已经输了,不能下棋 + if (chess.isCheckmate() && chess.isPlayerTurn()) { + return ItemInteractionResult.FAIL; + } + + // 60 回合自然限着、长将不能下棋 + if (chess.isMoveNumberLimit() || chess.isRepeat()) { + return ItemInteractionResult.FAIL; + } + + // 处理点击棋子的逻辑 + Position chessData = chess.getChessData(); + byte[] squares = chessData.squares; + int preClick = chess.getSelectChessPoint(); + if (preClick < 0 || squares.length <= preClick) { + preClick = 0; + } + byte prePiece = squares[preClick]; + byte nowPiece = squares[nowClick]; + + // 如果前一个选择为空,或者选中的是黑方,说明没有选中棋子 + if (prePiece <= 0 || CChessUtil.isBlack(prePiece)) { + // 当前点击的是红方棋子 + if (CChessUtil.isRed(nowPiece)) { + chess.setSelectChessPoint(nowClick); + chess.refresh(); + level.playSound(null, pos, InitSounds.GOMOKU.get(), SoundSource.BLOCKS, 1.0f, 0.8F + level.random.nextFloat() * 0.4F); + } + return ItemInteractionResult.SUCCESS; + } + + // 如果选的都是红方棋子,重选 + if (CChessUtil.isRed(prePiece) && CChessUtil.isRed(nowPiece)) { + chess.setSelectChessPoint(nowClick); + chess.refresh(); + level.playSound(null, pos, InitSounds.GOMOKU.get(), SoundSource.BLOCKS, 1.0f, 0.8F + level.random.nextFloat() * 0.4F); + return ItemInteractionResult.SUCCESS; + } + + // 判断移动是否合法 + int move = Position.MOVE(preClick, nowClick); + if (!chessData.legalMove(move)) { + return ItemInteractionResult.FAIL; + } + + // 没有将军,正常移动 + boolean notChecked = chessData.makeMove(move); + if (notChecked) { + // 如果吃子了,那么重置计数器(该计数器用于判断自然限着和长将) + if (chessData.captured()) { + chessData.setIrrev(); + } + chess.addChessCounter(); + chess.setSelectChessPoint(nowClick); + chess.refresh(); + level.playSound(null, pos, InitSounds.GOMOKU.get(), SoundSource.BLOCKS, 1.0f, 0.8F + level.random.nextFloat() * 0.4F); + if (player instanceof ServerPlayer serverPlayer) { + PacketDistributor.sendToPlayer(serverPlayer, new CChessToClientPackage(centerPos, chessData.toFen())); + } + return ItemInteractionResult.SUCCESS; + } + + // 如果将军,那么给予提示 + player.sendSystemMessage(Component.translatable("message.touhou_little_maid.cchess.check")); + level.playSound(null, pos, SoundEvents.NOTE_BLOCK_BELL.value(), SoundSource.BLOCKS, 1.0f, 0.8F + level.random.nextFloat() * 0.4F); + return ItemInteractionResult.FAIL; + } + return ItemInteractionResult.SKIP_DEFAULT_BLOCK_INTERACTION; + } + + @Override + protected Vec3 sitPosition() { + return Vec3.ZERO; + } + + @Override + protected String getTypeName() { + return Type.GOMOKU.getTypeName(); + } + + @Override + protected int sitYRot() { + return 0; + } + + @Override + protected void createBlockStateDefinition(StateDefinition.Builder builder) { + builder.add(PART, FACING); + } + + @Nullable + @Override + public BlockEntity newBlockEntity(BlockPos pos, BlockState state) { + if (state.getValue(PART).isCenter()) { + return new TileEntityCChess(pos, state); + } + return null; + } + + @Override + protected MapCodec codec() { + return simpleCodec((properties) -> new BlockCChess()); + } + + @Override + public VoxelShape getShape(BlockState pState, BlockGetter pLevel, BlockPos pPos, CollisionContext pContext) { + return AABB; + } +} diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/block/BlockGomoku.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/block/BlockGomoku.java index 5425c5811..2678d1b2e 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/block/BlockGomoku.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/block/BlockGomoku.java @@ -1,5 +1,7 @@ package com.github.tartaricacid.touhoulittlemaid.block; +import com.github.tartaricacid.touhoulittlemaid.advancements.maid.TriggerType; +import com.github.tartaricacid.touhoulittlemaid.api.block.IBoardGameBlock; import com.github.tartaricacid.touhoulittlemaid.api.game.gomoku.Point; import com.github.tartaricacid.touhoulittlemaid.api.game.gomoku.Statue; import com.github.tartaricacid.touhoulittlemaid.block.properties.GomokuPart; @@ -10,7 +12,8 @@ import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid; import com.github.tartaricacid.touhoulittlemaid.init.InitItems; import com.github.tartaricacid.touhoulittlemaid.init.InitSounds; -import com.github.tartaricacid.touhoulittlemaid.network.message.ChessDataClientPackage; +import com.github.tartaricacid.touhoulittlemaid.init.InitTrigger; +import com.github.tartaricacid.touhoulittlemaid.network.message.GomokuClientPackage; import com.github.tartaricacid.touhoulittlemaid.network.message.SpawnParticlePackage; import com.github.tartaricacid.touhoulittlemaid.tileentity.TileEntityGomoku; import com.github.tartaricacid.touhoulittlemaid.tileentity.TileEntityJoy; @@ -50,7 +53,7 @@ import javax.annotation.Nullable; -public class BlockGomoku extends BlockJoy { +public class BlockGomoku extends BlockJoy implements IBoardGameBlock { public static final EnumProperty PART = EnumProperty.create("part", GomokuPart.class); public static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING; public static final VoxelShape LEFT_UP = Block.box(8, 0, 8, 16, 2, 16); @@ -272,12 +275,15 @@ public ItemInteractionResult useItemOn(ItemStack itemStack, BlockState state, Le PacketDistributor.sendToPlayer(serverPlayer, new SpawnParticlePackage(maid.getId(), SpawnParticlePackage.Type.RANK_UP)); } } + if (player instanceof ServerPlayer serverPlayer) { + InitTrigger.MAID_EVENT.get().trigger(serverPlayer, TriggerType.WIN_GOMOKU); + } } gomoku.setInProgress(statue == Statue.IN_PROGRESS); level.playSound(null, pos, InitSounds.GOMOKU.get(), SoundSource.BLOCKS, 1.0f, 0.8F + level.random.nextFloat() * 0.4F); if (gomoku.isInProgress() && player instanceof ServerPlayer serverPlayer) { gomoku.setPlayerTurn(false); - PacketDistributor.sendToPlayer(serverPlayer, new ChessDataClientPackage(centerPos, chessData, playerPoint, MaidGomokuAI.getMaidCount(maid))); + PacketDistributor.sendToPlayer(serverPlayer, new GomokuClientPackage(centerPos, chessData, playerPoint, MaidGomokuAI.getMaidCount(maid))); } gomoku.refresh(); return ItemInteractionResult.SUCCESS; diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/block/BlockShrine.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/block/BlockShrine.java index 7e7469e91..fe2df8fd3 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/block/BlockShrine.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/block/BlockShrine.java @@ -1,11 +1,14 @@ package com.github.tartaricacid.touhoulittlemaid.block; +import com.github.tartaricacid.touhoulittlemaid.advancements.maid.TriggerType; +import com.github.tartaricacid.touhoulittlemaid.init.InitTrigger; import com.github.tartaricacid.touhoulittlemaid.item.ItemFilm; import com.github.tartaricacid.touhoulittlemaid.tileentity.TileEntityShrine; import com.mojang.serialization.MapCodec; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.InteractionHand; import net.minecraft.world.ItemInteractionResult; import net.minecraft.world.entity.player.Player; @@ -79,6 +82,9 @@ public ItemInteractionResult useItemOn(ItemStack itemStack, BlockState state, Le playerIn.setHealth(0.25f); ItemStack film = shrine.getStorageItem(); ItemFilm.filmToMaid(film, worldIn, pos.above(), playerIn); + if (playerIn instanceof ServerPlayer serverPlayer) { + InitTrigger.MAID_EVENT.get().trigger(serverPlayer, TriggerType.SHRINE_REBORN_MAID); + } } } return super.useItemOn(itemStack, state, worldIn, pos, playerIn, hand, hit); diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/block/BlockWChess.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/block/BlockWChess.java new file mode 100644 index 000000000..8bf133c1c --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/block/BlockWChess.java @@ -0,0 +1,353 @@ +package com.github.tartaricacid.touhoulittlemaid.block; + +import com.github.tartaricacid.touhoulittlemaid.advancements.maid.TriggerType; +import com.github.tartaricacid.touhoulittlemaid.api.block.IBoardGameBlock; +import com.github.tartaricacid.touhoulittlemaid.api.game.chess.Position; +import com.github.tartaricacid.touhoulittlemaid.block.properties.GomokuPart; +import com.github.tartaricacid.touhoulittlemaid.config.subconfig.MaidConfig; +import com.github.tartaricacid.touhoulittlemaid.entity.favorability.Type; +import com.github.tartaricacid.touhoulittlemaid.entity.item.EntitySit; +import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid; +import com.github.tartaricacid.touhoulittlemaid.init.InitItems; +import com.github.tartaricacid.touhoulittlemaid.init.InitSounds; +import com.github.tartaricacid.touhoulittlemaid.init.InitTrigger; +import com.github.tartaricacid.touhoulittlemaid.network.message.WChessToClientPackage; +import com.github.tartaricacid.touhoulittlemaid.tileentity.TileEntityJoy; +import com.github.tartaricacid.touhoulittlemaid.tileentity.TileEntityWChess; +import com.github.tartaricacid.touhoulittlemaid.util.WChessUtil; +import com.mojang.serialization.MapCodec; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Vec3i; +import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +import net.minecraft.util.Mth; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.ItemInteractionResult; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Explosion; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.BaseEntityBlock; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.SoundType; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockBehaviour; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.StateDefinition; +import net.minecraft.world.level.block.state.properties.EnumProperty; +import net.minecraft.world.level.material.MapColor; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.Vec3; +import net.minecraft.world.phys.shapes.CollisionContext; +import net.minecraft.world.phys.shapes.VoxelShape; +import net.neoforged.neoforge.network.PacketDistributor; +import org.jetbrains.annotations.Nullable; + +import java.util.UUID; + +public class BlockWChess extends BlockJoy implements IBoardGameBlock { + public static final EnumProperty PART = EnumProperty.create("part", GomokuPart.class); + public static final VoxelShape AABB = Block.box(0, 0, 0, 16, 2, 16); + + public BlockWChess() { + super(BlockBehaviour.Properties.of().mapColor(MapColor.WOOD).sound(SoundType.WOOD).strength(2.0F, 3.0F).noOcclusion()); + this.registerDefaultState(this.stateDefinition.any().setValue(PART, GomokuPart.CENTER).setValue(FACING, Direction.NORTH)); + } + + private static void handleWChessRemove(Level world, BlockPos pos, BlockState state) { + if (!world.isClientSide) { + GomokuPart part = state.getValue(PART); + BlockPos centerPos = pos.subtract(new Vec3i(part.getPosX(), 0, part.getPosY())); + BlockEntity te = world.getBlockEntity(centerPos); + popResource(world, centerPos, InitItems.WCHESS.get().getDefaultInstance()); + if (te instanceof TileEntityWChess) { + for (int i = -1; i < 2; i++) { + for (int j = -1; j < 2; j++) { + world.setBlockAndUpdate(centerPos.offset(i, 0, j), Blocks.AIR.defaultBlockState()); + } + } + } + } + } + + + public static void maidMove(ServerPlayer player, Level level, BlockPos pos, int move, boolean maidLost, boolean playerLost) { + if (level.getBlockEntity(pos) instanceof TileEntityWChess chess) { + if (chess.isPlayerTurn()) { + return; + } + + Position chessData = chess.getChessData(); + UUID sitId = chess.getSitId(); + // 女仆输,以防作弊,再检查一次 + if (maidLost && WChessUtil.isMaid(chessData) && chessData.isMate()) { + chess.setCheckmate(true); + chess.refresh(); + + if (level instanceof ServerLevel serverLevel && serverLevel.getEntity(sitId) instanceof EntitySit sit + && sit.getFirstPassenger() instanceof EntityMaid maid && maid.isOwnedBy(player)) { + // TODO: 暂时不加段位系统 + maid.getFavorabilityManager().apply(Type.WCHESS_WIN); + InitTrigger.MAID_EVENT.get().trigger(player, TriggerType.WIN_WCHESS); + } + + return; + } + + // 如果吃子/移兵了,那么重置计数器(该计数器用于判断限着和长将) + if (chessData.makeMove(move)) { + int pcSrc = chessData.squares[Position.SRC(move)]; + if (chessData.captured() || Position.PIECE_TYPE(pcSrc) == Position.PIECE_PAWN) { + chessData.setIrrev(); + } + } + chess.setSelectChessPoint(Position.DST(move)); + chess.setCheckmate(playerLost); + + // 如果玩家没输,那么检查其他和局情况 + if (!playerLost) { + if (WChessUtil.reachMoveLimit(chessData)) { + // 判断是否 50 回合限制 + chess.setMoveNumberLimit(true); + } else if (WChessUtil.isRepeat(chessData)) { + // 判断是否长打 + chess.setRepeat(true); + } + } + + if (level instanceof ServerLevel serverLevel && serverLevel.getEntity(sitId) instanceof EntitySit sit && sit.getFirstPassenger() instanceof EntityMaid maid) { + maid.swing(InteractionHand.MAIN_HAND); + } + level.playSound(null, pos, InitSounds.GOMOKU.get(), SoundSource.BLOCKS, 1.0f, 0.8F + level.random.nextFloat() * 0.4F); + chess.refresh(); + } + } + + @Override + public void startMaidSit(EntityMaid maid, BlockState state, Level worldIn, BlockPos pos) { + if (worldIn instanceof ServerLevel serverLevel && worldIn.getBlockEntity(pos) instanceof TileEntityJoy joy) { + Entity oldSitEntity = serverLevel.getEntity(joy.getSitId()); + if (oldSitEntity != null && oldSitEntity.isAlive()) { + return; + } + Direction face = state.getValue(FACING).getOpposite(); + Vec3 position = new Vec3(0.5 + face.getStepX() * 2, 0.1, 0.5 + face.getStepZ() * 2); + EntitySit newSitEntity = new EntitySit(worldIn, Vec3.atLowerCornerWithOffset(pos, position.x, position.y, position.z), this.getTypeName(), pos); + newSitEntity.setYRot(face.getOpposite().toYRot() + this.sitYRot()); + worldIn.addFreshEntity(newSitEntity); + joy.setSitId(newSitEntity.getUUID()); + joy.setChanged(); + maid.startRiding(newSitEntity); + } + } + + @Override + public BlockState playerWillDestroy(Level world, BlockPos pos, BlockState state, Player player) { + handleWChessRemove(world, pos, state); + return super.playerWillDestroy(world, pos, state, player); + } + + @Override + public void onBlockExploded(BlockState state, Level world, BlockPos pos, Explosion explosion) { + handleWChessRemove(world, pos, state); + super.onBlockExploded(state, world, pos, explosion); + } + + @Nullable + @Override + public BlockState getStateForPlacement(BlockPlaceContext context) { + BlockPos centerPos = context.getClickedPos(); + for (int i = -1; i < 2; i++) { + for (int j = -1; j < 2; j++) { + BlockPos searchPos = centerPos.offset(i, 0, j); + if (!context.getLevel().getBlockState(searchPos).canBeReplaced(context)) { + return null; + } + } + } + return this.defaultBlockState().setValue(FACING, context.getHorizontalDirection().getOpposite()); + } + + @Override + public void setPlacedBy(Level worldIn, BlockPos pos, BlockState state, @javax.annotation.Nullable LivingEntity placer, ItemStack stack) { + super.setPlacedBy(worldIn, pos, state, placer, stack); + if (worldIn.isClientSide) { + return; + } + for (int i = -1; i < 2; i++) { + for (int j = -1; j < 2; j++) { + BlockPos searchPos = pos.offset(i, 0, j); + GomokuPart part = GomokuPart.getPartByPos(i, j); + if (part != null && !part.isCenter()) { + worldIn.setBlock(searchPos, state.setValue(PART, part), Block.UPDATE_ALL); + } + } + } + } + + @Override + public ItemInteractionResult useItemOn(ItemStack itemStack, BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) { + if (level instanceof ServerLevel serverLevel && hand == InteractionHand.MAIN_HAND && player.getMainHandItem().isEmpty()) { + GomokuPart part = state.getValue(PART); + BlockPos centerPos = pos.subtract(new Vec3i(part.getPosX(), 0, part.getPosY())); + BlockEntity te = level.getBlockEntity(centerPos); + + if (!(te instanceof TileEntityWChess chess)) { + return ItemInteractionResult.FAIL; + } + if (!chess.isPlayerTurn() && !chess.isCheckmate()) { + return ItemInteractionResult.FAIL; + } + + // 检查女仆 + Entity sitEntity = serverLevel.getEntity(chess.getSitId()); + if (sitEntity == null || !sitEntity.isAlive() || !(sitEntity.getFirstPassenger() instanceof EntityMaid maid)) { + player.sendSystemMessage(Component.translatable("message.touhou_little_maid.gomoku.no_maid")); + return ItemInteractionResult.FAIL; + } + // 检查是不是自己的女仆 + if (MaidConfig.MAID_GOMOKU_OWNER_LIMIT.get() && !maid.isOwnedBy(player)) { + player.sendSystemMessage(Component.translatable("message.touhou_little_maid.gomoku.not_owner")); + return ItemInteractionResult.FAIL; + } + + // 点击坐标的转换 + Direction facing = state.getValue(FACING); + Vec3 clickPos = hit.getLocation() + .subtract(pos.getX(), pos.getY(), pos.getZ()) + .add(part.getPosX() - 0.5, 0, part.getPosY() - 0.5) + .yRot(facing.toYRot() * Mth.DEG_TO_RAD); + + // 重置棋盘 + boolean clickResetArea = WChessUtil.isClickResetArea(clickPos); + if (clickResetArea) { + chess.reset(); + chess.refresh(); + level.playSound(null, centerPos, InitSounds.GOMOKU_RESET.get(), SoundSource.BLOCKS, 1.0f, 1.0f); + } + + // 没有点击到棋盘上,返回 + int nowClick = WChessUtil.getClickPosition(clickPos); + if (nowClick < 0 || !Position.IN_BOARD(nowClick)) { + return ItemInteractionResult.SKIP_DEFAULT_BLOCK_INTERACTION; + } + + // 玩家已经输了,不能下棋 + if (chess.isCheckmate() && chess.isPlayerTurn()) { + return ItemInteractionResult.FAIL; + } + + // 50 回合自然限着、长将不能下棋 + if (chess.isMoveNumberLimit() || chess.isRepeat()) { + return ItemInteractionResult.FAIL; + } + + // 处理点击棋子的逻辑 + Position chessData = chess.getChessData(); + byte[] squares = chessData.squares; + int preClick = chess.getSelectChessPoint(); + if (preClick < 0 || squares.length <= preClick) { + preClick = 0; + } + byte prePiece = squares[preClick]; + byte nowPiece = squares[nowClick]; + + // 如果前一个选择为空,或者选中的是黑方,说明没有选中棋子 + if (prePiece <= 0 || WChessUtil.isBlack(prePiece)) { + // 当前点击的是白方棋子 + if (WChessUtil.isWhite(nowPiece)) { + chess.setSelectChessPoint(nowClick); + chess.refresh(); + level.playSound(null, pos, InitSounds.GOMOKU.get(), SoundSource.BLOCKS, 1.0f, 0.8F + level.random.nextFloat() * 0.4F); + } + return ItemInteractionResult.SUCCESS; + } + + // 如果选的都是白方棋子,重选 + if (WChessUtil.isWhite(prePiece) && WChessUtil.isWhite(nowPiece)) { + chess.setSelectChessPoint(nowClick); + chess.refresh(); + level.playSound(null, pos, InitSounds.GOMOKU.get(), SoundSource.BLOCKS, 1.0f, 0.8F + level.random.nextFloat() * 0.4F); + return ItemInteractionResult.SUCCESS; + } + + // 判断移动是否合法 + int move = Position.MOVE(preClick, nowClick); + if (!chessData.legalMove(move)) { + return ItemInteractionResult.FAIL; + } + + // 没有将军,正常移动 + boolean notChecked = chessData.makeMove(move); + if (notChecked) { + int pcSrc = chessData.squares[Position.SRC(move)]; + // 如果吃子、动兵了,那么重置计数器(该计数器用于判断自然限着和长将) + if (chessData.captured() || Position.PIECE_TYPE(pcSrc) == Position.PIECE_PAWN) { + chessData.setIrrev(); + } + chess.addChessCounter(); + chess.setSelectChessPoint(nowClick); + chess.refresh(); + level.playSound(null, pos, InitSounds.GOMOKU.get(), SoundSource.BLOCKS, 1.0f, 0.8F + level.random.nextFloat() * 0.4F); + if (player instanceof ServerPlayer serverPlayer) { + PacketDistributor.sendToPlayer(serverPlayer, new WChessToClientPackage(centerPos, chessData.toFen())); + } + return ItemInteractionResult.SUCCESS; + } + + // 如果将军,那么给予提示 + player.sendSystemMessage(Component.translatable("message.touhou_little_maid.cchess.check")); + level.playSound(null, pos, SoundEvents.NOTE_BLOCK_BELL.value(), SoundSource.BLOCKS, 1.0f, 0.8F + level.random.nextFloat() * 0.4F); + return ItemInteractionResult.FAIL; + } + return ItemInteractionResult.SKIP_DEFAULT_BLOCK_INTERACTION; + } + + @Override + protected Vec3 sitPosition() { + return Vec3.ZERO; + } + + @Override + protected String getTypeName() { + return Type.GOMOKU.getTypeName(); + } + + @Override + protected int sitYRot() { + return 0; + } + + @Override + protected void createBlockStateDefinition(StateDefinition.Builder builder) { + builder.add(PART, FACING); + } + + @Nullable + @Override + public BlockEntity newBlockEntity(BlockPos pos, BlockState state) { + if (state.getValue(PART).isCenter()) { + return new TileEntityWChess(pos, state); + } + return null; + } + + @Override + protected MapCodec codec() { + return simpleCodec((properties) -> new BlockWChess()); + } + + @Override + public VoxelShape getShape(BlockState pState, BlockGetter pLevel, BlockPos pPos, CollisionContext pContext) { + return AABB; + } +} diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/entity/GeckoMaidEntity.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/entity/GeckoMaidEntity.java index ed4227031..a441d1497 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/entity/GeckoMaidEntity.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/entity/GeckoMaidEntity.java @@ -13,7 +13,6 @@ import com.github.tartaricacid.touhoulittlemaid.geckolib3.geo.animated.AnimatedGeoModel; import com.github.tartaricacid.touhoulittlemaid.geckolib3.model.provider.data.EntityModelData; import com.github.tartaricacid.touhoulittlemaid.geckolib3.resource.GeckoLibCache; -import com.github.tartaricacid.touhoulittlemaid.geckolib3.util.RenderUtils; import net.minecraft.client.Minecraft; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.EquipmentSlot; @@ -40,7 +39,6 @@ public class GeckoMaidEntity extends AnimatableEntity { private static final ResourceLocation GECKO_DEFAULT_TEXTURE = ResourceLocation.fromNamespaceAndPath(TouhouLittleMaid.MOD_ID, "textures/entity/empty.png"); private static final int FPS = 60; - private volatile boolean renderedWithTempChanges = false; private final IMaid maid; private MaidModelInfo maidInfo; private final Vector2f headRot = new Vector2f(); @@ -129,16 +127,8 @@ public ResourceLocation getAnimationFileLocation() { @Override protected boolean forceUpdate(AnimationEvent animationEvent) { - if (RenderUtils.isRenderingEntitiesInInventory()) { - renderedWithTempChanges = true; - return true; - } - if (renderedWithTempChanges) { - renderedWithTempChanges = false; - return true; - } var tick = (float) getCurrentTick(animationEvent); - if (tick != this.currentTick) { + if (tick > this.currentTick) { this.currentTick = tick; this.state.updateState(); this.modelDirty = false; diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/event/MaidSoundFreqEvent.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/event/MaidSoundFreqEvent.java index cd4694e28..28245e255 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/event/MaidSoundFreqEvent.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/event/MaidSoundFreqEvent.java @@ -1,7 +1,7 @@ package com.github.tartaricacid.touhoulittlemaid.client.event; import com.github.tartaricacid.touhoulittlemaid.client.sound.data.MaidSoundInstance; -import com.github.tartaricacid.touhoulittlemaid.config.subconfig.InGameMaidConfig; +import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid; import net.neoforged.api.distmarker.Dist; import net.neoforged.bus.api.SubscribeEvent; import net.neoforged.fml.common.EventBusSubscriber; @@ -12,7 +12,12 @@ public class MaidSoundFreqEvent { @SubscribeEvent public static void onPlaySoundEvent(PlaySoundEvent event) { if (event.getSound() instanceof MaidSoundInstance maidSoundInstance) { - double soundFrequency = InGameMaidConfig.INSTANCE.getSoundFrequency(); + EntityMaid maid = maidSoundInstance.getMaid(); + if (maid == null) { + event.setSound(null); + return; + } + double soundFrequency = maid.getConfigManager().getSoundFreq(); if (soundFrequency < 1 && !maidSoundInstance.isTestSound()) { if (Math.random() > soundFrequency) { event.setSound(null); diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/gui/entity/maid/AbstractMaidContainerGui.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/gui/entity/maid/AbstractMaidContainerGui.java index 706afe3a3..b3c4ff230 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/gui/entity/maid/AbstractMaidContainerGui.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/gui/entity/maid/AbstractMaidContainerGui.java @@ -38,7 +38,6 @@ import net.neoforged.fml.ModList; import net.neoforged.neoforge.network.PacketDistributor; -import javax.annotation.Nullable; import java.text.DecimalFormat; import java.util.ArrayList; import java.util.Collections; @@ -56,7 +55,6 @@ public abstract class AbstractMaidContainerGui private static final int TASK_COUNT_PER_PAGE = 12; private static int TASK_PAGE = 0; private static boolean TASK_LIST_OPEN = false; - @Nullable protected final EntityMaid maid; protected final IMaidTask task; private TouhouStateSwitchButton home; @@ -612,6 +610,6 @@ private void addSideTabsButton() { // 绘制侧边栏底部贴图 private void drawSideTabGui(GuiGraphics graphics, float partialTicks, int x, int y) { - graphics.blit(SIDE, leftPos + 251 + 5, topPos + 28 + 9, 235, 107, 21, 99); + graphics.blit(SIDE, leftPos + 251 + 5, topPos + 28 + 9, 235, 107, 21, 50); } } diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/gui/entity/maid/MaidConfigContainerGui.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/gui/entity/maid/MaidConfigContainerGui.java deleted file mode 100644 index caa8c8132..000000000 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/gui/entity/maid/MaidConfigContainerGui.java +++ /dev/null @@ -1,92 +0,0 @@ -package com.github.tartaricacid.touhoulittlemaid.client.gui.entity.maid; - -import com.github.tartaricacid.touhoulittlemaid.TouhouLittleMaid; -import com.github.tartaricacid.touhoulittlemaid.client.gui.widget.button.MaidSoundFreqButton; -import com.github.tartaricacid.touhoulittlemaid.client.gui.widget.button.TouhouStateSwitchButton; -import com.github.tartaricacid.touhoulittlemaid.config.subconfig.InGameMaidConfig; -import com.github.tartaricacid.touhoulittlemaid.inventory.container.MaidConfigContainer; -import net.minecraft.client.gui.GuiGraphics; -import net.minecraft.network.chat.Component; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.entity.player.Inventory; -import org.anti_ad.mc.ipn.api.IPNButton; -import org.anti_ad.mc.ipn.api.IPNGuiHint; -import org.anti_ad.mc.ipn.api.IPNPlayerSideOnly; - -import static com.github.tartaricacid.touhoulittlemaid.config.subconfig.InGameMaidConfig.INSTANCE; - -@IPNPlayerSideOnly -@IPNGuiHint(button = IPNButton.SORT, horizontalOffset = -36, bottom = -12) -@IPNGuiHint(button = IPNButton.SORT_COLUMNS, horizontalOffset = -24, bottom = -24) -@IPNGuiHint(button = IPNButton.SORT_ROWS, horizontalOffset = -12, bottom = -36) -@IPNGuiHint(button = IPNButton.SHOW_EDITOR, horizontalOffset = -5) -@IPNGuiHint(button = IPNButton.SETTINGS, horizontalOffset = -5) -public class MaidConfigContainerGui extends AbstractMaidContainerGui { - private static final ResourceLocation ICON = ResourceLocation.fromNamespaceAndPath(TouhouLittleMaid.MOD_ID, "textures/gui/maid_gui_config.png"); - private int left; - private int top; - - public MaidConfigContainerGui(MaidConfigContainer screenContainer, Inventory inv, Component titleIn) { - super(screenContainer, inv, titleIn); - InGameMaidConfig.read(); - } - - @Override - protected void init() { - super.init(); - left = leftPos + 81; - top = topPos + 28; - - TouhouStateSwitchButton showChatBubble = new TouhouStateSwitchButton(left + 10, top + 10, 22, 22, INSTANCE.isShowChatBubble()) { - @Override - public void onClick(double mouseX, double mouseY) { - this.isStateTriggered = !this.isStateTriggered; - INSTANCE.setShowChatBubble(this.isStateTriggered); - InGameMaidConfig.save(); - } - }; - showChatBubble.initTextureValues(22, 0, -22, 0, ICON); - - TouhouStateSwitchButton showBackpack = new TouhouStateSwitchButton(left + 10, top + 10 + 24, 22, 22, INSTANCE.isShowBackpack()) { - @Override - public void onClick(double mouseX, double mouseY) { - this.isStateTriggered = !this.isStateTriggered; - INSTANCE.setShowBackpack(this.isStateTriggered); - InGameMaidConfig.save(); - } - }; - showBackpack.initTextureValues(22, 0, -22, 0, ICON); - - TouhouStateSwitchButton showBackItem = new TouhouStateSwitchButton(left + 10, top + 10 + 24 * 2, 22, 22, INSTANCE.isShowBackItem()) { - @Override - public void onClick(double mouseX, double mouseY) { - this.isStateTriggered = !this.isStateTriggered; - INSTANCE.setShowBackItem(this.isStateTriggered); - InGameMaidConfig.save(); - } - }; - showBackItem.initTextureValues(22, 0, -22, 0, ICON); - - this.addRenderableWidget(showChatBubble); - this.addRenderableWidget(showBackpack); - this.addRenderableWidget(showBackItem); - this.addRenderableWidget(new MaidSoundFreqButton(left + 10, top + 15 + 24 * 3)); - } - - @Override - protected void renderBg(GuiGraphics graphics, float partialTicks, int x, int y) { - super.renderBg(graphics, partialTicks, x, y); - graphics.drawString(font, Component.translatable("gui.touhou_little_maid.maid_config.show_chat_bubble"), left + 38, top + 17, 0x333333, false); - graphics.drawString(font, Component.translatable("gui.touhou_little_maid.maid_config.show_backpack"), left + 38, top + 17 + 24, 0x333333, false); - graphics.drawString(font, Component.translatable("gui.touhou_little_maid.maid_config.show_back_item"), left + 38, top + 17 + 24 * 2, 0x333333, false); - } - - @Override - public boolean mouseDragged(double mouseX, double mouseY, int button, double dragX, double dragY) { - if (this.getFocused() != null && this.isDragging() && button == 0) { - this.getFocused().mouseDragged(mouseX, mouseY, button, dragX, dragY); - return true; - } - return super.mouseDragged(mouseX, mouseY, button, dragX, dragY); - } -} \ No newline at end of file diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/gui/entity/maid/MaidSideTabs.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/gui/entity/maid/MaidSideTabs.java index c7e565843..2f26f59ac 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/gui/entity/maid/MaidSideTabs.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/gui/entity/maid/MaidSideTabs.java @@ -2,7 +2,6 @@ import com.github.tartaricacid.touhoulittlemaid.TouhouLittleMaid; import com.github.tartaricacid.touhoulittlemaid.api.event.client.OpenPatchouliBookEvent; -import com.github.tartaricacid.touhoulittlemaid.client.gui.entity.maid.task.MaidTaskConfigGui; import com.github.tartaricacid.touhoulittlemaid.client.gui.mod.PatchouliWarningScreen; import com.github.tartaricacid.touhoulittlemaid.client.gui.widget.button.MaidSideTabButton; import com.github.tartaricacid.touhoulittlemaid.compat.cloth.ClothConfigCompat; @@ -10,7 +9,6 @@ import com.github.tartaricacid.touhoulittlemaid.entity.passive.SideTab; import com.github.tartaricacid.touhoulittlemaid.init.registry.CompatRegistry; import com.github.tartaricacid.touhoulittlemaid.inventory.container.AbstractMaidContainer; -import com.github.tartaricacid.touhoulittlemaid.network.message.ToggleSideTabPackage; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.components.Button; import net.minecraft.client.gui.screens.Screen; @@ -18,7 +16,6 @@ import net.neoforged.fml.ModList; import net.neoforged.neoforge.client.gui.ConfigurationScreen; import net.neoforged.neoforge.common.NeoForge; -import net.neoforged.neoforge.network.PacketDistributor; import java.util.List; import java.util.Locale; @@ -37,17 +34,6 @@ public MaidSideTabs(int entityId, int rightPos, int topPos) { } public MaidSideTabButton[] getTabs(AbstractMaidContainerGui screen) { - // 任务配置界面按钮 - MaidSideTabButton taskConfig = genSideTabButton(SideTab.TASK_CONFIG, b -> { - EntityMaid maid = screen.getMaid(); - if (maid != null) { - PacketDistributor.sendToServer(new ToggleSideTabPackage(entityId, SideTab.TASK_CONFIG.getIndex(), maid.getTask().getUid())); - } - }); - if (screen instanceof MaidTaskConfigGui) { - taskConfig.active = false; - } - // 跳转帕秋莉手册按钮 MaidSideTabButton taskBook = genSideTabButton(SideTab.TASK_BOOK, (b) -> { if (ModList.get().isLoaded(CompatRegistry.PATCHOULI)) { @@ -60,11 +46,6 @@ public MaidSideTabButton[] getTabs(AbstractMaidContainerGui screen) { } }); - // TODO: 未完成信息界面内容 - // 任务信息界面按钮 - MaidSideTabButton taskInfo = genSideTabButton(SideTab.TASK_INFO, (b) -> { - }); - // 跳转全局配置按钮 MaidSideTabButton globalConfig = genSideTabButton(SideTab.GLOBAL_CONFIG, (b) -> { if (ModList.get().isLoaded(CompatRegistry.CLOTH_CONFIG)) { @@ -79,7 +60,7 @@ public MaidSideTabButton[] getTabs(AbstractMaidContainerGui screen) { } }); - return new MaidSideTabButton[]{taskConfig, taskBook, taskInfo, globalConfig}; + return new MaidSideTabButton[]{taskBook, globalConfig}; } private MaidSideTabButton genSideTabButton(SideTab sideTab, Button.OnPress onPressIn) { diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/gui/entity/maid/MaidTabs.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/gui/entity/maid/MaidTabs.java index 8c007d52b..a92ff0cf1 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/gui/entity/maid/MaidTabs.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/gui/entity/maid/MaidTabs.java @@ -1,6 +1,8 @@ package com.github.tartaricacid.touhoulittlemaid.client.gui.entity.maid; import com.github.tartaricacid.touhoulittlemaid.client.gui.entity.maid.backpack.IBackpackContainerScreen; +import com.github.tartaricacid.touhoulittlemaid.client.gui.entity.maid.config.MaidConfigContainerGui; +import com.github.tartaricacid.touhoulittlemaid.client.gui.entity.maid.task.MaidTaskConfigGui; import com.github.tartaricacid.touhoulittlemaid.client.gui.widget.button.MaidTabButton; import com.github.tartaricacid.touhoulittlemaid.entity.passive.TabIndex; import com.github.tartaricacid.touhoulittlemaid.inventory.container.AbstractMaidContainer; @@ -19,18 +21,24 @@ public MaidTabs(int entityId, int leftPos, int topPos) { } public MaidTabButton[] getTabs(AbstractMaidContainerGui screen) { - MaidTabButton main = new MaidTabButton(leftPos + 94, topPos + 5, 107, (b) -> - PacketDistributor.sendToServer(new ToggleTabPackage(entityId, TabIndex.MAIN))); + MaidTabButton main = new MaidTabButton(leftPos + 94, topPos + 5, 107, "main", + (b) -> PacketDistributor.sendToServer(new ToggleTabPackage(entityId, TabIndex.MAIN))); if (screen instanceof IBackpackContainerScreen) { main.active = false; } - MaidTabButton config = new MaidTabButton(leftPos + 219, topPos + 5, 232, (b) -> - PacketDistributor.sendToServer(new ToggleTabPackage(entityId, TabIndex.CONFIG))); + MaidTabButton taskConfig = new MaidTabButton(leftPos + 119, topPos + 5, 132, "task_config", + (b) -> PacketDistributor.sendToServer(new ToggleTabPackage(entityId, TabIndex.TASK_CONFIG))); + if (screen instanceof MaidTaskConfigGui) { + taskConfig.active = false; + } + + MaidTabButton maidConfig = new MaidTabButton(leftPos + 144, topPos + 5, 157, "maid_config", + (b) -> PacketDistributor.sendToServer(new ToggleTabPackage(entityId, TabIndex.MAID_CONFIG))); if (screen instanceof MaidConfigContainerGui) { - config.active = false; + maidConfig.active = false; } - return new MaidTabButton[]{main, config}; + return new MaidTabButton[]{main, taskConfig, maidConfig}; } } \ No newline at end of file diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/gui/entity/maid/config/MaidConfigContainerGui.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/gui/entity/maid/config/MaidConfigContainerGui.java new file mode 100644 index 000000000..1b9dfad89 --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/gui/entity/maid/config/MaidConfigContainerGui.java @@ -0,0 +1,137 @@ +package com.github.tartaricacid.touhoulittlemaid.client.gui.entity.maid.config; + +import com.github.tartaricacid.touhoulittlemaid.TouhouLittleMaid; +import com.github.tartaricacid.touhoulittlemaid.client.gui.entity.maid.AbstractMaidContainerGui; +import com.github.tartaricacid.touhoulittlemaid.client.gui.widget.button.MaidConfigButton; +import com.github.tartaricacid.touhoulittlemaid.entity.passive.MaidConfigManager; +import com.github.tartaricacid.touhoulittlemaid.entity.passive.PickType; +import com.github.tartaricacid.touhoulittlemaid.inventory.container.config.MaidConfigContainer; +import com.github.tartaricacid.touhoulittlemaid.network.message.MaidSubConfigPackage; +import net.minecraft.ChatFormatting; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.player.Inventory; +import net.neoforged.neoforge.network.PacketDistributor; +import org.anti_ad.mc.ipn.api.IPNButton; +import org.anti_ad.mc.ipn.api.IPNGuiHint; +import org.anti_ad.mc.ipn.api.IPNPlayerSideOnly; + +@IPNPlayerSideOnly +@IPNGuiHint(button = IPNButton.SORT, horizontalOffset = -36, bottom = -12) +@IPNGuiHint(button = IPNButton.SORT_COLUMNS, horizontalOffset = -24, bottom = -24) +@IPNGuiHint(button = IPNButton.SORT_ROWS, horizontalOffset = -12, bottom = -36) +@IPNGuiHint(button = IPNButton.SHOW_EDITOR, horizontalOffset = -5) +@IPNGuiHint(button = IPNButton.SETTINGS, horizontalOffset = -5) +public class MaidConfigContainerGui extends AbstractMaidContainerGui { + private static final ResourceLocation ICON = ResourceLocation.fromNamespaceAndPath(TouhouLittleMaid.MOD_ID, "textures/gui/maid_gui_config.png"); + private final MaidConfigManager.SyncNetwork syncNetwork; + + public MaidConfigContainerGui(MaidConfigContainer screenContainer, Inventory inv, Component titleIn) { + super(screenContainer, inv, titleIn); + this.syncNetwork = getMaid().getConfigManager().getSyncNetwork(); + } + + @Override + protected void renderBg(GuiGraphics graphics, float partialTicks, int x, int y) { + super.renderBg(graphics, partialTicks, x, y); + graphics.blit(ICON, leftPos + 80, topPos + 28, 0, 0, imageWidth, imageHeight); + } + + @Override + protected void initAdditionWidgets() { + int buttonLeft = leftPos + 86; + int buttonTop = topPos + 52; + + this.addRenderableWidget(new MaidConfigButton(buttonLeft, buttonTop, + Component.translatable("gui.touhou_little_maid.maid_config.show_backpack"), + Component.translatable("gui.touhou_little_maid.maid_config.value." + this.syncNetwork.showBackpack()), + button -> { + this.syncNetwork.setShowBackpack(!this.syncNetwork.showBackpack()); + button.setValue(Component.translatable("gui.touhou_little_maid.maid_config.value." + this.syncNetwork.showBackpack())); + } + )); + buttonTop += 13; + + this.addRenderableWidget(new MaidConfigButton(buttonLeft, buttonTop, + Component.translatable("gui.touhou_little_maid.maid_config.show_back_item"), + Component.translatable("gui.touhou_little_maid.maid_config.value." + this.syncNetwork.showBackItem()), + button -> { + this.syncNetwork.setShowBackItem(!this.syncNetwork.showBackItem()); + button.setValue(Component.translatable("gui.touhou_little_maid.maid_config.value." + this.syncNetwork.showBackItem())); + } + )); + buttonTop += 13; + + this.addRenderableWidget(new MaidConfigButton(buttonLeft, buttonTop, + Component.translatable("gui.touhou_little_maid.maid_config.show_chat_bubble"), + Component.translatable("gui.touhou_little_maid.maid_config.value." + this.syncNetwork.showChatBubble()), + button -> { + this.syncNetwork.setShowChatBubble(!this.syncNetwork.showChatBubble()); + button.setValue(Component.translatable("gui.touhou_little_maid.maid_config.value." + this.syncNetwork.showChatBubble())); + } + )); + buttonTop += 13; + + + this.addRenderableWidget(new MaidConfigButton(buttonLeft, buttonTop, + Component.translatable("gui.touhou_little_maid.maid_config.sound_frequency"), + Component.literal(Math.round(this.syncNetwork.soundFreq() * 100) + "%").withStyle(ChatFormatting.YELLOW), + button -> { + this.syncNetwork.setSoundFreq(this.syncNetwork.soundFreq() - 0.1f); + button.setValue(Component.literal(Math.round(this.syncNetwork.soundFreq() * 100) + "%").withStyle(ChatFormatting.YELLOW)); + }, + button -> { + this.syncNetwork.setSoundFreq(this.syncNetwork.soundFreq() + 0.1f); + button.setValue(Component.literal(Math.round(this.syncNetwork.soundFreq() * 100) + "%").withStyle(ChatFormatting.YELLOW)); + } + )); + buttonTop += 13; + + this.addRenderableWidget(new MaidConfigButton(buttonLeft, buttonTop, + Component.translatable("gui.touhou_little_maid.maid_config.pick_type"), + Component.translatable(PickType.getTransKey(this.syncNetwork.pickType())).withStyle(ChatFormatting.DARK_RED), + button -> { + this.syncNetwork.setPickType(PickType.getPreviousPickType(this.syncNetwork.pickType())); + button.setValue(Component.translatable(PickType.getTransKey(this.syncNetwork.pickType())).withStyle(ChatFormatting.DARK_RED)); + }, + button -> { + this.syncNetwork.setPickType(PickType.getNextPickType(this.syncNetwork.pickType())); + button.setValue(Component.translatable(PickType.getTransKey(this.syncNetwork.pickType())).withStyle(ChatFormatting.DARK_RED)); + } + )); + buttonTop += 13; + + this.addRenderableWidget(new MaidConfigButton(buttonLeft, buttonTop, + Component.translatable("gui.touhou_little_maid.maid_config.open_door"), + Component.translatable("gui.touhou_little_maid.maid_config.value." + this.syncNetwork.openDoor()), + button -> { + this.syncNetwork.setOpenDoor(!this.syncNetwork.openDoor()); + button.setValue(Component.translatable("gui.touhou_little_maid.maid_config.value." + this.syncNetwork.openDoor())); + } + )); + buttonTop += 13; + + this.addRenderableWidget(new MaidConfigButton(buttonLeft, buttonTop, + Component.translatable("gui.touhou_little_maid.maid_config.open_fence_gate"), + Component.translatable("gui.touhou_little_maid.maid_config.value." + this.syncNetwork.openFenceGate()), + button -> { + this.syncNetwork.setOpenFenceGate(!this.syncNetwork.openFenceGate()); + button.setValue(Component.translatable("gui.touhou_little_maid.maid_config.value." + this.syncNetwork.openFenceGate())); + } + )); + } + + @Override + protected void renderAddition(GuiGraphics graphics, int mouseX, int mouseY, float partialTicks) { + graphics.drawString(font, Component.translatable("gui.touhou_little_maid.button.maid_config"), leftPos + 140, topPos + 41, 0xFFFFFF, false); + } + + @Override + public void onClose() { + if (this.maid != null) { + PacketDistributor.sendToServer(new MaidSubConfigPackage(this.maid.getId(), this.syncNetwork)); + } + super.onClose(); + } +} \ No newline at end of file diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/gui/entity/maid/CheckSchedulePosGui.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/gui/entity/maid/other/CheckSchedulePosGui.java similarity index 94% rename from src/main/java/com/github/tartaricacid/touhoulittlemaid/client/gui/entity/maid/CheckSchedulePosGui.java rename to src/main/java/com/github/tartaricacid/touhoulittlemaid/client/gui/entity/maid/other/CheckSchedulePosGui.java index ba69232e4..8d56e32cf 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/gui/entity/maid/CheckSchedulePosGui.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/gui/entity/maid/other/CheckSchedulePosGui.java @@ -1,5 +1,6 @@ -package com.github.tartaricacid.touhoulittlemaid.client.gui.entity.maid; +package com.github.tartaricacid.touhoulittlemaid.client.gui.entity.maid.other; +import com.github.tartaricacid.touhoulittlemaid.client.gui.entity.maid.AbstractMaidContainerGui; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.components.Button; import net.minecraft.client.gui.components.Renderable; diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/gui/entity/maid/task/DefaultMaidTaskConfigContainerGui.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/gui/entity/maid/task/DefaultMaidTaskConfigGui.java similarity index 79% rename from src/main/java/com/github/tartaricacid/touhoulittlemaid/client/gui/entity/maid/task/DefaultMaidTaskConfigContainerGui.java rename to src/main/java/com/github/tartaricacid/touhoulittlemaid/client/gui/entity/maid/task/DefaultMaidTaskConfigGui.java index 736eababc..45e82bee1 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/gui/entity/maid/task/DefaultMaidTaskConfigContainerGui.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/gui/entity/maid/task/DefaultMaidTaskConfigGui.java @@ -13,8 +13,8 @@ @IPNGuiHint(button = IPNButton.SORT_ROWS, horizontalOffset = -12, bottom = -36) @IPNGuiHint(button = IPNButton.SHOW_EDITOR, horizontalOffset = -5) @IPNGuiHint(button = IPNButton.SETTINGS, horizontalOffset = -5) -public class DefaultMaidTaskConfigContainerGui extends MaidTaskConfigGui { - public DefaultMaidTaskConfigContainerGui(TaskConfigContainer screenContainer, Inventory inv, Component titleIn) { +public class DefaultMaidTaskConfigGui extends MaidTaskConfigGui { + public DefaultMaidTaskConfigGui(TaskConfigContainer screenContainer, Inventory inv, Component titleIn) { super(screenContainer, inv, titleIn); } } \ No newline at end of file diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/gui/entity/maid/task/MaidTaskConfigGui.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/gui/entity/maid/task/MaidTaskConfigGui.java index fe59def08..f842da518 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/gui/entity/maid/task/MaidTaskConfigGui.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/gui/entity/maid/task/MaidTaskConfigGui.java @@ -1,11 +1,8 @@ package com.github.tartaricacid.touhoulittlemaid.client.gui.entity.maid.task; -import com.github.tartaricacid.touhoulittlemaid.api.task.IMaidTask; import com.github.tartaricacid.touhoulittlemaid.client.gui.entity.maid.AbstractMaidContainerGui; -import com.github.tartaricacid.touhoulittlemaid.entity.passive.SideTab; import com.github.tartaricacid.touhoulittlemaid.inventory.container.task.TaskConfigContainer; import com.github.tartaricacid.touhoulittlemaid.network.message.RefreshMaidBrainPackage; -import com.github.tartaricacid.touhoulittlemaid.network.message.ToggleSideTabPackage; import net.minecraft.network.chat.Component; import net.minecraft.world.entity.player.Inventory; import net.neoforged.neoforge.network.PacketDistributor; @@ -15,14 +12,6 @@ public MaidTaskConfigGui(T screenContainer, Inventory inv, Component titleIn) { super(screenContainer, inv, titleIn); } - @Override - protected void taskButtonPressed(IMaidTask maidTask, boolean enable) { - super.taskButtonPressed(maidTask, enable); - if (this.maid != null) { - PacketDistributor.sendToServer(new ToggleSideTabPackage(this.maid.getId(), SideTab.TASK_CONFIG.getIndex(), maidTask.getUid())); - } - } - @Override public void onClose() { // 重置女仆 Brain,让女仆重新读取任务相关数据 diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/gui/item/PicnicBasketContainerScreen.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/gui/item/PicnicBasketContainerScreen.java index 5f2b673a5..e9c2a822d 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/gui/item/PicnicBasketContainerScreen.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/gui/item/PicnicBasketContainerScreen.java @@ -1,6 +1,6 @@ package com.github.tartaricacid.touhoulittlemaid.client.gui.item; -import com.github.tartaricacid.touhoulittlemaid.inventory.container.PicnicBasketContainer; +import com.github.tartaricacid.touhoulittlemaid.inventory.container.other.PicnicBasketContainer; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; import net.minecraft.network.chat.Component; diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/gui/item/WirelessIOContainerGui.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/gui/item/WirelessIOContainerGui.java index 49076d6cd..6371e2d32 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/gui/item/WirelessIOContainerGui.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/gui/item/WirelessIOContainerGui.java @@ -3,7 +3,7 @@ import com.github.tartaricacid.touhoulittlemaid.TouhouLittleMaid; import com.github.tartaricacid.touhoulittlemaid.client.gui.widget.button.TouhouImageButton; import com.github.tartaricacid.touhoulittlemaid.client.gui.widget.button.WirelessIOButton; -import com.github.tartaricacid.touhoulittlemaid.inventory.container.WirelessIOContainer; +import com.github.tartaricacid.touhoulittlemaid.inventory.container.other.WirelessIOContainer; import com.github.tartaricacid.touhoulittlemaid.item.ItemWirelessIO; import com.github.tartaricacid.touhoulittlemaid.network.message.WirelessIOGuiPackage; import com.mojang.blaze3d.systems.RenderSystem; diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/gui/widget/button/MaidConfigButton.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/gui/widget/button/MaidConfigButton.java new file mode 100644 index 000000000..0940fa3d2 --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/gui/widget/button/MaidConfigButton.java @@ -0,0 +1,89 @@ +package com.github.tartaricacid.touhoulittlemaid.client.gui.widget.button; + +import com.github.tartaricacid.touhoulittlemaid.TouhouLittleMaid; +import com.mojang.blaze3d.systems.RenderSystem; +import net.minecraft.ChatFormatting; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Font; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.components.Button; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.FormattedCharSequence; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; + +public class MaidConfigButton extends Button { + private static final ResourceLocation ICON = ResourceLocation.fromNamespaceAndPath(TouhouLittleMaid.MOD_ID, "textures/gui/maid_gui_button.png"); + private final MaidConfigButton.OnPress leftPress; + private final MaidConfigButton.OnPress rightPress; + private boolean leftClicked = false; + private Component value; + + public MaidConfigButton(int x, int y, Component title, Component value, MaidConfigButton.OnPress onLeftPressIn, MaidConfigButton.OnPress onRightPressIn) { + super(Button.builder(title, b -> { + }).pos(x, y).size(164, 13)); + this.leftPress = onLeftPressIn; + this.rightPress = onRightPressIn; + this.value = value; + } + + public MaidConfigButton(int x, int y, Component title, Component value, MaidConfigButton.OnPress onPress) { + this(x, y, title, value, onPress, onPress); + } + + @Override + protected void renderWidget(GuiGraphics graphics, int pMouseX, int pMouseY, float pPartialTick) { + Minecraft mc = Minecraft.getInstance(); + RenderSystem.enableDepthTest(); + if (this.isHovered) { + graphics.blit(ICON, this.getX(), this.getY(), 63, 141, this.width, this.height, 256, 256); + } else { + graphics.blit(ICON, this.getX(), this.getY(), 63, 128, this.width, this.height, 256, 256); + } + graphics.drawString(mc.font, this.getMessage(), this.getX() + 5, this.getY() + 3, 0x444444, false); + drawCenteredStringWithoutShadow(graphics, mc.font, this.value, this.getX() + 142, this.getY() + 3, ChatFormatting.GREEN.getColor()); + } + + public void setValue(Component value) { + this.value = value; + } + + @Override + protected boolean clicked(double mouseX, double mouseY) { + if (!this.active || !this.visible) { + return false; + } + boolean leftClickX = (this.getX() + 120) <= mouseX && mouseX <= (this.getX() + 130); + boolean rightClickX = (this.getX() + 154) <= mouseX && mouseX <= (this.getX() + 164); + boolean clickY = this.getY() <= mouseY && mouseY <= (this.getY() + this.getHeight()); + if (leftClickX && clickY) { + leftClicked = true; + return true; + } + if (rightClickX && clickY) { + leftClicked = false; + return true; + } + return false; + } + + @Override + public void onPress() { + if (leftClicked) { + leftPress.onPress(this); + } else { + rightPress.onPress(this); + } + } + + public void drawCenteredStringWithoutShadow(GuiGraphics graphics, Font pFont, Component pText, int pX, int pY, int pColor) { + FormattedCharSequence formattedcharsequence = pText.getVisualOrderText(); + graphics.drawString(pFont, formattedcharsequence, pX - pFont.width(formattedcharsequence) / 2, pY, pColor, false); + } + + @OnlyIn(Dist.CLIENT) + public interface OnPress { + void onPress(MaidConfigButton button); + } +} diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/gui/widget/button/MaidSoundFreqButton.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/gui/widget/button/MaidSoundFreqButton.java deleted file mode 100644 index fd960ef24..000000000 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/gui/widget/button/MaidSoundFreqButton.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.github.tartaricacid.touhoulittlemaid.client.gui.widget.button; - -import com.github.tartaricacid.touhoulittlemaid.config.subconfig.InGameMaidConfig; -import net.minecraft.client.gui.components.AbstractSliderButton; -import net.minecraft.network.chat.Component; -import net.minecraft.util.Mth; - -import static com.github.tartaricacid.touhoulittlemaid.config.subconfig.InGameMaidConfig.INSTANCE; - -public class MaidSoundFreqButton extends AbstractSliderButton { - public MaidSoundFreqButton(int x, int y) { - super(x, y, 156, 20, Component.empty(), Mth.clamp(INSTANCE.getSoundFrequency(), 0, 1.0)); - this.updateMessage(); - } - - @Override - protected void updateMessage() { - Component number = Component.literal((int) (this.value * 100.0D) + "%"); - this.setMessage((Component.translatable("gui.touhou_little_maid.maid_config.sound_frequency")).append(": ").append(number)); - } - - @Override - protected void applyValue() { - INSTANCE.setSoundFrequency(this.value); - InGameMaidConfig.save(); - } -} \ No newline at end of file diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/gui/widget/button/MaidTabButton.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/gui/widget/button/MaidTabButton.java index a67184468..3e7975424 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/gui/widget/button/MaidTabButton.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/gui/widget/button/MaidTabButton.java @@ -1,22 +1,32 @@ package com.github.tartaricacid.touhoulittlemaid.client.gui.widget.button; import com.github.tartaricacid.touhoulittlemaid.TouhouLittleMaid; +import com.github.tartaricacid.touhoulittlemaid.api.client.gui.ITooltipButton; +import com.google.common.collect.Lists; import com.mojang.blaze3d.systems.RenderSystem; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Font; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.components.Button; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; -public class MaidTabButton extends Button { +import java.util.List; + +public class MaidTabButton extends Button implements ITooltipButton { private static final ResourceLocation SIDE = ResourceLocation.fromNamespaceAndPath(TouhouLittleMaid.MOD_ID, "textures/gui/maid_gui_side.png"); private final int left; + private final List tooltips; - public MaidTabButton(int x, int y, int left, Button.OnPress onPressIn) { + public MaidTabButton(int x, int y, int left, String key, Button.OnPress onPressIn) { super(Button.builder(Component.empty(), onPressIn).pos(x, y).size(24, 26)); this.left = left; + this.tooltips = Lists.newArrayList( + Component.translatable("gui.touhou_little_maid.button." + key), + Component.translatable("gui.touhou_little_maid.button." + key + ".desc") + ); } - @Override public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY, float partialTicks) { RenderSystem.enableDepthTest(); @@ -25,4 +35,15 @@ public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY, float par } graphics.blit(SIDE, this.getX() + 4, this.getY() + 6, left, 47, 16, 16, 256, 256); } + + @Override + public boolean isTooltipHovered() { + return this.active && this.isHovered(); + } + + @Override + public void renderTooltip(GuiGraphics graphics, Minecraft mc, int mouseX, int mouseY) { + Font font = Minecraft.getInstance().font; + graphics.renderComponentTooltip(font, tooltips, mouseX, mouseY); + } } \ No newline at end of file diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/init/ClientSetupEvent.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/init/ClientSetupEvent.java index a749bae49..5f8c7b267 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/init/ClientSetupEvent.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/init/ClientSetupEvent.java @@ -6,7 +6,6 @@ import com.github.tartaricacid.touhoulittlemaid.client.overlay.BroomTipsOverlay; import com.github.tartaricacid.touhoulittlemaid.client.overlay.MaidTipsOverlay; import com.github.tartaricacid.touhoulittlemaid.client.overlay.ShowPowerOverlay; -import com.github.tartaricacid.touhoulittlemaid.config.subconfig.InGameMaidConfig; import net.neoforged.api.distmarker.Dist; import net.neoforged.bus.api.SubscribeEvent; import net.neoforged.fml.common.EventBusSubscriber; @@ -23,7 +22,6 @@ public class ClientSetupEvent { public static void onClientSetup(FMLClientSetupEvent event) { event.enqueueWork(AnimationRegister::registerAnimationState); event.enqueueWork(AnimationRegister::registerVariables); - event.enqueueWork(InGameMaidConfig::read); event.enqueueWork(MaidTipsOverlay::init); event.enqueueWork(ShowOptifineScreen::checkOptifineIsLoaded); } diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/init/InitContainerGui.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/init/InitContainerGui.java index 7258c0b40..3b43f9af0 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/init/InitContainerGui.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/init/InitContainerGui.java @@ -1,8 +1,8 @@ package com.github.tartaricacid.touhoulittlemaid.client.init; -import com.github.tartaricacid.touhoulittlemaid.client.gui.entity.maid.MaidConfigContainerGui; import com.github.tartaricacid.touhoulittlemaid.client.gui.entity.maid.backpack.*; -import com.github.tartaricacid.touhoulittlemaid.client.gui.entity.maid.task.DefaultMaidTaskConfigContainerGui; +import com.github.tartaricacid.touhoulittlemaid.client.gui.entity.maid.config.MaidConfigContainerGui; +import com.github.tartaricacid.touhoulittlemaid.client.gui.entity.maid.task.DefaultMaidTaskConfigGui; import com.github.tartaricacid.touhoulittlemaid.client.gui.item.PicnicBasketContainerScreen; import com.github.tartaricacid.touhoulittlemaid.client.gui.item.WirelessIOContainerGui; import com.github.tartaricacid.touhoulittlemaid.init.InitContainer; @@ -28,6 +28,6 @@ public static void clientSetup(RegisterMenuScreensEvent event) { event.register(InitContainer.WIRELESS_IO_CONTAINER.get(), WirelessIOContainerGui::new); event.register(InitContainer.PICNIC_BASKET_CONTAINER.get(), PicnicBasketContainerScreen::new); - event.register(InitContainer.DEFAULT_MAIK_TASK_CONFIG.get(), DefaultMaidTaskConfigContainerGui::new); + event.register(InitContainer.DEFAULT_MAIK_TASK_CONFIG.get(), DefaultMaidTaskConfigGui::new); } } diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/init/InitEntitiesRender.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/init/InitEntitiesRender.java index 10b23f112..09d5b8832 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/init/InitEntitiesRender.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/init/InitEntitiesRender.java @@ -45,6 +45,8 @@ public static void onEntityRenderers(EntityRenderersEvent.RegisterRenderers evt) BlockEntityRenderers.register(TileEntityStatue.TYPE, TileEntityStatueRenderer::new); BlockEntityRenderers.register(TileEntityGarageKit.TYPE, TileEntityGarageKitRenderer::new); BlockEntityRenderers.register(TileEntityGomoku.TYPE, TileEntityGomokuRenderer::new); + BlockEntityRenderers.register(TileEntityCChess.TYPE, TileEntityCChessRenderer::new); + BlockEntityRenderers.register(TileEntityWChess.TYPE, TileEntityWChessRenderer::new); BlockEntityRenderers.register(TileEntityKeyboard.TYPE, TileEntityKeyboardRenderer::new); BlockEntityRenderers.register(TileEntityBookshelf.TYPE, TileEntityBookshelfRenderer::new); BlockEntityRenderers.register(TileEntityComputer.TYPE, TileEntityComputerRenderer::new); @@ -67,7 +69,10 @@ public static void onRegisterLayers(EntityRenderersEvent.RegisterLayerDefinition event.registerLayerDefinition(EntityYukkuriModel.LAYER, EntityYukkuriModel::createBodyLayer); event.registerLayerDefinition(EntityMarisaYukkuriModel.LAYER, EntityMarisaYukkuriModel::createBodyLayer); event.registerLayerDefinition(GomokuModel.LAYER, GomokuModel::createBodyLayer); + event.registerLayerDefinition(CChessModel.LAYER, CChessModel::createBodyLayer); + event.registerLayerDefinition(WChessModel.LAYER, WChessModel::createBodyLayer); event.registerLayerDefinition(PieceModel.LAYER, PieceModel::createBodyLayer); + event.registerLayerDefinition(WChessPiecesModel.LAYER, WChessPiecesModel::createBodyLayer); event.registerLayerDefinition(CraftingTableBackpackModel.LAYER, CraftingTableBackpackModel::createBodyLayer); event.registerLayerDefinition(EnderChestBackpackModel.LAYER, EnderChestBackpackModel::createBodyLayer); event.registerLayerDefinition(FurnaceBackpackModel.LAYER, FurnaceBackpackModel::createBodyLayer); diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/model/CChessModel.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/model/CChessModel.java new file mode 100644 index 000000000..bcb38043f --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/model/CChessModel.java @@ -0,0 +1,45 @@ +package com.github.tartaricacid.touhoulittlemaid.client.model; + +import com.github.tartaricacid.touhoulittlemaid.TouhouLittleMaid; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.model.EntityModel; +import net.minecraft.client.model.geom.ModelLayerLocation; +import net.minecraft.client.model.geom.ModelPart; +import net.minecraft.client.model.geom.PartPose; +import net.minecraft.client.model.geom.builders.*; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.Entity; + +public class CChessModel extends EntityModel { + public static final ModelLayerLocation LAYER = new ModelLayerLocation(ResourceLocation.fromNamespaceAndPath(TouhouLittleMaid.MOD_ID, "main"), "cchess"); + private final ModelPart main; + + public CChessModel(ModelPart root) { + this.main = root.getChild("main"); + } + + public static LayerDefinition createBodyLayer() { + MeshDefinition meshdefinition = new MeshDefinition(); + PartDefinition partdefinition = meshdefinition.getRoot(); + + PartDefinition main = partdefinition.addOrReplaceChild("main", CubeListBuilder.create().texOffs(0, 0).addBox(-32.0F, -18.0F, -32.0F, 64.0F, 18.0F, 64.0F, new CubeDeformation(-8.0F)), PartPose.offset(0.0F, 32.0F, 0.0F)); + + PartDefinition bone = main.addOrReplaceChild("bone", CubeListBuilder.create().texOffs(0, 82).addBox(-28.5F, -16.05F, -16.0F, 32.0F, 32.0F, 32.0F, new CubeDeformation(-14.0F)) + .texOffs(128, 82).addBox(-23.75F, -16.05F, -16.0F, 32.0F, 32.0F, 32.0F, new CubeDeformation(-14.0F)), PartPose.offset(-2.125F, -8.0F, 0.0F)); + + PartDefinition bone2 = main.addOrReplaceChild("bone2", CubeListBuilder.create().texOffs(0, 146).mirror().addBox(-3.5F, -16.05F, -16.0F, 32.0F, 32.0F, 32.0F, new CubeDeformation(-14.0F)).mirror(false) + .texOffs(128, 146).mirror().addBox(-8.25F, -16.05F, -16.0F, 32.0F, 32.0F, 32.0F, new CubeDeformation(-14.0F)).mirror(false), PartPose.offset(-2.675F, -8.0F, 0.0F)); + + return LayerDefinition.create(meshdefinition, 256, 256); + } + + @Override + public void setupAnim(Entity entity, float limbSwing, float limbSwingAmount, float ageInTicks, float netHeadYaw, float headPitch) { + } + + @Override + public void renderToBuffer(PoseStack poseStack, VertexConsumer vertexConsumer, int packedLight, int packedOverlay, int color) { + main.render(poseStack, vertexConsumer, packedLight, packedOverlay, color); + } +} diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/model/CChessPiecesModel.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/model/CChessPiecesModel.java new file mode 100644 index 000000000..ed364f93c --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/model/CChessPiecesModel.java @@ -0,0 +1,65 @@ +package com.github.tartaricacid.touhoulittlemaid.client.model; + +import com.github.tartaricacid.touhoulittlemaid.TouhouLittleMaid; +import com.github.tartaricacid.touhoulittlemaid.client.model.bedrock.BedrockModel; +import com.github.tartaricacid.touhoulittlemaid.client.model.bedrock.BedrockPart; +import com.github.tartaricacid.touhoulittlemaid.client.model.pojo.BedrockModelPOJO; +import com.github.tartaricacid.touhoulittlemaid.client.resource.CustomPackLoader; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.Minecraft; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.LivingEntity; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; + +public class CChessPiecesModel { + private static final ResourceLocation MODEL = ResourceLocation.fromNamespaceAndPath(TouhouLittleMaid.MOD_ID, "models/entity/cchess_pieces.json"); + private static BedrockModel bedrockModel; + private final BedrockPart main; + + public CChessPiecesModel(String name) { + this.main = bedrockModel.getModelMap().get(name).getModelRenderer(); + } + + public static CChessPiecesModel[] initModel() { + Minecraft.getInstance().getResourceManager().getResource(MODEL).ifPresent(res -> { + try (InputStream stream = res.open()) { + BedrockModelPOJO pojo = CustomPackLoader.GSON.fromJson(new InputStreamReader(stream, StandardCharsets.UTF_8), BedrockModelPOJO.class); + bedrockModel = new BedrockModel<>(pojo, BedrockVersion.NEW); + } catch (IOException ignore) { + } + }); + + CChessPiecesModel[] models = new CChessPiecesModel[23]; + + models[8] = new CChessPiecesModel("ShuaiRed"); + models[9] = new CChessPiecesModel("ShiRed"); + models[10] = new CChessPiecesModel("XiangRed"); + models[11] = new CChessPiecesModel("MaRed"); + models[12] = new CChessPiecesModel("JuRed"); + models[13] = new CChessPiecesModel("PaoRed"); + models[14] = new CChessPiecesModel("BingRed"); + + models[16] = new CChessPiecesModel("JiangBlack"); + models[17] = new CChessPiecesModel("ShiBlack"); + models[18] = new CChessPiecesModel("XiangBlack"); + models[19] = new CChessPiecesModel("MaBlack"); + models[20] = new CChessPiecesModel("JuBlack"); + models[21] = new CChessPiecesModel("PaoBlack"); + models[22] = new CChessPiecesModel("ZuBlack"); + + return models; + } + + public static CChessPiecesModel getSelectedModel() { + return new CChessPiecesModel("Selected"); + } + + public void renderToBuffer(PoseStack poseStack, VertexConsumer vertexConsumer, int packedLight, int packedOverlay, float red, float green, float blue, float alpha) { + main.render(poseStack, vertexConsumer, packedLight, packedOverlay, red, green, blue, alpha); + } +} diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/model/WChessModel.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/model/WChessModel.java new file mode 100644 index 000000000..b67d72b5f --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/model/WChessModel.java @@ -0,0 +1,39 @@ +package com.github.tartaricacid.touhoulittlemaid.client.model; + +import com.github.tartaricacid.touhoulittlemaid.TouhouLittleMaid; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.model.EntityModel; +import net.minecraft.client.model.geom.ModelLayerLocation; +import net.minecraft.client.model.geom.ModelPart; +import net.minecraft.client.model.geom.PartPose; +import net.minecraft.client.model.geom.builders.*; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.Entity; + +public class WChessModel extends EntityModel { + public static final ModelLayerLocation LAYER = new ModelLayerLocation(ResourceLocation.fromNamespaceAndPath(TouhouLittleMaid.MOD_ID, "main"), "wchess"); + private final ModelPart main; + + public WChessModel(ModelPart root) { + this.main = root.getChild("main"); + } + + public static LayerDefinition createBodyLayer() { + MeshDefinition meshdefinition = new MeshDefinition(); + PartDefinition partdefinition = meshdefinition.getRoot(); + + PartDefinition main = partdefinition.addOrReplaceChild("main", CubeListBuilder.create().texOffs(0, 0).addBox(-24.0F, -2.0F, -24.0F, 48.0F, 2.0F, 48.0F, new CubeDeformation(0.0F)), PartPose.offset(0.0F, 24.0F, 0.0F)); + + return LayerDefinition.create(meshdefinition, 256, 256); + } + + @Override + public void setupAnim(Entity entity, float limbSwing, float limbSwingAmount, float ageInTicks, float netHeadYaw, float headPitch) { + } + + @Override + public void renderToBuffer(PoseStack poseStack, VertexConsumer vertexConsumer, int packedLight, int packedOverlay, int color) { + main.render(poseStack, vertexConsumer, packedLight, packedOverlay, color); + } +} diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/model/WChessPiecesModel.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/model/WChessPiecesModel.java new file mode 100644 index 000000000..6a13b7132 --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/model/WChessPiecesModel.java @@ -0,0 +1,87 @@ +package com.github.tartaricacid.touhoulittlemaid.client.model; + +import com.github.tartaricacid.touhoulittlemaid.TouhouLittleMaid; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import net.minecraft.client.model.EntityModel; +import net.minecraft.client.model.geom.ModelLayerLocation; +import net.minecraft.client.model.geom.ModelPart; +import net.minecraft.client.model.geom.PartPose; +import net.minecraft.client.model.geom.builders.*; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.Entity; + +public class WChessPiecesModel extends EntityModel { + public static final ModelLayerLocation LAYER = new ModelLayerLocation(ResourceLocation.fromNamespaceAndPath(TouhouLittleMaid.MOD_ID, "main"), "wchess_pieces"); + private final ModelPart main; + + public WChessPiecesModel(ModelPart root, String name) { + this.main = root.getChild(name); + } + + public static WChessPiecesModel[] initModel(ModelPart root) { + WChessPiecesModel[] models = new WChessPiecesModel[23]; + + models[8] = new WChessPiecesModel(root, "KING_W"); + models[9] = new WChessPiecesModel(root, "QUEEN_W"); + models[10] = new WChessPiecesModel(root, "ROOK_W"); + models[11] = new WChessPiecesModel(root, "BISHOP_W"); + models[12] = new WChessPiecesModel(root, "KNIGHT_W"); + models[13] = new WChessPiecesModel(root, "PAWN_W"); + + models[16] = new WChessPiecesModel(root, "KING_B"); + models[17] = new WChessPiecesModel(root, "QUEEN_B"); + models[18] = new WChessPiecesModel(root, "ROOK_B"); + models[19] = new WChessPiecesModel(root, "BISHOP_B"); + models[20] = new WChessPiecesModel(root, "KNIGHT_B"); + models[21] = new WChessPiecesModel(root, "PAWN_B"); + + return models; + } + + public static WChessPiecesModel getSelectedModel(ModelPart root) { + return new WChessPiecesModel(root, "SLECT"); + } + + public static LayerDefinition createBodyLayer() { + MeshDefinition meshdefinition = new MeshDefinition(); + PartDefinition partdefinition = meshdefinition.getRoot(); + + PartDefinition KING_W = partdefinition.addOrReplaceChild("KING_W", CubeListBuilder.create().texOffs(0, 0).addBox(-2.0F, -0.9F, -2.0F, 4.0F, 1.0F, 4.0F, new CubeDeformation(-0.1F)), PartPose.offset(0.0F, 24.0F, 0.0F)); + + PartDefinition QUEEN_W = partdefinition.addOrReplaceChild("QUEEN_W", CubeListBuilder.create().texOffs(0, 5).addBox(-2.0F, -0.9F, -2.0F, 4.0F, 1.0F, 4.0F, new CubeDeformation(-0.1F)), PartPose.offset(0.0F, 24.0F, 0.0F)); + + PartDefinition ROOK_W = partdefinition.addOrReplaceChild("ROOK_W", CubeListBuilder.create().texOffs(0, 10).addBox(-2.0F, -0.9F, -2.0F, 4.0F, 1.0F, 4.0F, new CubeDeformation(-0.1F)), PartPose.offset(0.0F, 24.0F, 0.0F)); + + PartDefinition BISHOP_W = partdefinition.addOrReplaceChild("BISHOP_W", CubeListBuilder.create().texOffs(0, 15).addBox(-2.0F, -0.9F, -2.0F, 4.0F, 1.0F, 4.0F, new CubeDeformation(-0.1F)), PartPose.offset(0.0F, 24.0F, 0.0F)); + + PartDefinition KNIGHT_W = partdefinition.addOrReplaceChild("KNIGHT_W", CubeListBuilder.create().texOffs(16, 0).addBox(-2.0F, -0.9F, -2.0F, 4.0F, 1.0F, 4.0F, new CubeDeformation(-0.1F)), PartPose.offset(0.0F, 24.0F, 0.0F)); + + PartDefinition PAWN_W = partdefinition.addOrReplaceChild("PAWN_W", CubeListBuilder.create().texOffs(16, 5).addBox(-2.0F, -0.9F, -2.0F, 4.0F, 1.0F, 4.0F, new CubeDeformation(-0.1F)), PartPose.offset(0.0F, 24.0F, 0.0F)); + + PartDefinition KING_B = partdefinition.addOrReplaceChild("KING_B", CubeListBuilder.create().texOffs(16, 10).addBox(-2.0F, -0.9F, -2.0F, 4.0F, 1.0F, 4.0F, new CubeDeformation(-0.1F)), PartPose.offset(0.0F, 24.0F, 0.0F)); + + PartDefinition QUEEN_B = partdefinition.addOrReplaceChild("QUEEN_B", CubeListBuilder.create().texOffs(16, 15).addBox(-2.0F, -0.9F, -2.0F, 4.0F, 1.0F, 4.0F, new CubeDeformation(-0.1F)), PartPose.offset(0.0F, 24.0F, 0.0F)); + + PartDefinition ROOK_B = partdefinition.addOrReplaceChild("ROOK_B", CubeListBuilder.create().texOffs(0, 20).addBox(-2.0F, -0.9F, -2.0F, 4.0F, 1.0F, 4.0F, new CubeDeformation(-0.1F)), PartPose.offset(0.0F, 24.0F, 0.0F)); + + PartDefinition BISHOP_B = partdefinition.addOrReplaceChild("BISHOP_B", CubeListBuilder.create().texOffs(16, 20).addBox(-2.0F, -0.9F, -2.0F, 4.0F, 1.0F, 4.0F, new CubeDeformation(-0.1F)), PartPose.offset(0.0F, 24.0F, 0.0F)); + + PartDefinition KNIGHT_B = partdefinition.addOrReplaceChild("KNIGHT_B", CubeListBuilder.create().texOffs(0, 25).addBox(-2.0F, -0.9F, -2.0F, 4.0F, 1.0F, 4.0F, new CubeDeformation(-0.1F)), PartPose.offset(0.0F, 24.0F, 0.0F)); + + PartDefinition PAWN_B = partdefinition.addOrReplaceChild("PAWN_B", CubeListBuilder.create().texOffs(16, 25).addBox(-2.0F, -0.9F, -2.0F, 4.0F, 1.0F, 4.0F, new CubeDeformation(-0.1F)), PartPose.offset(0.0F, 24.0F, 0.0F)); + + PartDefinition SLECT = partdefinition.addOrReplaceChild("SLECT", CubeListBuilder.create().texOffs(8, 0).addBox(-2.0F, -1.0F, -2.0F, 4.0F, 0.0F, 4.0F, new CubeDeformation(0.0F)), PartPose.offset(0.0F, 24.0F, 0.0F)); + + return LayerDefinition.create(meshdefinition, 32, 32); + } + + @Override + public void renderToBuffer(PoseStack poseStack, VertexConsumer vertexConsumer, int packedLight, int packedOverlay, int color) { + main.render(poseStack, vertexConsumer, packedLight, packedOverlay, color); + } + + @Override + public void setupAnim(Entity pEntity, float pLimbSwing, float pLimbSwingAmount, float pAgeInTicks, float pNetHeadYaw, float pHeadPitch) { + } +} diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/model/bedrock/BedrockModel.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/model/bedrock/BedrockModel.java index e8ffe1539..487fe0426 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/model/bedrock/BedrockModel.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/model/bedrock/BedrockModel.java @@ -457,4 +457,8 @@ public void setAnimations(@Nullable List animations) { public AABB getRenderBoundingBox() { return renderBoundingBox; } + + public HashMap getModelMap() { + return modelMap; + } } diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/renderer/entity/EntityMaidRenderer.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/renderer/entity/EntityMaidRenderer.java index 071146124..7b5ee4980 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/renderer/entity/EntityMaidRenderer.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/renderer/entity/EntityMaidRenderer.java @@ -10,7 +10,6 @@ import com.github.tartaricacid.touhoulittlemaid.client.resource.CustomPackLoader; import com.github.tartaricacid.touhoulittlemaid.client.resource.models.MaidModels; import com.github.tartaricacid.touhoulittlemaid.client.resource.pojo.MaidModelInfo; -import com.github.tartaricacid.touhoulittlemaid.config.subconfig.InGameMaidConfig; import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid; import com.google.common.collect.Lists; import com.mojang.blaze3d.vertex.PoseStack; @@ -77,7 +76,7 @@ public void render(Mob entity, float entityYaw, float partialTicks, PoseStack po // 渲染聊天气泡 EntityMaid maidEntity = maid.asStrictMaid(); // 暂定只能女仆显示 - if (maidEntity != null && InGameMaidConfig.INSTANCE.isShowChatBubble()) { + if (maidEntity != null && maidEntity.getConfigManager().isChatBubbleShow()) { ChatBubbleRenderer.renderChatBubble(this, maidEntity, poseStack, bufferIn, packedLightIn); } diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/renderer/entity/geckolayer/GeckoLayerMaidBackItem.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/renderer/entity/geckolayer/GeckoLayerMaidBackItem.java index 67854aae8..0b398851e 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/renderer/entity/geckolayer/GeckoLayerMaidBackItem.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/renderer/entity/geckolayer/GeckoLayerMaidBackItem.java @@ -3,8 +3,8 @@ import com.github.tartaricacid.touhoulittlemaid.api.entity.IMaid; import com.github.tartaricacid.touhoulittlemaid.client.renderer.entity.GeckoEntityMaidRenderer; import com.github.tartaricacid.touhoulittlemaid.compat.carryon.RenderFixer; -import com.github.tartaricacid.touhoulittlemaid.config.subconfig.InGameMaidConfig; import com.github.tartaricacid.touhoulittlemaid.entity.backpack.BackpackManager; +import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid; import com.github.tartaricacid.touhoulittlemaid.geckolib3.geo.GeoLayerRenderer; import com.github.tartaricacid.touhoulittlemaid.geckolib3.util.RenderUtils; import com.mojang.blaze3d.vertex.PoseStack; @@ -33,7 +33,10 @@ public void render(PoseStack matrixStack, MultiBufferSource bufferIn, int packed return; } ItemStack stack = maid.getBackpackShowItem(); - if (!this.entityRenderer.getAnimatableEntity(entity).getMaidInfo().isShowBackpack() || !InGameMaidConfig.INSTANCE.isShowBackItem() || entity.isSleeping() || entity.isInvisible() || RenderFixer.isCarryOnRender(stack, bufferIn)) { + if (!this.entityRenderer.getAnimatableEntity(entity).getMaidInfo().isShowBackpack() || entity.isSleeping() || entity.isInvisible() || RenderFixer.isCarryOnRender(stack, bufferIn)) { + return; + } + if (entity instanceof EntityMaid entityMaid && !entityMaid.getConfigManager().isShowBackItem()) { return; } if (stack.getItem() instanceof TieredItem) { @@ -46,7 +49,7 @@ public void render(PoseStack matrixStack, MultiBufferSource bufferIn, int packed matrixStack.mulPose(Axis.XP.rotationDegrees(180.0F)); matrixStack.translate(0, 0.5, -0.25); - if (InGameMaidConfig.INSTANCE.isShowBackpack()) { + if (entity instanceof EntityMaid entityMaid && entityMaid.getConfigManager().isShowBackpack()) { maid.getMaidBackpackType().offsetBackpackItem(matrixStack); } else { BackpackManager.getEmptyBackpack().offsetBackpackItem(matrixStack); diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/renderer/entity/geckolayer/GeckoLayerMaidBackpack.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/renderer/entity/geckolayer/GeckoLayerMaidBackpack.java index 2bb91861b..febf1a4a9 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/renderer/entity/geckolayer/GeckoLayerMaidBackpack.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/renderer/entity/geckolayer/GeckoLayerMaidBackpack.java @@ -3,7 +3,6 @@ import com.github.tartaricacid.touhoulittlemaid.api.backpack.IMaidBackpack; import com.github.tartaricacid.touhoulittlemaid.api.entity.IMaid; import com.github.tartaricacid.touhoulittlemaid.client.renderer.entity.GeckoEntityMaidRenderer; -import com.github.tartaricacid.touhoulittlemaid.config.subconfig.InGameMaidConfig; import com.github.tartaricacid.touhoulittlemaid.entity.backpack.BackpackManager; import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid; import com.github.tartaricacid.touhoulittlemaid.geckolib3.geo.GeoLayerRenderer; @@ -46,7 +45,8 @@ public void render(PoseStack poseStack, MultiBufferSource bufferIn, int packedLi RenderUtils.prepMatrixForLocator(poseStack, model.backpackBones()); poseStack.translate(0, 1, 0.25); poseStack.mulPose(Axis.ZP.rotationDegrees(180)); - IMaidBackpack backpack = InGameMaidConfig.INSTANCE.isShowBackpack() ? maid.getMaidBackpackType() : BackpackManager.getEmptyBackpack(); + boolean showBackpack = entity instanceof EntityMaid entityMaid && entityMaid.getConfigManager().isShowBackpack(); + IMaidBackpack backpack = showBackpack ? maid.getMaidBackpackType() : BackpackManager.getEmptyBackpack(); BackpackManager.findBackpackModel(backpack.getId()).ifPresent(pair -> renderColoredCutoutModel(pair.getLeft(), pair.getRight(), poseStack, bufferIn, packedLightIn, maid, 1.0f, 1.0f, 1.0f)); poseStack.popPose(); } diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/renderer/entity/geckolayer/GeckoLayerMaidBanner.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/renderer/entity/geckolayer/GeckoLayerMaidBanner.java index 82c2efe74..1a1c3513c 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/renderer/entity/geckolayer/GeckoLayerMaidBanner.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/renderer/entity/geckolayer/GeckoLayerMaidBanner.java @@ -4,7 +4,7 @@ import com.github.tartaricacid.touhoulittlemaid.api.entity.IMaid; import com.github.tartaricacid.touhoulittlemaid.client.model.MaidBannerModel; import com.github.tartaricacid.touhoulittlemaid.client.renderer.entity.GeckoEntityMaidRenderer; -import com.github.tartaricacid.touhoulittlemaid.config.subconfig.InGameMaidConfig; +import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid; import com.github.tartaricacid.touhoulittlemaid.geckolib3.geo.GeoLayerRenderer; import com.github.tartaricacid.touhoulittlemaid.geckolib3.geo.animated.AnimatedGeoModel; import com.github.tartaricacid.touhoulittlemaid.geckolib3.util.RenderUtils; @@ -41,7 +41,10 @@ public void render(PoseStack matrixStack, MultiBufferSource bufferIn, int packed return; } if (maid.getBackpackShowItem().getItem() instanceof BannerItem bannerItem) { - if (!this.entityRenderer.getAnimatableEntity(entity).getMaidInfo().isShowBackpack() || !InGameMaidConfig.INSTANCE.isShowBackItem() || entity.isSleeping() || entity.isInvisible()) { + if (!this.entityRenderer.getAnimatableEntity(entity).getMaidInfo().isShowBackpack() || entity.isSleeping() || entity.isInvisible()) { + return; + } + if (entity instanceof EntityMaid entityMaid && !entityMaid.getConfigManager().isShowBackItem()) { return; } AnimatedGeoModel geoModel = this.entityRenderer.getAnimatableEntity(entity).getCurrentModel(); diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/renderer/entity/layer/LayerMaidBackItem.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/renderer/entity/layer/LayerMaidBackItem.java index a6d11654c..def5bee0b 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/renderer/entity/layer/LayerMaidBackItem.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/renderer/entity/layer/LayerMaidBackItem.java @@ -4,8 +4,8 @@ import com.github.tartaricacid.touhoulittlemaid.client.model.bedrock.BedrockModel; import com.github.tartaricacid.touhoulittlemaid.client.renderer.entity.EntityMaidRenderer; import com.github.tartaricacid.touhoulittlemaid.compat.carryon.RenderFixer; -import com.github.tartaricacid.touhoulittlemaid.config.subconfig.InGameMaidConfig; import com.github.tartaricacid.touhoulittlemaid.entity.backpack.BackpackManager; +import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.math.Axis; import net.minecraft.client.Minecraft; @@ -32,8 +32,11 @@ public void render(PoseStack matrixStack, MultiBufferSource bufferIn, int packed return; } ItemStack stack = maid.getBackpackShowItem(); - if (!renderer.getMainInfo().isShowBackpack() || !InGameMaidConfig.INSTANCE.isShowBackItem() - || mob.isSleeping() || mob.isInvisible() || RenderFixer.isCarryOnRender(stack, bufferIn)) { + if (!renderer.getMainInfo().isShowBackpack() || mob.isSleeping() + || mob.isInvisible() || RenderFixer.isCarryOnRender(stack, bufferIn)) { + return; + } + if (maid instanceof EntityMaid entityMaid && !entityMaid.getConfigManager().isShowBackItem()) { return; } @@ -42,7 +45,7 @@ public void render(PoseStack matrixStack, MultiBufferSource bufferIn, int packed matrixStack.mulPose(Axis.ZP.rotationDegrees(180.0F)); matrixStack.mulPose(Axis.XP.rotationDegrees(180.0F)); matrixStack.translate(0, 0.5, -0.25); - if (InGameMaidConfig.INSTANCE.isShowBackpack()) { + if (maid instanceof EntityMaid entityMaid && entityMaid.getConfigManager().isShowBackpack()) { maid.getMaidBackpackType().offsetBackpackItem(matrixStack); } else { BackpackManager.getEmptyBackpack().offsetBackpackItem(matrixStack); diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/renderer/entity/layer/LayerMaidBackpack.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/renderer/entity/layer/LayerMaidBackpack.java index cd958c052..ad2965ab9 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/renderer/entity/layer/LayerMaidBackpack.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/renderer/entity/layer/LayerMaidBackpack.java @@ -5,7 +5,6 @@ import com.github.tartaricacid.touhoulittlemaid.client.model.bedrock.BedrockModel; import com.github.tartaricacid.touhoulittlemaid.client.model.bedrock.BedrockPart; import com.github.tartaricacid.touhoulittlemaid.client.renderer.entity.EntityMaidRenderer; -import com.github.tartaricacid.touhoulittlemaid.config.subconfig.InGameMaidConfig; import com.github.tartaricacid.touhoulittlemaid.entity.backpack.BackpackManager; import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid; import com.mojang.blaze3d.vertex.PoseStack; @@ -43,7 +42,7 @@ public void render(PoseStack poseStack, MultiBufferSource bufferIn, int packedLi } else { poseStack.translate(0, -0.5, 0.25); } - IMaidBackpack type = InGameMaidConfig.INSTANCE.isShowBackpack() ? maid.getMaidBackpackType() : BackpackManager.getEmptyBackpack(); + IMaidBackpack type = maid.getConfigManager().isShowBackpack() ? maid.getMaidBackpackType() : BackpackManager.getEmptyBackpack(); BackpackManager.findBackpackModel(type.getId()).ifPresent(pair -> renderColoredCutoutModel(pair.getLeft(), pair.getRight(), poseStack, bufferIn, packedLightIn, maid, new Color(1.0f, 1.0f, 1.0f).getRGB())); } } diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/renderer/entity/layer/LayerMaidBanner.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/renderer/entity/layer/LayerMaidBanner.java index 786d87c8e..a14e8446a 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/renderer/entity/layer/LayerMaidBanner.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/renderer/entity/layer/LayerMaidBanner.java @@ -5,7 +5,7 @@ import com.github.tartaricacid.touhoulittlemaid.client.model.MaidBannerModel; import com.github.tartaricacid.touhoulittlemaid.client.model.bedrock.BedrockModel; import com.github.tartaricacid.touhoulittlemaid.client.renderer.entity.EntityMaidRenderer; -import com.github.tartaricacid.touhoulittlemaid.config.subconfig.InGameMaidConfig; +import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.VertexConsumer; import com.mojang.math.Axis; @@ -42,7 +42,10 @@ public void render(PoseStack matrixStack, MultiBufferSource bufferIn, int packed } ItemStack stack = maid.getBackpackShowItem(); if (stack.getItem() instanceof BannerItem bannerItem) { - if (!renderer.getMainInfo().isShowBackpack() || !InGameMaidConfig.INSTANCE.isShowBackItem() || mob.isSleeping() || mob.isInvisible()) { + if (!renderer.getMainInfo().isShowBackpack() || mob.isSleeping() || mob.isInvisible()) { + return; + } + if (maid instanceof EntityMaid entityMaid && !entityMaid.getConfigManager().isShowBackItem()) { return; } matrixStack.pushPose(); diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/renderer/tileentity/TileEntityCChessRenderer.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/renderer/tileentity/TileEntityCChessRenderer.java new file mode 100644 index 000000000..d1677fdcd --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/renderer/tileentity/TileEntityCChessRenderer.java @@ -0,0 +1,164 @@ +package com.github.tartaricacid.touhoulittlemaid.client.renderer.tileentity; + +import com.github.tartaricacid.touhoulittlemaid.TouhouLittleMaid; +import com.github.tartaricacid.touhoulittlemaid.api.game.xqwlight.Position; +import com.github.tartaricacid.touhoulittlemaid.block.BlockGomoku; +import com.github.tartaricacid.touhoulittlemaid.client.model.CChessModel; +import com.github.tartaricacid.touhoulittlemaid.client.model.CChessPiecesModel; +import com.github.tartaricacid.touhoulittlemaid.tileentity.TileEntityCChess; +import com.github.tartaricacid.touhoulittlemaid.util.CChessUtil; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.math.Axis; +import net.minecraft.ChatFormatting; +import net.minecraft.client.Camera; +import net.minecraft.client.gui.Font; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.blockentity.BlockEntityRenderDispatcher; +import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.resources.ResourceLocation; + +public class TileEntityCChessRenderer implements BlockEntityRenderer { + private static final ResourceLocation TEXTURE = ResourceLocation.fromNamespaceAndPath(TouhouLittleMaid.MOD_ID, "textures/entity/cchess.png"); + private static final ResourceLocation PIECES_TEXTURE = ResourceLocation.fromNamespaceAndPath(TouhouLittleMaid.MOD_ID, "textures/entity/cchess_pieces.png"); + private static final int TIPS_RENDER_DISTANCE = 16; + private static final int PIECE_RENDER_DISTANCE = 24; + private final Font font; + private final BlockEntityRenderDispatcher dispatcher; + private final CChessModel chessModel; + private final CChessPiecesModel[] chessPiecesModels; + private final CChessPiecesModel selectedModels; + + public TileEntityCChessRenderer(BlockEntityRendererProvider.Context context) { + chessModel = new CChessModel(context.bakeLayer(CChessModel.LAYER)); + chessPiecesModels = CChessPiecesModel.initModel(); + selectedModels = CChessPiecesModel.getSelectedModel(); + dispatcher = context.getBlockEntityRenderDispatcher(); + font = context.getFont(); + } + + @Override + public void render(TileEntityCChess cchess, float pPartialTick, PoseStack poseStack, MultiBufferSource bufferIn, int combinedLightIn, int combinedOverlayIn) { + Direction facing = cchess.getBlockState().getValue(BlockGomoku.FACING); + this.renderChessboard(poseStack, bufferIn, combinedLightIn, combinedOverlayIn, facing); + this.renderPiece(cchess, poseStack, bufferIn, combinedLightIn, combinedOverlayIn, facing); + this.renderTipsText(cchess, poseStack, bufferIn, combinedLightIn); + } + + private void renderTipsText(TileEntityCChess chess, PoseStack poseStack, MultiBufferSource bufferIn, int combinedLightIn) { + boolean showTips = chess.isCheckmate() || chess.isRepeat() || chess.isMoveNumberLimit(); + if (!showTips || !inRenderDistance(chess, TIPS_RENDER_DISTANCE)) { + return; + } + + Camera camera = this.dispatcher.camera; + MutableComponent loseTips = null; + MutableComponent resetTips = Component.translatable("message.touhou_little_maid.cchess.reset").withStyle(ChatFormatting.UNDERLINE).withStyle(ChatFormatting.AQUA); + MutableComponent roundText = Component.translatable("message.touhou_little_maid.gomoku.round", chess.getChessCounter()).withStyle(ChatFormatting.WHITE); + MutableComponent preRoundIcon = Component.literal("⏹ ").withStyle(ChatFormatting.GREEN); + MutableComponent postRoundIcon = Component.literal(" ⏹").withStyle(ChatFormatting.GREEN); + MutableComponent roundTips = preRoundIcon.append(roundText).append(postRoundIcon); + + if (chess.isCheckmate()) { + if (!chess.isPlayerTurn()) { + loseTips = Component.translatable("message.touhou_little_maid.gomoku.win").withStyle(ChatFormatting.BOLD).withStyle(ChatFormatting.DARK_PURPLE); + } else { + loseTips = Component.translatable("message.touhou_little_maid.gomoku.lose").withStyle(ChatFormatting.BOLD).withStyle(ChatFormatting.DARK_PURPLE); + } + } else if (chess.isMoveNumberLimit()) { + loseTips = Component.translatable("message.touhou_little_maid.cchess.move_limit").withStyle(ChatFormatting.BOLD).withStyle(ChatFormatting.DARK_PURPLE); + } else if (chess.isRepeat()) { + loseTips = Component.translatable("message.touhou_little_maid.cchess.repeat").withStyle(ChatFormatting.BOLD).withStyle(ChatFormatting.DARK_PURPLE); + } + if (loseTips == null) { + return; + } + + float loseTipsWidth = (float) (-this.font.width(loseTips) / 2); + float resetTipsWidth = (float) (-this.font.width(resetTips) / 2); + float roundTipsWidth = (float) (-this.font.width(roundTips) / 2); + poseStack.pushPose(); + poseStack.translate(0.5, 0.75, 0.5); + poseStack.mulPose(Axis.YN.rotationDegrees(180 + camera.getYRot())); + poseStack.mulPose(Axis.XN.rotationDegrees(camera.getXRot())); + poseStack.scale(0.03F, -0.03F, 0.03F); + this.font.drawInBatch(loseTips, loseTipsWidth, -10, 0xFFFFFF, true, poseStack.last().pose(), bufferIn, Font.DisplayMode.POLYGON_OFFSET, 0, combinedLightIn); + poseStack.scale(0.5F, 0.5F, 0.5F); + this.font.drawInBatch(roundTips, roundTipsWidth, -30, 0xFFFFFF, true, poseStack.last().pose(), bufferIn, Font.DisplayMode.POLYGON_OFFSET, 0, combinedLightIn); + this.font.drawInBatch(resetTips, resetTipsWidth, 0, 0xFFFFFF, true, poseStack.last().pose(), bufferIn, Font.DisplayMode.POLYGON_OFFSET, 0, combinedLightIn); + poseStack.popPose(); + } + + private void renderPiece(TileEntityCChess cchess, PoseStack poseStack, MultiBufferSource bufferIn, int combinedLightIn, int combinedOverlayIn, Direction facing) { + if (inRenderDistance(cchess, PIECE_RENDER_DISTANCE)) { + VertexConsumer piecesBuff = bufferIn.getBuffer(RenderType.entityCutoutNoCull(PIECES_TEXTURE)); + int selectX = Position.FILE_X(cchess.getSelectChessPoint()); + int selectY = Position.RANK_Y(cchess.getSelectChessPoint()); + byte[] data = cchess.getChessData().squares; + poseStack.pushPose(); + switch (facing) { + case NORTH: + poseStack.translate(1.365 + 0.5, 1.625, 1.370 + 0.5); + break; + case EAST: + poseStack.translate(-1.365 + 0.5, 1.625, 1.370 + 0.5); + break; + case WEST: + poseStack.translate(1.365 + 0.5, 1.625, -1.370 + 0.5); + break; + default: + poseStack.translate(-1.365 + 0.5, 1.625, -1.370 + 0.5); + break; + } + poseStack.mulPose(Axis.ZN.rotationDegrees(180)); + poseStack.mulPose(Axis.YN.rotationDegrees(facing.get2DDataValue() * 90)); + if (facing == Direction.SOUTH || facing == Direction.NORTH) { + poseStack.mulPose(Axis.YN.rotationDegrees(180)); + } + for (int y = Position.RANK_TOP; y <= Position.RANK_BOTTOM; y++) { + for (int x = Position.FILE_LEFT; x <= Position.FILE_RIGHT; x++) { + byte piecesIndex = data[Position.COORD_XY(x, y)]; + if (CChessUtil.isRed(piecesIndex) || CChessUtil.isBlack(piecesIndex)) { + CChessPiecesModel chessPiecesModel = this.chessPiecesModels[piecesIndex]; + chessPiecesModel.renderToBuffer(poseStack, piecesBuff, combinedLightIn, combinedOverlayIn, 1.0F, 1.0F, 1.0F, 1.0F); + if (selectX == x && selectY == y) { + selectedModels.renderToBuffer(poseStack, piecesBuff, combinedLightIn, combinedOverlayIn, 1.0F, 1.0F, 1.0F, 1.0F); + } + } + poseStack.translate(0.304, 0, 0); + } + poseStack.translate(-0.304 * 9, 0, -0.304); + } + poseStack.popPose(); + } + } + + private void renderChessboard(PoseStack poseStack, MultiBufferSource bufferIn, int combinedLightIn, int combinedOverlayIn, Direction facing) { + poseStack.pushPose(); + poseStack.translate(0.5, 1.5, 0.5); + poseStack.mulPose(Axis.ZN.rotationDegrees(180)); + poseStack.mulPose(Axis.YN.rotationDegrees(facing.get2DDataValue() * 90)); + if (facing == Direction.SOUTH || facing == Direction.NORTH) { + poseStack.mulPose(Axis.YN.rotationDegrees(180)); + } + VertexConsumer checkerBoardBuff = bufferIn.getBuffer(RenderType.entityCutoutNoCull(TEXTURE)); + chessModel.renderToBuffer(poseStack, checkerBoardBuff, combinedLightIn, combinedOverlayIn); + poseStack.popPose(); + } + + private boolean inRenderDistance(TileEntityCChess chess, int distance) { + BlockPos pos = chess.getBlockPos(); + return this.dispatcher.camera.getPosition().distanceToSqr(pos.getX(), pos.getY(), pos.getZ()) < distance * distance; + } + + @Override + public boolean shouldRenderOffScreen(TileEntityCChess te) { + return true; + } +} diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/renderer/tileentity/TileEntityWChessRenderer.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/renderer/tileentity/TileEntityWChessRenderer.java new file mode 100644 index 000000000..f2404d9ba --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/client/renderer/tileentity/TileEntityWChessRenderer.java @@ -0,0 +1,164 @@ +package com.github.tartaricacid.touhoulittlemaid.client.renderer.tileentity; + +import com.github.tartaricacid.touhoulittlemaid.TouhouLittleMaid; +import com.github.tartaricacid.touhoulittlemaid.api.game.chess.Position; +import com.github.tartaricacid.touhoulittlemaid.block.BlockGomoku; +import com.github.tartaricacid.touhoulittlemaid.client.model.WChessModel; +import com.github.tartaricacid.touhoulittlemaid.client.model.WChessPiecesModel; +import com.github.tartaricacid.touhoulittlemaid.tileentity.TileEntityWChess; +import com.github.tartaricacid.touhoulittlemaid.util.WChessUtil; +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.VertexConsumer; +import com.mojang.math.Axis; +import net.minecraft.ChatFormatting; +import net.minecraft.client.Camera; +import net.minecraft.client.gui.Font; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.blockentity.BlockEntityRenderDispatcher; +import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.resources.ResourceLocation; + +public class TileEntityWChessRenderer implements BlockEntityRenderer { + private static final ResourceLocation TEXTURE = ResourceLocation.fromNamespaceAndPath(TouhouLittleMaid.MOD_ID, "textures/entity/wchess.png"); + private static final ResourceLocation PIECES_TEXTURE = ResourceLocation.fromNamespaceAndPath(TouhouLittleMaid.MOD_ID, "textures/entity/wchess_pieces.png"); + private static final int TIPS_RENDER_DISTANCE = 16; + private static final int PIECE_RENDER_DISTANCE = 24; + private final Font font; + private final BlockEntityRenderDispatcher dispatcher; + private final WChessModel chessModel; + private final WChessPiecesModel[] chessPiecesModels; + private final WChessPiecesModel selectedModels; + + public TileEntityWChessRenderer(BlockEntityRendererProvider.Context context) { + chessModel = new WChessModel(context.bakeLayer(WChessModel.LAYER)); + chessPiecesModels = WChessPiecesModel.initModel(context.bakeLayer(WChessPiecesModel.LAYER)); + selectedModels = WChessPiecesModel.getSelectedModel(context.bakeLayer(WChessPiecesModel.LAYER)); + dispatcher = context.getBlockEntityRenderDispatcher(); + font = context.getFont(); + } + + @Override + public void render(TileEntityWChess cchess, float pPartialTick, PoseStack poseStack, MultiBufferSource bufferIn, int combinedLightIn, int combinedOverlayIn) { + Direction facing = cchess.getBlockState().getValue(BlockGomoku.FACING); + this.renderChessboard(poseStack, bufferIn, combinedLightIn, combinedOverlayIn, facing); + this.renderPiece(cchess, poseStack, bufferIn, combinedLightIn, combinedOverlayIn, facing); + this.renderTipsText(cchess, poseStack, bufferIn, combinedLightIn); + } + + private void renderTipsText(TileEntityWChess chess, PoseStack poseStack, MultiBufferSource bufferIn, int combinedLightIn) { + boolean showTips = chess.isCheckmate() || chess.isRepeat() || chess.isMoveNumberLimit(); + if (!showTips || !inRenderDistance(chess, TIPS_RENDER_DISTANCE)) { + return; + } + + Camera camera = this.dispatcher.camera; + MutableComponent loseTips = null; + MutableComponent resetTips = Component.translatable("message.touhou_little_maid.wchess.reset").withStyle(ChatFormatting.UNDERLINE).withStyle(ChatFormatting.AQUA); + MutableComponent roundText = Component.translatable("message.touhou_little_maid.gomoku.round", chess.getChessCounter()).withStyle(ChatFormatting.WHITE); + MutableComponent preRoundIcon = Component.literal("⏹ ").withStyle(ChatFormatting.GREEN); + MutableComponent postRoundIcon = Component.literal(" ⏹").withStyle(ChatFormatting.GREEN); + MutableComponent roundTips = preRoundIcon.append(roundText).append(postRoundIcon); + + if (chess.isCheckmate()) { + if (!chess.isPlayerTurn()) { + loseTips = Component.translatable("message.touhou_little_maid.gomoku.win").withStyle(ChatFormatting.BOLD).withStyle(ChatFormatting.DARK_PURPLE); + } else { + loseTips = Component.translatable("message.touhou_little_maid.gomoku.lose").withStyle(ChatFormatting.BOLD).withStyle(ChatFormatting.DARK_PURPLE); + } + } else if (chess.isMoveNumberLimit()) { + loseTips = Component.translatable("message.touhou_little_maid.cchess.move_limit").withStyle(ChatFormatting.BOLD).withStyle(ChatFormatting.DARK_PURPLE); + } else if (chess.isRepeat()) { + loseTips = Component.translatable("message.touhou_little_maid.cchess.repeat").withStyle(ChatFormatting.BOLD).withStyle(ChatFormatting.DARK_PURPLE); + } + if (loseTips == null) { + return; + } + + float loseTipsWidth = (float) (-this.font.width(loseTips) / 2); + float resetTipsWidth = (float) (-this.font.width(resetTips) / 2); + float roundTipsWidth = (float) (-this.font.width(roundTips) / 2); + poseStack.pushPose(); + poseStack.translate(0.5, 0.75, 0.5); + poseStack.mulPose(Axis.YN.rotationDegrees(180 + camera.getYRot())); + poseStack.mulPose(Axis.XN.rotationDegrees(camera.getXRot())); + poseStack.scale(0.03F, -0.03F, 0.03F); + this.font.drawInBatch(loseTips, loseTipsWidth, -10, 0xFFFFFF, true, poseStack.last().pose(), bufferIn, Font.DisplayMode.POLYGON_OFFSET, 0, combinedLightIn); + poseStack.scale(0.5F, 0.5F, 0.5F); + this.font.drawInBatch(roundTips, roundTipsWidth, -30, 0xFFFFFF, true, poseStack.last().pose(), bufferIn, Font.DisplayMode.POLYGON_OFFSET, 0, combinedLightIn); + this.font.drawInBatch(resetTips, resetTipsWidth, 0, 0xFFFFFF, true, poseStack.last().pose(), bufferIn, Font.DisplayMode.POLYGON_OFFSET, 0, combinedLightIn); + poseStack.popPose(); + } + + private void renderPiece(TileEntityWChess cchess, PoseStack poseStack, MultiBufferSource bufferIn, int combinedLightIn, int combinedOverlayIn, Direction facing) { + if (inRenderDistance(cchess, PIECE_RENDER_DISTANCE)) { + VertexConsumer piecesBuff = bufferIn.getBuffer(RenderType.entityCutoutNoCull(PIECES_TEXTURE)); + int selectX = Position.FILE_X(cchess.getSelectChessPoint()); + int selectY = Position.RANK_Y(cchess.getSelectChessPoint()); + byte[] data = cchess.getChessData().squares; + poseStack.pushPose(); + switch (facing) { + case NORTH: + poseStack.translate(0.875 + 0.5, 1.625, 0.875 + 0.5); + break; + case EAST: + poseStack.translate(-0.875 + 0.5, 1.625, 0.875 + 0.5); + break; + case WEST: + poseStack.translate(0.875 + 0.5, 1.625, -0.875 + 0.5); + break; + default: + poseStack.translate(-0.875 + 0.5, 1.625, -0.875 + 0.5); + break; + } + poseStack.mulPose(Axis.ZN.rotationDegrees(180)); + poseStack.mulPose(Axis.YN.rotationDegrees(facing.get2DDataValue() * 90)); + if (facing == Direction.SOUTH || facing == Direction.NORTH) { + poseStack.mulPose(Axis.YN.rotationDegrees(180)); + } + for (int y = Position.RANK_TOP; y <= Position.RANK_BOTTOM; y++) { + for (int x = Position.FILE_LEFT; x <= Position.FILE_RIGHT; x++) { + byte piecesIndex = data[Position.COORD_XY(x, y)]; + if (WChessUtil.isWhite(piecesIndex) || WChessUtil.isBlack(piecesIndex)) { + WChessPiecesModel chessPiecesModel = this.chessPiecesModels[piecesIndex]; + chessPiecesModel.renderToBuffer(poseStack, piecesBuff, combinedLightIn, combinedOverlayIn); + if (selectX == x && selectY == y) { + selectedModels.renderToBuffer(poseStack, piecesBuff, combinedLightIn, combinedOverlayIn); + } + } + poseStack.translate(0.25, 0, 0); + } + poseStack.translate(-0.25 * 8, 0, -0.25); + } + poseStack.popPose(); + } + } + + private void renderChessboard(PoseStack poseStack, MultiBufferSource bufferIn, int combinedLightIn, int combinedOverlayIn, Direction facing) { + poseStack.pushPose(); + poseStack.translate(0.5, 1.5, 0.5); + poseStack.mulPose(Axis.ZN.rotationDegrees(180)); + poseStack.mulPose(Axis.YN.rotationDegrees(facing.get2DDataValue() * 90)); + if (facing == Direction.SOUTH || facing == Direction.NORTH) { + poseStack.mulPose(Axis.YN.rotationDegrees(180)); + } + VertexConsumer checkerBoardBuff = bufferIn.getBuffer(RenderType.entityCutoutNoCull(TEXTURE)); + chessModel.renderToBuffer(poseStack, checkerBoardBuff, combinedLightIn, combinedOverlayIn); + poseStack.popPose(); + } + + private boolean inRenderDistance(TileEntityWChess chess, int distance) { + BlockPos pos = chess.getBlockPos(); + return this.dispatcher.camera.getPosition().distanceToSqr(pos.getX(), pos.getY(), pos.getZ()) < distance * distance; + } + + @Override + public boolean shouldRenderOffScreen(TileEntityWChess te) { + return true; + } +} diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/compat/aquaculture/entity/AquacultureFishingHook.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/compat/aquaculture/entity/AquacultureFishingHook.java index c391d716f..eddafdd80 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/compat/aquaculture/entity/AquacultureFishingHook.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/compat/aquaculture/entity/AquacultureFishingHook.java @@ -165,6 +165,7 @@ private List getAquaLoot(MinecraftServer server, LootParams lootParam @Override protected void afterFishing() { + super.afterFishing(); ItemStackHandler rodHandler = AquaFishingRodItem.getHandler(this.fishingRod); ItemStack bait = rodHandler.getStackInSlot(1); if (!bait.isEmpty()) { diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/config/subconfig/InGameMaidConfig.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/config/subconfig/InGameMaidConfig.java deleted file mode 100644 index 79aff9a0e..000000000 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/config/subconfig/InGameMaidConfig.java +++ /dev/null @@ -1,84 +0,0 @@ -package com.github.tartaricacid.touhoulittlemaid.config.subconfig; - -import com.github.tartaricacid.touhoulittlemaid.client.resource.CustomPackLoader; -import com.google.gson.annotations.SerializedName; -import net.minecraft.client.Minecraft; -import net.neoforged.api.distmarker.Dist; -import net.neoforged.api.distmarker.OnlyIn; -import org.apache.commons.io.FileUtils; - -import java.io.File; -import java.io.IOException; -import java.io.InputStreamReader; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; - -@OnlyIn(Dist.CLIENT) -public class InGameMaidConfig { - private static final File CONFIG_FILE = Minecraft.getInstance().gameDirectory.toPath().resolve("config").resolve("touhou_little_maid").resolve("in_game_maid_config.json").toFile(); - public static InGameMaidConfig INSTANCE; - - @SerializedName("sound_frequency") - private double soundFrequency = 1.0; - - @SerializedName("show_chat_bubble") - private boolean showChatBubble = true; - - @SerializedName("show_backpack") - private boolean showBackpack = true; - - @SerializedName("show_back_item") - private boolean showBackItem = true; - - public static void read() { - if (CONFIG_FILE.isFile()) { - try (InputStreamReader reader = new InputStreamReader(Files.newInputStream(CONFIG_FILE.toPath()), StandardCharsets.UTF_8)) { - INSTANCE = CustomPackLoader.GSON.fromJson(reader, InGameMaidConfig.class); - } catch (IOException e) { - e.printStackTrace(); - } - } else { - INSTANCE = new InGameMaidConfig(); - } - } - - public static void save() { - try { - FileUtils.write(CONFIG_FILE, CustomPackLoader.GSON.toJson(INSTANCE), StandardCharsets.UTF_8); - } catch (IOException e) { - e.printStackTrace(); - } - } - - public double getSoundFrequency() { - return soundFrequency; - } - - public void setSoundFrequency(double soundFrequency) { - this.soundFrequency = soundFrequency; - } - - public boolean isShowChatBubble() { - return showChatBubble; - } - - public void setShowChatBubble(boolean showChatBubble) { - this.showChatBubble = showChatBubble; - } - - public boolean isShowBackpack() { - return showBackpack; - } - - public void setShowBackpack(boolean showBackpack) { - this.showBackpack = showBackpack; - } - - public boolean isShowBackItem() { - return showBackItem; - } - - public void setShowBackItem(boolean showBackItem) { - this.showBackItem = showBackItem; - } -} \ No newline at end of file diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/datagen/AdvancementDataGen.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/datagen/AdvancementDataGen.java index 31f20180c..bddb7ae84 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/datagen/AdvancementDataGen.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/datagen/AdvancementDataGen.java @@ -1,7 +1,11 @@ package com.github.tartaricacid.touhoulittlemaid.datagen; import com.github.tartaricacid.touhoulittlemaid.TouhouLittleMaid; -import com.github.tartaricacid.touhoulittlemaid.advancements.GiveSmartSlabConfigTrigger; +import com.github.tartaricacid.touhoulittlemaid.advancements.rewards.GiveSmartSlabConfigTrigger; +import com.github.tartaricacid.touhoulittlemaid.datagen.advancement.BaseAdvancement; +import com.github.tartaricacid.touhoulittlemaid.datagen.advancement.ChallengeAdvancement; +import com.github.tartaricacid.touhoulittlemaid.datagen.advancement.FavorabilityAdvancement; +import com.github.tartaricacid.touhoulittlemaid.datagen.advancement.MaidBaseAdvancement; import net.minecraft.advancements.Advancement; import net.minecraft.advancements.AdvancementHolder; import net.minecraft.advancements.AdvancementRewards; @@ -18,6 +22,7 @@ public class AdvancementDataGen extends AdvancementProvider { public AdvancementDataGen(PackOutput packOutput, CompletableFuture provider, ExistingFileHelper helper) { super(packOutput, provider, helper, List.of( + new MainAdvancement(), new GiveSmartSlab() )); } @@ -31,4 +36,14 @@ public void generate(HolderLookup.Provider provider, Consumer .save(saver, ResourceLocation.fromNamespaceAndPath(TouhouLittleMaid.MOD_ID, "give_smart_slab"), helper); } } + + private static final class MainAdvancement implements AdvancementGenerator { + @Override + public void generate(HolderLookup.Provider registries, Consumer saver, ExistingFileHelper existingFileHelper) { + BaseAdvancement.generate(saver, existingFileHelper); + MaidBaseAdvancement.generate(saver, existingFileHelper); + FavorabilityAdvancement.generate(saver, existingFileHelper); + ChallengeAdvancement.generate(saver, existingFileHelper); + } + } } diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/datagen/LootTableGenerator.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/datagen/LootTableGenerator.java index 0d8f2a073..fcbab2802 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/datagen/LootTableGenerator.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/datagen/LootTableGenerator.java @@ -12,6 +12,7 @@ import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.flag.FeatureFlags; +import net.minecraft.world.item.Items; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.properties.BedPart; import net.minecraft.world.level.block.state.properties.DoubleBlockHalf; @@ -28,6 +29,8 @@ public class LootTableGenerator { public static final ResourceKey ADDITIONAL_LOOT_TABLE = ResourceKey.create(Registries.LOOT_TABLE, ResourceLocation.fromNamespaceAndPath(TouhouLittleMaid.MOD_ID, "chests/additional_loot_table")); public static final ResourceKey GIVE_SMART_SLAB = ResourceKey.create(Registries.LOOT_TABLE, ResourceLocation.fromNamespaceAndPath(TouhouLittleMaid.MOD_ID, "give_smart_slab")); + public static final ResourceKey POWER_POINT = ResourceKey.create(Registries.LOOT_TABLE, ResourceLocation.fromNamespaceAndPath(TouhouLittleMaid.MOD_ID, "advancement/power_point")); + public static final ResourceKey CAKE = ResourceKey.create(Registries.LOOT_TABLE, ResourceLocation.fromNamespaceAndPath(TouhouLittleMaid.MOD_ID, "advancement/cake")); public record ChestLootTables(HolderLookup.Provider provider) implements LootTableSubProvider { @Override @@ -53,6 +56,14 @@ public void generate(BiConsumer, LootTable.Builder> consu .withPool(LootPool.lootPool() .setRolls(ConstantValue.exactly(1)) .add(LootItem.lootTableItem(InitItems.SMART_SLAB_INIT)))); + + consumer.accept(POWER_POINT, LootTable.lootTable().withPool(LootPool.lootPool() + .setRolls(ConstantValue.exactly(5)) + .add(LootItem.lootTableItem(InitItems.POWER_POINT.get())))); + + consumer.accept(CAKE, LootTable.lootTable().withPool(LootPool.lootPool() + .setRolls(ConstantValue.exactly(1)) + .add(LootItem.lootTableItem(Items.CAKE)))); } } diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/datagen/advancement/BaseAdvancement.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/datagen/advancement/BaseAdvancement.java new file mode 100644 index 000000000..8a54dabcb --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/datagen/advancement/BaseAdvancement.java @@ -0,0 +1,118 @@ +package com.github.tartaricacid.touhoulittlemaid.datagen.advancement; + +import com.github.tartaricacid.touhoulittlemaid.TouhouLittleMaid; +import com.github.tartaricacid.touhoulittlemaid.advancements.altar.AltarCraftTrigger; +import com.github.tartaricacid.touhoulittlemaid.advancements.maid.MaidEventTrigger; +import com.github.tartaricacid.touhoulittlemaid.advancements.maid.TriggerType; +import com.github.tartaricacid.touhoulittlemaid.datagen.LootTableGenerator; +import com.github.tartaricacid.touhoulittlemaid.init.InitEntities; +import com.github.tartaricacid.touhoulittlemaid.init.InitItems; +import com.github.tartaricacid.touhoulittlemaid.item.ItemEntityPlaceholder; +import net.minecraft.advancements.*; +import net.minecraft.advancements.critereon.EntityPredicate; +import net.minecraft.advancements.critereon.KilledTrigger; +import net.minecraft.advancements.critereon.RecipeCraftedTrigger; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.world.level.ItemLike; +import net.neoforged.neoforge.common.data.ExistingFileHelper; + +import java.util.function.Consumer; + + +public class BaseAdvancement { + public static void generate(Consumer saver, ExistingFileHelper existingFileHelper) { + AdvancementHolder root = make(InitItems.HAKUREI_GOHEI.get(), "craft_gohei") + .requirements(AdvancementRequirements.Strategy.OR) + .addCriterion("craft_hakurei_gohei", RecipeCraftedTrigger.TriggerInstance.craftedItem(id("hakurei_gohei"))) + .addCriterion("craft_sanae_gohei", RecipeCraftedTrigger.TriggerInstance.craftedItem(id("sanae_gohei"))) + .rewards(AdvancementRewards.Builder.experience(50)) + .save(saver, id("base/craft_gohei"), existingFileHelper); + + generateAltar(saver, existingFileHelper, root); + + generateMaid(saver, existingFileHelper, root); + + generateChair(saver, existingFileHelper, root); + } + + private static void generateChair(Consumer saver, ExistingFileHelper existingFileHelper, AdvancementHolder root) { + AdvancementHolder chair = make(InitItems.CHAIR.get(), "craft_chair").parent(root) + .addCriterion("craft_chair", RecipeCraftedTrigger.TriggerInstance.craftedItem(id("chair"))) + .save(saver, id("base/craft_chair"), existingFileHelper); + + make(InitItems.CHANGE_CHAIR_MODEL.get(), "change_chair_model").parent(chair) + .addCriterion("maid_event", MaidEventTrigger.create(TriggerType.CHANGE_CHAIR_MODEL)) + .save(saver, id("base/change_chair_model"), existingFileHelper); + } + + private static void generateMaid(Consumer saver, ExistingFileHelper existingFileHelper, AdvancementHolder root) { + ItemStack stack = ItemEntityPlaceholder.setRecipeId(new ItemStack(InitItems.ENTITY_PLACEHOLDER.get()), "spawn_box"); + AdvancementHolder spawnMaid = make(stack, "spawn_maid").parent(root) + .addCriterion("altar_craft", AltarCraftTrigger.Instance.recipe(id("altar_recipe/spawn_box"))) + .rewards(AdvancementRewards.Builder.loot(LootTableGenerator.CAKE)) + .save(saver, id("base/spawn_maid"), existingFileHelper); + + makeGoal(Items.CAKE, "tamed_maid").parent(spawnMaid) + .addCriterion("maid_event", MaidEventTrigger.create(TriggerType.TAMED_MAID)) + .save(saver, id("base/tamed_maid"), existingFileHelper); + + make(InitItems.CHANGE_MAID_MODEL.get(), "change_maid_model").parent(spawnMaid) + .addCriterion("maid_event", MaidEventTrigger.create(TriggerType.CHANGE_MAID_MODEL)) + .save(saver, id("base/change_maid_model"), existingFileHelper); + + make(Items.JUKEBOX, "change_maid_sound").parent(spawnMaid) + .addCriterion("maid_event", MaidEventTrigger.create(TriggerType.CHANGE_MAID_SOUND)) + .save(saver, id("base/change_maid_sound"), existingFileHelper); + } + + private static void generateAltar(Consumer saver, ExistingFileHelper existingFileHelper, AdvancementHolder root) { + AdvancementHolder altar = make(Items.RED_WOOL, "build_altar").parent(root) + .addCriterion("maid_event", MaidEventTrigger.create(TriggerType.BUILD_ALTAR)) + .rewards(AdvancementRewards.Builder.loot(LootTableGenerator.POWER_POINT)) + .save(saver, id("base/build_altar"), existingFileHelper); + + EntityPredicate.Builder predicate = EntityPredicate.Builder.entity().of(InitEntities.FAIRY.get()); + make(InitItems.FAIRY_SPAWN_EGG.get(), "kill_maid_fairy").parent(altar) + .addCriterion("killed_entity", KilledTrigger.TriggerInstance.playerKilledEntity(predicate)) + .save(saver, id("base/kill_maid_fairy"), existingFileHelper); + + make(InitItems.POWER_POINT.get(), "pickup_power_point").parent(altar) + .addCriterion("maid_event", MaidEventTrigger.create(TriggerType.PICKUP_POWER_POINT)) + .save(saver, id("base/pickup_power_point"), existingFileHelper); + } + + private static Advancement.Builder make(ItemLike item, String key) { + MutableComponent title = Component.translatable(String.format("advancements.touhou_little_maid.base.%s.title", key)); + MutableComponent desc = Component.translatable(String.format("advancements.touhou_little_maid.base.%s.description", key)); + + return Advancement.Builder.advancement().display(item, title, desc, + ResourceLocation.fromNamespaceAndPath(TouhouLittleMaid.MOD_ID, "textures/advancements/backgrounds/stone.png"), + AdvancementType.TASK, true, true, false); + } + + private static Advancement.Builder make(ItemStack item, String key) { + MutableComponent title = Component.translatable(String.format("advancements.touhou_little_maid.base.%s.title", key)); + MutableComponent desc = Component.translatable(String.format("advancements.touhou_little_maid.base.%s.description", key)); + + return Advancement.Builder.advancement().display(item, title, desc, + ResourceLocation.fromNamespaceAndPath(TouhouLittleMaid.MOD_ID, "textures/advancements/backgrounds/stone.png"), + AdvancementType.TASK, true, true, false); + } + + private static Advancement.Builder makeGoal(ItemLike item, String key) { + MutableComponent title = Component.translatable(String.format("advancements.touhou_little_maid.base.%s.title", key)); + MutableComponent desc = Component.translatable(String.format("advancements.touhou_little_maid.base.%s.description", key)); + + return Advancement.Builder.advancement().display(item, title, desc, + ResourceLocation.fromNamespaceAndPath(TouhouLittleMaid.MOD_ID, "textures/advancements/backgrounds/stone.png"), + AdvancementType.GOAL, true, true, false); + } + + private static ResourceLocation id(String id) { + return ResourceLocation.fromNamespaceAndPath(TouhouLittleMaid.MOD_ID, id); + } +} diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/datagen/advancement/ChallengeAdvancement.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/datagen/advancement/ChallengeAdvancement.java new file mode 100644 index 000000000..d33657bed --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/datagen/advancement/ChallengeAdvancement.java @@ -0,0 +1,123 @@ +package com.github.tartaricacid.touhoulittlemaid.datagen.advancement; + +import com.github.tartaricacid.touhoulittlemaid.TouhouLittleMaid; +import com.github.tartaricacid.touhoulittlemaid.advancements.maid.MaidEventTrigger; +import com.github.tartaricacid.touhoulittlemaid.advancements.maid.TriggerType; +import com.github.tartaricacid.touhoulittlemaid.init.InitItems; +import com.github.tartaricacid.touhoulittlemaid.item.ItemEntityPlaceholder; +import net.minecraft.advancements.Advancement; +import net.minecraft.advancements.AdvancementHolder; +import net.minecraft.advancements.AdvancementRewards; +import net.minecraft.advancements.AdvancementType; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.world.level.ItemLike; +import net.neoforged.neoforge.common.data.ExistingFileHelper; + +import java.util.function.Consumer; + + +public class ChallengeAdvancement { + public static void generate(Consumer saver, ExistingFileHelper existingFileHelper) { + AdvancementHolder root = make(Items.IRON_HELMET, "any_equipment") + .addCriterion("maid_event", MaidEventTrigger.create(TriggerType.ANY_EQUIPMENT)) + .save(saver, id("challenge/any_equipment"), existingFileHelper); + + generateProtect(root, saver, existingFileHelper); + + generateKill(root, saver, existingFileHelper); + } + + private static void generateProtect(AdvancementHolder root, Consumer saver, ExistingFileHelper existingFileHelper) { + AdvancementHolder protect = make(Items.ENCHANTED_GOLDEN_APPLE, "eat_enchanted_golden_apple").parent(root) + .addCriterion("maid_event", MaidEventTrigger.create(TriggerType.EAT_ENCHANTED_GOLDEN_APPLE)) + .save(saver, id("challenge/eat_enchanted_golden_apple"), existingFileHelper); + + makeChallenge(InitItems.ALL_NETHERITE_EQUIPMENT.get(), "all_netherite_equipment").parent(protect) + .rewards(AdvancementRewards.Builder.experience(50)) + .addCriterion("maid_event", MaidEventTrigger.create(TriggerType.ALL_NETHERITE_EQUIPMENT)) + .save(saver, id("challenge/all_netherite_equipment"), existingFileHelper); + + ItemStack stack = ItemEntityPlaceholder.setRecipeId(new ItemStack(InitItems.ENTITY_PLACEHOLDER.get()), "spawn_lightning_bolt"); + AdvancementHolder lightningBolt = make(stack, "lightning_bolt").parent(protect) + .addCriterion("maid_event", MaidEventTrigger.create(TriggerType.LIGHTNING_BOLT)) + .save(saver, id("challenge/lightning_bolt"), existingFileHelper); + + makeGoal(InitItems.MAID_100_HEALTHY.get(), "maid_100_healthy").parent(lightningBolt) + .addCriterion("maid_event", MaidEventTrigger.create(TriggerType.MAID_100_HEALTHY)) + .save(saver, id("challenge/maid_100_healthy"), existingFileHelper); + } + + private static void generateKill(AdvancementHolder root, Consumer saver, ExistingFileHelper existingFileHelper) { + AdvancementHolder kill = makeGoal(Items.DIAMOND_SWORD, "kill_100").parent(root) + .addCriterion("maid_event", MaidEventTrigger.create(TriggerType.KILL_100)) + .rewards(AdvancementRewards.Builder.experience(50)) + .save(saver, id("challenge/kill_100"), existingFileHelper); + + makeChallenge(InitItems.KILL_SLIME_300.get(), "kill_slime_300").parent(kill) + .addCriterion("maid_event", MaidEventTrigger.create(TriggerType.KILL_SLIME_300)) + .rewards(AdvancementRewards.Builder.experience(50)) + .save(saver, id("challenge/kill_slime_300"), existingFileHelper); + + AdvancementHolder wither = makeChallenge(InitItems.KILL_WITHER.get(), "kill_wither").parent(kill) + .addCriterion("maid_event", MaidEventTrigger.create(TriggerType.KILL_WITHER)) + .save(saver, id("challenge/kill_wither"), existingFileHelper); + + makeChallenge(InitItems.KILL_DRAGON.get(), "kill_dragon").parent(wither) + .addCriterion("maid_event", MaidEventTrigger.create(TriggerType.KILL_DRAGON)) + .save(saver, id("challenge/kill_dragon"), existingFileHelper); + } + + private static void generateOther(AdvancementHolder root, Consumer saver, ExistingFileHelper existingFileHelper) { + makeGoal(Items.ENCHANTED_BOOK, "maid_fishing_enchanted_book").parent(root) + .addCriterion("maid_event", MaidEventTrigger.create(TriggerType.MAID_FISHING_ENCHANTED_BOOK)) + .save(saver, id("challenge/maid_fishing_enchanted_book"), existingFileHelper); + + makeGoal(Items.CAKE, "tamed_maid_in_pillager_outpost").parent(root) + .addCriterion("maid_event", MaidEventTrigger.create(TriggerType.TAMED_MAID_FROM_STRUCTURE)) + .save(saver, id("challenge/tamed_maid_in_pillager_outpost"), existingFileHelper); + } + + private static Advancement.Builder make(ItemLike item, String key) { + MutableComponent title = Component.translatable(String.format("advancements.touhou_little_maid.challenge.%s.title", key)); + MutableComponent desc = Component.translatable(String.format("advancements.touhou_little_maid.challenge.%s.description", key)); + + return Advancement.Builder.advancement().display(item, title, desc, + ResourceLocation.fromNamespaceAndPath(TouhouLittleMaid.MOD_ID, "textures/advancements/backgrounds/stone.png"), + AdvancementType.TASK, true, true, false); + } + + private static Advancement.Builder make(ItemStack item, String key) { + MutableComponent title = Component.translatable(String.format("advancements.touhou_little_maid.challenge.%s.title", key)); + MutableComponent desc = Component.translatable(String.format("advancements.touhou_little_maid.challenge.%s.description", key)); + + return Advancement.Builder.advancement().display(item, title, desc, + ResourceLocation.fromNamespaceAndPath(TouhouLittleMaid.MOD_ID, "textures/advancements/backgrounds/stone.png"), + AdvancementType.TASK, true, true, false); + } + + private static Advancement.Builder makeGoal(ItemLike item, String key) { + MutableComponent title = Component.translatable(String.format("advancements.touhou_little_maid.challenge.%s.title", key)); + MutableComponent desc = Component.translatable(String.format("advancements.touhou_little_maid.challenge.%s.description", key)); + + return Advancement.Builder.advancement().display(item, title, desc, + ResourceLocation.fromNamespaceAndPath(TouhouLittleMaid.MOD_ID, "textures/advancements/backgrounds/stone.png"), + AdvancementType.GOAL, true, true, false); + } + + private static Advancement.Builder makeChallenge(ItemLike item, String key) { + MutableComponent title = Component.translatable(String.format("advancements.touhou_little_maid.challenge.%s.title", key)); + MutableComponent desc = Component.translatable(String.format("advancements.touhou_little_maid.challenge.%s.description", key)); + + return Advancement.Builder.advancement().display(item, title, desc, + ResourceLocation.fromNamespaceAndPath(TouhouLittleMaid.MOD_ID, "textures/advancements/backgrounds/stone.png"), + AdvancementType.CHALLENGE, true, true, false); + } + + private static ResourceLocation id(String id) { + return ResourceLocation.fromNamespaceAndPath(TouhouLittleMaid.MOD_ID, id); + } +} diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/datagen/advancement/FavorabilityAdvancement.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/datagen/advancement/FavorabilityAdvancement.java new file mode 100644 index 000000000..8a0c6361b --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/datagen/advancement/FavorabilityAdvancement.java @@ -0,0 +1,85 @@ +package com.github.tartaricacid.touhoulittlemaid.datagen.advancement; + +import com.github.tartaricacid.touhoulittlemaid.TouhouLittleMaid; +import com.github.tartaricacid.touhoulittlemaid.advancements.maid.MaidEventTrigger; +import com.github.tartaricacid.touhoulittlemaid.advancements.maid.TriggerType; +import com.github.tartaricacid.touhoulittlemaid.init.InitItems; +import net.minecraft.advancements.Advancement; +import net.minecraft.advancements.AdvancementHolder; +import net.minecraft.advancements.AdvancementRewards; +import net.minecraft.advancements.AdvancementType; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.ItemLike; +import net.neoforged.neoforge.common.data.ExistingFileHelper; + +import java.util.function.Consumer; + + +public class FavorabilityAdvancement { + public static void generate(Consumer saver, ExistingFileHelper existingFileHelper) { + AdvancementHolder root = make(InitItems.BOOKSHELF.get(), "maid_sit_joy") + .addCriterion("maid_event", MaidEventTrigger.create(TriggerType.MAID_SIT_JOY)) + .rewards(AdvancementRewards.Builder.experience(50)) + .save(saver, id("favorability/maid_sit_joy"), existingFileHelper); + + generateFavorability(saver, existingFileHelper, root); + + generateJoy(saver, existingFileHelper, root); + } + + private static void generateJoy(Consumer saver, ExistingFileHelper existingFileHelper, AdvancementHolder root) { + AdvancementHolder joy = make(InitItems.PICNIC_BASKET.get(), "maid_picnic_eat").parent(root) + .addCriterion("maid_event", MaidEventTrigger.create(TriggerType.MAID_PICNIC_EAT)) + .save(saver, id("favorability/maid_picnic_eat"), existingFileHelper); + + AdvancementHolder gomoku = makeGoal(InitItems.GOMOKU.get(), "win_gomoku").parent(joy) + .addCriterion("maid_event", MaidEventTrigger.create(TriggerType.WIN_GOMOKU)) + .save(saver, id("favorability/win_gomoku"), existingFileHelper); + + AdvancementHolder cchess = makeGoal(InitItems.CCHESS.get(), "win_cchess").parent(gomoku) + .addCriterion("maid_event", MaidEventTrigger.create(TriggerType.WIN_CCHESS)) + .save(saver, id("favorability/win_cchess"), existingFileHelper); + + makeGoal(InitItems.WCHESS.get(), "win_wchess").parent(cchess) + .addCriterion("maid_event", MaidEventTrigger.create(TriggerType.WIN_WCHESS)) + .save(saver, id("favorability/win_wchess"), existingFileHelper); + + make(InitItems.MAID_BED.get(), "maid_sleep").parent(joy) + .addCriterion("maid_event", MaidEventTrigger.create(TriggerType.MAID_SLEEP)) + .save(saver, id("favorability/maid_sleep"), existingFileHelper); + } + + private static void generateFavorability(Consumer saver, ExistingFileHelper existingFileHelper, AdvancementHolder root) { + AdvancementHolder increased = make(InitItems.FAVORABILITY_TOOL_ADD.get(), "favorability_increased").parent(root) + .addCriterion("maid_event", MaidEventTrigger.create(TriggerType.FAVORABILITY_INCREASED)) + .save(saver, id("favorability/favorability_increased"), existingFileHelper); + + makeGoal(InitItems.FAVORABILITY_TOOL_FULL.get(), "favorability_increased_max").parent(increased) + .addCriterion("maid_event", MaidEventTrigger.create(TriggerType.FAVORABILITY_INCREASED_MAX)) + .save(saver, id("favorability/favorability_increased_max"), existingFileHelper); + } + + private static Advancement.Builder make(ItemLike item, String key) { + MutableComponent title = Component.translatable(String.format("advancements.touhou_little_maid.favorability.%s.title", key)); + MutableComponent desc = Component.translatable(String.format("advancements.touhou_little_maid.favorability.%s.description", key)); + + return Advancement.Builder.advancement().display(item, title, desc, + ResourceLocation.fromNamespaceAndPath(TouhouLittleMaid.MOD_ID, "textures/advancements/backgrounds/stone.png"), + AdvancementType.TASK, true, true, false); + } + + private static Advancement.Builder makeGoal(ItemLike item, String key) { + MutableComponent title = Component.translatable(String.format("advancements.touhou_little_maid.favorability.%s.title", key)); + MutableComponent desc = Component.translatable(String.format("advancements.touhou_little_maid.favorability.%s.description", key)); + + return Advancement.Builder.advancement().display(item, title, desc, + ResourceLocation.fromNamespaceAndPath(TouhouLittleMaid.MOD_ID, "textures/advancements/backgrounds/stone.png"), + AdvancementType.GOAL, true, true, false); + } + + private static ResourceLocation id(String id) { + return ResourceLocation.fromNamespaceAndPath(TouhouLittleMaid.MOD_ID, id); + } +} diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/datagen/advancement/MaidBaseAdvancement.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/datagen/advancement/MaidBaseAdvancement.java new file mode 100644 index 000000000..538344a21 --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/datagen/advancement/MaidBaseAdvancement.java @@ -0,0 +1,187 @@ +package com.github.tartaricacid.touhoulittlemaid.datagen.advancement; + +import com.github.tartaricacid.touhoulittlemaid.TouhouLittleMaid; +import com.github.tartaricacid.touhoulittlemaid.advancements.altar.AltarCraftTrigger; +import com.github.tartaricacid.touhoulittlemaid.advancements.maid.MaidEventTrigger; +import com.github.tartaricacid.touhoulittlemaid.advancements.maid.TriggerType; +import com.github.tartaricacid.touhoulittlemaid.init.InitItems; +import com.github.tartaricacid.touhoulittlemaid.item.ItemEntityPlaceholder; +import net.minecraft.advancements.Advancement; +import net.minecraft.advancements.AdvancementHolder; +import net.minecraft.advancements.AdvancementType; +import net.minecraft.advancements.critereon.ItemPredicate; +import net.minecraft.advancements.critereon.PickedUpItemTrigger; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.world.level.ItemLike; +import net.neoforged.neoforge.common.data.ExistingFileHelper; + +import java.util.Optional; +import java.util.function.Consumer; + + +public class MaidBaseAdvancement { + public static void generate(Consumer saver, ExistingFileHelper existingFileHelper) { + AdvancementHolder root = make(InitItems.HAKUREI_GOHEI.get(), "switch_task") + .addCriterion("maid_event", MaidEventTrigger.create(TriggerType.SWITCH_TASK)) + .save(saver, id("maid_base/switch_task"), existingFileHelper); + + generateTask(root, saver, existingFileHelper); + + generateOther(saver, existingFileHelper, root); + + generateBauble(root, saver, existingFileHelper); + + generatePhoto(root, saver, existingFileHelper); + + generateFind(saver, existingFileHelper, root); + + generateReborn(root, saver, existingFileHelper); + } + + private static void generateFind(Consumer saver, ExistingFileHelper existingFileHelper, AdvancementHolder root) { + AdvancementHolder base = make(InitItems.SERVANT_BELL.get(), "use_servant_bell").parent(root) + .addCriterion("maid_event", MaidEventTrigger.create(TriggerType.USE_SERVANT_BELL)) + .save(saver, id("maid_base/use_servant_bell"), existingFileHelper); + + make(InitItems.TRUMPET.get(), "use_trumpet").parent(base) + .addCriterion("maid_event", MaidEventTrigger.create(TriggerType.USE_TRUMPET)) + .save(saver, id("maid_base/use_trumpet"), existingFileHelper); + + AdvancementHolder redFoxScroll = make(InitItems.RED_FOX_SCROLL.get(), "use_red_fox_scroll").parent(base) + .addCriterion("maid_event", MaidEventTrigger.create(TriggerType.USE_RED_FOX_SCROLL)) + .save(saver, id("maid_base/use_red_fox_scroll"), existingFileHelper); + + make(InitItems.WHITE_FOX_SCROLL.get(), "use_white_fox_scroll").parent(redFoxScroll) + .addCriterion("maid_event", MaidEventTrigger.create(TriggerType.USE_WHITE_FOX_SCROLL)) + .save(saver, id("maid_base/use_white_fox_scroll"), existingFileHelper); + } + + private static void generateOther(Consumer saver, ExistingFileHelper existingFileHelper, AdvancementHolder root) { + AdvancementHolder base = make(Items.SADDLE, "pickup_maid").parent(root) + .addCriterion("maid_event", MaidEventTrigger.create(TriggerType.PICKUP_MAID)) + .save(saver, id("maid_base/pickup_maid"), existingFileHelper); + + make(Items.EXPERIENCE_BOTTLE, "take_maid_xp").parent(base) + .addCriterion("maid_event", MaidEventTrigger.create(TriggerType.TAKE_MAID_XP)) + .save(saver, id("maid_base/take_maid_xp"), existingFileHelper); + + make(Items.MILK_BUCKET, "clear_maid_effects").parent(base) + .addCriterion("maid_event", MaidEventTrigger.create(TriggerType.CLEAR_MAID_EFFECTS)) + .save(saver, id("maid_base/clear_maid_effects"), existingFileHelper); + } + + private static void generateTask(AdvancementHolder root, Consumer saver, ExistingFileHelper existingFileHelper) { + AdvancementHolder taskRoot = make(Items.CLOCK, "switch_schedule").parent(root) + .addCriterion("maid_event", MaidEventTrigger.create(TriggerType.SWITCH_SCHEDULE)) + .save(saver, id("maid_base/switch_schedule"), existingFileHelper); + + AdvancementHolder backpack = make(InitItems.MAID_BACKPACK_BIG.get(), "maid_backpack").parent(taskRoot) + .addCriterion("maid_event", MaidEventTrigger.create(TriggerType.MAID_BACKPACK)) + .save(saver, id("maid_base/maid_backpack"), existingFileHelper); + + makeGoal(Items.DIAMOND_SWORD, "maid_kill_mob").parent(backpack) + .addCriterion("maid_event", MaidEventTrigger.create(TriggerType.MAID_KILL_MOB)) + .save(saver, id("maid_base/maid_kill_mob"), existingFileHelper); + + make(Items.FISHING_ROD, "maid_fishing").parent(backpack) + .addCriterion("maid_event", MaidEventTrigger.create(TriggerType.MAID_FISHING)) + .save(saver, id("maid_base/maid_fishing"), existingFileHelper); + + AdvancementHolder farm = makeGoal(Items.IRON_HOE, "maid_farm").parent(taskRoot) + .addCriterion("maid_event", MaidEventTrigger.create(TriggerType.MAID_FARM)) + .save(saver, id("maid_base/maid_farm"), existingFileHelper); + + AdvancementHolder feedAnimal = make(Items.WHEAT, "maid_feed_animal").parent(farm) + .addCriterion("maid_event", MaidEventTrigger.create(TriggerType.MAID_FEED_ANIMAL)) + .save(saver, id("maid_base/maid_feed_animal"), existingFileHelper); + + make(Items.COOKED_BEEF, "maid_feed_player").parent(feedAnimal) + .addCriterion("maid_event", MaidEventTrigger.create(TriggerType.MAID_FEED_PLAYER)) + .save(saver, id("maid_base/maid_feed_player"), existingFileHelper); + } + + private static void generateBauble(AdvancementHolder root, Consumer saver, ExistingFileHelper existingFileHelper) { + AdvancementHolder baubleRoot = make(InitItems.FIRE_PROTECT_BAUBLE.get(), "use_protect_bauble").parent(root) + .addCriterion("maid_event", MaidEventTrigger.create(TriggerType.USE_PROTECT_BAUBLE)) + .save(saver, id("maid_base/use_protect_bauble"), existingFileHelper); + + AdvancementHolder fabric = make(InitItems.NIMBLE_FABRIC.get(), "use_nimble_fabric").parent(baubleRoot) + .addCriterion("maid_event", MaidEventTrigger.create(TriggerType.USE_NIMBLE_FABRIC)) + .save(saver, id("maid_base/use_nimble_fabric"), existingFileHelper); + + makeGoal(InitItems.ULTRAMARINE_ORB_ELIXIR.get(), "use_undead_bauble").parent(fabric) + .addCriterion("maid_event", MaidEventTrigger.create(TriggerType.USE_UNDEAD_BAUBLE)) + .save(saver, id("maid_base/use_undead_bauble"), existingFileHelper); + + AdvancementHolder magnet = make(InitItems.ITEM_MAGNET_BAUBLE.get(), "use_item_magnet_bauble").parent(baubleRoot) + .addCriterion("maid_event", MaidEventTrigger.create(TriggerType.USE_ITEM_MAGNET_BAUBLE)) + .save(saver, id("maid_base/use_item_magnet_bauble"), existingFileHelper); + + make(InitItems.WIRELESS_IO.get(), "use_wireless_io").parent(magnet) + .addCriterion("maid_event", MaidEventTrigger.create(TriggerType.USE_WIRELESS_IO)) + .save(saver, id("maid_base/use_wireless_io"), existingFileHelper); + } + + private static void generatePhoto(AdvancementHolder root, Consumer saver, ExistingFileHelper existingFileHelper) { + AdvancementHolder photoRoot = make(InitItems.CAMERA.get(), "photo_maid").parent(root) + .addCriterion("maid_event", MaidEventTrigger.create(TriggerType.PHOTO_MAID)) + .save(saver, id("maid_base/photo_maid"), existingFileHelper); + + AdvancementHolder statue = make(InitItems.CHISEL.get(), "chisel_statue").parent(photoRoot) + .addCriterion("maid_event", MaidEventTrigger.create(TriggerType.CHISEL_STATUE)) + .save(saver, id("maid_base/chisel_statue"), existingFileHelper); + + make(InitItems.GARAGE_KIT.get(), "pickup_garage_kit").parent(statue) + .addCriterion("pickup_item", PickedUpItemTrigger.TriggerInstance.thrownItemPickedUpByPlayer( + Optional.empty(), + Optional.of(ItemPredicate.Builder.item().of(InitItems.GARAGE_KIT.get()).build()), + Optional.empty())) + .save(saver, id("maid_base/pickup_garage_kit"), existingFileHelper); + } + + private static void generateReborn(AdvancementHolder root, Consumer saver, ExistingFileHelper existingFileHelper) { + ItemStack stack = ItemEntityPlaceholder.setRecipeId(new ItemStack(InitItems.ENTITY_PLACEHOLDER.get()), "reborn_maid"); + AdvancementHolder rebornRoot = make(stack, "reborn_maid").parent(root) + .addCriterion("altar_craft", AltarCraftTrigger.Instance.recipe(id("altar_recipe/reborn_maid"))) + .save(saver, id("maid_base/reborn_maid"), existingFileHelper); + + makeGoal(InitItems.SHRINE.get(), "shrine_reborn_maid").parent(rebornRoot) + .addCriterion("maid_event", MaidEventTrigger.create(TriggerType.SHRINE_REBORN_MAID)) + .save(saver, id("maid_base/shrine_reborn_maid"), existingFileHelper); + } + + private static Advancement.Builder make(ItemLike item, String key) { + MutableComponent title = Component.translatable(String.format("advancements.touhou_little_maid.maid_base.%s.title", key)); + MutableComponent desc = Component.translatable(String.format("advancements.touhou_little_maid.maid_base.%s.description", key)); + + return Advancement.Builder.advancement().display(item, title, desc, + ResourceLocation.fromNamespaceAndPath(TouhouLittleMaid.MOD_ID, "textures/advancements/backgrounds/stone.png"), + AdvancementType.TASK, true, true, false); + } + + private static Advancement.Builder make(ItemStack item, String key) { + MutableComponent title = Component.translatable(String.format("advancements.touhou_little_maid.maid_base.%s.title", key)); + MutableComponent desc = Component.translatable(String.format("advancements.touhou_little_maid.maid_base.%s.description", key)); + + return Advancement.Builder.advancement().display(item, title, desc, + ResourceLocation.fromNamespaceAndPath(TouhouLittleMaid.MOD_ID, "textures/advancements/backgrounds/stone.png"), + AdvancementType.TASK, true, true, false); + } + + private static Advancement.Builder makeGoal(ItemLike item, String key) { + MutableComponent title = Component.translatable(String.format("advancements.touhou_little_maid.maid_base.%s.title", key)); + MutableComponent desc = Component.translatable(String.format("advancements.touhou_little_maid.maid_base.%s.description", key)); + + return Advancement.Builder.advancement().display(item, title, desc, + ResourceLocation.fromNamespaceAndPath(TouhouLittleMaid.MOD_ID, "textures/advancements/backgrounds/stone.png"), + AdvancementType.GOAL, true, true, false); + } + + private static ResourceLocation id(String id) { + return ResourceLocation.fromNamespaceAndPath(TouhouLittleMaid.MOD_ID, id); + } +} diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/ai/brain/ExtraMaidBrainManager.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/ai/brain/ExtraMaidBrainManager.java new file mode 100644 index 000000000..e0ee3eb19 --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/ai/brain/ExtraMaidBrainManager.java @@ -0,0 +1,23 @@ +package com.github.tartaricacid.touhoulittlemaid.entity.ai.brain; + +import com.github.tartaricacid.touhoulittlemaid.TouhouLittleMaid; +import com.github.tartaricacid.touhoulittlemaid.api.ILittleMaid; +import com.github.tartaricacid.touhoulittlemaid.api.entity.ai.IExtraMaidBrain; +import com.google.common.collect.Lists; + +import java.util.List; + +public final class ExtraMaidBrainManager { + static List EXTRA_MAID_BRAINS = Lists.newArrayList(); + + public static void init() { + ExtraMaidBrainManager manager = new ExtraMaidBrainManager(); + for (ILittleMaid littleMaid : TouhouLittleMaid.EXTENSIONS) { + littleMaid.addExtraMaidBrain(manager); + } + } + + public void addExtraMaidBrain(IExtraMaidBrain extraMaidBrain) { + EXTRA_MAID_BRAINS.add(extraMaidBrain); + } +} \ No newline at end of file diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/ai/brain/MaidBrain.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/ai/brain/MaidBrain.java index 752c6e4c5..c756a404f 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/ai/brain/MaidBrain.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/ai/brain/MaidBrain.java @@ -21,7 +21,7 @@ public final class MaidBrain { public static ImmutableList> getMemoryTypes() { - return ImmutableList.of( + List> defaultTypes = Lists.newArrayList( MemoryModuleType.PATH, MemoryModuleType.DOORS_TO_CLOSE, MemoryModuleType.LOOK_TARGET, @@ -34,15 +34,19 @@ public static ImmutableList> getMemoryTypes() { MemoryModuleType.ATTACK_COOLING_DOWN, InitEntities.TARGET_POS.get() ); + ExtraMaidBrainManager.EXTRA_MAID_BRAINS.forEach(extra -> defaultTypes.addAll(extra.getExtraMemoryTypes())); + return ImmutableList.copyOf(defaultTypes); } public static ImmutableList>> getSensorTypes() { - return ImmutableList.of( + List>> defaultTypes = Lists.newArrayList( InitEntities.MAID_NEAREST_LIVING_ENTITY_SENSOR.get(), SensorType.HURT_BY, InitEntities.MAID_HOSTILES_SENSOR.get(), InitEntities.MAID_PICKUP_ENTITIES_SENSOR.get() ); + ExtraMaidBrainManager.EXTRA_MAID_BRAINS.forEach(extra -> defaultTypes.addAll(extra.getExtraSensorTypes())); + return ImmutableList.copyOf(defaultTypes); } public static void registerBrainGoals(Brain brain, EntityMaid maid) { @@ -132,9 +136,8 @@ private static void registerRestGoals(Brain brain) { private static void registerPanicGoals(Brain brain) { Pair> clearHurt = Pair.of(5, new MaidClearHurtTask()); Pair> runAway = Pair.of(5, MaidRunAwayTask.entity(MemoryModuleType.NEAREST_HOSTILE, 0.7f, false)); - Pair> runAwayHurt = Pair.of(5, MaidRunAwayTask.entity(MemoryModuleType.HURT_BY_ENTITY, 0.7f, false)); - brain.addActivity(Activity.PANIC, ImmutableList.of(clearHurt, runAway, runAwayHurt)); + brain.addActivity(Activity.PANIC, ImmutableList.of(clearHurt, runAway)); } private static void registerRideIdleGoals(Brain brain) { diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/ai/brain/task/MaidGomokuTask.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/ai/brain/task/MaidBoardGameTask.java similarity index 69% rename from src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/ai/brain/task/MaidGomokuTask.java rename to src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/ai/brain/task/MaidBoardGameTask.java index a04e70d1f..d8579eb74 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/ai/brain/task/MaidGomokuTask.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/ai/brain/task/MaidBoardGameTask.java @@ -1,13 +1,16 @@ package com.github.tartaricacid.touhoulittlemaid.entity.ai.brain.task; -import com.github.tartaricacid.touhoulittlemaid.block.BlockGomoku; +import com.github.tartaricacid.touhoulittlemaid.advancements.maid.TriggerType; +import com.github.tartaricacid.touhoulittlemaid.api.block.IBoardGameBlock; +import com.github.tartaricacid.touhoulittlemaid.api.block.IBoardGameEntityBlock; import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid; import com.github.tartaricacid.touhoulittlemaid.init.InitEntities; import com.github.tartaricacid.touhoulittlemaid.init.InitPoi; -import com.github.tartaricacid.touhoulittlemaid.tileentity.TileEntityGomoku; +import com.github.tartaricacid.touhoulittlemaid.init.InitTrigger; import com.google.common.collect.ImmutableMap; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.ai.behavior.BehaviorUtils; import net.minecraft.world.entity.ai.behavior.BlockPosTracker; import net.minecraft.world.entity.ai.memory.MemoryModuleType; @@ -20,11 +23,11 @@ import javax.annotation.Nullable; import java.util.Comparator; -public class MaidGomokuTask extends MaidCheckRateTask { +public class MaidBoardGameTask extends MaidCheckRateTask { private final int closeEnoughDist; private final float speed; - public MaidGomokuTask(float movementSpeed, int closeEnoughDist) { + public MaidBoardGameTask(float movementSpeed, int closeEnoughDist) { super(ImmutableMap.of(MemoryModuleType.WALK_TARGET, MemoryStatus.VALUE_ABSENT, InitEntities.TARGET_POS.get(), MemoryStatus.VALUE_ABSENT)); this.closeEnoughDist = closeEnoughDist; @@ -35,13 +38,13 @@ public MaidGomokuTask(float movementSpeed, int closeEnoughDist) { @Override protected boolean checkExtraStartConditions(ServerLevel worldIn, EntityMaid maid) { if (super.checkExtraStartConditions(worldIn, maid) && maid.canBrainMoving()) { - BlockPos gomokuPos = findGomoku(worldIn, maid); - if (gomokuPos != null && maid.isWithinRestriction(gomokuPos)) { - if (gomokuPos.distToCenterSqr(maid.position()) < Math.pow(this.closeEnoughDist, 2)) { - maid.getBrain().setMemory(InitEntities.TARGET_POS.get(), new BlockPosTracker(gomokuPos)); + BlockPos gamePos = findGameBlock(worldIn, maid); + if (gamePos != null && maid.isWithinRestriction(gamePos)) { + if (gamePos.distToCenterSqr(maid.position()) < Math.pow(this.closeEnoughDist, 2)) { + maid.getBrain().setMemory(InitEntities.TARGET_POS.get(), new BlockPosTracker(gamePos)); return true; } - BehaviorUtils.setWalkAndLookTargetMemories(maid, gomokuPos, speed, 1); + BehaviorUtils.setWalkAndLookTargetMemories(maid, gamePos, speed, 1); this.setNextCheckTickCount(5); } else { maid.getBrain().eraseMemory(InitEntities.TARGET_POS.get()); @@ -55,8 +58,11 @@ protected void start(ServerLevel worldIn, EntityMaid maid, long gameTimeIn) { maid.getBrain().getMemory(InitEntities.TARGET_POS.get()).ifPresent((targetPos) -> { BlockPos pos = targetPos.currentBlockPosition(); BlockState blockState = worldIn.getBlockState(pos); - if (blockState.getBlock() instanceof BlockGomoku gomoku) { - gomoku.startMaidSit(maid, blockState, worldIn, pos); + if (blockState.getBlock() instanceof IBoardGameBlock gameBlock) { + gameBlock.startMaidSit(maid, blockState, worldIn, pos); + if (maid.getOwner() instanceof ServerPlayer serverPlayer) { + InitTrigger.MAID_EVENT.get().trigger(serverPlayer, TriggerType.MAID_SIT_JOY); + } } }); maid.getBrain().eraseMemory(InitEntities.TARGET_POS.get()); @@ -65,7 +71,7 @@ protected void start(ServerLevel worldIn, EntityMaid maid, long gameTimeIn) { } @Nullable - private BlockPos findGomoku(ServerLevel world, EntityMaid maid) { + private BlockPos findGameBlock(ServerLevel world, EntityMaid maid) { BlockPos blockPos = maid.getBrainSearchPos(); PoiManager poiManager = world.getPoiManager(); int range = (int) maid.getRestrictRadius(); @@ -76,8 +82,8 @@ private BlockPos findGomoku(ServerLevel world, EntityMaid maid) { private boolean isOccupied(ServerLevel worldIn, BlockPos pos) { BlockEntity te = worldIn.getBlockEntity(pos); - if (te instanceof TileEntityGomoku gomoku) { - return worldIn.getEntity(gomoku.getSitId()) != null; + if (te instanceof IBoardGameEntityBlock gameBlock) { + return worldIn.getEntity(gameBlock.getSitId()) != null; } return true; } diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/ai/brain/task/MaidFarmPlantTask.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/ai/brain/task/MaidFarmPlantTask.java index 930a2d782..a4474326a 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/ai/brain/task/MaidFarmPlantTask.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/ai/brain/task/MaidFarmPlantTask.java @@ -1,12 +1,15 @@ package com.github.tartaricacid.touhoulittlemaid.entity.ai.brain.task; +import com.github.tartaricacid.touhoulittlemaid.advancements.maid.TriggerType; import com.github.tartaricacid.touhoulittlemaid.api.task.IFarmTask; import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid; import com.github.tartaricacid.touhoulittlemaid.init.InitEntities; +import com.github.tartaricacid.touhoulittlemaid.init.InitTrigger; import com.github.tartaricacid.touhoulittlemaid.util.ItemsUtil; import com.google.common.collect.ImmutableMap; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.InteractionHand; import net.minecraft.world.entity.ai.Brain; import net.minecraft.world.entity.ai.behavior.Behavior; @@ -56,6 +59,9 @@ protected void start(ServerLevel world, EntityMaid maid, long gameTimeIn) { maid.swing(InteractionHand.MAIN_HAND); maid.getBrain().eraseMemory(InitEntities.TARGET_POS.get()); maid.getBrain().eraseMemory(MemoryModuleType.WALK_TARGET); + if (maid.getOwner() instanceof ServerPlayer serverPlayer) { + InitTrigger.MAID_EVENT.get().trigger(serverPlayer, TriggerType.MAID_FARM); + } } CombinedInvWrapper availableInv = maid.getAvailableInv(true); @@ -70,6 +76,9 @@ protected void start(ServerLevel world, EntityMaid maid, long gameTimeIn) { maid.swing(InteractionHand.MAIN_HAND); maid.getBrain().eraseMemory(InitEntities.TARGET_POS.get()); maid.getBrain().eraseMemory(MemoryModuleType.WALK_TARGET); + if (maid.getOwner() instanceof ServerPlayer serverPlayer) { + InitTrigger.MAID_EVENT.get().trigger(serverPlayer, TriggerType.MAID_FARM); + } return; } } diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/ai/brain/task/MaidFeedAnimalTask.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/ai/brain/task/MaidFeedAnimalTask.java index 8b8d9906b..664cacba2 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/ai/brain/task/MaidFeedAnimalTask.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/ai/brain/task/MaidFeedAnimalTask.java @@ -1,10 +1,13 @@ package com.github.tartaricacid.touhoulittlemaid.entity.ai.brain.task; +import com.github.tartaricacid.touhoulittlemaid.advancements.maid.TriggerType; import com.github.tartaricacid.touhoulittlemaid.entity.chatbubble.ChatBubbleManger; import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid; +import com.github.tartaricacid.touhoulittlemaid.init.InitTrigger; import com.github.tartaricacid.touhoulittlemaid.util.ItemsUtil; import com.google.common.collect.ImmutableMap; import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.InteractionHand; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.ai.behavior.BehaviorUtils; @@ -57,6 +60,9 @@ protected void start(ServerLevel worldIn, EntityMaid maid, long gameTimeIn) { food.shrink(1); maid.swing(InteractionHand.MAIN_HAND); feedEntity.setInLove(null); + if (maid.getOwner() instanceof ServerPlayer serverPlayer) { + InitTrigger.MAID_EVENT.get().trigger(serverPlayer, TriggerType.MAID_FEED_ANIMAL); + } } feedEntity = null; } diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/ai/brain/task/MaidFeedOwnerTask.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/ai/brain/task/MaidFeedOwnerTask.java index de174a358..df47d9de8 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/ai/brain/task/MaidFeedOwnerTask.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/ai/brain/task/MaidFeedOwnerTask.java @@ -1,11 +1,14 @@ package com.github.tartaricacid.touhoulittlemaid.entity.ai.brain.task; +import com.github.tartaricacid.touhoulittlemaid.advancements.maid.TriggerType; import com.github.tartaricacid.touhoulittlemaid.api.task.IFeedTask; import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid; +import com.github.tartaricacid.touhoulittlemaid.init.InitTrigger; import com.google.common.collect.ImmutableMap; import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.ints.IntList; import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.InteractionHand; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.ai.behavior.BehaviorUtils; @@ -82,6 +85,9 @@ protected void start(ServerLevel worldIn, EntityMaid maid, long gameTimeIn) { inv.setStackInSlot(slot, task.feed(inv.getStackInSlot(slot), player)); maid.swing(InteractionHand.MAIN_HAND); this.setNextCheckTickCount(5); + if (maid.getOwner() instanceof ServerPlayer serverPlayer) { + InitTrigger.MAID_EVENT.get().trigger(serverPlayer, TriggerType.MAID_FEED_PLAYER); + } }); } } diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/ai/brain/task/MaidHomeMealTask.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/ai/brain/task/MaidHomeMealTask.java index 45837abce..fec4b3ef7 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/ai/brain/task/MaidHomeMealTask.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/ai/brain/task/MaidHomeMealTask.java @@ -1,5 +1,6 @@ package com.github.tartaricacid.touhoulittlemaid.entity.ai.brain.task; +import com.github.tartaricacid.touhoulittlemaid.advancements.maid.TriggerType; import com.github.tartaricacid.touhoulittlemaid.api.task.meal.IMaidMeal; import com.github.tartaricacid.touhoulittlemaid.api.task.meal.MaidMealType; import com.github.tartaricacid.touhoulittlemaid.entity.chatbubble.ChatBubbleManger; @@ -7,12 +8,14 @@ import com.github.tartaricacid.touhoulittlemaid.entity.item.EntitySit; import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid; import com.github.tartaricacid.touhoulittlemaid.entity.task.meal.MaidMealManager; +import com.github.tartaricacid.touhoulittlemaid.init.InitTrigger; import com.github.tartaricacid.touhoulittlemaid.tileentity.TileEntityPicnicMat; import com.google.common.collect.ImmutableMap; import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.ints.IntList; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.InteractionHand; import net.minecraft.world.item.ItemStack; import net.neoforged.neoforge.items.IItemHandlerModifiable; @@ -109,6 +112,9 @@ protected void start(ServerLevel serverLevel, EntityMaid maid, long gameTime) { for (IMaidMeal maidMeal : maidMeals) { if (maidMeal.canMaidEat(maid, refreshItemInHand, hand)) { maidMeal.onMaidEat(maid, refreshItemInHand, hand); + if (maid.getOwner() instanceof ServerPlayer serverPlayer) { + InitTrigger.MAID_EVENT.get().trigger(serverPlayer, TriggerType.MAID_PICNIC_EAT); + } return; } } diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/ai/brain/task/MaidInteractWithDoor.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/ai/brain/task/MaidInteractWithDoor.java index 0e124cf4d..a4c3aa9eb 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/ai/brain/task/MaidInteractWithDoor.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/ai/brain/task/MaidInteractWithDoor.java @@ -1,5 +1,6 @@ package com.github.tartaricacid.touhoulittlemaid.entity.ai.brain.task; +import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid; import com.github.tartaricacid.touhoulittlemaid.mixin.FenceGateBlockAccessor; import com.google.common.collect.Sets; import com.mojang.datafixers.kinds.OptionalBox; @@ -50,19 +51,22 @@ public static BehaviorControl create() { return false; } + boolean canOpenDoor = entity instanceof EntityMaid maid && maid.getConfigManager().isOpenDoor(); + boolean canOpenFenceGate = entity instanceof EntityMaid maid && maid.getConfigManager().isOpenFenceGate(); + mutableObject.setValue(path.getNextNode()); Node previousNode = path.getPreviousNode(); Node nextNode = path.getNextNode(); BlockPos previousNodeBlockPos = previousNode.asBlockPos(); BlockState previousNodeBlockState = serverLevel.getBlockState(previousNodeBlockPos); - if (previousNodeBlockState.is(BlockTags.WOODEN_DOORS, (stateBase) -> stateBase.getBlock() instanceof DoorBlock)) { + if (canOpenDoor && previousNodeBlockState.is(BlockTags.WOODEN_DOORS, (stateBase) -> stateBase.getBlock() instanceof DoorBlock)) { DoorBlock doorBlock = (DoorBlock) previousNodeBlockState.getBlock(); if (!doorBlock.isOpen(previousNodeBlockState)) { doorBlock.setOpen(entity, serverLevel, previousNodeBlockState, previousNodeBlockPos, true); } doorToClosePos = rememberDoorToClose(doorToCloseMemory, doorToClosePos, serverLevel, previousNodeBlockPos); - } else if (previousNodeBlockState.is(BlockTags.FENCE_GATES, (stateBase) -> stateBase.getBlock() instanceof FenceGateBlock)) { + } else if (canOpenFenceGate && previousNodeBlockState.is(BlockTags.FENCE_GATES, (stateBase) -> stateBase.getBlock() instanceof FenceGateBlock)) { if (!previousNodeBlockState.getValue(FenceGateBlock.OPEN)) { setFenceGate(entity, serverLevel, previousNodeBlockState, previousNodeBlockPos, true); } @@ -71,13 +75,13 @@ public static BehaviorControl create() { BlockPos nextNodeBlockPos = nextNode.asBlockPos(); BlockState nextNodeBlockState = serverLevel.getBlockState(nextNodeBlockPos); - if (nextNodeBlockState.is(BlockTags.WOODEN_DOORS, (stateBase) -> stateBase.getBlock() instanceof DoorBlock)) { + if (canOpenDoor && nextNodeBlockState.is(BlockTags.WOODEN_DOORS, (stateBase) -> stateBase.getBlock() instanceof DoorBlock)) { DoorBlock doorBlock = (DoorBlock) nextNodeBlockState.getBlock(); if (!doorBlock.isOpen(nextNodeBlockState)) { doorBlock.setOpen(entity, serverLevel, nextNodeBlockState, nextNodeBlockPos, true); doorToClosePos = rememberDoorToClose(doorToCloseMemory, doorToClosePos, serverLevel, nextNodeBlockPos); } - } else if (nextNodeBlockState.is(BlockTags.FENCE_GATES, (stateBase) -> stateBase.getBlock() instanceof FenceGateBlock)) { + } else if (canOpenFenceGate && nextNodeBlockState.is(BlockTags.FENCE_GATES, (stateBase) -> stateBase.getBlock() instanceof FenceGateBlock)) { if (!nextNodeBlockState.getValue(FenceGateBlock.OPEN)) { setFenceGate(entity, serverLevel, nextNodeBlockState, nextNodeBlockPos, true); doorToClosePos = rememberDoorToClose(doorToCloseMemory, doorToClosePos, serverLevel, nextNodeBlockPos); diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/ai/brain/task/MaidJoyTask.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/ai/brain/task/MaidJoyTask.java index d5c06fa65..81a891613 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/ai/brain/task/MaidJoyTask.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/ai/brain/task/MaidJoyTask.java @@ -1,13 +1,16 @@ package com.github.tartaricacid.touhoulittlemaid.entity.ai.brain.task; +import com.github.tartaricacid.touhoulittlemaid.advancements.maid.TriggerType; import com.github.tartaricacid.touhoulittlemaid.block.BlockJoy; import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid; import com.github.tartaricacid.touhoulittlemaid.init.InitEntities; import com.github.tartaricacid.touhoulittlemaid.init.InitPoi; +import com.github.tartaricacid.touhoulittlemaid.init.InitTrigger; import com.github.tartaricacid.touhoulittlemaid.tileentity.TileEntityJoy; import com.google.common.collect.ImmutableMap; import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.ai.behavior.BehaviorUtils; import net.minecraft.world.entity.ai.behavior.BlockPosTracker; import net.minecraft.world.entity.ai.memory.MemoryModuleType; @@ -57,6 +60,9 @@ protected void start(ServerLevel worldIn, EntityMaid maid, long gameTimeIn) { BlockState blockState = worldIn.getBlockState(pos); if (blockState.getBlock() instanceof BlockJoy blockJoy) { blockJoy.startMaidSit(maid, blockState, worldIn, pos); + if (maid.getOwner() instanceof ServerPlayer serverPlayer) { + InitTrigger.MAID_EVENT.get().trigger(serverPlayer, TriggerType.MAID_SIT_JOY); + } } }); maid.getBrain().eraseMemory(InitEntities.TARGET_POS.get()); diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/ai/navigation/MaidNodeEvaluator.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/ai/navigation/MaidNodeEvaluator.java index e972506f3..120f5fffc 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/ai/navigation/MaidNodeEvaluator.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/ai/navigation/MaidNodeEvaluator.java @@ -1,6 +1,9 @@ package com.github.tartaricacid.touhoulittlemaid.entity.ai.navigation; +import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid; import net.minecraft.core.BlockPos; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.DoorBlock; import net.minecraft.world.level.block.FenceGateBlock; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.pathfinder.PathType; @@ -16,7 +19,7 @@ public PathType getPathType(PathfindingContext pContext, int pX, int pY, int pZ) return getMaidBlockPathTypeStatic(pContext, new BlockPos.MutableBlockPos(pX, pY, pZ)); } - private static PathType getMaidBlockPathTypeStatic(PathfindingContext context, BlockPos.MutableBlockPos pos) { + private PathType getMaidBlockPathTypeStatic(PathfindingContext context, BlockPos.MutableBlockPos pos) { int x = pos.getX(); int y = pos.getY(); int z = pos.getZ(); @@ -38,13 +41,28 @@ private static PathType getMaidBlockPathTypeStatic(PathfindingContext context, B } } - private static PathType getMaidBlockPathTypeRaw(PathfindingContext context, int pX, int pY, int pZ) { + private PathType getMaidBlockPathTypeRaw(PathfindingContext context, int pX, int pY, int pZ) { BlockPos pos = new BlockPos(pX, pY, pZ); BlockState blockState = context.getBlockState(pos); + PathType pathType; if (blockState.getBlock() instanceof FenceGateBlock) { - return blockState.getValue(FenceGateBlock.OPEN) ? PathType.DOOR_OPEN : PathType.DOOR_WOOD_CLOSED; + pathType = blockState.getValue(FenceGateBlock.OPEN) ? PathType.DOOR_OPEN : PathType.DOOR_WOOD_CLOSED; } else { - return context.getPathTypeFromState(pX, pY, pZ); + pathType = context.getPathTypeFromState(pX, pY, pZ); } + if (pathType == PathType.DOOR_WOOD_CLOSED && this.mob instanceof EntityMaid maid && !this.canOpenDoor(blockState.getBlock(), maid)) { + pathType = PathType.DOOR_IRON_CLOSED; + } + return pathType; + } + + private boolean canOpenDoor(Block block, EntityMaid maid) { + if (block instanceof DoorBlock) { + return maid.getConfigManager().isOpenDoor(); + } + if (block instanceof FenceGateBlock) { + return maid.getConfigManager().isOpenFenceGate(); + } + return true; } } \ No newline at end of file diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/favorability/FavorabilityManager.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/favorability/FavorabilityManager.java index f0738c4ef..6e9180412 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/favorability/FavorabilityManager.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/favorability/FavorabilityManager.java @@ -1,11 +1,14 @@ package com.github.tartaricacid.touhoulittlemaid.entity.favorability; +import com.github.tartaricacid.touhoulittlemaid.advancements.maid.TriggerType; import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid; +import com.github.tartaricacid.touhoulittlemaid.init.InitTrigger; import com.github.tartaricacid.touhoulittlemaid.network.NetworkHandler; import com.github.tartaricacid.touhoulittlemaid.network.message.SpawnParticlePackage; import com.google.common.collect.Maps; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.Tag; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.sounds.SoundEvents; import net.minecraft.util.Mth; import net.minecraft.world.entity.Entity; @@ -241,6 +244,15 @@ public void add(int addPoint) { if (maid.getHealth() > maid.getMaxHealth()) { maid.setHealth(maid.getMaxHealth()); } + if (maid.getMaxHealth() >= 100 && maid.getOwner() instanceof ServerPlayer serverPlayer) { + InitTrigger.MAID_EVENT.get().trigger(serverPlayer, TriggerType.MAID_100_HEALTHY); + } + } + if (maid.getOwner() instanceof ServerPlayer serverPlayer) { + InitTrigger.MAID_EVENT.get().trigger(serverPlayer, TriggerType.FAVORABILITY_INCREASED); + if (levelAfter == LEVEL_3) { + InitTrigger.MAID_EVENT.get().trigger(serverPlayer, TriggerType.FAVORABILITY_INCREASED_MAX); + } } maid.playSound(SoundEvents.PLAYER_LEVELUP, 0.5F, maid.getRandom().nextFloat() * 0.1F + 0.9F); } diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/favorability/Type.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/favorability/Type.java index 95a09b7ff..ff881e861 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/favorability/Type.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/favorability/Type.java @@ -7,6 +7,8 @@ public class Type { public static final Type GOMOKU = new Type("Gomoku", 2, 24000); public static final Type SLEEP = new Type("Sleep", 2, 24000); public static final Type GOMOKU_WIN = new Type("GomokuWin", 8, 12000); + public static final Type CCHESS_WIN = new Type("CChessWin", 4, 18000); + public static final Type WCHESS_WIN = new Type("CChessWin", 4, 18000); public static final Type WORK_MEAL = new Type("WorkMeal", 1, 2 * 60 * 20); public static final Type ON_HOME_MEAL = new Type("OnHomeMeal", 1, 24000); public static final Type HOME_MEAL = new Type("HomeMeal", 1, 60 * 20); diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/item/EntityPowerPoint.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/item/EntityPowerPoint.java index 88e85580a..15d1b40bb 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/item/EntityPowerPoint.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/item/EntityPowerPoint.java @@ -1,8 +1,10 @@ package com.github.tartaricacid.touhoulittlemaid.entity.item; +import com.github.tartaricacid.touhoulittlemaid.advancements.maid.TriggerType; import com.github.tartaricacid.touhoulittlemaid.data.MaidNumAttachment; import com.github.tartaricacid.touhoulittlemaid.data.PowerAttachment; import com.github.tartaricacid.touhoulittlemaid.init.InitDataAttachment; +import com.github.tartaricacid.touhoulittlemaid.init.InitTrigger; import com.github.tartaricacid.touhoulittlemaid.network.NetworkHandler; import com.github.tartaricacid.touhoulittlemaid.network.message.BeaconAbsorbPackage; import com.github.tartaricacid.touhoulittlemaid.network.message.SyncDataPackage; @@ -265,6 +267,9 @@ public void playerTouch(Player player) { } PacketDistributor.sendToPlayer((ServerPlayer) player, new SyncDataPackage(power.get(), maidNum.get())); this.discard(); + if (player instanceof ServerPlayer serverPlayer) { + InitTrigger.MAID_EVENT.get().trigger(serverPlayer, TriggerType.PICKUP_POWER_POINT); + } } } diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/passive/EntityMaid.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/passive/EntityMaid.java index 3be1eebd1..25e216dd1 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/passive/EntityMaid.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/passive/EntityMaid.java @@ -1,5 +1,6 @@ package com.github.tartaricacid.touhoulittlemaid.entity.passive; +import com.github.tartaricacid.touhoulittlemaid.advancements.maid.TriggerType; import com.github.tartaricacid.touhoulittlemaid.api.backpack.IBackpackData; import com.github.tartaricacid.touhoulittlemaid.api.backpack.IMaidBackpack; import com.github.tartaricacid.touhoulittlemaid.api.entity.IMaid; @@ -33,7 +34,8 @@ import com.github.tartaricacid.touhoulittlemaid.entity.task.TaskManager; import com.github.tartaricacid.touhoulittlemaid.init.InitEntities; import com.github.tartaricacid.touhoulittlemaid.init.InitSounds; -import com.github.tartaricacid.touhoulittlemaid.inventory.container.MaidConfigContainer; +import com.github.tartaricacid.touhoulittlemaid.init.InitTrigger; +import com.github.tartaricacid.touhoulittlemaid.inventory.container.config.MaidConfigContainer; import com.github.tartaricacid.touhoulittlemaid.inventory.handler.BaubleItemHandler; import com.github.tartaricacid.touhoulittlemaid.inventory.handler.MaidBackpackHandler; import com.github.tartaricacid.touhoulittlemaid.inventory.handler.MaidHandsInvWrapper; @@ -60,6 +62,7 @@ import net.minecraft.nbt.NbtUtils; import net.minecraft.nbt.Tag; import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; import net.minecraft.network.syncher.EntityDataAccessor; import net.minecraft.network.syncher.EntityDataSerializers; import net.minecraft.network.syncher.SynchedEntityData; @@ -150,9 +153,6 @@ public class EntityMaid extends TamableAnimal implements CrossbowAttackMob, IMai private static final EntityDataAccessor DATA_SOUND_PACK_ID = SynchedEntityData.defineId(EntityMaid.class, EntityDataSerializers.STRING); private static final EntityDataAccessor DATA_TASK = SynchedEntityData.defineId(EntityMaid.class, EntityDataSerializers.STRING); private static final EntityDataAccessor DATA_BEGGING = SynchedEntityData.defineId(EntityMaid.class, EntityDataSerializers.BOOLEAN); - private static final EntityDataAccessor DATA_PICKUP = SynchedEntityData.defineId(EntityMaid.class, EntityDataSerializers.BOOLEAN); - private static final EntityDataAccessor DATA_HOME_MODE = SynchedEntityData.defineId(EntityMaid.class, EntityDataSerializers.BOOLEAN); - private static final EntityDataAccessor DATA_RIDEABLE = SynchedEntityData.defineId(EntityMaid.class, EntityDataSerializers.BOOLEAN); private static final EntityDataAccessor DATA_INVULNERABLE = SynchedEntityData.defineId(EntityMaid.class, EntityDataSerializers.BOOLEAN); private static final EntityDataAccessor DATA_HUNGER = SynchedEntityData.defineId(EntityMaid.class, EntityDataSerializers.INT); private static final EntityDataAccessor DATA_FAVORABILITY = SynchedEntityData.defineId(EntityMaid.class, EntityDataSerializers.INT); @@ -173,9 +173,6 @@ public class EntityMaid extends TamableAnimal implements CrossbowAttackMob, IMai */ private static final EntityDataAccessor TASK_DATA_SYNC = SynchedEntityData.defineId(EntityMaid.class, EntityDataSerializers.COMPOUND_TAG); private static final String TASK_TAG = "MaidTask"; - private static final String PICKUP_TAG = "MaidIsPickup"; - private static final String HOME_TAG = "MaidIsHome"; - private static final String RIDEABLE_TAG = "MaidIsRideable"; private static final String STRUCK_BY_LIGHTNING_TAG = "StruckByLightning"; private static final String INVULNERABLE_TAG = "Invulnerable"; private static final String HUNGER_TAG = "MaidHunger"; @@ -183,6 +180,7 @@ public class EntityMaid extends TamableAnimal implements CrossbowAttackMob, IMai private static final String SCHEDULE_MODE_TAG = "MaidScheduleMode"; private static final String BACKPACK_DATA_TAG = "MaidBackpackData"; private static final String GAME_SKILL_TAG = "MaidGameSkillData"; + private static final String STRUCTURE_SPAWN_TAG = "StructureSpawn"; @Deprecated private static final String BACKPACK_LEVEL_TAG = "MaidBackpackLevel"; @Deprecated @@ -194,6 +192,7 @@ public class EntityMaid extends TamableAnimal implements CrossbowAttackMob, IMai private final EntityHandsInvWrapper handsInvWrapper = new MaidHandsInvWrapper(this); private final ItemStackHandler maidInv = new MaidBackpackHandler(36, this); private final BaubleItemHandler maidBauble = new BaubleItemHandler(9); + private final MaidKillRecordManager killRecordManager = new MaidKillRecordManager(); private final MaidTaskDataMaps taskDataMaps = new MaidTaskDataMaps(); private final FavorabilityManager favorabilityManager; private final MaidScriptBookManager scriptBookManager; @@ -209,6 +208,12 @@ public class EntityMaid extends TamableAnimal implements CrossbowAttackMob, IMai private int backpackDelay = 0; private IBackpackData backpackData = null; private boolean syncTaskDataMaps = false; + private MaidConfigManager configManager = new MaidConfigManager(this.entityData); + + /** + * 女仆现在可以在前哨站生成,那么会打上这个标签 + */ + private boolean structureSpawn = false; protected EntityMaid(EntityType type, Level world) { super(type, world); @@ -264,9 +269,6 @@ protected void defineSynchedData(SynchedEntityData.Builder builder) { builder.define(DATA_SOUND_PACK_ID, DefaultMaidSoundPack.getInitSoundPackId()); builder.define(DATA_TASK, TaskIdle.UID.toString()); builder.define(DATA_BEGGING, false); - builder.define(DATA_PICKUP, true); - builder.define(DATA_HOME_MODE, false); - builder.define(DATA_RIDEABLE, true); builder.define(DATA_INVULNERABLE, false); builder.define(DATA_HUNGER, 0); builder.define(DATA_FAVORABILITY, 0); @@ -283,6 +285,12 @@ protected void defineSynchedData(SynchedEntityData.Builder builder) { builder.define(BACKPACK_FLUID, StringUtils.EMPTY); builder.define(GAME_SKILL, new CompoundTag()); builder.define(TASK_DATA_SYNC, new CompoundTag()); + + // 父类构造方法调用此类,就会出现这种初始化混乱的问题 + if (this.configManager == null) { + this.configManager = new MaidConfigManager(this.entityData); + } + this.configManager.defineSynchedData(builder); } @Override @@ -389,6 +397,16 @@ public void baseTick() { this.syncData(); } + @Override + public void rideTick() { + super.rideTick(); + // 当玩家抱起女仆时,能够同步朝向 + if (this.getVehicle() instanceof Player player) { + this.setYHeadRot(player.getYRot()); + this.setYBodyRot(player.getYRot()); + } + } + /** * 把数据同步到客户端 */ @@ -469,8 +487,20 @@ private InteractionResult tameMaid(ItemStack stack, Player player) { this.brain.eraseMemory(MemoryModuleType.ATTACK_TARGET); this.level.broadcastEntityEvent(this, (byte) 7); this.playSound(InitSounds.MAID_TAMED.get(), 1, 1); + if (player instanceof ServerPlayer serverPlayer) { + InitTrigger.MAID_EVENT.get().trigger(serverPlayer, TriggerType.TAMED_MAID); + if (this.isStructureSpawn()) { + InitTrigger.MAID_EVENT.get().trigger(serverPlayer, TriggerType.TAMED_MAID_FROM_STRUCTURE); + } + } return InteractionResult.SUCCESS; } + } else { + if (player instanceof ServerPlayer) { + MutableComponent msg = Component.translatable("message.touhou_little_maid.owner_maid_num.can_not_add", + cap.get(), cap.getMaxNum()); + player.sendSystemMessage(msg); + } } return InteractionResult.PASS; } @@ -807,12 +837,17 @@ public boolean canPickup(Entity pickupEntity, boolean checkInWater) { if (checkInWater && pickupEntity.isInWater()) { return false; } - return switch (pickupEntity) { - case ItemEntity itemEntity -> pickupItem(itemEntity, true); - case AbstractArrow abstractArrow -> pickupArrow(abstractArrow, true); - case ExperienceOrb ignored -> true; - default -> pickupEntity instanceof EntityPowerPoint; - }; + PickType pickupType = this.configManager.getPickupType(); + if (pickupType.canPickItem() && pickupEntity instanceof ItemEntity) { + return pickupItem((ItemEntity) pickupEntity, true); + } + if (pickupType.canPickItem() && pickupEntity instanceof AbstractArrow) { + return pickupArrow((AbstractArrow) pickupEntity, true); + } + if (pickupType.canPickXp() && pickupEntity instanceof ExperienceOrb) { + return true; + } + return pickupType.canPickXp() && pickupEntity instanceof EntityPowerPoint; } return false; } @@ -863,6 +898,9 @@ public void thunderHit(ServerLevel world, LightningBolt lightning) { double beforeMaxHealth = this.getAttributeBaseValue(Attributes.MAX_HEALTH); Objects.requireNonNull(this.getAttribute(Attributes.MAX_HEALTH)).setBaseValue(beforeMaxHealth + 20); setStruckByLightning(true); + if (this.getOwner() instanceof ServerPlayer serverPlayer) { + InitTrigger.MAID_EVENT.get().trigger(serverPlayer, TriggerType.LIGHTNING_BOLT); + } } } @@ -1000,9 +1038,6 @@ public void addAdditionalSaveData(CompoundTag compound) { compound.putString(MODEL_ID_TAG_NAME, getModelId()); compound.putString(SOUND_PACK_ID_TAG, getSoundPackId()); compound.putString(TASK_TAG, getTask().getUid().toString()); - compound.putBoolean(PICKUP_TAG, isPickup()); - compound.putBoolean(HOME_TAG, isHomeModeEnable()); - compound.putBoolean(RIDEABLE_TAG, isRideable()); compound.put(MAID_INVENTORY_TAG, maidInv.serializeNBT(this.registryAccess())); compound.put(MAID_BAUBLE_INVENTORY_TAG, maidBauble.serializeNBT(this.registryAccess())); compound.putBoolean(STRUCK_BY_LIGHTNING_TAG, isStruckByLightning()); @@ -1013,6 +1048,8 @@ public void addAdditionalSaveData(CompoundTag compound) { compound.putString(SCHEDULE_MODE_TAG, getSchedule().name()); compound.putString(MAID_BACKPACK_TYPE, getMaidBackpackType().getId().toString()); compound.put(GAME_SKILL_TAG, getGameSkill()); + compound.putBoolean(STRUCTURE_SPAWN_TAG, this.structureSpawn); + this.configManager.addAdditionalSaveData(compound); this.favorabilityManager.addAdditionalSaveData(compound); this.scriptBookManager.addAdditionalSaveData(compound); this.schedulePos.save(compound); @@ -1024,6 +1061,7 @@ public void addAdditionalSaveData(CompoundTag compound) { compound.put(BACKPACK_DATA_TAG, new CompoundTag()); } this.taskDataMaps.writeSaveData(compound); + this.killRecordManager.addAdditionalSaveData(compound); } @Override @@ -1045,15 +1083,6 @@ public void readAdditionalSaveData(CompoundTag compound) { IMaidTask task = TaskManager.findTask(uid).orElse(TaskManager.getIdleTask()); setTask(task); } - if (compound.contains(PICKUP_TAG, Tag.TAG_BYTE)) { - setPickup(compound.getBoolean(PICKUP_TAG)); - } - if (compound.contains(HOME_TAG, Tag.TAG_BYTE)) { - setHomeModeEnable(compound.getBoolean(HOME_TAG)); - } - if (compound.contains(RIDEABLE_TAG, Tag.TAG_BYTE)) { - setRideable(compound.getBoolean(RIDEABLE_TAG)); - } if (compound.contains(BACKPACK_LEVEL_TAG, Tag.TAG_INT)) { // 存档迁移 int backpackLevel = compound.getInt(BACKPACK_LEVEL_TAG); @@ -1092,6 +1121,9 @@ public void readAdditionalSaveData(CompoundTag compound) { if (compound.contains(GAME_SKILL_TAG, Tag.TAG_COMPOUND)) { setGameSkill(compound.getCompound(GAME_SKILL_TAG)); } + if (compound.contains(STRUCTURE_SPAWN_TAG, Tag.TAG_BYTE)) { + this.structureSpawn = compound.getBoolean(STRUCTURE_SPAWN_TAG); + } if (compound.contains(RESTRICT_CENTER_TAG, Tag.TAG_COMPOUND)) { // 存档迁移 NbtUtils.readBlockPos(compound, RESTRICT_CENTER_TAG).ifPresent(blockPos -> this.schedulePos.setHomeModeEnable(this, blockPos)); @@ -1105,10 +1137,12 @@ public void readAdditionalSaveData(CompoundTag compound) { this.backpackData.load(compound.getCompound(BACKPACK_DATA_TAG), this); } } + this.configManager.readAdditionalSaveData(compound); this.favorabilityManager.readAdditionalSaveData(compound); this.scriptBookManager.readAdditionalSaveData(compound); this.schedulePos.load(compound, this); this.setBackpackShowItem(maidInv.getStackInSlot(MaidBackpackHandler.BACKPACK_ITEM_SLOT)); + this.killRecordManager.readAdditionalSaveData(compound); } public boolean openMaidGui(Player player) { @@ -1125,29 +1159,12 @@ public boolean openMaidGui(Player player, int tabIndex) { private MenuProvider getGuiProvider(int tabIndex) { return switch (tabIndex) { - case TabIndex.CONFIG -> MaidConfigContainer.create(getId()); + case TabIndex.TASK_CONFIG -> task.getTaskConfigGuiProvider(this); + case TabIndex.MAID_CONFIG -> MaidConfigContainer.create(getId()); default -> this.getMaidBackpackType().getGuiProvider(getId()); }; } - public boolean openMaidGuiFromSideTab(Player player, int tabIndex) { - if (player instanceof ServerPlayer && !this.isSleeping()) { - this.navigation.stop(); - player.openMenu(getGuiProviderFromSideTab(tabIndex), (buffer) -> buffer.writeInt(getId())); - } - return true; - } - - public MenuProvider getGuiProviderFromSideTab(int tabIndex) { - if (tabIndex == SideTab.TASK_CONFIG.getIndex()) { - return task.getTaskConfigGuiProvider(this); - } else if (tabIndex == SideTab.TASK_INFO.getIndex()) { - return task.getTaskInfoGuiProvider(this); - } else { - return this.getMaidBackpackType().getGuiProvider(getId()); - } - } - @Override protected void dropEquipment() { if (this.getOwnerUUID() != null && !level.isClientSide /* && !PetBedDrop.hasPetBedPos(this) */) { @@ -1213,6 +1230,10 @@ protected Component getTypeName() { @Override public SpawnGroupData finalizeSpawn(ServerLevelAccessor worldIn, DifficultyInstance difficultyIn, MobSpawnType reason, @Nullable SpawnGroupData spawnDataIn) { + // 为结构生成的女仆添加特殊标签 + if (reason == MobSpawnType.STRUCTURE) { + this.structureSpawn = true; + } int modelSize = ServerCustomPackLoader.SERVER_MAID_MODELS.getModelSize(); // 这里居然可能为 0 if (modelSize > 0) { @@ -1234,6 +1255,44 @@ public void setItemSlot(EquipmentSlot slot, ItemStack stack) { } } + @Override + public void onEquipItem(EquipmentSlot slot, ItemStack oldItem, ItemStack newItem) { + super.onEquipItem(slot, oldItem, newItem); + if (newItem.isEmpty() || this.firstTick || !slot.isArmor()) { + return; + } + + // 触发成就 + if (this.getOwner() instanceof ServerPlayer serverPlayer) { + InitTrigger.MAID_EVENT.get().trigger(serverPlayer, TriggerType.ANY_EQUIPMENT); + } + + // 如果是下界合金 + if (isNetheriteArmor(newItem)) { + // 检查全身装备 + for (EquipmentSlot slotIn : EquipmentSlot.values()) { + if (!slotIn.isArmor() || slotIn == slot || slotIn == EquipmentSlot.BODY) { + continue; + } + ItemStack itemBySlot = getItemBySlot(slotIn); + if (!isNetheriteArmor(itemBySlot)) { + return; + } + } + // 触发事件 + if (this.getOwner() instanceof ServerPlayer serverPlayer) { + InitTrigger.MAID_EVENT.get().trigger(serverPlayer, TriggerType.ALL_NETHERITE_EQUIPMENT); + } + } + } + + private boolean isNetheriteArmor(ItemStack stack) { + if (stack.getItem() instanceof ArmorItem armorItem) { + return armorItem.getMaterial() == ArmorMaterials.NETHERITE; + } + return false; + } + @Override public void playSound(SoundEvent soundEvent, float volume, float pitch) { if (soundEvent.getLocation().getPath().startsWith("maid") && !level.isClientSide) { @@ -1366,6 +1425,9 @@ public void startSleeping(BlockPos pPos) { super.startSleeping(pPos); this.setHealth(this.getMaxHealth()); this.favorabilityManager.apply(Type.SLEEP); + if (this.getOwner() instanceof ServerPlayer serverPlayer) { + InitTrigger.MAID_EVENT.get().trigger(serverPlayer, TriggerType.MAID_SLEEP); + } } public void setBackpackDelay() { @@ -1408,11 +1470,15 @@ public void setBegging(boolean begging) { } public boolean isHomeModeEnable() { - return this.entityData.get(DATA_HOME_MODE); + return this.configManager.isHomeModeEnable(); } public void setHomeModeEnable(boolean enable) { - this.entityData.set(DATA_HOME_MODE, enable); + this.configManager.setHomeModeEnable(enable); + } + + public MaidConfigManager getConfigManager() { + return configManager; } @Override @@ -1487,19 +1553,19 @@ public MaidScriptBookManager getScriptBookManager() { } public boolean isPickup() { - return this.entityData.get(DATA_PICKUP); + return this.configManager.isPickup(); } public void setPickup(boolean isPickup) { - this.entityData.set(DATA_PICKUP, isPickup); + this.configManager.setPickup(isPickup); } public boolean isRideable() { - return this.entityData.get(DATA_RIDEABLE); + return this.configManager.isRideable(); } public void setRideable(boolean rideable) { - this.entityData.set(DATA_RIDEABLE, rideable); + this.configManager.setRideable(rideable); } public int getHunger() { @@ -1697,11 +1763,19 @@ public float getLuck() { return (float) this.getAttributeValue(Attributes.LUCK); } + public MaidKillRecordManager getKillRecordManager() { + return killRecordManager; + } + @Override public boolean hasFishingHook() { return this.fishing != null; } + public boolean isStructureSpawn() { + return structureSpawn; + } + public List getEffects() { return effects; } diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/passive/MaidConfigManager.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/passive/MaidConfigManager.java new file mode 100644 index 000000000..0843795bb --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/passive/MaidConfigManager.java @@ -0,0 +1,310 @@ +package com.github.tartaricacid.touhoulittlemaid.entity.passive; + +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.Tag; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.syncher.EntityDataAccessor; +import net.minecraft.network.syncher.EntityDataSerializers; +import net.minecraft.network.syncher.SynchedEntityData; +import net.minecraft.util.Mth; + +public class MaidConfigManager { + private static final EntityDataAccessor DATA_PICKUP = SynchedEntityData.defineId(EntityMaid.class, EntityDataSerializers.BOOLEAN); + private static final EntityDataAccessor DATA_HOME_MODE = SynchedEntityData.defineId(EntityMaid.class, EntityDataSerializers.BOOLEAN); + private static final EntityDataAccessor DATA_RIDEABLE = SynchedEntityData.defineId(EntityMaid.class, EntityDataSerializers.BOOLEAN); + + private static final EntityDataAccessor BACKPACK_SHOW = SynchedEntityData.defineId(EntityMaid.class, EntityDataSerializers.BOOLEAN); + private static final EntityDataAccessor BACK_ITEM_SHOW = SynchedEntityData.defineId(EntityMaid.class, EntityDataSerializers.BOOLEAN); + private static final EntityDataAccessor CHATBUBBLE_SHOW = SynchedEntityData.defineId(EntityMaid.class, EntityDataSerializers.BOOLEAN); + private static final EntityDataAccessor SOUND_FREQ = SynchedEntityData.defineId(EntityMaid.class, EntityDataSerializers.FLOAT); + private static final EntityDataAccessor PICKUP_TYPE = SynchedEntityData.defineId(EntityMaid.class, EntityDataSerializers.INT); + private static final EntityDataAccessor OPEN_DOOR = SynchedEntityData.defineId(EntityMaid.class, EntityDataSerializers.BOOLEAN); + private static final EntityDataAccessor OPEN_FENCE_GATE = SynchedEntityData.defineId(EntityMaid.class, EntityDataSerializers.BOOLEAN); + + private static final String PICKUP_TAG = "MaidIsPickup"; + private static final String HOME_TAG = "MaidIsHome"; + private static final String RIDEABLE_TAG = "MaidIsRideable"; + + private static final String MAID_SUB_CONFIG_TAG = "MaidSubConfig"; + private static final String BACKPACK_SHOW_TAG = "BackpackShow"; + private static final String BACK_ITEM_SHOW_TAG = "BackItemShow"; + private static final String CHATBUBBLE_SHOW_TAG = "ChatBubbleShow"; + private static final String SOUND_FREQ_TAG = "SoundFreq"; + private static final String PICKUP_TYPE_TAG = "PickupType"; + private static final String OPEN_DOOR_TAG = "OpenDoor"; + private static final String OPEN_FENCE_GATE_TAG = "OpenFenceGate"; + + private final SynchedEntityData entityData; + + MaidConfigManager(SynchedEntityData entityData) { + this.entityData = entityData; + } + + void defineSynchedData(SynchedEntityData.Builder builder) { + builder.define(DATA_PICKUP, true); + builder.define(DATA_HOME_MODE, false); + builder.define(DATA_RIDEABLE, true); + + builder.define(BACKPACK_SHOW, true); + builder.define(BACK_ITEM_SHOW, true); + builder.define(CHATBUBBLE_SHOW, true); + builder.define(SOUND_FREQ, 1.0f); + builder.define(PICKUP_TYPE, PickType.ALL.ordinal()); + builder.define(OPEN_DOOR, true); + builder.define(OPEN_FENCE_GATE, true); + } + + void addAdditionalSaveData(CompoundTag compound) { + compound.putBoolean(PICKUP_TAG, isPickup()); + compound.putBoolean(HOME_TAG, isHomeModeEnable()); + compound.putBoolean(RIDEABLE_TAG, isRideable()); + + CompoundTag maidSubConfig = new CompoundTag(); + maidSubConfig.putBoolean(BACKPACK_SHOW_TAG, isShowBackpack()); + maidSubConfig.putBoolean(BACK_ITEM_SHOW_TAG, isShowBackItem()); + maidSubConfig.putBoolean(CHATBUBBLE_SHOW_TAG, isChatBubbleShow()); + maidSubConfig.putFloat(SOUND_FREQ_TAG, getSoundFreq()); + maidSubConfig.putInt(PICKUP_TYPE_TAG, getPickupType().ordinal()); + maidSubConfig.putBoolean(OPEN_DOOR_TAG, isOpenDoor()); + maidSubConfig.putBoolean(OPEN_FENCE_GATE_TAG, isOpenFenceGate()); + compound.put(MAID_SUB_CONFIG_TAG, maidSubConfig); + } + + void readAdditionalSaveData(CompoundTag compound) { + if (compound.contains(PICKUP_TAG, Tag.TAG_BYTE)) { + setPickup(compound.getBoolean(PICKUP_TAG)); + } + if (compound.contains(HOME_TAG, Tag.TAG_BYTE)) { + setHomeModeEnable(compound.getBoolean(HOME_TAG)); + } + if (compound.contains(RIDEABLE_TAG, Tag.TAG_BYTE)) { + setRideable(compound.getBoolean(RIDEABLE_TAG)); + } + if (compound.contains(MAID_SUB_CONFIG_TAG, Tag.TAG_COMPOUND)) { + CompoundTag maidSubConfig = compound.getCompound(MAID_SUB_CONFIG_TAG); + if (maidSubConfig.contains(BACKPACK_SHOW_TAG)) { + setShowBackpack(maidSubConfig.getBoolean(BACKPACK_SHOW_TAG)); + } + if (maidSubConfig.contains(BACK_ITEM_SHOW_TAG)) { + setShowBackItem(maidSubConfig.getBoolean(BACK_ITEM_SHOW_TAG)); + } + if (maidSubConfig.contains(CHATBUBBLE_SHOW_TAG)) { + setChatBubbleShow(maidSubConfig.getBoolean(CHATBUBBLE_SHOW_TAG)); + } + if (maidSubConfig.contains(SOUND_FREQ_TAG)) { + setSoundFreq(maidSubConfig.getFloat(SOUND_FREQ_TAG)); + } + if (maidSubConfig.contains(PICKUP_TYPE_TAG)) { + setPickupType(PickType.values()[maidSubConfig.getInt(PICKUP_TYPE_TAG)]); + } + if (maidSubConfig.contains(OPEN_DOOR_TAG)) { + setOpenDoor(maidSubConfig.getBoolean(OPEN_DOOR_TAG)); + } + if (maidSubConfig.contains(OPEN_FENCE_GATE_TAG)) { + setOpenFenceGate(maidSubConfig.getBoolean(OPEN_FENCE_GATE_TAG)); + } + } + } + + boolean isHomeModeEnable() { + return this.entityData.get(DATA_HOME_MODE); + } + + void setHomeModeEnable(boolean enable) { + this.entityData.set(DATA_HOME_MODE, enable); + } + + boolean isPickup() { + return this.entityData.get(DATA_PICKUP); + } + + void setPickup(boolean isPickup) { + this.entityData.set(DATA_PICKUP, isPickup); + } + + boolean isRideable() { + return this.entityData.get(DATA_RIDEABLE); + } + + void setRideable(boolean rideable) { + this.entityData.set(DATA_RIDEABLE, rideable); + } + + public SyncNetwork getSyncNetwork() { + return new SyncNetwork( + this.isShowBackpack(), + this.isShowBackItem(), + this.isChatBubbleShow(), + this.getSoundFreq(), + this.getPickupType(), + this.isOpenDoor(), + this.isOpenFenceGate() + ); + } + + public boolean isShowBackpack() { + return this.entityData.get(BACKPACK_SHOW); + } + + public void setShowBackpack(boolean show) { + this.entityData.set(BACKPACK_SHOW, show); + } + + public boolean isShowBackItem() { + return this.entityData.get(BACK_ITEM_SHOW); + } + + public void setShowBackItem(boolean show) { + this.entityData.set(BACK_ITEM_SHOW, show); + } + + public boolean isChatBubbleShow() { + return this.entityData.get(CHATBUBBLE_SHOW); + } + + public void setChatBubbleShow(boolean show) { + this.entityData.set(CHATBUBBLE_SHOW, show); + } + + public float getSoundFreq() { + return this.entityData.get(SOUND_FREQ); + } + + public void setSoundFreq(float freq) { + this.entityData.set(SOUND_FREQ, Mth.clamp(freq, 0f, 1f)); + } + + public PickType getPickupType() { + int index = this.entityData.get(PICKUP_TYPE); + return PickType.values()[index]; + } + + public void setPickupType(PickType type) { + this.entityData.set(PICKUP_TYPE, type.ordinal()); + } + + public boolean isOpenDoor() { + return this.entityData.get(OPEN_DOOR); + } + + public void setOpenDoor(boolean openDoor) { + this.entityData.set(OPEN_DOOR, openDoor); + } + + public boolean isOpenFenceGate() { + return this.entityData.get(OPEN_FENCE_GATE); + } + + public void setOpenFenceGate(boolean openFenceGate) { + this.entityData.set(OPEN_FENCE_GATE, openFenceGate); + } + + public static final class SyncNetwork { + private boolean showBackpack; + private boolean showBackItem; + private boolean showChatBubble; + private float soundFreq; + private PickType pickType; + private boolean openDoor; + private boolean openFenceGate; + + public SyncNetwork(boolean showBackpack, boolean showBackItem, boolean showChatBubble, float soundFreq, + PickType pickType, boolean openDoor, boolean openFenceGate) { + this.showBackpack = showBackpack; + this.showBackItem = showBackItem; + this.showChatBubble = showChatBubble; + this.soundFreq = soundFreq; + this.pickType = pickType; + this.openDoor = openDoor; + this.openFenceGate = openFenceGate; + } + + public static void encode(SyncNetwork message, FriendlyByteBuf buf) { + buf.writeBoolean(message.showBackpack); + buf.writeBoolean(message.showBackItem); + buf.writeBoolean(message.showChatBubble); + buf.writeFloat(message.soundFreq); + buf.writeEnum(message.pickType); + buf.writeBoolean(message.openDoor); + buf.writeBoolean(message.openFenceGate); + } + + public static SyncNetwork decode(FriendlyByteBuf buf) { + boolean showBackpack = buf.readBoolean(); + boolean showBackItem = buf.readBoolean(); + boolean showChatBubble = buf.readBoolean(); + float soundFreq = buf.readFloat(); + PickType pickType = buf.readEnum(PickType.class); + boolean openDoor = buf.readBoolean(); + boolean openFenceGate = buf.readBoolean(); + return new SyncNetwork(showBackpack, showBackItem, showChatBubble, soundFreq, pickType, openDoor, openFenceGate); + } + + public static void handle(SyncNetwork message, EntityMaid maid) { + MaidConfigManager configManager = maid.getConfigManager(); + configManager.setShowBackpack(message.showBackpack); + configManager.setShowBackItem(message.showBackItem); + configManager.setChatBubbleShow(message.showChatBubble); + configManager.setSoundFreq(message.soundFreq); + configManager.setPickupType(message.pickType); + configManager.setOpenDoor(message.openDoor); + configManager.setOpenFenceGate(message.openFenceGate); + } + + public boolean showBackpack() { + return showBackpack; + } + + public boolean showBackItem() { + return showBackItem; + } + + public boolean showChatBubble() { + return showChatBubble; + } + + public float soundFreq() { + return soundFreq; + } + + public PickType pickType() { + return pickType; + } + + public boolean openDoor() { + return openDoor; + } + + public boolean openFenceGate() { + return openFenceGate; + } + + public void setShowBackpack(boolean showBackpack) { + this.showBackpack = showBackpack; + } + + public void setShowBackItem(boolean showBackItem) { + this.showBackItem = showBackItem; + } + + public void setShowChatBubble(boolean showChatBubble) { + this.showChatBubble = showChatBubble; + } + + public void setSoundFreq(float soundFreq) { + this.soundFreq = Mth.clamp(soundFreq, 0f, 1f); + } + + public void setPickType(PickType pickType) { + this.pickType = pickType; + } + + public void setOpenDoor(boolean openDoor) { + this.openDoor = openDoor; + } + + public void setOpenFenceGate(boolean openFenceGate) { + this.openFenceGate = openFenceGate; + } + } +} diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/passive/MaidKillRecordManager.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/passive/MaidKillRecordManager.java new file mode 100644 index 000000000..330d2b037 --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/passive/MaidKillRecordManager.java @@ -0,0 +1,73 @@ +package com.github.tartaricacid.touhoulittlemaid.entity.passive; + +import com.github.tartaricacid.touhoulittlemaid.advancements.maid.TriggerType; +import com.github.tartaricacid.touhoulittlemaid.init.InitTrigger; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.boss.enderdragon.EnderDragon; +import net.minecraft.world.entity.boss.wither.WitherBoss; +import net.minecraft.world.entity.monster.Slime; + +import javax.annotation.Nullable; + +public final class MaidKillRecordManager { + private static final String KILL_RECORD = "KillRecord"; + private static final String TOTAL_COUNT = "TotalCount"; + private static final String SLIME_COUNT = "Slime"; + private static final String WITHER_COUNT = "Wither"; + private static final String ENDER_DRAGON_COUNT = "EnderDragon"; + + private int totalCount; + private int slimeCount; + private int witherCount; + private int enderDragonCount; + + void addAdditionalSaveData(CompoundTag compound) { + CompoundTag killRecord = new CompoundTag(); + killRecord.putInt(KILL_RECORD, totalCount); + killRecord.putInt(SLIME_COUNT, slimeCount); + killRecord.putInt(WITHER_COUNT, witherCount); + killRecord.putInt(ENDER_DRAGON_COUNT, enderDragonCount); + compound.put(KILL_RECORD, killRecord); + } + + void readAdditionalSaveData(CompoundTag compound) { + if (compound.contains(KILL_RECORD)) { + CompoundTag killRecord = compound.getCompound(KILL_RECORD); + totalCount = killRecord.getInt(TOTAL_COUNT); + slimeCount = killRecord.getInt(SLIME_COUNT); + witherCount = killRecord.getInt(WITHER_COUNT); + enderDragonCount = killRecord.getInt(ENDER_DRAGON_COUNT); + } + } + + public void onTargetDeath(EntityMaid maid, LivingEntity target) { + LivingEntity owner = maid.getOwner(); + this.totalCount++; + triggerKill(owner, TriggerType.MAID_KILL_MOB); + if (this.totalCount >= 100) { + triggerKill(owner, TriggerType.KILL_100); + } + if (target instanceof Slime) { + this.slimeCount++; + if (slimeCount >= 300) { + triggerKill(owner, TriggerType.KILL_SLIME_300); + } + } + if (target instanceof WitherBoss) { + this.witherCount++; + triggerKill(owner, TriggerType.KILL_WITHER); + } + if (target instanceof EnderDragon) { + this.enderDragonCount++; + triggerKill(owner, TriggerType.KILL_DRAGON); + } + } + + private void triggerKill(@Nullable LivingEntity owner, String eventName) { + if (owner instanceof ServerPlayer serverPlayer) { + InitTrigger.MAID_EVENT.get().trigger(serverPlayer, eventName); + } + } +} diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/passive/PickType.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/passive/PickType.java new file mode 100644 index 000000000..06ae8088c --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/passive/PickType.java @@ -0,0 +1,43 @@ +package com.github.tartaricacid.touhoulittlemaid.entity.passive; + +public enum PickType { + ONLY_ITEM(true, false), + ONLY_XP(false, true), + ALL(true, true); + + private final boolean pickItem; + private final boolean pickXp; + + PickType(boolean pickItem, boolean pickXp) { + this.pickItem = pickItem; + this.pickXp = pickXp; + } + + public boolean canPickItem() { + return pickItem; + } + + public boolean canPickXp() { + return pickXp; + } + + public static String getTransKey(final PickType pickType) { + return switch (pickType) { + case ONLY_ITEM -> "gui.touhou_little_maid.maid_config.value.item"; + case ONLY_XP -> "gui.touhou_little_maid.maid_config.value.xp"; + default -> "gui.touhou_little_maid.maid_config.value.all"; + }; + } + + public static PickType getNextPickType(final PickType pickType) { + return values()[(pickType.ordinal() + 1) % values().length]; + } + + public static PickType getPreviousPickType(final PickType pickType) { + int index = pickType.ordinal() - 1; + if (index < 0) { + index = values().length - 1; + } + return values()[index % values().length]; + } +} \ No newline at end of file diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/passive/SideTab.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/passive/SideTab.java index de12909f3..057375b84 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/passive/SideTab.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/passive/SideTab.java @@ -1,10 +1,8 @@ package com.github.tartaricacid.touhoulittlemaid.entity.passive; public enum SideTab { - TASK_CONFIG(0), - TASK_BOOK(1), - TASK_INFO(2), - GLOBAL_CONFIG(3); + TASK_BOOK(0), + GLOBAL_CONFIG(1); private final int index; diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/passive/TabIndex.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/passive/TabIndex.java index 04caa2401..7f0606290 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/passive/TabIndex.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/passive/TabIndex.java @@ -2,5 +2,6 @@ public final class TabIndex { public static final int MAIN = 0; - public static final int CONFIG = 5; + public static final int TASK_CONFIG = 1; + public static final int MAID_CONFIG = 2; } \ No newline at end of file diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/poi/MaidPoiManager.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/poi/MaidPoiManager.java index bbec54217..940e03090 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/poi/MaidPoiManager.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/poi/MaidPoiManager.java @@ -14,7 +14,8 @@ import java.util.Set; public final class MaidPoiManager { - private static final Set JOYS = ImmutableList.of(InitBlocks.COMPUTER.get(), InitBlocks.BOOKSHELF.get(), InitBlocks.KEYBOARD.get(), InitBlocks.GOMOKU.get()) + private static final Set JOYS = ImmutableList.of(InitBlocks.COMPUTER.get(), InitBlocks.BOOKSHELF.get(), InitBlocks.KEYBOARD.get(), + InitBlocks.GOMOKU.get(), InitBlocks.CCHESS.get(), InitBlocks.WCHESS.get()) .stream().flatMap(block -> block.getStateDefinition().getPossibleStates().stream()) .collect(ImmutableSet.toImmutableSet()); private static final Set BEDS = ImmutableList.of(InitBlocks.MAID_BED.get()) diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/projectile/MaidFishingHook.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/projectile/MaidFishingHook.java index df50b187e..6325f9646 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/projectile/MaidFishingHook.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/projectile/MaidFishingHook.java @@ -1,9 +1,11 @@ package com.github.tartaricacid.touhoulittlemaid.entity.projectile; import com.github.tartaricacid.touhoulittlemaid.TouhouLittleMaid; +import com.github.tartaricacid.touhoulittlemaid.advancements.maid.TriggerType; import com.github.tartaricacid.touhoulittlemaid.api.event.MaidFishedEvent; import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid; import com.github.tartaricacid.touhoulittlemaid.entity.task.TaskFishing; +import com.github.tartaricacid.touhoulittlemaid.init.InitTrigger; import net.minecraft.core.BlockPos; import net.minecraft.core.particles.ParticleTypes; import net.minecraft.nbt.CompoundTag; @@ -16,6 +18,7 @@ import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerEntity; import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.sounds.SoundEvents; import net.minecraft.sounds.SoundSource; import net.minecraft.tags.FluidTags; @@ -26,6 +29,7 @@ import net.minecraft.world.entity.item.ItemEntity; import net.minecraft.world.entity.projectile.Projectile; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.state.BlockState; @@ -393,7 +397,15 @@ protected List getLoot(MinecraftServer server, LootParams lootParams) } protected void spawnLoot(List randomItems, EntityMaid maid) { + EntityMaid maidOwner = getMaidOwner(); + ServerPlayer serverPlayer = null; + if (maidOwner != null && maidOwner.getOwner() instanceof ServerPlayer serverPlayerIn) { + serverPlayer = serverPlayerIn; + } for (ItemStack result : randomItems) { + if (serverPlayer != null && result.is(Items.ENCHANTED_BOOK)) { + InitTrigger.MAID_EVENT.get().trigger(serverPlayer, TriggerType.MAID_FISHING_ENCHANTED_BOOK); + } ItemEntity itemEntity = new ItemEntity(this.level(), maid.getX(), maid.getY() + 0.5, maid.getZ(), result); itemEntity.setDeltaMovement(0, 0.1, 0); this.level.addFreshEntity(itemEntity); @@ -405,6 +417,10 @@ protected void addExtraLoot(List randomItems) { } protected void afterFishing() { + EntityMaid maidOwner = getMaidOwner(); + if (maidOwner != null && maidOwner.getOwner() instanceof ServerPlayer serverPlayer) { + InitTrigger.MAID_EVENT.get().trigger(serverPlayer, TriggerType.MAID_FISHING); + } } protected void hurtRod(EntityMaid maid, ItemStack rodItem, int rodDamage) { diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/task/TaskBoardGames.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/task/TaskBoardGames.java index 8b4e4681d..c1714e443 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/task/TaskBoardGames.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/entity/task/TaskBoardGames.java @@ -2,7 +2,7 @@ import com.github.tartaricacid.touhoulittlemaid.TouhouLittleMaid; import com.github.tartaricacid.touhoulittlemaid.api.task.IMaidTask; -import com.github.tartaricacid.touhoulittlemaid.entity.ai.brain.task.MaidGomokuTask; +import com.github.tartaricacid.touhoulittlemaid.entity.ai.brain.task.MaidBoardGameTask; import com.github.tartaricacid.touhoulittlemaid.entity.favorability.Type; import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid; import com.github.tartaricacid.touhoulittlemaid.init.InitItems; @@ -39,8 +39,8 @@ public SoundEvent getAmbientSound(EntityMaid maid) { @Override public List>> createBrainTasks(EntityMaid maid) { - Pair> gomoku = Pair.of(5, new MaidGomokuTask(0.6f, 2)); - return Lists.newArrayList(gomoku); + Pair> boardGame = Pair.of(5, new MaidBoardGameTask(0.6f, 2)); + return Lists.newArrayList(boardGame); } @Override diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/event/EntityDeathEvent.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/event/EntityDeathEvent.java new file mode 100644 index 000000000..9f71c2718 --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/event/EntityDeathEvent.java @@ -0,0 +1,18 @@ +package com.github.tartaricacid.touhoulittlemaid.event; + +import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid; +import net.minecraft.world.entity.Entity; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.event.entity.living.LivingDeathEvent; + +@EventBusSubscriber +public class EntityDeathEvent { + @SubscribeEvent + public static void onEntityDeath(LivingDeathEvent event) { + Entity causingEntity = event.getSource().getEntity(); + if (causingEntity instanceof EntityMaid maid) { + maid.getKillRecordManager().onTargetDeath(maid, event.getEntity()); + } + } +} diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/event/maid/ApplyGoldenAppleEvent.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/event/maid/ApplyGoldenAppleEvent.java index e9b091d92..5eb3c5cd1 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/event/maid/ApplyGoldenAppleEvent.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/event/maid/ApplyGoldenAppleEvent.java @@ -1,8 +1,11 @@ package com.github.tartaricacid.touhoulittlemaid.event.maid; +import com.github.tartaricacid.touhoulittlemaid.advancements.maid.TriggerType; import com.github.tartaricacid.touhoulittlemaid.api.event.InteractMaidEvent; import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid; +import com.github.tartaricacid.touhoulittlemaid.init.InitTrigger; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.player.Player; import net.minecraft.world.food.FoodProperties; import net.minecraft.world.food.Foods; @@ -23,6 +26,9 @@ public static void onInteractMaid(InteractMaidEvent event) { if (player.isDiscrete() && (food == Foods.GOLDEN_APPLE || food == Foods.ENCHANTED_GOLDEN_APPLE)) { maid.eat(world, stack); + if (food == Foods.ENCHANTED_GOLDEN_APPLE && player instanceof ServerPlayer serverPlayer) { + InitTrigger.MAID_EVENT.get().trigger(serverPlayer, TriggerType.EAT_ENCHANTED_GOLDEN_APPLE); + } event.setCanceled(true); } } diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/event/maid/ApplyPotionEffectEvent.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/event/maid/ApplyPotionEffectEvent.java index dd6a2094d..61d9b2c74 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/event/maid/ApplyPotionEffectEvent.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/event/maid/ApplyPotionEffectEvent.java @@ -1,8 +1,11 @@ package com.github.tartaricacid.touhoulittlemaid.event.maid; +import com.github.tartaricacid.touhoulittlemaid.advancements.maid.TriggerType; import com.github.tartaricacid.touhoulittlemaid.api.event.InteractMaidEvent; import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid; +import com.github.tartaricacid.touhoulittlemaid.init.InitTrigger; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.sounds.SoundEvents; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; @@ -39,6 +42,9 @@ public static void onInteractMaid(InteractMaidEvent event) { ItemHandlerHelper.giveItemToPlayer(player, new ItemStack(Items.BUCKET)); } maid.playSound(SoundEvents.GENERIC_DRINK, 0.6f, 0.8F + world.random.nextFloat() * 0.4F); + if (player instanceof ServerPlayer serverPlayer) { + InitTrigger.MAID_EVENT.get().trigger(serverPlayer, TriggerType.CLEAR_MAID_EFFECTS); + } event.setCanceled(true); } } diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/event/maid/GetExpBottleEvent.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/event/maid/GetExpBottleEvent.java index 568413b78..0c79d6001 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/event/maid/GetExpBottleEvent.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/event/maid/GetExpBottleEvent.java @@ -1,7 +1,10 @@ package com.github.tartaricacid.touhoulittlemaid.event.maid; +import com.github.tartaricacid.touhoulittlemaid.advancements.maid.TriggerType; import com.github.tartaricacid.touhoulittlemaid.api.event.InteractMaidEvent; import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid; +import com.github.tartaricacid.touhoulittlemaid.init.InitTrigger; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.sounds.SoundEvents; import net.minecraft.world.Containers; import net.minecraft.world.entity.player.Player; @@ -45,6 +48,9 @@ public static void onInteract(InteractMaidEvent event) { Containers.dropItemStack(world, player.getX(), player.getY(), player.getZ(), xpBottles); } maid.playSound(SoundEvents.ITEM_PICKUP, 0.2F, ((world.random.nextFloat() - world.random.nextFloat()) * 0.7F + 1.0F) * 2.0F); + if (player instanceof ServerPlayer serverPlayer) { + InitTrigger.MAID_EVENT.get().trigger(serverPlayer, TriggerType.TAKE_MAID_XP); + } event.setCanceled(true); } } diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/event/maid/HandleBackpackEvent.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/event/maid/HandleBackpackEvent.java index 254fdcdcd..7e52a6f1f 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/event/maid/HandleBackpackEvent.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/event/maid/HandleBackpackEvent.java @@ -1,9 +1,12 @@ package com.github.tartaricacid.touhoulittlemaid.event.maid; +import com.github.tartaricacid.touhoulittlemaid.advancements.maid.TriggerType; import com.github.tartaricacid.touhoulittlemaid.api.backpack.IMaidBackpack; import com.github.tartaricacid.touhoulittlemaid.api.event.InteractMaidEvent; import com.github.tartaricacid.touhoulittlemaid.entity.backpack.BackpackManager; import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid; +import com.github.tartaricacid.touhoulittlemaid.init.InitTrigger; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.sounds.SoundEvents; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; @@ -42,6 +45,9 @@ public static void onInteractMaid(InteractMaidEvent event) { backpack.onPutOn(stack, player, maid); stack.shrink(1); maid.playSound(SoundEvents.HORSE_SADDLE, 0.5F, 1.0F); + if (maid.getOwner() instanceof ServerPlayer serverPlayer) { + InitTrigger.MAID_EVENT.get().trigger(serverPlayer, TriggerType.MAID_BACKPACK); + } event.setCanceled(true); } }); diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/event/maid/SaddleMaidEvent.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/event/maid/SaddleMaidEvent.java index 472ca9b72..e17e12672 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/event/maid/SaddleMaidEvent.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/event/maid/SaddleMaidEvent.java @@ -1,9 +1,12 @@ package com.github.tartaricacid.touhoulittlemaid.event.maid; +import com.github.tartaricacid.touhoulittlemaid.advancements.maid.TriggerType; import com.github.tartaricacid.touhoulittlemaid.api.event.InteractMaidEvent; import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid; +import com.github.tartaricacid.touhoulittlemaid.init.InitTrigger; import net.minecraft.client.Minecraft; import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; @@ -26,6 +29,9 @@ public static void onInteract(InteractMaidEvent event) { if (success && FMLLoader.getDist() == Dist.CLIENT) { SaddleMaidEvent.showTips(); } + if (player instanceof ServerPlayer serverPlayer) { + InitTrigger.MAID_EVENT.get().trigger(serverPlayer, TriggerType.PICKUP_MAID); + } event.setCanceled(true); return; } diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/geckolib3/core/AnimatableEntity.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/geckolib3/core/AnimatableEntity.java index ff5232608..09f455729 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/geckolib3/core/AnimatableEntity.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/geckolib3/core/AnimatableEntity.java @@ -60,7 +60,7 @@ public boolean setCustomAnimations(@NotNull AnimationEvent animationEvent) { } if (!mc.isPaused() || this.manager.shouldPlayWhilePaused) { - this.manager.tick = currentTick; + this.manager.tick = Math.max(this.manager.tick, currentTick); double gameTick = manager.tick; double deltaTicks = gameTick - this.lastGameTickTime; this.seekTime += deltaTicks; @@ -118,7 +118,11 @@ public AnimatedGeoModel getCurrentModel() { } public double getCurrentTick(AnimationEvent animationEvent) { - return this.entity.tickCount + animationEvent.getPartialTick(); + float partialTick = animationEvent.getPartialTick(); + if (partialTick == 1.0f && partialTick != Minecraft.getInstance().getTimer().getGameTimeDeltaPartialTick(false)) { + partialTick = Minecraft.getInstance().getTimer().getGameTimeDeltaPartialTick(false); + } + return this.entity.tickCount + partialTick; } public void setMolangQueries(double seekTime) { diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/geckolib3/util/RenderUtils.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/geckolib3/util/RenderUtils.java index 7776082d6..388dc343f 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/geckolib3/util/RenderUtils.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/geckolib3/util/RenderUtils.java @@ -1,7 +1,6 @@ package com.github.tartaricacid.touhoulittlemaid.geckolib3.util; import com.github.tartaricacid.touhoulittlemaid.geckolib3.core.processor.IBone; -import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; import org.joml.Matrix4f; import org.joml.Quaternionf; @@ -9,16 +8,6 @@ import java.util.List; public final class RenderUtils { - private static boolean renderingEntitiesInInventory = false; - - public static void setRenderingEntitiesInInventory(boolean value) { - renderingEntitiesInInventory = value; - } - - public static boolean isRenderingEntitiesInInventory() { - return RenderSystem.isOnRenderThread() && renderingEntitiesInInventory; - } - public static void translateMatrixToBone(PoseStack poseStack, IBone bone) { poseStack.translate(-bone.getPositionX() / 16f, bone.getPositionY() / 16f, bone.getPositionZ() / 16f); } diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/init/InitBlocks.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/init/InitBlocks.java index 4a454d1b4..76bac9191 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/init/InitBlocks.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/init/InitBlocks.java @@ -23,6 +23,8 @@ public final class InitBlocks { public static DeferredBlock MODEL_SWITCHER = BLOCKS.register("model_switcher", BlockModelSwitcher::new); public static DeferredBlock PICNIC_MAT = BLOCKS.register("picnic_mat", BlockPicnicMat::new); public static DeferredBlock GOMOKU = BLOCKS.register("gomoku", BlockGomoku::new); + public static DeferredBlock CCHESS = BLOCKS.register("cchess", BlockCChess::new); + public static DeferredBlock WCHESS = BLOCKS.register("wchess", BlockWChess::new); public static DeferredBlock KEYBOARD = BLOCKS.register("keyboard", BlockKeyboard::new); public static DeferredBlock BOOKSHELF = BLOCKS.register("bookshelf", BlockBookshelf::new); public static DeferredBlock COMPUTER = BLOCKS.register("computer", BlockComputer::new); @@ -35,6 +37,8 @@ public final class InitBlocks { public static Supplier> MAID_BEACON_TE = TILE_ENTITIES.register("maid_beacon", () -> TileEntityMaidBeacon.TYPE); public static Supplier> MODEL_SWITCHER_TE = TILE_ENTITIES.register("model_switcher", () -> TileEntityModelSwitcher.TYPE); public static Supplier> GOMOKU_TE = TILE_ENTITIES.register("gomoku", () -> TileEntityGomoku.TYPE); + public static Supplier> CCHESS_TE = TILE_ENTITIES.register("cchess", () -> TileEntityCChess.TYPE); + public static Supplier> WCHESS_TE = TILE_ENTITIES.register("wchess", () -> TileEntityWChess.TYPE); public static Supplier> KEYBOARD_TE = TILE_ENTITIES.register("keyboard", () -> TileEntityKeyboard.TYPE); public static Supplier> BOOKSHELF_TE = TILE_ENTITIES.register("bookshelf", () -> TileEntityBookshelf.TYPE); public static Supplier> COMPUTER_TE = TILE_ENTITIES.register("computer", () -> TileEntityComputer.TYPE); diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/init/InitContainer.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/init/InitContainer.java index 96b15aaa1..dd57bc29a 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/init/InitContainer.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/init/InitContainer.java @@ -1,10 +1,10 @@ package com.github.tartaricacid.touhoulittlemaid.init; import com.github.tartaricacid.touhoulittlemaid.TouhouLittleMaid; -import com.github.tartaricacid.touhoulittlemaid.inventory.container.MaidConfigContainer; -import com.github.tartaricacid.touhoulittlemaid.inventory.container.PicnicBasketContainer; -import com.github.tartaricacid.touhoulittlemaid.inventory.container.WirelessIOContainer; import com.github.tartaricacid.touhoulittlemaid.inventory.container.backpack.*; +import com.github.tartaricacid.touhoulittlemaid.inventory.container.config.MaidConfigContainer; +import com.github.tartaricacid.touhoulittlemaid.inventory.container.other.PicnicBasketContainer; +import com.github.tartaricacid.touhoulittlemaid.inventory.container.other.WirelessIOContainer; import com.github.tartaricacid.touhoulittlemaid.inventory.container.task.DefaultMaidTaskConfigContainer; import net.minecraft.core.registries.Registries; import net.minecraft.world.inventory.MenuType; diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/init/InitCreativeTabs.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/init/InitCreativeTabs.java index 6a11b04b4..90229aaac 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/init/InitCreativeTabs.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/init/InitCreativeTabs.java @@ -67,6 +67,8 @@ public class InitCreativeTabs { output.accept(KAPPA_COMPASS.get()); output.accept(EXTINGUISHER.get()); output.accept(GOMOKU.get()); + output.accept(CCHESS.get()); + output.accept(WCHESS.get()); output.accept(KEYBOARD.get()); output.accept(BOOKSHELF.get()); output.accept(COMPUTER.get()); diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/init/InitItems.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/init/InitItems.java index d5be1c7de..3fd3cd364 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/init/InitItems.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/init/InitItems.java @@ -53,6 +53,8 @@ public final class InitItems { public static DeferredItem MODEL_SWITCHER = ITEMS.register("model_switcher", ItemModelSwitcher::new); public static DeferredItem CHAIR_SHOW = ITEMS.register("chair_show", ItemChairShow::new); public static DeferredItem GOMOKU = ITEMS.register("gomoku", () -> new BlockItem(InitBlocks.GOMOKU.get(), new Item.Properties())); + public static DeferredItem CCHESS = ITEMS.register("cchess", () -> new BlockItem(InitBlocks.CCHESS.get(), new Item.Properties())); + public static DeferredItem WCHESS = ITEMS.register("wchess", () -> new BlockItem(InitBlocks.WCHESS.get(), new Item.Properties())); public static DeferredItem RED_FOX_SCROLL = ITEMS.register("red_fox_scroll", ItemFoxScroll::new); public static DeferredItem WHITE_FOX_SCROLL = ITEMS.register("white_fox_scroll", ItemFoxScroll::new); public static DeferredItem KEYBOARD = ITEMS.register("keyboard", () -> new BlockItem(InitBlocks.KEYBOARD.get(), new Item.Properties())); @@ -73,4 +75,13 @@ public final class InitItems { public static DeferredItem FAIRY_SPAWN_EGG = ITEMS.register("fairy_spawn_egg", () -> new DeferredSpawnEggItem(() -> EntityFairy.TYPE, 0x171c20, 0xffffff, new Item.Properties())); public static final ResourceLocation MEMORIZABLE_GENSOKYO_LOCATION = ResourceLocation.fromNamespaceAndPath(TouhouLittleMaid.MOD_ID, "memorizable_gensokyo"); + + // 成就图标 + public static DeferredItem CHANGE_CHAIR_MODEL = ITEMS.register("change_chair_model", ItemAdvancementIcon::new); + public static DeferredItem CHANGE_MAID_MODEL = ITEMS.register("change_maid_model", ItemAdvancementIcon::new); + public static DeferredItem MAID_100_HEALTHY = ITEMS.register("maid_100_healthy", ItemAdvancementIcon::new); + public static DeferredItem KILL_SLIME_300 = ITEMS.register("kill_slime_300", ItemAdvancementIcon::new); + public static DeferredItem ALL_NETHERITE_EQUIPMENT = ITEMS.register("all_netherite_equipment", ItemAdvancementIcon::new); + public static DeferredItem KILL_WITHER = ITEMS.register("kill_wither", ItemAdvancementIcon::new); + public static DeferredItem KILL_DRAGON = ITEMS.register("kill_dragon", ItemAdvancementIcon::new); } \ No newline at end of file diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/init/InitTrigger.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/init/InitTrigger.java index cab3f419c..281dff115 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/init/InitTrigger.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/init/InitTrigger.java @@ -1,8 +1,10 @@ package com.github.tartaricacid.touhoulittlemaid.init; import com.github.tartaricacid.touhoulittlemaid.TouhouLittleMaid; -import com.github.tartaricacid.touhoulittlemaid.advancements.GivePatchouliBookConfigTrigger; -import com.github.tartaricacid.touhoulittlemaid.advancements.GiveSmartSlabConfigTrigger; +import com.github.tartaricacid.touhoulittlemaid.advancements.altar.AltarCraftTrigger; +import com.github.tartaricacid.touhoulittlemaid.advancements.maid.MaidEventTrigger; +import com.github.tartaricacid.touhoulittlemaid.advancements.rewards.GivePatchouliBookConfigTrigger; +import com.github.tartaricacid.touhoulittlemaid.advancements.rewards.GiveSmartSlabConfigTrigger; import net.minecraft.advancements.CriterionTrigger; import net.minecraft.core.registries.Registries; import net.neoforged.neoforge.registries.DeferredHolder; @@ -12,4 +14,6 @@ public final class InitTrigger { public static final DeferredRegister> TRIGGERS = DeferredRegister.create(Registries.TRIGGER_TYPE, TouhouLittleMaid.MOD_ID); public static final DeferredHolder, GiveSmartSlabConfigTrigger> GIVE_SMART_SLAB_CONFIG = TRIGGERS.register("give_smart_slab_config", GiveSmartSlabConfigTrigger::new); public static final DeferredHolder, GivePatchouliBookConfigTrigger> GIVE_PATCHOULI_BOOK_CONFIG = TRIGGERS.register("give_patchouli_book_config", GivePatchouliBookConfigTrigger::new); + public static final DeferredHolder, AltarCraftTrigger> ALTAR_CRAFT = TRIGGERS.register("altar_craft", AltarCraftTrigger::new); + public static final DeferredHolder, MaidEventTrigger> MAID_EVENT = TRIGGERS.register("maid_event", MaidEventTrigger::new); } diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/init/registry/CommonRegistry.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/init/registry/CommonRegistry.java index b44d52637..d6fb2c64a 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/init/registry/CommonRegistry.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/init/registry/CommonRegistry.java @@ -2,6 +2,7 @@ import com.github.tartaricacid.touhoulittlemaid.TouhouLittleMaid; import com.github.tartaricacid.touhoulittlemaid.block.multiblock.MultiBlockManager; +import com.github.tartaricacid.touhoulittlemaid.entity.ai.brain.ExtraMaidBrainManager; import com.github.tartaricacid.touhoulittlemaid.entity.ai.fishing.FishingTypeManager; import com.github.tartaricacid.touhoulittlemaid.entity.backpack.BackpackManager; import com.github.tartaricacid.touhoulittlemaid.entity.data.TaskDataRegister; @@ -25,6 +26,7 @@ public static void onSetupEvent(FMLCommonSetupEvent event) { private static void modApiInit() { TouhouLittleMaid.EXTENSIONS = AnnotatedInstanceUtil.getModExtensions(); + ExtraMaidBrainManager.init(); TaskManager.init(); BackpackManager.init(); BaubleManager.init(); diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/inventory/container/MaidConfigContainer.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/inventory/container/config/MaidConfigContainer.java similarity index 95% rename from src/main/java/com/github/tartaricacid/touhoulittlemaid/inventory/container/MaidConfigContainer.java rename to src/main/java/com/github/tartaricacid/touhoulittlemaid/inventory/container/config/MaidConfigContainer.java index bd49bd9c6..1644ddcdf 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/inventory/container/MaidConfigContainer.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/inventory/container/config/MaidConfigContainer.java @@ -1,5 +1,6 @@ -package com.github.tartaricacid.touhoulittlemaid.inventory.container; +package com.github.tartaricacid.touhoulittlemaid.inventory.container.config; +import com.github.tartaricacid.touhoulittlemaid.inventory.container.AbstractMaidContainer; import net.minecraft.network.chat.Component; import net.minecraft.world.MenuProvider; import net.minecraft.world.entity.player.Inventory; diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/inventory/container/PicnicBasketContainer.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/inventory/container/other/PicnicBasketContainer.java similarity index 99% rename from src/main/java/com/github/tartaricacid/touhoulittlemaid/inventory/container/PicnicBasketContainer.java rename to src/main/java/com/github/tartaricacid/touhoulittlemaid/inventory/container/other/PicnicBasketContainer.java index 87109b432..b493c4ca5 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/inventory/container/PicnicBasketContainer.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/inventory/container/other/PicnicBasketContainer.java @@ -1,4 +1,4 @@ -package com.github.tartaricacid.touhoulittlemaid.inventory.container; +package com.github.tartaricacid.touhoulittlemaid.inventory.container.other; import com.github.tartaricacid.touhoulittlemaid.init.InitItems; import com.github.tartaricacid.touhoulittlemaid.item.ItemPicnicBasket; diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/inventory/container/WirelessIOContainer.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/inventory/container/other/WirelessIOContainer.java similarity index 97% rename from src/main/java/com/github/tartaricacid/touhoulittlemaid/inventory/container/WirelessIOContainer.java rename to src/main/java/com/github/tartaricacid/touhoulittlemaid/inventory/container/other/WirelessIOContainer.java index d6e510256..bc923cb1b 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/inventory/container/WirelessIOContainer.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/inventory/container/other/WirelessIOContainer.java @@ -1,112 +1,112 @@ -package com.github.tartaricacid.touhoulittlemaid.inventory.container; - -import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid; -import com.github.tartaricacid.touhoulittlemaid.init.InitItems; -import com.github.tartaricacid.touhoulittlemaid.item.ItemWirelessIO; -import net.minecraft.world.entity.player.Inventory; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.inventory.AbstractContainerMenu; -import net.minecraft.world.inventory.ClickType; -import net.minecraft.world.inventory.MenuType; -import net.minecraft.world.inventory.Slot; -import net.minecraft.world.item.ItemStack; -import net.neoforged.neoforge.common.extensions.IMenuTypeExtension; -import net.neoforged.neoforge.items.IItemHandler; -import net.neoforged.neoforge.items.ItemStackHandler; -import net.neoforged.neoforge.items.SlotItemHandler; -import org.jetbrains.annotations.NotNull; - -public class WirelessIOContainer extends AbstractContainerMenu { - public static final MenuType TYPE = IMenuTypeExtension.create((windowId, inv, data) -> new WirelessIOContainer(windowId, inv, ItemStack.STREAM_CODEC.decode(data))); - private final ItemStack wirelessIO; - private final ItemStackHandler filterListInv; - - public WirelessIOContainer(int id, Inventory inventory, ItemStack wirelessIO) { - super(TYPE, id); - this.wirelessIO = wirelessIO; - this.filterListInv = ItemWirelessIO.getFilterList(inventory.player.registryAccess(), wirelessIO); - this.addPlayerSlots(inventory); - this.addWirelessIOSlots(); - } - - @Override - public boolean stillValid(Player playerIn) { - return playerIn.getMainHandItem().getItem() == InitItems.WIRELESS_IO.get(); - } - - @Override - public void clicked(int slotId, int button, ClickType clickTypeIn, Player player) { - // 禁阻一切对当前手持物品的交互,防止刷物品 bug - if (slotId == 27 + player.getInventory().selected) { - return; - } - if (clickTypeIn == ClickType.SWAP) { - return; - } - super.clicked(slotId, button, clickTypeIn, player); - ItemWirelessIO.setFilterList(player.registryAccess(), wirelessIO, filterListInv); - } - - private void addWirelessIOSlots() { - for (int row = 0; row < 3; ++row) { - for (int col = 0; col < 3; ++col) { - this.addSlot(new WirelessIOSlotItemHandler(filterListInv, col + row * 3, 62 + col * 18, 17 + row * 18)); - } - } - } - - private void addPlayerSlots(Inventory inventory) { - for (int row = 0; row < 3; ++row) { - for (int col = 0; col < 9; ++col) { - this.addSlot(new Slot(inventory, col + row * 9 + 9, 8 + col * 18, 84 + row * 18)); - } - } - - for (int col = 0; col < 9; ++col) { - this.addSlot(new Slot(inventory, col, 8 + col * 18, 142)); - } - } - - @Override - public ItemStack quickMoveStack(Player playerIn, int index) { - ItemStack stack1 = ItemStack.EMPTY; - Slot slot = this.slots.get(index); - if (slot != null && slot.hasItem()) { - ItemStack stack2 = slot.getItem(); - stack1 = stack2.copy(); - if (index < 27) { - if (!this.moveItemStackTo(stack2, 27, 36, true)) { - return ItemStack.EMPTY; - } - } else if (!this.moveItemStackTo(stack2, 0, 27, false)) { - return ItemStack.EMPTY; - } - if (stack2.isEmpty()) { - slot.set(ItemStack.EMPTY); - } else { - slot.setChanged(); - } - } - return stack1; - } - - public ItemStack getWirelessIO() { - return wirelessIO; - } - - private class WirelessIOSlotItemHandler extends SlotItemHandler { - private WirelessIOSlotItemHandler(IItemHandler itemHandler, int index, int xPosition, int yPosition) { - super(itemHandler, index, xPosition, yPosition); - } - - @Override - public int getMaxStackSize() { - return 1; - } - - @Override - public boolean mayPlace(@NotNull ItemStack stack) { - return EntityMaid.canInsertItem(stack) && super.mayPlace(stack); - } - } -} +package com.github.tartaricacid.touhoulittlemaid.inventory.container.other; + +import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid; +import com.github.tartaricacid.touhoulittlemaid.init.InitItems; +import com.github.tartaricacid.touhoulittlemaid.item.ItemWirelessIO; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.inventory.ClickType; +import net.minecraft.world.inventory.MenuType; +import net.minecraft.world.inventory.Slot; +import net.minecraft.world.item.ItemStack; +import net.neoforged.neoforge.common.extensions.IMenuTypeExtension; +import net.neoforged.neoforge.items.IItemHandler; +import net.neoforged.neoforge.items.ItemStackHandler; +import net.neoforged.neoforge.items.SlotItemHandler; +import org.jetbrains.annotations.NotNull; + +public class WirelessIOContainer extends AbstractContainerMenu { + public static final MenuType TYPE = IMenuTypeExtension.create((windowId, inv, data) -> new WirelessIOContainer(windowId, inv, ItemStack.STREAM_CODEC.decode(data))); + private final ItemStack wirelessIO; + private final ItemStackHandler filterListInv; + + public WirelessIOContainer(int id, Inventory inventory, ItemStack wirelessIO) { + super(TYPE, id); + this.wirelessIO = wirelessIO; + this.filterListInv = ItemWirelessIO.getFilterList(inventory.player.registryAccess(), wirelessIO); + this.addPlayerSlots(inventory); + this.addWirelessIOSlots(); + } + + @Override + public boolean stillValid(Player playerIn) { + return playerIn.getMainHandItem().getItem() == InitItems.WIRELESS_IO.get(); + } + + @Override + public void clicked(int slotId, int button, ClickType clickTypeIn, Player player) { + // 禁阻一切对当前手持物品的交互,防止刷物品 bug + if (slotId == 27 + player.getInventory().selected) { + return; + } + if (clickTypeIn == ClickType.SWAP) { + return; + } + super.clicked(slotId, button, clickTypeIn, player); + ItemWirelessIO.setFilterList(player.registryAccess(), wirelessIO, filterListInv); + } + + private void addWirelessIOSlots() { + for (int row = 0; row < 3; ++row) { + for (int col = 0; col < 3; ++col) { + this.addSlot(new WirelessIOSlotItemHandler(filterListInv, col + row * 3, 62 + col * 18, 17 + row * 18)); + } + } + } + + private void addPlayerSlots(Inventory inventory) { + for (int row = 0; row < 3; ++row) { + for (int col = 0; col < 9; ++col) { + this.addSlot(new Slot(inventory, col + row * 9 + 9, 8 + col * 18, 84 + row * 18)); + } + } + + for (int col = 0; col < 9; ++col) { + this.addSlot(new Slot(inventory, col, 8 + col * 18, 142)); + } + } + + @Override + public ItemStack quickMoveStack(Player playerIn, int index) { + ItemStack stack1 = ItemStack.EMPTY; + Slot slot = this.slots.get(index); + if (slot != null && slot.hasItem()) { + ItemStack stack2 = slot.getItem(); + stack1 = stack2.copy(); + if (index < 27) { + if (!this.moveItemStackTo(stack2, 27, 36, true)) { + return ItemStack.EMPTY; + } + } else if (!this.moveItemStackTo(stack2, 0, 27, false)) { + return ItemStack.EMPTY; + } + if (stack2.isEmpty()) { + slot.set(ItemStack.EMPTY); + } else { + slot.setChanged(); + } + } + return stack1; + } + + public ItemStack getWirelessIO() { + return wirelessIO; + } + + private class WirelessIOSlotItemHandler extends SlotItemHandler { + private WirelessIOSlotItemHandler(IItemHandler itemHandler, int index, int xPosition, int yPosition) { + super(itemHandler, index, xPosition, yPosition); + } + + @Override + public int getMaxStackSize() { + return 1; + } + + @Override + public boolean mayPlace(@NotNull ItemStack stack) { + return EntityMaid.canInsertItem(stack) && super.mayPlace(stack); + } + } +} diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/ItemAdvancementIcon.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/ItemAdvancementIcon.java new file mode 100644 index 000000000..6421f648a --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/ItemAdvancementIcon.java @@ -0,0 +1,25 @@ +package com.github.tartaricacid.touhoulittlemaid.item; + +import net.minecraft.ChatFormatting; +import net.minecraft.network.chat.Component; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.TooltipFlag; + +import java.util.List; + +public class ItemAdvancementIcon extends Item { + public ItemAdvancementIcon() { + super((new Properties()).stacksTo(1)); + } + + @Override + public String getDescriptionId() { + return "item.touhou_little_maid.advancement_icon"; + } + + @Override + public void appendHoverText(ItemStack pStack, TooltipContext pContext, List components, TooltipFlag pIsAdvanced) { + components.add(Component.translatable("tooltips.touhou_little_maid.advancement_icon.desc").withStyle(ChatFormatting.GRAY)); + } +} \ No newline at end of file diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/ItemCamera.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/ItemCamera.java index 20257d73d..e2963027d 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/ItemCamera.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/ItemCamera.java @@ -1,15 +1,14 @@ package com.github.tartaricacid.touhoulittlemaid.item; +import com.github.tartaricacid.touhoulittlemaid.advancements.maid.TriggerType; import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid; -import com.github.tartaricacid.touhoulittlemaid.init.InitDataComponent; -import com.github.tartaricacid.touhoulittlemaid.init.InitEntities; -import com.github.tartaricacid.touhoulittlemaid.init.InitItems; -import com.github.tartaricacid.touhoulittlemaid.init.InitSounds; +import com.github.tartaricacid.touhoulittlemaid.init.*; import com.github.tartaricacid.touhoulittlemaid.util.MaidRayTraceHelper; import net.minecraft.ChatFormatting; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.Containers; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; @@ -45,6 +44,9 @@ public InteractionResultHolder use(Level worldIn, Player playerIn, In maid.discard(); playerIn.getCooldowns().addCooldown(this, 20); camera.hurtAndBreak(1, playerIn, EquipmentSlot.MAINHAND); + if (playerIn instanceof ServerPlayer serverPlayer) { + InitTrigger.MAID_EVENT.get().trigger(serverPlayer, TriggerType.PHOTO_MAID); + } } maid.spawnExplosionParticle(); playerIn.playSound(InitSounds.CAMERA_USE.get(), 1.0f, 1.0f); diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/ItemChisel.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/ItemChisel.java index 04000861b..fcee6e633 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/ItemChisel.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/ItemChisel.java @@ -1,15 +1,18 @@ package com.github.tartaricacid.touhoulittlemaid.item; +import com.github.tartaricacid.touhoulittlemaid.advancements.maid.TriggerType; import com.github.tartaricacid.touhoulittlemaid.block.BlockStatue; import com.github.tartaricacid.touhoulittlemaid.init.InitBlocks; import com.github.tartaricacid.touhoulittlemaid.init.InitDataComponent; import com.github.tartaricacid.touhoulittlemaid.init.InitItems; +import com.github.tartaricacid.touhoulittlemaid.init.InitTrigger; import com.github.tartaricacid.touhoulittlemaid.tileentity.TileEntityStatue; import com.google.common.collect.Lists; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.core.Vec3i; import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.sounds.SoundEvents; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; @@ -51,6 +54,9 @@ public InteractionResult useOn(UseOnContext context) { return InteractionResult.PASS; } genStatueBlocks(player, worldIn, pos, context.getClickedFace()); + if (player instanceof ServerPlayer serverPlayer) { + InitTrigger.MAID_EVENT.get().trigger(serverPlayer, TriggerType.CHISEL_STATUE); + } return InteractionResult.SUCCESS; } return super.useOn(context); diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/ItemEntityPlaceholder.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/ItemEntityPlaceholder.java index c51d2c09f..962ce7865 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/ItemEntityPlaceholder.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/ItemEntityPlaceholder.java @@ -53,7 +53,7 @@ public static ItemStack setRecipeId(ItemStack stack, String id) { @Nullable public static ResourceLocation getRecipeId(ItemStack stack) { if (stack.has(InitDataComponent.RECIPES_ID_TAG)) { - return ResourceLocation.fromNamespaceAndPath(TouhouLittleMaid.MOD_ID, InitRecipes.ALTAR_CRAFTING.getId().getPath() +"/" + stack.get(InitDataComponent.RECIPES_ID_TAG)); + return ResourceLocation.fromNamespaceAndPath(TouhouLittleMaid.MOD_ID, InitRecipes.ALTAR_CRAFTING.getId().getPath() + "/" + stack.get(InitDataComponent.RECIPES_ID_TAG)); } return null; } @@ -62,7 +62,7 @@ public static ResourceLocation getRecipeId(ItemStack stack) { @Nullable public static ResourceLocation getId(ItemStack stack) { if (stack.has(InitDataComponent.RECIPES_ID_TAG)) { - return ResourceLocation.fromNamespaceAndPath(TouhouLittleMaid.MOD_ID,stack.get(InitDataComponent.RECIPES_ID_TAG)); + return ResourceLocation.fromNamespaceAndPath(TouhouLittleMaid.MOD_ID, stack.get(InitDataComponent.RECIPES_ID_TAG)); } return null; } diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/ItemFoxScroll.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/ItemFoxScroll.java index 43b253053..3cd5f7c22 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/ItemFoxScroll.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/ItemFoxScroll.java @@ -1,7 +1,9 @@ package com.github.tartaricacid.touhoulittlemaid.item; +import com.github.tartaricacid.touhoulittlemaid.advancements.maid.TriggerType; import com.github.tartaricacid.touhoulittlemaid.init.InitDataComponent; import com.github.tartaricacid.touhoulittlemaid.init.InitItems; +import com.github.tartaricacid.touhoulittlemaid.init.InitTrigger; import com.github.tartaricacid.touhoulittlemaid.network.message.FoxScrollPackage; import com.github.tartaricacid.touhoulittlemaid.world.data.MaidInfo; import com.github.tartaricacid.touhoulittlemaid.world.data.MaidWorldData; @@ -66,7 +68,14 @@ public InteractionResultHolder use(Level level, Player player, Intera List scrollData = data.computeIfAbsent(info.getDimension(), dim -> Lists.newArrayList()); scrollData.add(new FoxScrollPackage.FoxScrollData(info.getChunkPos(), info.getName(), info.getTimestamp())); }); - PacketDistributor.sendToPlayer((ServerPlayer) player,new FoxScrollPackage(data)); + PacketDistributor.sendToPlayer((ServerPlayer) player, new FoxScrollPackage(data)); + if (player instanceof ServerPlayer serverPlayer) { + if (item.getItem() == InitItems.RED_FOX_SCROLL.get()) { + InitTrigger.MAID_EVENT.get().trigger(serverPlayer, TriggerType.USE_RED_FOX_SCROLL); + } else if (item.getItem() == InitItems.WHITE_FOX_SCROLL.get()) { + InitTrigger.MAID_EVENT.get().trigger(serverPlayer, TriggerType.USE_WHITE_FOX_SCROLL); + } + } return InteractionResultHolder.success(item); } return super.use(level, player, hand); diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/ItemHakureiGohei.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/ItemHakureiGohei.java index bb94b774d..6e39762b6 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/ItemHakureiGohei.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/ItemHakureiGohei.java @@ -1,11 +1,14 @@ package com.github.tartaricacid.touhoulittlemaid.item; +import com.github.tartaricacid.touhoulittlemaid.advancements.maid.TriggerType; import com.github.tartaricacid.touhoulittlemaid.api.block.IMultiBlock; import com.github.tartaricacid.touhoulittlemaid.block.multiblock.MultiBlockManager; +import com.github.tartaricacid.touhoulittlemaid.init.InitTrigger; import com.google.common.base.Predicates; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.entity.EquipmentSlotGroup; @@ -82,6 +85,9 @@ public InteractionResult useOn(UseOnContext context) { StructureTemplate template = multiBlock.getTemplate((ServerLevel) world, direction); if (multiBlock.isMatch(world, posStart, direction, template)) { multiBlock.build(world, posStart, direction, template); + if (context.getPlayer() instanceof ServerPlayer serverPlayer) { + InitTrigger.MAID_EVENT.get().trigger(serverPlayer, TriggerType.BUILD_ALTAR); + } } } return InteractionResult.SUCCESS; diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/ItemPicnicBasket.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/ItemPicnicBasket.java index ea909ea99..4f5be71a6 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/ItemPicnicBasket.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/ItemPicnicBasket.java @@ -2,7 +2,7 @@ import com.github.tartaricacid.touhoulittlemaid.client.renderer.tileentity.PicnicBasketRender; import com.github.tartaricacid.touhoulittlemaid.init.InitItems; -import com.github.tartaricacid.touhoulittlemaid.inventory.container.PicnicBasketContainer; +import com.github.tartaricacid.touhoulittlemaid.inventory.container.other.PicnicBasketContainer; import com.github.tartaricacid.touhoulittlemaid.inventory.tooltip.ItemContainerTooltip; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.BlockEntityWithoutLevelRenderer; diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/ItemServantBell.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/ItemServantBell.java index 1b6337357..24958341f 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/ItemServantBell.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/ItemServantBell.java @@ -1,8 +1,10 @@ package com.github.tartaricacid.touhoulittlemaid.item; +import com.github.tartaricacid.touhoulittlemaid.advancements.maid.TriggerType; import com.github.tartaricacid.touhoulittlemaid.client.gui.item.ServantBellSetScreen; import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid; import com.github.tartaricacid.touhoulittlemaid.init.InitItems; +import com.github.tartaricacid.touhoulittlemaid.init.InitTrigger; import com.github.tartaricacid.touhoulittlemaid.world.data.MaidInfo; import com.github.tartaricacid.touhoulittlemaid.world.data.MaidWorldData; import net.minecraft.ChatFormatting; @@ -10,6 +12,7 @@ import net.minecraft.network.chat.CommonComponents; import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.sounds.SoundEvents; import net.minecraft.sounds.SoundSource; import net.minecraft.world.InteractionHand; @@ -98,6 +101,9 @@ public void releaseUsing(ItemStack stack, Level worldIn, LivingEntity entityLivi } } worldIn.playSound(null, player.blockPosition(), SoundEvents.BELL_BLOCK, SoundSource.BLOCKS, 2.0F, 1.0F); + if (player instanceof ServerPlayer serverPlayer) { + InitTrigger.MAID_EVENT.get().trigger(serverPlayer, TriggerType.USE_SERVANT_BELL); + } player.getCooldowns().addCooldown(this, 20); } diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/ItemTrumpet.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/ItemTrumpet.java index bd6d831f6..182f06156 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/ItemTrumpet.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/ItemTrumpet.java @@ -1,11 +1,14 @@ package com.github.tartaricacid.touhoulittlemaid.item; +import com.github.tartaricacid.touhoulittlemaid.advancements.maid.TriggerType; import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid; +import com.github.tartaricacid.touhoulittlemaid.init.InitTrigger; import com.github.tartaricacid.touhoulittlemaid.world.data.MaidInfo; import com.github.tartaricacid.touhoulittlemaid.world.data.MaidWorldData; import net.minecraft.ChatFormatting; import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResultHolder; import net.minecraft.world.entity.Entity; @@ -42,6 +45,9 @@ public void releaseUsing(ItemStack stack, Level worldIn, LivingEntity entityLivi } } } + if (player instanceof ServerPlayer serverPlayer) { + InitTrigger.MAID_EVENT.get().trigger(serverPlayer, TriggerType.USE_TRUMPET); + } player.getCooldowns().addCooldown(this, 200); } } diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/ItemWirelessIO.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/ItemWirelessIO.java index 57f771a01..867138f80 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/ItemWirelessIO.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/ItemWirelessIO.java @@ -3,7 +3,7 @@ import com.github.tartaricacid.touhoulittlemaid.api.bauble.IChestType; import com.github.tartaricacid.touhoulittlemaid.init.InitItems; import com.github.tartaricacid.touhoulittlemaid.inventory.chest.ChestManager; -import com.github.tartaricacid.touhoulittlemaid.inventory.container.WirelessIOContainer; +import com.github.tartaricacid.touhoulittlemaid.inventory.container.other.WirelessIOContainer; import net.minecraft.ChatFormatting; import net.minecraft.client.resources.language.I18n; import net.minecraft.core.BlockPos; diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/bauble/DrownProtectBauble.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/bauble/DrownProtectBauble.java index 40fedf0b8..bbcdae117 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/bauble/DrownProtectBauble.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/bauble/DrownProtectBauble.java @@ -1,11 +1,14 @@ package com.github.tartaricacid.touhoulittlemaid.item.bauble; +import com.github.tartaricacid.touhoulittlemaid.advancements.maid.TriggerType; import com.github.tartaricacid.touhoulittlemaid.api.bauble.IMaidBauble; import com.github.tartaricacid.touhoulittlemaid.api.event.MaidDamageEvent; import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid; +import com.github.tartaricacid.touhoulittlemaid.init.InitTrigger; import com.github.tartaricacid.touhoulittlemaid.network.NetworkHandler; import com.github.tartaricacid.touhoulittlemaid.network.message.SpawnParticlePackage; import com.github.tartaricacid.touhoulittlemaid.util.ItemsUtil; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.tags.DamageTypeTags; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.item.ItemStack; @@ -31,6 +34,9 @@ public void onLivingDamage(MaidDamageEvent event) { maid.getMaidBauble().setStackInSlot(slot, stack); maid.setAirSupply(200); NetworkHandler.sendToNearby(maid, new SpawnParticlePackage(maid.getId(), SpawnParticlePackage.Type.BUBBLE)); + if (maid.getOwner() instanceof ServerPlayer serverPlayer) { + InitTrigger.MAID_EVENT.get().trigger(serverPlayer, TriggerType.USE_PROTECT_BAUBLE); + } } } } diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/bauble/ExplosionProtectBauble.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/bauble/ExplosionProtectBauble.java index 287b388ef..e2453c737 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/bauble/ExplosionProtectBauble.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/bauble/ExplosionProtectBauble.java @@ -1,9 +1,12 @@ package com.github.tartaricacid.touhoulittlemaid.item.bauble; +import com.github.tartaricacid.touhoulittlemaid.advancements.maid.TriggerType; import com.github.tartaricacid.touhoulittlemaid.api.bauble.IMaidBauble; import com.github.tartaricacid.touhoulittlemaid.api.event.MaidDamageEvent; import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid; +import com.github.tartaricacid.touhoulittlemaid.init.InitTrigger; import com.github.tartaricacid.touhoulittlemaid.util.ItemsUtil; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.tags.DamageTypeTags; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.item.ItemStack; @@ -27,6 +30,9 @@ public void onLivingDamage(MaidDamageEvent event) { ItemStack stack = maid.getMaidBauble().getStackInSlot(slot); maid.hurtAndBreak(stack, 1); maid.getMaidBauble().setStackInSlot(slot, stack); + if (maid.getOwner() instanceof ServerPlayer serverPlayer) { + InitTrigger.MAID_EVENT.get().trigger(serverPlayer, TriggerType.USE_PROTECT_BAUBLE); + } } } } diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/bauble/ExtraLifeBauble.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/bauble/ExtraLifeBauble.java index 011a21c2c..ddb5a3e61 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/bauble/ExtraLifeBauble.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/bauble/ExtraLifeBauble.java @@ -1,11 +1,14 @@ package com.github.tartaricacid.touhoulittlemaid.item.bauble; +import com.github.tartaricacid.touhoulittlemaid.advancements.maid.TriggerType; import com.github.tartaricacid.touhoulittlemaid.api.bauble.IMaidBauble; import com.github.tartaricacid.touhoulittlemaid.api.event.MaidDeathEvent; import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid; +import com.github.tartaricacid.touhoulittlemaid.init.InitTrigger; import com.github.tartaricacid.touhoulittlemaid.network.NetworkHandler; import com.github.tartaricacid.touhoulittlemaid.network.message.SpawnParticlePackage; import com.github.tartaricacid.touhoulittlemaid.util.ItemsUtil; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.sounds.SoundEvents; import net.minecraft.tags.DamageTypeTags; import net.minecraft.world.damagesource.DamageSource; @@ -33,6 +36,9 @@ public void onLivingDamage(MaidDeathEvent event) { maid.setHealth(maid.getMaxHealth()); NetworkHandler.sendToNearby(maid, new SpawnParticlePackage(maid.getId(), SpawnParticlePackage.Type.HEART)); maid.playSound(SoundEvents.GLASS_BREAK, 1.0f, 1.0f); + if (maid.getOwner() instanceof ServerPlayer serverPlayer) { + InitTrigger.MAID_EVENT.get().trigger(serverPlayer, TriggerType.USE_UNDEAD_BAUBLE); + } } } } diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/bauble/FallProtectBauble.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/bauble/FallProtectBauble.java index bc03d80b7..07d591ae0 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/bauble/FallProtectBauble.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/bauble/FallProtectBauble.java @@ -1,11 +1,14 @@ package com.github.tartaricacid.touhoulittlemaid.item.bauble; +import com.github.tartaricacid.touhoulittlemaid.advancements.maid.TriggerType; import com.github.tartaricacid.touhoulittlemaid.api.bauble.IMaidBauble; import com.github.tartaricacid.touhoulittlemaid.api.event.MaidDamageEvent; import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid; +import com.github.tartaricacid.touhoulittlemaid.init.InitTrigger; import com.github.tartaricacid.touhoulittlemaid.network.NetworkHandler; import com.github.tartaricacid.touhoulittlemaid.network.message.SpawnParticlePackage; import com.github.tartaricacid.touhoulittlemaid.util.ItemsUtil; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.tags.DamageTypeTags; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.item.ItemStack; @@ -30,6 +33,9 @@ public void onLivingDamage(MaidDamageEvent event) { maid.hurtAndBreak(stack, 1); maid.getMaidBauble().setStackInSlot(slot, stack); NetworkHandler.sendToNearby(maid, new SpawnParticlePackage(maid.getId(), SpawnParticlePackage.Type.EXPLOSION)); + if (maid.getOwner() instanceof ServerPlayer serverPlayer) { + InitTrigger.MAID_EVENT.get().trigger(serverPlayer, TriggerType.USE_PROTECT_BAUBLE); + } } } } diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/bauble/FireProtectBauble.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/bauble/FireProtectBauble.java index aac4572a6..b90290d30 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/bauble/FireProtectBauble.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/bauble/FireProtectBauble.java @@ -1,10 +1,13 @@ package com.github.tartaricacid.touhoulittlemaid.item.bauble; +import com.github.tartaricacid.touhoulittlemaid.advancements.maid.TriggerType; import com.github.tartaricacid.touhoulittlemaid.api.bauble.IMaidBauble; import com.github.tartaricacid.touhoulittlemaid.api.event.MaidDamageEvent; import com.github.tartaricacid.touhoulittlemaid.entity.item.EntityExtinguishingAgent; import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid; +import com.github.tartaricacid.touhoulittlemaid.init.InitTrigger; import com.github.tartaricacid.touhoulittlemaid.util.ItemsUtil; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.tags.DamageTypeTags; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.effect.MobEffectInstance; @@ -34,6 +37,9 @@ public void onLivingDamage(MaidDamageEvent event) { if (!maid.level.isClientSide) { maid.level.addFreshEntity(new EntityExtinguishingAgent(maid.level, maid.position())); } + if (maid.getOwner() instanceof ServerPlayer serverPlayer) { + InitTrigger.MAID_EVENT.get().trigger(serverPlayer, TriggerType.USE_PROTECT_BAUBLE); + } } } } diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/bauble/ItemMagnetBauble.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/bauble/ItemMagnetBauble.java index 8515ca2af..1729033ed 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/bauble/ItemMagnetBauble.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/bauble/ItemMagnetBauble.java @@ -1,8 +1,11 @@ package com.github.tartaricacid.touhoulittlemaid.item.bauble; +import com.github.tartaricacid.touhoulittlemaid.advancements.maid.TriggerType; import com.github.tartaricacid.touhoulittlemaid.api.bauble.IMaidBauble; import com.github.tartaricacid.touhoulittlemaid.entity.item.EntityPowerPoint; import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid; +import com.github.tartaricacid.touhoulittlemaid.init.InitTrigger; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.ExperienceOrb; import net.minecraft.world.entity.item.ItemEntity; @@ -46,6 +49,9 @@ private void handlePickup(EntityMaid maid) { maid.pickupArrow((AbstractArrow) entityPickup, false); } } + if (maid.getOwner() instanceof ServerPlayer serverPlayer) { + InitTrigger.MAID_EVENT.get().trigger(serverPlayer, TriggerType.USE_ITEM_MAGNET_BAUBLE); + } } } } diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/bauble/MagicProtectBauble.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/bauble/MagicProtectBauble.java index 4002b86bf..bc7960b27 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/bauble/MagicProtectBauble.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/bauble/MagicProtectBauble.java @@ -1,11 +1,14 @@ package com.github.tartaricacid.touhoulittlemaid.item.bauble; +import com.github.tartaricacid.touhoulittlemaid.advancements.maid.TriggerType; import com.github.tartaricacid.touhoulittlemaid.api.bauble.IMaidBauble; import com.github.tartaricacid.touhoulittlemaid.api.event.MaidDamageEvent; import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid; +import com.github.tartaricacid.touhoulittlemaid.init.InitTrigger; import com.github.tartaricacid.touhoulittlemaid.network.NetworkHandler; import com.github.tartaricacid.touhoulittlemaid.network.message.SpawnParticlePackage; import com.github.tartaricacid.touhoulittlemaid.util.ItemsUtil; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.tags.DamageTypeTags; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.item.ItemStack; @@ -31,6 +34,9 @@ public void onLivingDamage(MaidDamageEvent event) { maid.getMaidBauble().setStackInSlot(slot, stack); maid.removeAllEffects(); NetworkHandler.sendToNearby(maid, new SpawnParticlePackage(maid.getId(), SpawnParticlePackage.Type.EXPLOSION)); + if (maid.getOwner() instanceof ServerPlayer serverPlayer) { + InitTrigger.MAID_EVENT.get().trigger(serverPlayer, TriggerType.USE_PROTECT_BAUBLE); + } } } } diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/bauble/NimbleFabricBauble.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/bauble/NimbleFabricBauble.java index 33db908fe..ae35457ca 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/bauble/NimbleFabricBauble.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/bauble/NimbleFabricBauble.java @@ -1,10 +1,13 @@ package com.github.tartaricacid.touhoulittlemaid.item.bauble; +import com.github.tartaricacid.touhoulittlemaid.advancements.maid.TriggerType; import com.github.tartaricacid.touhoulittlemaid.api.bauble.IMaidBauble; import com.github.tartaricacid.touhoulittlemaid.api.event.MaidAttackEvent; import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid; +import com.github.tartaricacid.touhoulittlemaid.init.InitTrigger; import com.github.tartaricacid.touhoulittlemaid.util.ItemsUtil; import com.github.tartaricacid.touhoulittlemaid.util.TeleportHelper; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.tags.DamageTypeTags; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.item.ItemStack; @@ -32,6 +35,9 @@ public void onLivingDamage(MaidAttackEvent event) { maid.getMaidBauble().setStackInSlot(slot, stack); for (int i = 0; i < MAX_RETRY; ++i) { if (TeleportHelper.teleport(maid)) { + if (maid.getOwner() instanceof ServerPlayer serverPlayer) { + InitTrigger.MAID_EVENT.get().trigger(serverPlayer, TriggerType.USE_NIMBLE_FABRIC); + } return; } } diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/bauble/ProjectileProtectBauble.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/bauble/ProjectileProtectBauble.java index 080d69bf7..950f9e3a3 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/bauble/ProjectileProtectBauble.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/bauble/ProjectileProtectBauble.java @@ -1,11 +1,14 @@ package com.github.tartaricacid.touhoulittlemaid.item.bauble; +import com.github.tartaricacid.touhoulittlemaid.advancements.maid.TriggerType; import com.github.tartaricacid.touhoulittlemaid.api.bauble.IMaidBauble; import com.github.tartaricacid.touhoulittlemaid.api.event.MaidDamageEvent; import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid; +import com.github.tartaricacid.touhoulittlemaid.init.InitTrigger; import com.github.tartaricacid.touhoulittlemaid.network.NetworkHandler; import com.github.tartaricacid.touhoulittlemaid.network.message.SpawnParticlePackage; import com.github.tartaricacid.touhoulittlemaid.util.ItemsUtil; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.tags.DamageTypeTags; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.item.ItemStack; @@ -30,6 +33,9 @@ public void onLivingDamage(MaidDamageEvent event) { maid.hurtAndBreak(stack, 1); maid.getMaidBauble().setStackInSlot(slot, stack); NetworkHandler.sendToNearby(maid, new SpawnParticlePackage(maid.getId(), SpawnParticlePackage.Type.EXPLOSION)); + if (maid.getOwner() instanceof ServerPlayer serverPlayer) { + InitTrigger.MAID_EVENT.get().trigger(serverPlayer, TriggerType.USE_PROTECT_BAUBLE); + } } } } diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/bauble/UndyingTotemBauble.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/bauble/UndyingTotemBauble.java index 0434bd66b..d26bf4a9d 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/bauble/UndyingTotemBauble.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/bauble/UndyingTotemBauble.java @@ -1,9 +1,12 @@ package com.github.tartaricacid.touhoulittlemaid.item.bauble; +import com.github.tartaricacid.touhoulittlemaid.advancements.maid.TriggerType; import com.github.tartaricacid.touhoulittlemaid.api.bauble.IMaidBauble; import com.github.tartaricacid.touhoulittlemaid.api.event.MaidDeathEvent; import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid; +import com.github.tartaricacid.touhoulittlemaid.init.InitTrigger; import com.github.tartaricacid.touhoulittlemaid.util.ItemsUtil; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.tags.DamageTypeTags; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.effect.MobEffectInstance; @@ -34,6 +37,9 @@ public void onLivingDamage(MaidDeathEvent event) { maid.addEffect(new MobEffectInstance(MobEffects.ABSORPTION, 100, 1)); maid.addEffect(new MobEffectInstance(MobEffects.FIRE_RESISTANCE, 800, 0)); maid.level.broadcastEntityEvent(maid, EntityEvent.TALISMAN_ACTIVATE); + if (maid.getOwner() instanceof ServerPlayer serverPlayer) { + InitTrigger.MAID_EVENT.get().trigger(serverPlayer, TriggerType.USE_UNDEAD_BAUBLE); + } } } } diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/bauble/WirelessIOBauble.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/bauble/WirelessIOBauble.java index 1e027b37d..3a4417b38 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/bauble/WirelessIOBauble.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/item/bauble/WirelessIOBauble.java @@ -1,11 +1,14 @@ package com.github.tartaricacid.touhoulittlemaid.item.bauble; +import com.github.tartaricacid.touhoulittlemaid.advancements.maid.TriggerType; import com.github.tartaricacid.touhoulittlemaid.api.bauble.IChestType; import com.github.tartaricacid.touhoulittlemaid.api.bauble.IMaidBauble; import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid; +import com.github.tartaricacid.touhoulittlemaid.init.InitTrigger; import com.github.tartaricacid.touhoulittlemaid.inventory.chest.ChestManager; import com.github.tartaricacid.touhoulittlemaid.item.ItemWirelessIO; import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.block.entity.BlockEntity; import net.neoforged.neoforge.capabilities.Capabilities; @@ -121,6 +124,9 @@ public void onTick(EntityMaid maid, ItemStack baubleItem) { chestToMaid(chestInv, maidInv, isBlacklist, filterList, slotConfigData); } } + if (maid.getOwner() instanceof ServerPlayer serverPlayer) { + InitTrigger.MAID_EVENT.get().trigger(serverPlayer, TriggerType.USE_WIRELESS_IO); + } return; } } diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/mixin/client/RenderSystemMixin.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/mixin/client/RenderSystemMixin.java deleted file mode 100644 index 9055beb8f..000000000 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/mixin/client/RenderSystemMixin.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.github.tartaricacid.touhoulittlemaid.mixin.client; - -import com.github.tartaricacid.touhoulittlemaid.geckolib3.util.RenderUtils; -import com.mojang.blaze3d.systems.RenderSystem; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -@Mixin(RenderSystem.class) -public class RenderSystemMixin { - @Inject(at = @At("HEAD"), method = "runAsFancy(Ljava/lang/Runnable;)V") - private static void beforeRunAsFancy(Runnable fancyRunnable, CallbackInfo ci) { - RenderUtils.setRenderingEntitiesInInventory(true); - } - - @Inject(at = @At("TAIL"), method = "runAsFancy(Ljava/lang/Runnable;)V") - private static void afterRunAsFancy(Runnable fancyRunnable, CallbackInfo ci) { - RenderUtils.setRenderingEntitiesInInventory(false); - } -} \ No newline at end of file diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/network/NetworkHandler.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/network/NetworkHandler.java index b83e86ceb..4a54fe76d 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/network/NetworkHandler.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/network/NetworkHandler.java @@ -38,16 +38,20 @@ public static void registerPacket(final RegisterPayloadHandlersEvent event) { registrar.playToClient(SendEffectPackage.TYPE, SendEffectPackage.STREAM_CODEC, SendEffectPackage::handle); registrar.playToClient(PlayMaidSoundPackage.TYPE, PlayMaidSoundPackage.STREAM_CODEC, PlayMaidSoundPackage::handle); registrar.playToServer(SetMaidSoundIdPackage.TYPE, SetMaidSoundIdPackage.STREAM_CODEC, SetMaidSoundIdPackage::handle); - registrar.playToClient(ChessDataClientPackage.TYPE, ChessDataClientPackage.STREAM_CODEC, ChessDataClientPackage::handle); - registrar.playToServer(ChessDataServerPackage.TYPE, ChessDataServerPackage.STREAM_CODEC, ChessDataServerPackage::handle); + registrar.playToClient(GomokuClientPackage.TYPE, GomokuClientPackage.STREAM_CODEC, GomokuClientPackage::handle); + registrar.playToServer(GomokuServerPackage.TYPE, GomokuServerPackage.STREAM_CODEC, GomokuServerPackage::handle); registrar.playToClient(FoxScrollPackage.TYPE, FoxScrollPackage.STREAM_CODEC, FoxScrollPackage::handle); registrar.playToServer(SetScrollPackage.TYPE, SetScrollPackage.STREAM_CODEC, SetScrollPackage::handle); registrar.playToClient(CheckSchedulePosPacket.TYPE, CheckSchedulePosPacket.STREAM_CODEC, CheckSchedulePosPacket::handle); registrar.playToClient(SyncMaidAreaPackage.TYPE, SyncMaidAreaPackage.STREAM_CODEC, SyncMaidAreaPackage::handle); registrar.playToServer(ServantBellSetPackage.TYPE, ServantBellSetPackage.STREAM_CODEC, ServantBellSetPackage::handle); registrar.playToServer(SetMonsterListMessage.TYPE, SetMonsterListMessage.STREAM_CODEC, SetMonsterListMessage::handle); - registrar.playToServer(ToggleSideTabPackage.TYPE, ToggleSideTabPackage.STREAM_CODEC, ToggleSideTabPackage::handle); registrar.playToServer(RefreshMaidBrainPackage.TYPE, RefreshMaidBrainPackage.STREAM_CODEC, RefreshMaidBrainPackage::handle); + registrar.playToServer(MaidSubConfigPackage.TYPE, MaidSubConfigPackage.STREAM_CODEC, MaidSubConfigPackage::handle); + registrar.playToClient(CChessToClientPackage.TYPE, CChessToClientPackage.STREAM_CODEC, CChessToClientPackage::handle); + registrar.playToServer(CChessToServerPackage.TYPE, CChessToServerPackage.STREAM_CODEC, CChessToServerPackage::handle); + registrar.playToClient(WChessToClientPackage.TYPE, WChessToClientPackage.STREAM_CODEC, WChessToClientPackage::handle); + registrar.playToServer(WChessToServerPackage.TYPE, WChessToServerPackage.STREAM_CODEC, WChessToServerPackage::handle); } public static void sendToNearby(Entity entity, CustomPacketPayload toSend) { diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/network/message/CChessToClientPackage.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/network/message/CChessToClientPackage.java new file mode 100644 index 000000000..077c7de26 --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/network/message/CChessToClientPackage.java @@ -0,0 +1,77 @@ +package com.github.tartaricacid.touhoulittlemaid.network.message; + +import com.github.tartaricacid.touhoulittlemaid.api.game.xqwlight.Position; +import com.github.tartaricacid.touhoulittlemaid.api.game.xqwlight.Search; +import com.github.tartaricacid.touhoulittlemaid.util.CChessUtil; +import io.netty.buffer.ByteBuf; +import net.minecraft.Util; +import net.minecraft.client.Minecraft; +import net.minecraft.core.BlockPos; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; +import net.neoforged.neoforge.network.PacketDistributor; +import net.neoforged.neoforge.network.handling.IPayloadContext; + +import java.util.concurrent.CompletableFuture; + +import static com.github.tartaricacid.touhoulittlemaid.util.ResourceLoactionUtil.getResourceLocation; + +public record CChessToClientPackage(BlockPos pos, String fenData) implements CustomPacketPayload { + public static final CustomPacketPayload.Type TYPE = new CustomPacketPayload.Type<>(getResourceLocation("cchess_to_client")); + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + BlockPos.STREAM_CODEC, + CChessToClientPackage::pos, + ByteBufCodecs.STRING_UTF8, + CChessToClientPackage::fenData, + CChessToClientPackage::new + ); + + @Override + public Type type() { + return TYPE; + } + + public static void handle(CChessToClientPackage message, IPayloadContext context) { + if (context.flow().isClientbound()) { + context.enqueueWork(() -> CompletableFuture.runAsync(() -> onHandle(message), Util.backgroundExecutor())); + } + } + + @OnlyIn(Dist.CLIENT) + private static void onHandle(CChessToClientPackage message) { + int levelTime = 1000; + long timeStart = System.currentTimeMillis(); + int move = 0; + + Position position = new Position(); + position.fromFen(message.fenData); + + // 先判断玩家是否赢了 + // 是的,我放客户端,减轻服务端压力,理论上你可直接传布尔值判断女仆输掉来作弊 + boolean maidLost = CChessUtil.isMaid(position) && position.isMate(); + boolean playerLost = false; + if (!maidLost) { + // TODO: 暂时不做女仆的棋技系统 + move = new Search(position, 12).searchMain(levelTime); + // 玩家是否输了 + playerLost = position.makeMove(move) && CChessUtil.isPlayer(position) && position.isMate(); + } + + // 如果时间还有剩余,那么 sleep 一会儿 + long timeRemain = Math.max(0, levelTime - (int) (System.currentTimeMillis() - timeStart)); + try { + if (timeRemain > 0) { + Thread.sleep(timeRemain); + } + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + + final int moveFinal = move; + final boolean playerLostFinal = playerLost; + Minecraft.getInstance().submitAsync(() -> PacketDistributor.sendToServer(new CChessToServerPackage(message.pos, moveFinal, maidLost, playerLostFinal))); + } +} diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/network/message/CChessToServerPackage.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/network/message/CChessToServerPackage.java new file mode 100644 index 000000000..5d84c76a2 --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/network/message/CChessToServerPackage.java @@ -0,0 +1,45 @@ +package com.github.tartaricacid.touhoulittlemaid.network.message; + +import com.github.tartaricacid.touhoulittlemaid.block.BlockCChess; +import io.netty.buffer.ByteBuf; +import net.minecraft.core.BlockPos; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.level.Level; +import net.neoforged.neoforge.network.handling.IPayloadContext; + +import static com.github.tartaricacid.touhoulittlemaid.util.ResourceLoactionUtil.getResourceLocation; + +public record CChessToServerPackage(BlockPos pos, int move, boolean maidLost, + boolean playerLost) implements CustomPacketPayload { + public static final CustomPacketPayload.Type TYPE = new CustomPacketPayload.Type<>(getResourceLocation("cchess_to_server")); + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + BlockPos.STREAM_CODEC, CChessToServerPackage::pos, + ByteBufCodecs.VAR_INT, CChessToServerPackage::move, + ByteBufCodecs.BOOL, CChessToServerPackage::maidLost, + ByteBufCodecs.BOOL, CChessToServerPackage::playerLost, + CChessToServerPackage::new + ); + + @Override + public Type type() { + return TYPE; + } + + public static void handle(CChessToServerPackage message, IPayloadContext context) { + if (context.flow().isServerbound()) { + context.enqueueWork(() -> { + if (!(context.player() instanceof ServerPlayer sender)) { + return; + } + Level level = sender.level; + if (!level.isLoaded(message.pos)) { + return; + } + BlockCChess.maidMove(sender, level, message.pos, message.move, message.maidLost, message.playerLost); + }); + } + } +} diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/network/message/ChairModelPackage.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/network/message/ChairModelPackage.java index 6ebfcede5..691c0470c 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/network/message/ChairModelPackage.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/network/message/ChairModelPackage.java @@ -1,7 +1,9 @@ package com.github.tartaricacid.touhoulittlemaid.network.message; +import com.github.tartaricacid.touhoulittlemaid.advancements.maid.TriggerType; import com.github.tartaricacid.touhoulittlemaid.config.subconfig.ChairConfig; import com.github.tartaricacid.touhoulittlemaid.entity.item.EntityChair; +import com.github.tartaricacid.touhoulittlemaid.init.InitTrigger; import io.netty.buffer.ByteBuf; import net.minecraft.network.chat.Component; import net.minecraft.network.codec.ByteBufCodecs; @@ -54,6 +56,7 @@ public static void handle(ChairModelPackage message, IPayloadContext context) { if (!message.tameableCanRide && !chair.getPassengers().isEmpty()) { chair.ejectPassengers(); } + InitTrigger.MAID_EVENT.get().trigger(sender, TriggerType.CHANGE_CHAIR_MODEL); } else { if (sender.isAlive()) { sender.sendSystemMessage(Component.translatable("message.touhou_little_maid.change_model.disabled")); diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/network/message/CheckSchedulePosPacket.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/network/message/CheckSchedulePosPacket.java index 5b7f7f94f..00e2ad86b 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/network/message/CheckSchedulePosPacket.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/network/message/CheckSchedulePosPacket.java @@ -1,7 +1,7 @@ package com.github.tartaricacid.touhoulittlemaid.network.message; import com.github.tartaricacid.touhoulittlemaid.client.gui.entity.maid.AbstractMaidContainerGui; -import com.github.tartaricacid.touhoulittlemaid.client.gui.entity.maid.CheckSchedulePosGui; +import com.github.tartaricacid.touhoulittlemaid.client.gui.entity.maid.other.CheckSchedulePosGui; import io.netty.buffer.ByteBuf; import net.minecraft.client.Minecraft; import net.minecraft.network.chat.Component; diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/network/message/ChessDataClientPackage.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/network/message/GomokuClientPackage.java similarity index 68% rename from src/main/java/com/github/tartaricacid/touhoulittlemaid/network/message/ChessDataClientPackage.java rename to src/main/java/com/github/tartaricacid/touhoulittlemaid/network/message/GomokuClientPackage.java index 03030adce..134b3c6ff 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/network/message/ChessDataClientPackage.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/network/message/GomokuClientPackage.java @@ -22,38 +22,38 @@ import static com.github.tartaricacid.touhoulittlemaid.util.ResourceLoactionUtil.getResourceLocation; -public record ChessDataClientPackage(BlockPos pos, List chessData, Point point, - int count) implements CustomPacketPayload { - public static final CustomPacketPayload.Type TYPE = new CustomPacketPayload.Type<>(getResourceLocation("chess_data_to_client")); +public record GomokuClientPackage(BlockPos pos, List chessData, Point point, + int count) implements CustomPacketPayload { + public static final CustomPacketPayload.Type TYPE = new CustomPacketPayload.Type<>(getResourceLocation("gomoku_to_client")); public static final StreamCodec> BYTE_BUF_LIST_STREAM_CODEC = ByteBufCodecs.collection( ArrayList::new, ByteBufCodecs.BYTE_ARRAY, 15 ); - public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( BlockPos.STREAM_CODEC, - ChessDataClientPackage::pos, + GomokuClientPackage::pos, BYTE_BUF_LIST_STREAM_CODEC, - ChessDataClientPackage::chessData, + GomokuClientPackage::chessData, Point.POINT_STREAM_CODEC, - ChessDataClientPackage::point, + GomokuClientPackage::point, ByteBufCodecs.VAR_INT, - ChessDataClientPackage::count, - ChessDataClientPackage::new + GomokuClientPackage::count, + GomokuClientPackage::new ); - public ChessDataClientPackage(BlockPos pos, byte[][] chessData, Point point, int count) { + public GomokuClientPackage(BlockPos pos, byte[][] chessData, Point point, int count) { this(pos, Arrays.stream(chessData).toList(), point, count); } - public static void handle(ChessDataClientPackage message, IPayloadContext context) { + public static void handle(GomokuClientPackage message, IPayloadContext context) { if (context.flow().isClientbound()) { context.enqueueWork(() -> CompletableFuture.runAsync(() -> onHandle(message), Util.backgroundExecutor())); } } @OnlyIn(Dist.CLIENT) - private static void onHandle(ChessDataClientPackage message) { + private static void onHandle(GomokuClientPackage message) { Point aiPoint = MaidGomokuAI.getService(message.count).getPoint(message.chessData.toArray(new byte[15][]), message.point); int time = (int) (Math.random() * 1250) + 250; try { @@ -61,7 +61,7 @@ private static void onHandle(ChessDataClientPackage message) { } catch (InterruptedException e) { throw new RuntimeException(e); } - Minecraft.getInstance().submitAsync(() -> PacketDistributor.sendToServer(new ChessDataServerPackage(message.pos, aiPoint))); + Minecraft.getInstance().submitAsync(() -> PacketDistributor.sendToServer(new GomokuServerPackage(message.pos, aiPoint))); } @Override diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/network/message/ChessDataServerPackage.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/network/message/GomokuServerPackage.java similarity index 83% rename from src/main/java/com/github/tartaricacid/touhoulittlemaid/network/message/ChessDataServerPackage.java rename to src/main/java/com/github/tartaricacid/touhoulittlemaid/network/message/GomokuServerPackage.java index 87a416644..96ba17aa6 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/network/message/ChessDataServerPackage.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/network/message/GomokuServerPackage.java @@ -21,17 +21,17 @@ import static com.github.tartaricacid.touhoulittlemaid.util.ResourceLoactionUtil.getResourceLocation; -public record ChessDataServerPackage(BlockPos pos, Point point) implements CustomPacketPayload { - public static final CustomPacketPayload.Type TYPE = new CustomPacketPayload.Type<>(getResourceLocation("chess_data_to_server")); - public static final StreamCodec STREAM_CODEC = StreamCodec.composite( +public record GomokuServerPackage(BlockPos pos, Point point) implements CustomPacketPayload { + public static final CustomPacketPayload.Type TYPE = new CustomPacketPayload.Type<>(getResourceLocation("gomoku_to_server")); + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( BlockPos.STREAM_CODEC, - ChessDataServerPackage::pos, + GomokuServerPackage::pos, Point.POINT_STREAM_CODEC, - ChessDataServerPackage::point, - ChessDataServerPackage::new + GomokuServerPackage::point, + GomokuServerPackage::new ); - public static void handle(ChessDataServerPackage message, IPayloadContext context) { + public static void handle(GomokuServerPackage message, IPayloadContext context) { if (context.flow().isServerbound()) { context.enqueueWork(() -> { ServerPlayer sender = (ServerPlayer) context.player(); diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/network/message/MaidConfigPackage.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/network/message/MaidConfigPackage.java index 98850642d..fb9754655 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/network/message/MaidConfigPackage.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/network/message/MaidConfigPackage.java @@ -1,9 +1,11 @@ package com.github.tartaricacid.touhoulittlemaid.network.message; +import com.github.tartaricacid.touhoulittlemaid.advancements.maid.TriggerType; import com.github.tartaricacid.touhoulittlemaid.config.subconfig.MaidConfig; import com.github.tartaricacid.touhoulittlemaid.entity.ai.brain.MaidSchedule; import com.github.tartaricacid.touhoulittlemaid.entity.item.EntitySit; import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid; +import com.github.tartaricacid.touhoulittlemaid.init.InitTrigger; import io.netty.buffer.ByteBuf; import net.minecraft.core.BlockPos; import net.minecraft.network.codec.ByteBufCodecs; @@ -60,6 +62,9 @@ public static void handle(MaidConfigPackage message, IPayloadContext context) { if (maid.isHomeModeEnable()) { BehaviorUtils.setWalkAndLookTargetMemories(maid, maid.getRestrictCenter(), 0.7f, 3); } + if (maid.getOwner() instanceof ServerPlayer serverPlayer) { + InitTrigger.MAID_EVENT.get().trigger(serverPlayer, TriggerType.SWITCH_SCHEDULE); + } } } }); diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/network/message/MaidModelPackage.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/network/message/MaidModelPackage.java index 380fb4041..d3d055c08 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/network/message/MaidModelPackage.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/network/message/MaidModelPackage.java @@ -1,7 +1,9 @@ package com.github.tartaricacid.touhoulittlemaid.network.message; +import com.github.tartaricacid.touhoulittlemaid.advancements.maid.TriggerType; import com.github.tartaricacid.touhoulittlemaid.config.subconfig.MaidConfig; import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid; +import com.github.tartaricacid.touhoulittlemaid.init.InitTrigger; import io.netty.buffer.ByteBuf; import net.minecraft.network.chat.Component; import net.minecraft.network.codec.ByteBufCodecs; @@ -38,6 +40,7 @@ public static void handle(MaidModelPackage message, IPayloadContext context) { if (entity instanceof EntityMaid && ((EntityMaid) entity).isOwnedBy(sender)) { if (sender.isCreative() || MaidConfig.MAID_CHANGE_MODEL.get()) { ((EntityMaid) entity).setModelId(message.modelId.toString()); + InitTrigger.MAID_EVENT.get().trigger(sender, TriggerType.CHANGE_MAID_MODEL); } else { sender.sendSystemMessage(Component.translatable("message.touhou_little_maid.change_model.disabled")); } diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/network/message/MaidSubConfigPackage.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/network/message/MaidSubConfigPackage.java new file mode 100644 index 000000000..f88297f20 --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/network/message/MaidSubConfigPackage.java @@ -0,0 +1,52 @@ +package com.github.tartaricacid.touhoulittlemaid.network.message; + +import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid; +import com.github.tartaricacid.touhoulittlemaid.entity.passive.MaidConfigManager; +import io.netty.buffer.ByteBuf; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.Entity; +import net.neoforged.neoforge.network.handling.IPayloadContext; + +import static com.github.tartaricacid.touhoulittlemaid.util.ResourceLoactionUtil.getResourceLocation; + +public record MaidSubConfigPackage(int id, MaidConfigManager.SyncNetwork syncNetwork) implements CustomPacketPayload { + public static final CustomPacketPayload.Type TYPE = new CustomPacketPayload.Type<>(getResourceLocation("maid_sub_config")); + public static final StreamCodec STREAM_CODEC = new StreamCodec<>() { + @Override + public void encode(ByteBuf buffer, MaidSubConfigPackage message) { + FriendlyByteBuf buf = new FriendlyByteBuf(buffer); + buf.writeVarInt(message.id); + MaidConfigManager.SyncNetwork.encode(message.syncNetwork, buf); + } + + @Override + public MaidSubConfigPackage decode(ByteBuf buffer) { + FriendlyByteBuf buf = new FriendlyByteBuf(buffer); + int entityId = buf.readVarInt(); + MaidConfigManager.SyncNetwork network = MaidConfigManager.SyncNetwork.decode(buf); + return new MaidSubConfigPackage(entityId, network); + } + }; + + @Override + public Type type() { + return TYPE; + } + + public static void handle(MaidSubConfigPackage message, IPayloadContext context) { + if (context.flow().isServerbound()) { + context.enqueueWork(() -> { + if (!(context.player() instanceof ServerPlayer sender)) { + return; + } + Entity entity = sender.level.getEntity(message.id); + if (entity instanceof EntityMaid maid && maid.isOwnedBy(sender)) { + MaidConfigManager.SyncNetwork.handle(message.syncNetwork, maid); + } + }); + } + } +} diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/network/message/MaidTaskPackage.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/network/message/MaidTaskPackage.java index 17520ece2..83397f034 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/network/message/MaidTaskPackage.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/network/message/MaidTaskPackage.java @@ -1,8 +1,12 @@ package com.github.tartaricacid.touhoulittlemaid.network.message; +import com.github.tartaricacid.touhoulittlemaid.advancements.maid.TriggerType; import com.github.tartaricacid.touhoulittlemaid.api.task.IMaidTask; import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid; +import com.github.tartaricacid.touhoulittlemaid.entity.passive.TabIndex; import com.github.tartaricacid.touhoulittlemaid.entity.task.TaskManager; +import com.github.tartaricacid.touhoulittlemaid.init.InitTrigger; +import com.github.tartaricacid.touhoulittlemaid.inventory.container.task.TaskConfigContainer; import io.netty.buffer.ByteBuf; import net.minecraft.network.codec.ByteBufCodecs; import net.minecraft.network.codec.StreamCodec; @@ -40,6 +44,13 @@ public static void handle(MaidTaskPackage message, IPayloadContext context) { return; } maid.setTask(task); + if (!TaskManager.getIdleTask().equals(task) && maid.getOwner() instanceof ServerPlayer serverPlayer) { + InitTrigger.MAID_EVENT.get().trigger(serverPlayer, TriggerType.SWITCH_TASK); + } + // 如果此时玩家打开的是配置界面 + if (sender.containerMenu instanceof TaskConfigContainer) { + maid.openMaidGui(sender, TabIndex.TASK_CONFIG); + } } }); } diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/network/message/SetMaidSoundIdPackage.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/network/message/SetMaidSoundIdPackage.java index 516b736c4..f7d36441e 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/network/message/SetMaidSoundIdPackage.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/network/message/SetMaidSoundIdPackage.java @@ -1,6 +1,8 @@ package com.github.tartaricacid.touhoulittlemaid.network.message; +import com.github.tartaricacid.touhoulittlemaid.advancements.maid.TriggerType; import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid; +import com.github.tartaricacid.touhoulittlemaid.init.InitTrigger; import io.netty.buffer.ByteBuf; import net.minecraft.network.codec.ByteBufCodecs; import net.minecraft.network.codec.StreamCodec; @@ -29,6 +31,7 @@ public static void handle(SetMaidSoundIdPackage message, IPayloadContext context Entity entity = sender.level.getEntity(message.entityId); if (entity instanceof EntityMaid maid && maid.isOwnedBy(sender)) { maid.setSoundPackId(message.soundId); + InitTrigger.MAID_EVENT.get().trigger(sender, TriggerType.CHANGE_MAID_SOUND); } }); } diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/network/message/ToggleSideTabPackage.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/network/message/ToggleSideTabPackage.java deleted file mode 100644 index 1c583aab6..000000000 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/network/message/ToggleSideTabPackage.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.github.tartaricacid.touhoulittlemaid.network.message; - -import com.github.tartaricacid.touhoulittlemaid.api.task.IMaidTask; -import com.github.tartaricacid.touhoulittlemaid.entity.passive.EntityMaid; -import com.github.tartaricacid.touhoulittlemaid.entity.task.TaskManager; -import io.netty.buffer.ByteBuf; -import net.minecraft.network.codec.ByteBufCodecs; -import net.minecraft.network.codec.StreamCodec; -import net.minecraft.network.protocol.common.custom.CustomPacketPayload; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.player.Player; -import net.neoforged.neoforge.network.handling.IPayloadContext; -import org.jetbrains.annotations.NotNull; - -import static com.github.tartaricacid.touhoulittlemaid.util.ResourceLoactionUtil.getResourceLocation; - -public record ToggleSideTabPackage(int entityId, int tabId, ResourceLocation taskUid) implements CustomPacketPayload { - public static final CustomPacketPayload.Type TYPE = new CustomPacketPayload.Type<>(getResourceLocation("toggle_side_tab")); - public static final StreamCodec STREAM_CODEC = StreamCodec.composite( - ByteBufCodecs.VAR_INT, ToggleSideTabPackage::entityId, - ByteBufCodecs.VAR_INT, ToggleSideTabPackage::tabId, - ResourceLocation.STREAM_CODEC, ToggleSideTabPackage::taskUid, - ToggleSideTabPackage::new - ); - - public static void handle(ToggleSideTabPackage message, IPayloadContext context) { - if (context.flow().isServerbound()) { - context.enqueueWork(() -> { - Player sender = context.player(); - Entity entity = sender.level.getEntity(message.entityId); - if (entity instanceof EntityMaid maid && maid.isOwnedBy(sender)) { - IMaidTask task = TaskManager.findTask(message.taskUid).orElse(TaskManager.getIdleTask()); - if (!task.isEnable(maid)) { - return; - } - maid.openMaidGuiFromSideTab(sender, message.tabId); - } - }); - } - } - - @Override - public @NotNull Type type() { - return TYPE; - } -} \ No newline at end of file diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/network/message/WChessToClientPackage.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/network/message/WChessToClientPackage.java new file mode 100644 index 000000000..b9bca2517 --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/network/message/WChessToClientPackage.java @@ -0,0 +1,77 @@ +package com.github.tartaricacid.touhoulittlemaid.network.message; + +import com.github.tartaricacid.touhoulittlemaid.api.game.chess.Position; +import com.github.tartaricacid.touhoulittlemaid.api.game.chess.Search; +import com.github.tartaricacid.touhoulittlemaid.util.WChessUtil; +import io.netty.buffer.ByteBuf; +import net.minecraft.Util; +import net.minecraft.client.Minecraft; +import net.minecraft.core.BlockPos; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.api.distmarker.OnlyIn; +import net.neoforged.neoforge.network.PacketDistributor; +import net.neoforged.neoforge.network.handling.IPayloadContext; + +import java.util.concurrent.CompletableFuture; + +import static com.github.tartaricacid.touhoulittlemaid.util.ResourceLoactionUtil.getResourceLocation; + +public record WChessToClientPackage(BlockPos pos, String fenData) implements CustomPacketPayload { + public static final Type TYPE = new Type<>(getResourceLocation("wchess_to_client")); + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + BlockPos.STREAM_CODEC, + WChessToClientPackage::pos, + ByteBufCodecs.STRING_UTF8, + WChessToClientPackage::fenData, + WChessToClientPackage::new + ); + + @Override + public Type type() { + return TYPE; + } + + public static void handle(WChessToClientPackage message, IPayloadContext context) { + if (context.flow().isClientbound()) { + context.enqueueWork(() -> CompletableFuture.runAsync(() -> onHandle(message), Util.backgroundExecutor())); + } + } + + @OnlyIn(Dist.CLIENT) + private static void onHandle(WChessToClientPackage message) { + int levelTime = 1000; + long timeStart = System.currentTimeMillis(); + int move = 0; + + Position position = new Position(); + position.fromFen(message.fenData); + + // 先判断玩家是否赢了 + // 是的,我放客户端,减轻服务端压力,理论上你可直接传布尔值判断女仆输掉来作弊 + boolean maidLost = WChessUtil.isMaid(position) && position.isMate(); + boolean playerLost = false; + if (!maidLost) { + // TODO: 暂时不做女仆的棋技系统 + move = new Search(position, 12).searchMain(levelTime); + // 玩家是否输了 + playerLost = position.makeMove(move) && WChessUtil.isPlayer(position) && position.isMate(); + } + + // 如果时间还有剩余,那么 sleep 一会儿 + long timeRemain = Math.max(0, levelTime - (int) (System.currentTimeMillis() - timeStart)); + try { + if (timeRemain > 0) { + Thread.sleep(timeRemain); + } + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + + final int moveFinal = move; + final boolean playerLostFinal = playerLost; + Minecraft.getInstance().submitAsync(() -> PacketDistributor.sendToServer(new WChessToServerPackage(message.pos, moveFinal, maidLost, playerLostFinal))); + } +} diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/network/message/WChessToServerPackage.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/network/message/WChessToServerPackage.java new file mode 100644 index 000000000..dc7350575 --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/network/message/WChessToServerPackage.java @@ -0,0 +1,45 @@ +package com.github.tartaricacid.touhoulittlemaid.network.message; + +import com.github.tartaricacid.touhoulittlemaid.block.BlockWChess; +import io.netty.buffer.ByteBuf; +import net.minecraft.core.BlockPos; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.network.protocol.common.custom.CustomPacketPayload; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.level.Level; +import net.neoforged.neoforge.network.handling.IPayloadContext; + +import static com.github.tartaricacid.touhoulittlemaid.util.ResourceLoactionUtil.getResourceLocation; + +public record WChessToServerPackage(BlockPos pos, int move, boolean maidLost, + boolean playerLost) implements CustomPacketPayload { + public static final Type TYPE = new Type<>(getResourceLocation("wchess_to_server")); + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + BlockPos.STREAM_CODEC, WChessToServerPackage::pos, + ByteBufCodecs.VAR_INT, WChessToServerPackage::move, + ByteBufCodecs.BOOL, WChessToServerPackage::maidLost, + ByteBufCodecs.BOOL, WChessToServerPackage::playerLost, + WChessToServerPackage::new + ); + + @Override + public Type type() { + return TYPE; + } + + public static void handle(WChessToServerPackage message, IPayloadContext context) { + if (context.flow().isServerbound()) { + context.enqueueWork(() -> { + if (!(context.player() instanceof ServerPlayer sender)) { + return; + } + Level level = sender.level; + if (!level.isLoaded(message.pos)) { + return; + } + BlockWChess.maidMove(sender, level, message.pos, message.move, message.maidLost, message.playerLost); + }); + } + } +} diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/tileentity/TileEntityCChess.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/tileentity/TileEntityCChess.java new file mode 100644 index 000000000..4a0e63e8d --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/tileentity/TileEntityCChess.java @@ -0,0 +1,122 @@ +package com.github.tartaricacid.touhoulittlemaid.tileentity; + +import com.github.tartaricacid.touhoulittlemaid.api.block.IBoardGameEntityBlock; +import com.github.tartaricacid.touhoulittlemaid.api.game.xqwlight.Position; +import com.github.tartaricacid.touhoulittlemaid.init.InitBlocks; +import com.github.tartaricacid.touhoulittlemaid.util.CChessUtil; +import net.minecraft.core.BlockPos; +import net.minecraft.core.HolderLookup; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; + +public class TileEntityCChess extends TileEntityJoy implements IBoardGameEntityBlock { + public static final BlockEntityType TYPE = BlockEntityType.Builder.of(TileEntityCChess::new, InitBlocks.CCHESS.get()).build(null); + + private static final String CHESS_DATA = "ChessData"; + private static final String CHESS_COUNTER = "ChessCounter"; + private static final String SELECT_CHESS_POINT = "SelectChessPoint"; + private static final String CHECKMATE = "Checkmate"; + private static final String REPEAT = "Repeat"; + private static final String MOVE_NUMBER_LIMIT = "MoveNumberLimit"; + + private final Position chessData; + + // 回合计数器 + private int chessCounter = 0; + // 当前选中的棋子 + private int selectChessPoint = 0; + // 将死(依据下棋方,判断谁输谁赢) + private boolean checkmate = false; + // 长打(判和) + private boolean repeat = false; + // 60 回自然限着(判和) + private boolean moveNumberLimit = false; + + public TileEntityCChess(BlockPos pos, BlockState blockState) { + super(TYPE, pos, blockState); + this.chessData = new Position(); + this.chessData.fromFen(CChessUtil.INIT); + } + + @Override + protected void saveAdditional(CompoundTag tag, HolderLookup.Provider provider) { + CompoundTag data = getPersistentData(); + data.putString(CHESS_DATA, chessData.toFen()); + data.putInt(CHESS_COUNTER, chessCounter); + data.putInt(SELECT_CHESS_POINT, selectChessPoint); + data.putBoolean(CHECKMATE, checkmate); + data.putBoolean(REPEAT, repeat); + data.putBoolean(MOVE_NUMBER_LIMIT, moveNumberLimit); + super.saveAdditional(tag, provider); + } + + @Override + public void loadAdditional(CompoundTag nbt, HolderLookup.Provider provider) { + super.loadAdditional(nbt, provider); + CompoundTag data = getPersistentData(); + chessCounter = data.getInt(CHESS_COUNTER); + selectChessPoint = data.getInt(SELECT_CHESS_POINT); + chessData.fromFen(data.getString(CHESS_DATA)); + checkmate = data.getBoolean(CHECKMATE); + repeat = data.getBoolean(REPEAT); + moveNumberLimit = data.getBoolean(MOVE_NUMBER_LIMIT); + } + + public void reset() { + this.chessCounter = 0; + this.selectChessPoint = 0; + this.chessData.fromFen(CChessUtil.INIT); + this.checkmate = false; + this.repeat = false; + this.moveNumberLimit = false; + } + + public Position getChessData() { + return chessData; + } + + public boolean isCheckmate() { + return checkmate; + } + + public void setCheckmate(boolean checkmate) { + this.checkmate = checkmate; + } + + public boolean isPlayerTurn() { + return CChessUtil.isPlayer(this.chessData); + } + + public int getChessCounter() { + return chessCounter; + } + + public void addChessCounter() { + this.chessCounter += 1; + } + + public int getSelectChessPoint() { + return selectChessPoint; + } + + public void setSelectChessPoint(int selectChessPoint) { + this.selectChessPoint = selectChessPoint; + } + + public boolean isRepeat() { + return repeat; + } + + public void setRepeat(boolean repeat) { + this.repeat = repeat; + } + + public boolean isMoveNumberLimit() { + return moveNumberLimit; + } + + public void setMoveNumberLimit(boolean moveNumberLimit) { + this.moveNumberLimit = moveNumberLimit; + } +} diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/tileentity/TileEntityGomoku.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/tileentity/TileEntityGomoku.java index 013918530..36e9131ee 100644 --- a/src/main/java/com/github/tartaricacid/touhoulittlemaid/tileentity/TileEntityGomoku.java +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/tileentity/TileEntityGomoku.java @@ -1,5 +1,6 @@ package com.github.tartaricacid.touhoulittlemaid.tileentity; +import com.github.tartaricacid.touhoulittlemaid.api.block.IBoardGameEntityBlock; import com.github.tartaricacid.touhoulittlemaid.api.game.gomoku.Point; import com.github.tartaricacid.touhoulittlemaid.init.InitBlocks; import net.minecraft.core.BlockPos; @@ -13,7 +14,7 @@ import java.util.List; -public class TileEntityGomoku extends TileEntityJoy { +public class TileEntityGomoku extends TileEntityJoy implements IBoardGameEntityBlock { public static final BlockEntityType TYPE = BlockEntityType.Builder.of(TileEntityGomoku::new, InitBlocks.GOMOKU.get()).build(null); private static final String CHESS_DATA = "ChessData"; private static final String IN_PROGRESS = "InProgress"; diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/tileentity/TileEntityWChess.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/tileentity/TileEntityWChess.java new file mode 100644 index 000000000..db72685b1 --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/tileentity/TileEntityWChess.java @@ -0,0 +1,122 @@ +package com.github.tartaricacid.touhoulittlemaid.tileentity; + +import com.github.tartaricacid.touhoulittlemaid.api.block.IBoardGameEntityBlock; +import com.github.tartaricacid.touhoulittlemaid.api.game.chess.Position; +import com.github.tartaricacid.touhoulittlemaid.init.InitBlocks; +import com.github.tartaricacid.touhoulittlemaid.util.WChessUtil; +import net.minecraft.core.BlockPos; +import net.minecraft.core.HolderLookup; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; + +public class TileEntityWChess extends TileEntityJoy implements IBoardGameEntityBlock { + public static final BlockEntityType TYPE = BlockEntityType.Builder.of(TileEntityWChess::new, InitBlocks.WCHESS.get()).build(null); + + private static final String CHESS_DATA = "ChessData"; + private static final String CHESS_COUNTER = "ChessCounter"; + private static final String SELECT_CHESS_POINT = "SelectChessPoint"; + private static final String CHECKMATE = "Checkmate"; + private static final String REPEAT = "Repeat"; + private static final String MOVE_NUMBER_LIMIT = "MoveNumberLimit"; + + private final Position chessData; + + // 回合计数器 + private int chessCounter = 0; + // 当前选中的棋子 + private int selectChessPoint = 0; + // 将死(依据下棋方,判断谁输谁赢) + private boolean checkmate = false; + // 长打(判和) + private boolean repeat = false; + // 50 回限着(判和) + private boolean moveNumberLimit = false; + + public TileEntityWChess(BlockPos pos, BlockState blockState) { + super(TYPE, pos, blockState); + this.chessData = new Position(); + this.chessData.fromFen(WChessUtil.INIT); + } + + @Override + protected void saveAdditional(CompoundTag tag, HolderLookup.Provider provider) { + CompoundTag data = getPersistentData(); + data.putString(CHESS_DATA, chessData.toFen()); + data.putInt(CHESS_COUNTER, chessCounter); + data.putInt(SELECT_CHESS_POINT, selectChessPoint); + data.putBoolean(CHECKMATE, checkmate); + data.putBoolean(REPEAT, repeat); + data.putBoolean(MOVE_NUMBER_LIMIT, moveNumberLimit); + super.saveAdditional(tag, provider); + } + + @Override + public void loadAdditional(CompoundTag nbt, HolderLookup.Provider provider) { + super.loadAdditional(nbt, provider); + CompoundTag data = getPersistentData(); + chessCounter = data.getInt(CHESS_COUNTER); + selectChessPoint = data.getInt(SELECT_CHESS_POINT); + chessData.fromFen(data.getString(CHESS_DATA)); + checkmate = data.getBoolean(CHECKMATE); + repeat = data.getBoolean(REPEAT); + moveNumberLimit = data.getBoolean(MOVE_NUMBER_LIMIT); + } + + public void reset() { + this.chessCounter = 0; + this.selectChessPoint = 0; + this.chessData.fromFen(WChessUtil.INIT); + this.checkmate = false; + this.repeat = false; + this.moveNumberLimit = false; + } + + public Position getChessData() { + return chessData; + } + + public boolean isCheckmate() { + return checkmate; + } + + public void setCheckmate(boolean checkmate) { + this.checkmate = checkmate; + } + + public boolean isPlayerTurn() { + return WChessUtil.isPlayer(this.chessData); + } + + public int getChessCounter() { + return chessCounter; + } + + public void addChessCounter() { + this.chessCounter += 1; + } + + public int getSelectChessPoint() { + return selectChessPoint; + } + + public void setSelectChessPoint(int selectChessPoint) { + this.selectChessPoint = selectChessPoint; + } + + public boolean isRepeat() { + return repeat; + } + + public void setRepeat(boolean repeat) { + this.repeat = repeat; + } + + public boolean isMoveNumberLimit() { + return moveNumberLimit; + } + + public void setMoveNumberLimit(boolean moveNumberLimit) { + this.moveNumberLimit = moveNumberLimit; + } +} diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/util/CChessUtil.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/util/CChessUtil.java new file mode 100644 index 000000000..91baf4a47 --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/util/CChessUtil.java @@ -0,0 +1,67 @@ +package com.github.tartaricacid.touhoulittlemaid.util; + +import com.github.tartaricacid.touhoulittlemaid.api.game.xqwlight.Position; +import net.minecraft.world.phys.Vec3; + +public final class CChessUtil { + // 女仆必输残局,测试用 + // rnbakab1r/9/8R/p1p1C4/1C4p1p/9/P1P1P1P1P/2N5N/9/R1BAKAB2 + // 长打残局 + // 1C1a2br1/3rak3/7c1/p3P2Rp/5n3/9/P1R3p1P/4C4/4A3N/2BAK3c + // 六十回合自然限着 + // 3aka3/9/9/9/9/9/9/9/9/3AKA3 + public static final String INIT = "rnbakabnr/9/1c5c1/p1p1p1p1p/9/9/P1P1P1P1P/1C5C1/9/RNBAKABNR"; + + public static boolean isClickResetArea(Vec3 clickPos) { + double x = clickPos.x; + double z = clickPos.z; + if (1.199 < x && x < 1.431) { + return (0.464 < z && z < 1.061) || (-1.061 < z && z < -0.464); + } + return false; + } + + public static int getClickPosition(Vec3 clickPos) { + double x = (clickPos.x + 1.365) / 0.304; + double z = (clickPos.z + 1.370) / 0.304; + int xRound = (int) Math.round(x); + int zRound = (int) Math.round(z); + double xAbs = Math.abs(xRound - x); + double zAbs = Math.abs(zRound - z); + + if (xAbs < 0.3 && zAbs < 0.3) { + xRound += Position.FILE_LEFT; + zRound += Position.RANK_TOP; + if (xRound <= Position.FILE_RIGHT && zRound <= Position.RANK_BOTTOM) { + return Position.COORD_XY(xRound, zRound); + } + } + return -1; + } + + public static boolean isRed(byte piecesIndex) { + return (piecesIndex & 8) == 8; + } + + public static boolean isBlack(byte piecesIndex) { + return (piecesIndex & 16) == 16; + } + + public static boolean isPlayer(Position position) { + return position.sdPlayer == 0; + } + + public static boolean isMaid(Position position) { + return position.sdPlayer == 1; + } + + // 六十回自然限着 + public static boolean reachMoveLimit(Position position) { + return position.moveNum > 60; + } + + // 三回合长打 + public static boolean isRepeat(Position position) { + return position.repStatus(3) > 0; + } +} diff --git a/src/main/java/com/github/tartaricacid/touhoulittlemaid/util/WChessUtil.java b/src/main/java/com/github/tartaricacid/touhoulittlemaid/util/WChessUtil.java new file mode 100644 index 000000000..24547459a --- /dev/null +++ b/src/main/java/com/github/tartaricacid/touhoulittlemaid/util/WChessUtil.java @@ -0,0 +1,60 @@ +package com.github.tartaricacid.touhoulittlemaid.util; + +import com.github.tartaricacid.touhoulittlemaid.api.game.chess.Position; +import net.minecraft.world.phys.Vec3; + +public final class WChessUtil { + public static final String INIT = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"; + + public static boolean isClickResetArea(Vec3 clickPos) { + double x = clickPos.x; + double z = clickPos.z; + if (-0.25 < z && z < 0.25) { + return (1.125 < x && x < 1.375) || (-1.375 < x && x < -1.125); + } + return false; + } + + public static int getClickPosition(Vec3 clickPos) { + double x = (clickPos.x + 1) / 0.25; + double z = (clickPos.z + 1) / 0.25; + if (x < 0 || z < 0) { + return -1; + } + int xFloor = (int) Math.floor(x); + int zFloor = (int) Math.floor(z); + + xFloor += Position.FILE_LEFT; + zFloor += Position.RANK_TOP; + if (xFloor <= Position.FILE_RIGHT && zFloor <= Position.RANK_BOTTOM) { + return Position.COORD_XY(xFloor, zFloor); + } + return -1; + } + + public static boolean isWhite(byte piecesIndex) { + return (piecesIndex & 8) == 8; + } + + public static boolean isBlack(byte piecesIndex) { + return (piecesIndex & 16) == 16; + } + + public static boolean isPlayer(Position position) { + return position.sdPlayer == 0; + } + + public static boolean isMaid(Position position) { + return position.sdPlayer == 1; + } + + // 五十回限制 + public static boolean reachMoveLimit(Position position) { + return position.moveNum > (50 * 2); + } + + // 三回合长打 + public static boolean isRepeat(Position position) { + return position.isRep(2); + } +} diff --git a/src/main/resources/assets/touhou_little_maid/blockstates/cchess.json b/src/main/resources/assets/touhou_little_maid/blockstates/cchess.json new file mode 100644 index 000000000..b6550dc05 --- /dev/null +++ b/src/main/resources/assets/touhou_little_maid/blockstates/cchess.json @@ -0,0 +1,7 @@ +{ + "variants": { + "": { + "model": "touhou_little_maid:block/cchess" + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/touhou_little_maid/blockstates/wchess.json b/src/main/resources/assets/touhou_little_maid/blockstates/wchess.json new file mode 100644 index 000000000..e11074b02 --- /dev/null +++ b/src/main/resources/assets/touhou_little_maid/blockstates/wchess.json @@ -0,0 +1,7 @@ +{ + "variants": { + "": { + "model": "touhou_little_maid:block/wchess" + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/touhou_little_maid/book/cchess/BOOK.DAT b/src/main/resources/assets/touhou_little_maid/book/cchess/BOOK.DAT new file mode 100644 index 0000000000000000000000000000000000000000..8f5eeaebcbca20f8429a0d682fc90b09a55c80d8 GIT binary patch literal 96648 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

gs5f3+Njn`uRA2t_tU#PM?=C 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%0D9PR>r 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

4>|0st(UoStjDxQ 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

IoU*x9ONC%V?hLLZ!LHpLzyzP|arITrr< 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/touhou_little_maid/lang/en_us.json b/src/main/resources/assets/touhou_little_maid/lang/en_us.json index e6bb078f0..26b78973f 100644 --- a/src/main/resources/assets/touhou_little_maid/lang/en_us.json +++ b/src/main/resources/assets/touhou_little_maid/lang/en_us.json @@ -1,4 +1,112 @@ { + "advancements.touhou_little_maid.base.craft_gohei.description": "Craft a gohei", + "advancements.touhou_little_maid.base.craft_gohei.title": "The Key to Gensou?", + "advancements.touhou_little_maid.base.build_altar.description": "Build an altar, and let the fun begin", + "advancements.touhou_little_maid.base.build_altar.title": "Construction Complete", + "advancements.touhou_little_maid.base.change_chair_model.description": "Change chair skins", + "advancements.touhou_little_maid.base.change_chair_model.title": "Different Seating", + "advancements.touhou_little_maid.base.change_maid_model.description": "Switch maid skins", + "advancements.touhou_little_maid.base.change_maid_model.title": "Cosplay!", + "advancements.touhou_little_maid.base.change_maid_sound.description": "Switch maid sounds", + "advancements.touhou_little_maid.base.change_maid_sound.title": "Voice Acting", + "advancements.touhou_little_maid.base.craft_chair.description": "Craft a chair", + "advancements.touhou_little_maid.base.craft_chair.title": "Reiner, Sit Down", + "advancements.touhou_little_maid.base.kill_maid_fairy.description": "Kill a maid fairy", + "advancements.touhou_little_maid.base.kill_maid_fairy.title": "Annoying Little Faes", + "advancements.touhou_little_maid.base.pickup_power_point.description": "Pickup the power point", + "advancements.touhou_little_maid.base.pickup_power_point.title": "Taste the Rainbow", + "advancements.touhou_little_maid.base.spawn_maid.description": "Summon a maid from the altar", + "advancements.touhou_little_maid.base.spawn_maid.title": "A New Life", + "advancements.touhou_little_maid.base.tamed_maid.description": "Tame a maid with a cake, I know they love sweets", + "advancements.touhou_little_maid.base.tamed_maid.title": "Welcome Home, Master", + "advancements.touhou_little_maid.challenge.all_netherite_equipment.description": "Armor up your maid with all netherite armor", + "advancements.touhou_little_maid.challenge.all_netherite_equipment.title": "Bofuri", + "advancements.touhou_little_maid.challenge.any_equipment.description": "Armor up your maid with any armor", + "advancements.touhou_little_maid.challenge.any_equipment.title": "Gearing Up", + "advancements.touhou_little_maid.challenge.eat_enchanted_golden_apple.description": "Feed the maid with a enchanted golden apple", + "advancements.touhou_little_maid.challenge.eat_enchanted_golden_apple.title": "Good Apple", + "advancements.touhou_little_maid.challenge.kill_100.description": "Maid kills 100 mobs", + "advancements.touhou_little_maid.challenge.kill_100.title": "Lunatic Hunter", + "advancements.touhou_little_maid.challenge.kill_wither.description": "Maid kills a wither", + "advancements.touhou_little_maid.challenge.kill_wither.title": "Wither Killer", + "advancements.touhou_little_maid.challenge.kill_dragon.description": "Maid kills an ender dragon", + "advancements.touhou_little_maid.challenge.kill_dragon.title": "Dra-gone with a Bang", + "advancements.touhou_little_maid.challenge.kill_slime_300.description": "Maid Kills 300 slimes, either regular or magma cube", + "advancements.touhou_little_maid.challenge.kill_slime_300.title": "Ooey-Gooey Goodness", + "advancements.touhou_little_maid.challenge.lightning_bolt.description": "Summon a lightning bolt from an altar", + "advancements.touhou_little_maid.challenge.lightning_bolt.title": "Tojiko is Mad!", + "advancements.touhou_little_maid.challenge.maid_100_healthy.description": "The maid's HP reaches 100", + "advancements.touhou_little_maid.challenge.maid_100_healthy.title": "100% Healthy", + "advancements.touhou_little_maid.challenge.maid_fishing_enchanted_book.description": "The maid fished and caught a enchanted book", + "advancements.touhou_little_maid.challenge.maid_fishing_enchanted_book.title": "Let's be Reel", + "advancements.touhou_little_maid.challenge.tamed_maid_in_pillager_outpost.description": "Tame a maid from pillager outpost", + "advancements.touhou_little_maid.challenge.tamed_maid_in_pillager_outpost.title": "Rescued a Princess!", + "advancements.touhou_little_maid.favorability.favorability_increased.description": "Increase favorability on your maid", + "advancements.touhou_little_maid.favorability.favorability_increased.title": "With Great Power...", + "advancements.touhou_little_maid.favorability.favorability_increased_max.description": "Max out favorability on your maid", + "advancements.touhou_little_maid.favorability.favorability_increased_max.title": "Comes a Great Responsibility!", + "advancements.touhou_little_maid.favorability.maid_picnic_eat.description": "Maids eats food at the picnic", + "advancements.touhou_little_maid.favorability.maid_picnic_eat.title": "A Good Time Together", + "advancements.touhou_little_maid.favorability.maid_sit_joy.description": "Your Maid sits on the any joy block", + "advancements.touhou_little_maid.favorability.maid_sit_joy.title": "A Comfy Spot", + "advancements.touhou_little_maid.favorability.maid_sleep.description": "Maid sleeps on the Bed", + "advancements.touhou_little_maid.favorability.maid_sleep.title": "Don't Let The Bed Bugs Bite", + "advancements.touhou_little_maid.favorability.win_cchess.description": "Win against your maid on the Xiangqi", + "advancements.touhou_little_maid.favorability.win_cchess.title": "Chess Master!", + "advancements.touhou_little_maid.favorability.win_wchess.description": "Win against your maid on the chess", + "advancements.touhou_little_maid.favorability.win_wchess.title": "Checkmate!", + "advancements.touhou_little_maid.favorability.win_gomoku.description": "Win against your maid on gomoku", + "advancements.touhou_little_maid.favorability.win_gomoku.title": "Five In a Row!", + "advancements.touhou_little_maid.maid_base.chisel_statue.description": "Chisel a statue from a clay block", + "advancements.touhou_little_maid.maid_base.chisel_statue.title": "Arts Craft", + "advancements.touhou_little_maid.maid_base.clear_maid_effects.description": "Maid drinks a milk bucket", + "advancements.touhou_little_maid.maid_base.clear_maid_effects.title": "Pesky Witches...", + "advancements.touhou_little_maid.maid_base.maid_backpack.description": "Equip any backpack onto your maid", + "advancements.touhou_little_maid.maid_base.maid_backpack.title": "Pack It Up", + "advancements.touhou_little_maid.maid_base.maid_farm.description": "Let the maid plant or harvest crops", + "advancements.touhou_little_maid.maid_base.maid_farm.title": "Oh MacDonald Had a Farm", + "advancements.touhou_little_maid.maid_base.maid_feed_animal.description": "Let the maid breed animals", + "advancements.touhou_little_maid.maid_base.maid_feed_animal.title": "Animal Expert", + "advancements.touhou_little_maid.maid_base.maid_feed_player.description": "Maid feeds a hungry player", + "advancements.touhou_little_maid.maid_base.maid_feed_player.title": "Eat-up", + "advancements.touhou_little_maid.maid_base.maid_fishing.description": "Maid goes out fishing", + "advancements.touhou_little_maid.maid_base.maid_fishing.title": "No, This isn't KKHTA", + "advancements.touhou_little_maid.maid_base.maid_kill_mob.description": "Maid kills a mob", + "advancements.touhou_little_maid.maid_base.maid_kill_mob.title": "Little Hunter", + "advancements.touhou_little_maid.maid_base.photo_maid.description": "Photoshoot your maid", + "advancements.touhou_little_maid.maid_base.photo_maid.title": "Ayaya...", + "advancements.touhou_little_maid.maid_base.pickup_garage_kit.description": "Pick up the garage kit", + "advancements.touhou_little_maid.maid_base.pickup_garage_kit.title": "Garage Kit!", + "advancements.touhou_little_maid.maid_base.pickup_maid.description": "Right click your maid with the saddle", + "advancements.touhou_little_maid.maid_base.pickup_maid.title": "Princess Carry", + "advancements.touhou_little_maid.maid_base.reborn_maid.description": "Ressurect your maid from the altar", + "advancements.touhou_little_maid.maid_base.reborn_maid.title": "After Afterlife", + "advancements.touhou_little_maid.maid_base.shrine_reborn_maid.description": "Ressurect your maid from the shrine", + "advancements.touhou_little_maid.maid_base.shrine_reborn_maid.title": "Life Shared", + "advancements.touhou_little_maid.maid_base.switch_schedule.description": "Toggle the maid's schedule", + "advancements.touhou_little_maid.maid_base.switch_schedule.title": "Keep Track of Time", + "advancements.touhou_little_maid.maid_base.switch_task.description": "Toggle the maid's task", + "advancements.touhou_little_maid.maid_base.switch_task.title": "Job-Change", + "advancements.touhou_little_maid.maid_base.take_maid_xp.description": "Right click on the maid with a glass bottle to take out the xp", + "advancements.touhou_little_maid.maid_base.take_maid_xp.title": "Today's Harvest", + "advancements.touhou_little_maid.maid_base.use_item_magnet_bauble.description": "Equip a item magnet bauble onto your maid", + "advancements.touhou_little_maid.maid_base.use_item_magnet_bauble.title": "Not-so Outta Reach", + "advancements.touhou_little_maid.maid_base.use_nimble_fabric.description": "Maid dodges projectile with nimble fabric", + "advancements.touhou_little_maid.maid_base.use_nimble_fabric.title": "Grazed!", + "advancements.touhou_little_maid.maid_base.use_protect_bauble.description": "Equip any protect bauble onto your maid", + "advancements.touhou_little_maid.maid_base.use_protect_bauble.title": "Protect!", + "advancements.touhou_little_maid.maid_base.use_red_fox_scroll.description": "Use the red fox scroll to find the maid", + "advancements.touhou_little_maid.maid_base.use_red_fox_scroll.title": "Never Gonna Say Goodbye", + "advancements.touhou_little_maid.maid_base.use_servant_bell.description": "Use the servant bell to recall the maid", + "advancements.touhou_little_maid.maid_base.use_servant_bell.title": "Never Gonna Give You Up", + "advancements.touhou_little_maid.maid_base.use_trumpet.description": "Use the trumpet to recall all maid", + "advancements.touhou_little_maid.maid_base.use_trumpet.title": "Zun-pets", + "advancements.touhou_little_maid.maid_base.use_undead_bauble.description": "Maid cancels death with ultramarine orb elixir or undying totem", + "advancements.touhou_little_maid.maid_base.use_undead_bauble.title": "Oooh, I'm a Zombie", + "advancements.touhou_little_maid.maid_base.use_white_fox_scroll.description": "Use the white fox scroll to find the maid's tombstone", + "advancements.touhou_little_maid.maid_base.use_white_fox_scroll.title": "Never Gonna Run Around and Desert You", + "advancements.touhou_little_maid.maid_base.use_wireless_io.description": "Transfer some items from chest to maid by gap, vice versa", + "advancements.touhou_little_maid.maid_base.use_wireless_io.title": "Mind the Gap", "entity.touhou_little_maid.chair": "Chair", "entity.touhou_little_maid.maid": "Maid", "entity.touhou_little_maid.fairy": "Maid Fairy", @@ -58,6 +166,7 @@ "item.touhou_little_maid.picnic_basket": "Picnic Basket", "item.touhou_little_maid.servant_bell": "Servant Bell", "item.touhou_little_maid.monster_list": "Monster List", + "item.touhou_little_maid.advancement_icon": "Advancement Icon", "enchantment.touhou_little_maid.impeding": "Impeding Danmaku", "enchantment.touhou_little_maid.impeding.desc": "Danmaku can inflict slowness I - IV on the enemy", "enchantment.touhou_little_maid.speedy": "Speedy Danmaku", @@ -76,6 +185,8 @@ "block.touhou_little_maid.altar": "Altar", "block.touhou_little_maid.statue": "Statue", "block.touhou_little_maid.picnic_mat": "Picnic Mat", + "block.touhou_little_maid.cchess": "Xiangqi (Chinese Chess)", + "block.touhou_little_maid.wchess": "Chess", "block.touhou_little_maid.scarecrow": "Granite Inari Fox", "tooltips.touhou_little_maid.chair.place.desc": "Right click on the top of the block to place it.", "tooltips.touhou_little_maid.chair.destroy.desc": "Shift left hit can destroy it.", @@ -132,6 +243,7 @@ "tooltips.touhou_little_maid.servant_bell.desc.1": "- Right click on the maid to mark it.", "tooltips.touhou_little_maid.servant_bell.desc.2": "- After mark, you can teleport the bound maid after using it.", "tooltips.touhou_little_maid.monster_list.desc": "Placed in the maid's offhand, she can attack based on this list", + "tooltips.touhou_little_maid.advancement_icon.desc": "For advancement icon display only", "overlay.touhou_little_maid.compass.tips": "Right click to display the maid's task area", "overlay.touhou_little_maid.golden_apple.tips": "Golden apple shift click can be fed to maid", "overlay.touhou_little_maid.potion.tips": "Potion shift click can be fed to maid", @@ -174,8 +286,12 @@ "gui.touhou_little_maid.button.model_download": "Open Model Pack Download GUI", "gui.touhou_little_maid.button.model_download.statue.first": "Click here to download more models and sounds!", "gui.touhou_little_maid.button.model_download.statue.update": "There are some new models and sounds!", + "gui.touhou_little_maid.button.main": "Main", + "gui.touhou_little_maid.button.main.desc": " -§a The maid's main screen, which is mainly used to manage the inventory", "gui.touhou_little_maid.button.task_config": "Task Config", - "gui.touhou_little_maid.button.task_config.desc": " -§a Used for config task", + "gui.touhou_little_maid.button.task_config.desc": " -§a Set up special configurations for work tasks", + "gui.touhou_little_maid.button.maid_config": "Maid Config", + "gui.touhou_little_maid.button.maid_config.desc": " -§a Configuration for setting up some of the functions of the current maid", "gui.touhou_little_maid.button.task_book": "Task Book", "gui.touhou_little_maid.button.task_book.desc": " -§a Used to open the task book entry from Memorizable Gensokyo", "gui.touhou_little_maid.button.task_info": "Task Info", @@ -245,6 +361,14 @@ "gui.touhou_little_maid.maid_config.show_chat_bubble": "Show Chat Bubbles", "gui.touhou_little_maid.maid_config.show_backpack": "Show Backpack", "gui.touhou_little_maid.maid_config.show_back_item": "Show Back Item", + "gui.touhou_little_maid.maid_config.pick_type": "Pickup Type", + "gui.touhou_little_maid.maid_config.open_door": "Open Door", + "gui.touhou_little_maid.maid_config.open_fence_gate": "Open Fence Gate", + "gui.touhou_little_maid.maid_config.value.true": "ON", + "gui.touhou_little_maid.maid_config.value.false": "OFF", + "gui.touhou_little_maid.maid_config.value.item": "Item", + "gui.touhou_little_maid.maid_config.value.xp": "XP", + "gui.touhou_little_maid.maid_config.value.all": "All", "gui.touhou_little_maid.model_switcher.direction.north": "Face: N", "gui.touhou_little_maid.model_switcher.direction.south": "Face: S", "gui.touhou_little_maid.model_switcher.direction.east": "Face: E", @@ -292,7 +416,7 @@ "message.touhou_little_maid.gomoku.lose": "Player Lost", "message.touhou_little_maid.gomoku.reset": "Right click the chess box to reset", "message.touhou_little_maid.gomoku.round": "Round: %d", - "message.touhou_little_maid.gomoku.no_maid": "There are no maid participating in the gomoku game", + "message.touhou_little_maid.gomoku.no_maid": "There are no maid participating in the game", "message.touhou_little_maid.gomoku.not_owner": "The maid participating in the game is not yours", "message.touhou_little_maid.gomoku.rank_up.title": "§6§nCongratulations", "message.touhou_little_maid.gomoku.rank_up.subtitle": "Your maid's gomoku skills have improved!", @@ -329,6 +453,12 @@ "message.touhou_little_maid.servant_bell.not_same_dimension": "The maid and you are not in the same dimension, the maid is in the %s dimension", "message.touhou_little_maid.servant_bell.no_result": "No maids were found", "message.touhou_little_maid.servant_bell.data_is_empty": "There is no data recorded on it", + "message.touhou_little_maid.cchess.check": "Check", + "message.touhou_little_maid.cchess.repeat": "Draw by Repetition!", + "message.touhou_little_maid.cchess.move_limit": "Draw by 60-Move Rule!", + "message.touhou_little_maid.cchess.reset": "Right click on the right black area to reset", + "message.touhou_little_maid.wchess.move_limit": "Draw by 50-Move Rule!", + "message.touhou_little_maid.wchess.reset": "Right click on the red area on either side to reset", "commands.touhou_little_maid.pack.reload.info": "All model pack have been reloaded!", "commands.touhou_little_maid.power.handle.info": "%d players's power point is changed", "commands.touhou_little_maid.maid_num.handle.info": "%d players's maid num is changed", diff --git a/src/main/resources/assets/touhou_little_maid/lang/zh_cn.json b/src/main/resources/assets/touhou_little_maid/lang/zh_cn.json index af857840f..ffcc21965 100644 --- a/src/main/resources/assets/touhou_little_maid/lang/zh_cn.json +++ b/src/main/resources/assets/touhou_little_maid/lang/zh_cn.json @@ -1,7 +1,115 @@ { + "advancements.touhou_little_maid.base.craft_gohei.description": "合成御币", + "advancements.touhou_little_maid.base.craft_gohei.title": "赤色幻想", + "advancements.touhou_little_maid.base.build_altar.description": "修建女仆模组的祭坛", + "advancements.touhou_little_maid.base.build_altar.title": "Construction Complete", + "advancements.touhou_little_maid.base.change_chair_model.description": "修改坐垫的模型", + "advancements.touhou_little_maid.base.change_chair_model.title": "我新买的家具啊", + "advancements.touhou_little_maid.base.change_maid_model.description": "切换女仆的模型", + "advancements.touhou_little_maid.base.change_maid_model.title": "Cosplay!", + "advancements.touhou_little_maid.base.change_maid_sound.description": "切换女仆的声音", + "advancements.touhou_little_maid.base.change_maid_sound.title": "喵帕斯", + "advancements.touhou_little_maid.base.craft_chair.description": "合成坐垫", + "advancements.touhou_little_maid.base.craft_chair.title": "莱纳,你坐啊", + "advancements.touhou_little_maid.base.kill_maid_fairy.description": "杀死一只妖精女仆", + "advancements.touhou_little_maid.base.kill_maid_fairy.title": "退治异变", + "advancements.touhou_little_maid.base.pickup_power_point.description": "捡起任意数量的 P 点", + "advancements.touhou_little_maid.base.pickup_power_point.title": "P 点充能中", + "advancements.touhou_little_maid.base.spawn_maid.description": "从祭坛中生成一只女仆", + "advancements.touhou_little_maid.base.spawn_maid.title": "见习神明", + "advancements.touhou_little_maid.base.tamed_maid.description": "用蛋糕驯服女仆", + "advancements.touhou_little_maid.base.tamed_maid.title": "欢迎回家,主人", + "advancements.touhou_little_maid.challenge.all_netherite_equipment.description": "将女仆全部装备上下界合金护甲", + "advancements.touhou_little_maid.challenge.all_netherite_equipment.title": "因为怕痛所以全点防御力了", + "advancements.touhou_little_maid.challenge.any_equipment.description": "给女仆装备任意护甲", + "advancements.touhou_little_maid.challenge.any_equipment.title": "整装待发", + "advancements.touhou_little_maid.challenge.eat_enchanted_golden_apple.description": "用附魔金苹果喂养女仆", + "advancements.touhou_little_maid.challenge.eat_enchanted_golden_apple.title": "Good Apple", + "advancements.touhou_little_maid.challenge.kill_100.description": "女仆杀死100只生物", + "advancements.touhou_little_maid.challenge.kill_100.title": "赤色杀人魔", + "advancements.touhou_little_maid.challenge.kill_wither.description": "女仆杀死凋零", + "advancements.touhou_little_maid.challenge.kill_wither.title": "凋零杀手", + "advancements.touhou_little_maid.challenge.kill_dragon.description": "女仆杀死末影龙", + "advancements.touhou_little_maid.challenge.kill_dragon.title": "屠龙勇士", + "advancements.touhou_little_maid.challenge.kill_slime_300.description": "女仆杀死 300 只史莱姆", + "advancements.touhou_little_maid.challenge.kill_slime_300.title": "杀了三百只史莱姆,不知不觉就满级了", + "advancements.touhou_little_maid.challenge.lightning_bolt.description": "从祭坛中合成出闪电", + "advancements.touhou_little_maid.challenge.lightning_bolt.title": "何方道友在此渡劫?", + "advancements.touhou_little_maid.challenge.maid_100_healthy.description": "女仆血量达到一百点", + "advancements.touhou_little_maid.challenge.maid_100_healthy.title": "百分百健康", + "advancements.touhou_little_maid.challenge.maid_fishing_enchanted_book.description": "女仆钓鱼钓到附魔书", + "advancements.touhou_little_maid.challenge.maid_fishing_enchanted_book.title": "这本书真不是偷得啦", + "advancements.touhou_little_maid.challenge.tamed_maid_in_pillager_outpost.description": "驯服一只掠夺者前哨站生成的女仆", + "advancements.touhou_little_maid.challenge.tamed_maid_in_pillager_outpost.title": "勇者救公主!", + "advancements.touhou_little_maid.favorability.favorability_increased.description": "女仆好感度达到一级", + "advancements.touhou_little_maid.favorability.favorability_increased.title": "相识的前奏曲", + "advancements.touhou_little_maid.favorability.favorability_increased_max.description": "女仆好感度达到满级", + "advancements.touhou_little_maid.favorability.favorability_increased_max.title": "最最最最喜欢主人了", + "advancements.touhou_little_maid.favorability.maid_picnic_eat.description": "女仆在野餐垫上吃东西", + "advancements.touhou_little_maid.favorability.maid_picnic_eat.title": "野炊时刻到", + "advancements.touhou_little_maid.favorability.maid_sit_joy.description": "女仆使用任意娱乐方块", + "advancements.touhou_little_maid.favorability.maid_sit_joy.title": "休息,休息一下", + "advancements.touhou_little_maid.favorability.maid_sleep.description": "女仆在女仆床上睡觉", + "advancements.touhou_little_maid.favorability.maid_sleep.title": "甜蜜的梦~女仆版", + "advancements.touhou_little_maid.favorability.win_cchess.description": "在中国象棋中赢得一局", + "advancements.touhou_little_maid.favorability.win_cchess.title": "将军!", + "advancements.touhou_little_maid.favorability.win_wchess.description": "在国际象棋中赢得一局", + "advancements.touhou_little_maid.favorability.win_wchess.title": "国像大师", + "advancements.touhou_little_maid.favorability.win_gomoku.description": "在五子棋中赢得一局", + "advancements.touhou_little_maid.favorability.win_gomoku.title": "我要成为五子棋大师!", + "advancements.touhou_little_maid.maid_base.chisel_statue.description": "把黏土雕刻成女仆雕像", + "advancements.touhou_little_maid.maid_base.chisel_statue.title": "陛下,奇观误国啊", + "advancements.touhou_little_maid.maid_base.clear_maid_effects.description": "使用牛奶桶清除女仆的效果", + "advancements.touhou_little_maid.maid_base.clear_maid_effects.title": "邪气退散", + "advancements.touhou_little_maid.maid_base.maid_backpack.description": "给女仆装备任意背包", + "advancements.touhou_little_maid.maid_base.maid_backpack.title": "背背背背背起了行囊", + "advancements.touhou_little_maid.maid_base.maid_farm.description": "让女仆种田", + "advancements.touhou_little_maid.maid_base.maid_farm.title": "五谷丰登", + "advancements.touhou_little_maid.maid_base.maid_feed_animal.description": "让女仆繁殖动物", + "advancements.touhou_little_maid.maid_base.maid_feed_animal.title": "六畜兴旺", + "advancements.touhou_little_maid.maid_base.maid_feed_player.description": "让女仆喂养玩家", + "advancements.touhou_little_maid.maid_base.maid_feed_player.title": "来人,喂公子吃饼", + "advancements.touhou_little_maid.maid_base.maid_fishing.description": "让女仆钓鱼", + "advancements.touhou_little_maid.maid_base.maid_fishing.title": "无本万利", + "advancements.touhou_little_maid.maid_base.maid_kill_mob.description": "女仆击杀怪物", + "advancements.touhou_little_maid.maid_base.maid_kill_mob.title": "城管执法中……", + "advancements.touhou_little_maid.maid_base.photo_maid.description": "给女仆拍照", + "advancements.touhou_little_maid.maid_base.photo_maid.title": "拍个照吧", + "advancements.touhou_little_maid.maid_base.pickup_garage_kit.description": "拾起烧制好的手办", + "advancements.touhou_little_maid.maid_base.pickup_garage_kit.title": "手办!", + "advancements.touhou_little_maid.maid_base.pickup_maid.description": "使用鞍右击抱起女仆", + "advancements.touhou_little_maid.maid_base.pickup_maid.title": "公主抱", + "advancements.touhou_little_maid.maid_base.reborn_maid.description": "从祭坛中复活女仆", + "advancements.touhou_little_maid.maid_base.reborn_maid.title": "少女祈祷中……", + "advancements.touhou_little_maid.maid_base.shrine_reborn_maid.description": "从神龛中复活女仆", + "advancements.touhou_little_maid.maid_base.shrine_reborn_maid.title": "我又复活啦!", + "advancements.touhou_little_maid.maid_base.switch_schedule.description": "切换女仆的日程表", + "advancements.touhou_little_maid.maid_base.switch_schedule.title": "996", + "advancements.touhou_little_maid.maid_base.switch_task.description": "切换女仆的工作模式", + "advancements.touhou_little_maid.maid_base.switch_task.title": "工作中……", + "advancements.touhou_little_maid.maid_base.take_maid_xp.description": "使用玻璃瓶右击女仆取出经验", + "advancements.touhou_little_maid.maid_base.take_maid_xp.title": "今天的收获", + "advancements.touhou_little_maid.maid_base.use_item_magnet_bauble.description": "给女仆装备物品磁铁饰品", + "advancements.touhou_little_maid.maid_base.use_item_magnet_bauble.title": "吸尘器运转中……", + "advancements.touhou_little_maid.maid_base.use_nimble_fabric.description": "给女仆装备闪避布饰品", + "advancements.touhou_little_maid.maid_base.use_nimble_fabric.title": "我闪!", + "advancements.touhou_little_maid.maid_base.use_protect_bauble.description": "给女仆装备任意保护饰品", + "advancements.touhou_little_maid.maid_base.use_protect_bauble.title": "保护!", + "advancements.touhou_little_maid.maid_base.use_red_fox_scroll.description": "使用红狐狸卷轴寻找女仆", + "advancements.touhou_little_maid.maid_base.use_red_fox_scroll.title": "Never Gonna Say Goodbye", + "advancements.touhou_little_maid.maid_base.use_servant_bell.description": "使用仆人铃召回女仆", + "advancements.touhou_little_maid.maid_base.use_servant_bell.title": "Never Gonna Give You Up", + "advancements.touhou_little_maid.maid_base.use_trumpet.description": "使用小号召回所有女仆", + "advancements.touhou_little_maid.maid_base.use_trumpet.title": "ZUN号", + "advancements.touhou_little_maid.maid_base.use_undead_bauble.description": "女仆装备绀珠之药或者不死图腾抵消一次死亡", + "advancements.touhou_little_maid.maid_base.use_undead_bauble.title": "少女折寿中……", + "advancements.touhou_little_maid.maid_base.use_white_fox_scroll.description": "使用白狐狸卷轴寻找女仆墓碑", + "advancements.touhou_little_maid.maid_base.use_white_fox_scroll.title": "Never Gonna Run Around and Desert You", + "advancements.touhou_little_maid.maid_base.use_wireless_io.description": "使用隙间饰品进行物品传输", + "advancements.touhou_little_maid.maid_base.use_wireless_io.title": "小心地铁隙间", "entity.touhou_little_maid.chair": "椅子", "entity.touhou_little_maid.maid": "小女仆", - "entity.touhou_little_maid.fairy": "妖精女仆", + "entity.touhou_little_maid.fairy": "女仆妖精", "entity.touhou_little_maid.danmaku": "弹幕", "entity.touhou_little_maid.box": "蛋糕盒", "entity.touhou_little_maid.power_point": "P 点", @@ -58,6 +166,7 @@ "item.touhou_little_maid.picnic_basket": "野餐篮", "item.touhou_little_maid.servant_bell": "仆人铃", "item.touhou_little_maid.monster_list": "妖怪名单", + "item.touhou_little_maid.advancement_icon": "进度图标", "enchantment.touhou_little_maid.impeding": "阻碍", "enchantment.touhou_little_maid.impeding.desc": "弹幕会对敌方造成缓慢 I - IV 的效果", "enchantment.touhou_little_maid.speedy": "极速", @@ -76,6 +185,8 @@ "block.touhou_little_maid.altar": "祭坛", "block.touhou_little_maid.statue": "雕像", "block.touhou_little_maid.picnic_mat": "野餐垫", + "block.touhou_little_maid.cchess": "中国象棋", + "block.touhou_little_maid.wchess": "国际象棋", "block.touhou_little_maid.scarecrow": "麻石狐像", "tooltips.touhou_little_maid.chair.place.desc": "右击方块顶部进行放置。", "tooltips.touhou_little_maid.chair.destroy.desc": "Shift 左击破坏它。", @@ -107,7 +218,7 @@ "tooltips.touhou_little_maid.wireless_io.io_mode.output": "箱子 -> 女仆", "tooltips.touhou_little_maid.wireless_io.filter_mode.blacklist": "黑名单", "tooltips.touhou_little_maid.wireless_io.filter_mode.whitelist": "白名单", - "tooltips.touhou_little_maid.wireless_io.binding_pos.has": "绑定坐标:%d, %d, %d", + "tooltips.touhou_little_maid.wireless_io.binding_pos.has": "绑定坐标:%d,%d,%d", "tooltips.touhou_little_maid.wireless_io.binding_pos.none": "未绑定箱子", "tooltips.touhou_little_maid.maid_beacon.desc": "存储 P 点:%s", "tooltips.touhou_little_maid.chair_show.desc": "潜行时手持此物品可以查看坐垫的碰撞箱", @@ -127,15 +238,16 @@ "tooltips.touhou_little_maid.tank_backpack.capacity": "容量:%d mB", "tooltips.touhou_little_maid.item_container.empty": "空", "tooltips.touhou_little_maid.broom.desc": "右击方块来放置扫帚", - "tooltips.touhou_little_maid.scarecrow.desc": "放置在地上,可与阻止%dx%d方形范围内妖精女仆的生成", - "tooltips.touhou_little_maid.servant_bell.uuid": "UUID: %s", + "tooltips.touhou_little_maid.scarecrow.desc": "放置在地上,可以阻止女仆妖精在 %dx%d 方形范围内生成", + "tooltips.touhou_little_maid.servant_bell.uuid": "UUID:%s", "tooltips.touhou_little_maid.servant_bell.desc.1": "- 右击女仆进行绑定;", - "tooltips.touhou_little_maid.servant_bell.desc.2": "- 绑定后,右键使用即可召回女仆。", + "tooltips.touhou_little_maid.servant_bell.desc.2": "- 绑定后,右击使用即可召回女仆。", "tooltips.touhou_little_maid.monster_list.desc": "放置在女仆的副手,她会依据此名单来进行攻击", + "tooltips.touhou_little_maid.advancement_icon.desc": "仅用于进度图标显示的物品", "overlay.touhou_little_maid.compass.tips": "右击可以显示女仆的任务区域", - "overlay.touhou_little_maid.golden_apple.tips": "金苹果可以 Shift 右击喂给女仆", - "overlay.touhou_little_maid.potion.tips": "药水可以 Shift 右击喂给女仆", - "overlay.touhou_little_maid.milk_bucket.tips": "牛奶桶可以 Shift 右击清除女仆的药水效果", + "overlay.touhou_little_maid.golden_apple.tips": "手持金苹果可以使用 Shift 右击喂给女仆", + "overlay.touhou_little_maid.potion.tips": "手持药水可以使用 Shift 右击喂给女仆", + "overlay.touhou_little_maid.milk_bucket.tips": "手持奶桶可以使用 Shift 右击清除女仆的药水效果", "overlay.touhou_little_maid.script_book.tips": "它可以向女仆写入聊天气泡文本", "overlay.touhou_little_maid.glass_bottle.tips": "右击取出经验,Shift 右击全部取出", "overlay.touhou_little_maid.name_tag.tips": "右击命名女仆", @@ -174,8 +286,12 @@ "gui.touhou_little_maid.button.model_download": "打开模型包下载界面", "gui.touhou_little_maid.button.model_download.statue.first": "点击此处下载更多模型包和声音包!", "gui.touhou_little_maid.button.model_download.statue.update": "有一些新的模型包和声音包!", + "gui.touhou_little_maid.button.main": "主界面", + "gui.touhou_little_maid.button.main.desc": " -§a 女仆主界面,主要用于管理物品栏", "gui.touhou_little_maid.button.task_config": "任务设置", - "gui.touhou_little_maid.button.task_config.desc": " -§a 用于一些任务的设置", + "gui.touhou_little_maid.button.task_config.desc": " -§a 用于女仆工作模式的相关设置", + "gui.touhou_little_maid.button.maid_config": "女仆配置界面", + "gui.touhou_little_maid.button.maid_config.desc": " -§a 配置当前女仆的某些功能", "gui.touhou_little_maid.button.task_book": "任务手册", "gui.touhou_little_maid.button.task_book.desc": " -§a 用于跳转到手册对应的章节", "gui.touhou_little_maid.button.task_info": "任务信息", @@ -202,7 +318,7 @@ "gui.touhou_little_maid.skin_details.left_mouse": "鼠标左键:旋转", "gui.touhou_little_maid.skin_details.right_mouse": "鼠标右键:移动", "gui.touhou_little_maid.skin_details.mouse_wheel": "鼠标滚轮:缩放", - "gui.touhou_little_maid.maid_beacon.cost_power": "消耗P点:%s/h", + "gui.touhou_little_maid.maid_beacon.cost_power": "消耗 P 点:%s/h", "gui.touhou_little_maid.maid_beacon.add_one": "存入一点", "gui.touhou_little_maid.maid_beacon.min_one": "取出一点", "gui.touhou_little_maid.maid_beacon.overflow_delete_true": "删除溢出 P 点", @@ -234,7 +350,7 @@ "gui.touhou_little_maid.resources_download.open_folder": "打开资源包文件夹", "gui.touhou_little_maid.resources_download.search": "搜索……", "gui.touhou_little_maid.resources_download.hot_search": "热门搜索:", - "gui.touhou_little_maid.resources_download.hot_search_key": "可莉,星,拉姆,爱丽丝,铃兰,纳希坦,芙莉莲,长门,伊蕾娜,柴郡,崩坏,奈亚子,Fate", + "gui.touhou_little_maid.resources_download.hot_search_key": "可莉、星、拉姆、爱丽丝、铃兰、纳希坦、芙莉莲、长门、伊蕾娜、柴郡、崩坏、奈亚子、Fate", "gui.touhou_little_maid.resources_download.need_reload.title": "§6§n需要重载", "gui.touhou_little_maid.resources_download.need_reload.subtitle": "使用 §4§o/tlm pack reload§r 指令重载所有资源包!", "gui.touhou_little_maid.resources_download.state.downloading": "正在下载 %s 文件……", @@ -245,6 +361,14 @@ "gui.touhou_little_maid.maid_config.show_chat_bubble": "显示聊天气泡", "gui.touhou_little_maid.maid_config.show_backpack": "显示背包", "gui.touhou_little_maid.maid_config.show_back_item": "显示背部物品", + "gui.touhou_little_maid.maid_config.pick_type": "拾取类型", + "gui.touhou_little_maid.maid_config.open_door": "能否开门", + "gui.touhou_little_maid.maid_config.open_fence_gate": "能否开栅栏门", + "gui.touhou_little_maid.maid_config.value.true": "开启", + "gui.touhou_little_maid.maid_config.value.false": "关闭", + "gui.touhou_little_maid.maid_config.value.item": "物品", + "gui.touhou_little_maid.maid_config.value.xp": "经验", + "gui.touhou_little_maid.maid_config.value.all": "全部", "gui.touhou_little_maid.model_switcher.direction.north": "朝向:北", "gui.touhou_little_maid.model_switcher.direction.south": "朝向:南", "gui.touhou_little_maid.model_switcher.direction.east": "朝向:东", @@ -260,13 +384,13 @@ "gui.touhou_little_maid.fox_scroll.track": "追踪", "gui.touhou_little_maid.fox_scroll.empty": "没有任何女仆坐标", "gui.touhou_little_maid.optifine_warning.title": "车万女仆 Optifine 警告", - "gui.touhou_little_maid.optifine_warning.text": "在您点击继续按钮之前,请注意: Optifine 目前很容易导致游戏崩溃、实体渲染错误和许多其他问题。\n\n在反馈错误之前,请先删除 Optifine,然后再次检查错误是否仍然存在。\n\nOptifine 相关问题在女仆模组这边可能永远无法解决!\n\n推荐您使用 Oculus 和 Embeddium 模组作为 Optifine 的替代品。", + "gui.touhou_little_maid.optifine_warning.text": "在你点击继续按钮之前,请注意:Optifine 目前很容易导致游戏崩溃、实体渲染错误和许多其他问题。\n\n在反馈错误之前,请先删除 Optifine,然后再次检查错误是否仍然存在。\n\nOptifine 相关问题在女仆模组这边可能永远无法解决!\n\n推荐你使用 Oculus 和 Embeddium 模组作为 Optifine 的替代品。", "gui.touhou_little_maid.optifine_warning.embeddium": "下载 Embeddium 模组", "gui.touhou_little_maid.optifine_warning.oculus": "下载 Oculus 模组", - "gui.touhou_little_maid.cloth_config_warning.tips": "您需要安装 Cloth Config API 模组才能使用游戏内配置功能", + "gui.touhou_little_maid.cloth_config_warning.tips": "你需要安装 Cloth Config API 模组才能使用游戏内配置功能", "gui.touhou_little_maid.cloth_config_warning.download": "下载 Cloth Config API 模组", - "gui.touhou_little_maid.patchouli_warning.tips": "你需要下载Patchouli Mod才可以启用跳转到手册对应章节功能", - "gui.touhou_little_maid.patchouli_warning.download": "下载 Patchouli 模组", + "gui.touhou_little_maid.patchouli_warning.tips": "你需要下载帕秋莉手册才可以启用跳转到手册对应章节功能", + "gui.touhou_little_maid.patchouli_warning.download": "下载帕秋莉手册模组", "gui.touhou_little_maid.servant_bell.edit_box": "请输入提示文本", "gui.touhou_little_maid.cache_screen.progress": "进度:%d/%d", "gui.touhou_little_maid.cache_screen.desc": "缓存模型图标中,请等待……", @@ -276,17 +400,18 @@ "chat_bubble.touhou_little_maid.inner.feed_animal.max_number": "动物太多了……我不再喂养它们了!", "chat_bubble.touhou_little_maid.inner.home_meal.two_hand_is_full": "我的双手根本空不出来……我没法吃饭了!", "chat_bubble.touhou_little_maid.inner.home_meal.meal_is_empty": "快上菜、快上菜,我都没东西吃了!", + "chat_bubble.touhou_little_maid.inner.fishing.no_sit": "我必须坐在椅子或船上才能钓鱼!", "message.touhou_little_maid.missing_patchouli.title": "[车万女仆]", - "message.touhou_little_maid.missing_patchouli.click_here": "点击这里安装 Patchouli 模组来获取手册", + "message.touhou_little_maid.missing_patchouli.click_here": "点击这里安装帕秋莉手册模组来获取手册", "message.touhou_little_maid.missing_patchouli.url": "https://www.curseforge.com/minecraft/mc-mods/patchouli", - "message.touhou_little_maid.change_model.disabled": "模型切换功能已被禁止", + "message.touhou_little_maid.change_model.disabled": "模型切换功能已禁用", "message.touhou_little_maid.extinguisher.player_cannot_use": "你匮乏的知识并不了解这物品该如何使用", "message.touhou_little_maid.altar.not_enough_power": "你没有足够多的 P 点", "message.touhou_little_maid.owner_maid_num.can_not_add": "你无法再驯服女仆,你已经达到了上限(%d/%d)", "message.touhou_little_maid.photo.not_suitable_for_place_maid": "这该死的地方不能放置女仆", "message.touhou_little_maid.photo.have_no_nbt_data": "这该死的照片没有 NBT 数据", - "message.touhou_little_maid.chisel.hit_block_error": "请右击粘土块", - "message.touhou_little_maid.chisel.offhand_not_photo": "请副手持有一张女仆照片", + "message.touhou_little_maid.chisel.hit_block_error": "请右击黏土块", + "message.touhou_little_maid.chisel.offhand_not_photo": "请将女仆照片拿在副手", "message.touhou_little_maid.gomoku.win": "玩家获胜", "message.touhou_little_maid.gomoku.lose": "玩家失败", "message.touhou_little_maid.gomoku.reset": "右击棋盒进行重置", @@ -305,9 +430,9 @@ "message.touhou_little_maid.kappa_compass.maid_clear": "成功清除女仆的坐标", "message.touhou_little_maid.kappa_compass.maid_dimension_check": "记录的维度与当前女仆所处的维度不相同", "message.touhou_little_maid.kappa_compass.no_data": "这个罗盘没有记录任何坐标", - "message.touhou_little_maid.kappa_compass.work": "§a▍ §7工作区域:[%d, %d, %d§7]", - "message.touhou_little_maid.kappa_compass.idle": "§a▍ §7休息区域:[%d, %d, %d§7]", - "message.touhou_little_maid.kappa_compass.sleep": "§a▍ §7睡觉区域:[%d, %d, %d§7]", + "message.touhou_little_maid.kappa_compass.work": "§a▍ §7工作区域:[%d,%d,%d§7]", + "message.touhou_little_maid.kappa_compass.idle": "§a▍ §7休息区域:[%d,%d,%d§7]", + "message.touhou_little_maid.kappa_compass.sleep": "§a▍ §7睡觉区域:[%d,%d,%d§7]", "message.touhou_little_maid.kappa_compass.work_area": "工作区域", "message.touhou_little_maid.kappa_compass.idle_area": "休息区域", "message.touhou_little_maid.kappa_compass.sleep_area": "睡觉区域", @@ -324,19 +449,25 @@ "message.touhou_little_maid.saddle.how_to_eject": "使用鞍再次右击即可放下女仆", "message.touhou_little_maid.tombstone.not_yours.1": "这个女仆墓碑不是你的!如果你是服务器管理员,请使用 NTR 物品来移除它", "message.touhou_little_maid.tombstone.not_yours.2": "当前 NTR 物品:", - "message.touhou_little_maid.servant_bell.no_result": "找不到女仆", - "message.touhou_little_maid.servant_bell.data_is_empty": "这上面没有任何数据", "message.touhou_little_maid.servant_bell.show_pos": "女仆在卸载区块上,请遵循坐标指引来找到她", "message.touhou_little_maid.servant_bell.not_same_dimension": "女仆和你不在同一维度,女仆在 %s 维度", + "message.touhou_little_maid.servant_bell.no_result": "找不到女仆", + "message.touhou_little_maid.servant_bell.data_is_empty": "这上面没有任何数据", + "message.touhou_little_maid.cchess.check": "将军", + "message.touhou_little_maid.cchess.repeat": "长打判和!", + "message.touhou_little_maid.cchess.move_limit": "六十回合自然限着!", + "message.touhou_little_maid.cchess.reset": "右击棋盘右侧黑色区域重置", + "message.touhou_little_maid.wchess.move_limit": "五十回合限制!", + "message.touhou_little_maid.wchess.reset": "右击任意一侧的红色区域进行重置", "commands.touhou_little_maid.pack.reload.info": "所有的模型包已经重载!", "commands.touhou_little_maid.power.handle.info": "修改了 %d 位玩家的 P 点", "commands.touhou_little_maid.maid_num.handle.info": "修改了 %d 位玩家的女仆数量", "commands.touhou_little_maid.power.get.info": "%s: %.2f", "commands.touhou_little_maid.maid_num.get.info": "%s: %d", "argument.touhou_little_maid.handle_type.invalid": "不合法的 Handle 类型", - "death.touhou_little_maid.attack.danmaku.1": "%1$s被%2$s用弹幕干掉了", - "death.touhou_little_maid.attack.danmaku.2": "%1$s在躲避%2$s的弹幕时不慎 biu 了~", - "death.touhou_little_maid.attack.danmaku.3": "%1$s被%2$s的弹幕打的满身疮痍", + "death.touhou_little_maid.attack.danmaku.1": "%1$s被%2$s用弹幕杀死了", + "death.touhou_little_maid.attack.danmaku.2": "%1$s被%2$s用弹幕射杀", + "death.touhou_little_maid.attack.danmaku.3": "%1$s被%2$s的弹幕打得满身疮痍", "config.touhou_little_maid.maid": "女仆", "config.touhou_little_maid.maid.maid_tamed_item": "驯服女仆的物品", "config.touhou_little_maid.maid.maid_tamed_item.tooltip": "这个物品可以右击女仆进行驯服", @@ -411,9 +542,9 @@ "config.touhou_little_maid.misc.close_optifine_warning": "关闭 Optifine 警告", "config.touhou_little_maid.misc.close_optifine_warning.tooltip": "是否关闭 Optifine 警告", "config.touhou_little_maid.misc.scarecrow_range": "麻石狐像范围", - "config.touhou_little_maid.misc.scarecrow_range.tooltip": "麻石狐像阻止妖精女仆生成的范围", - "config.touhou_little_maid.misc.use_new_maid_fairy_model": "使用新版妖精女仆模型", - "config.touhou_little_maid.misc.use_new_maid_fairy_model.tooltip": "是否使用新版妖精女仆模型", + "config.touhou_little_maid.misc.scarecrow_range.tooltip": "麻石狐像阻止女仆妖精生成的范围", + "config.touhou_little_maid.misc.use_new_maid_fairy_model": "使用新版女仆妖精模型", + "config.touhou_little_maid.misc.use_new_maid_fairy_model.tooltip": "是否使用新版女仆妖精模型", "config.touhou_little_maid.vanilla": "原版设置", "config.touhou_little_maid.vanilla.replace_slime_model": "替换史莱姆模型", "config.touhou_little_maid.vanilla.replace_slime_model.tooltip": "将史莱姆模型替换为油库里", @@ -443,6 +574,7 @@ "task.touhou_little_maid.extinguishing": "灭火", "task.touhou_little_maid.board_games": "游戏", "task.touhou_little_maid.gun_attack": "枪械", + "task.touhou_little_maid.fishing": "钓鱼", "task.touhou_little_maid.desc.title": "[提示]", "task.touhou_little_maid.desc.condition": "[额外条件]", "task.touhou_little_maid.desc.enable_condition": "[启用条件]", @@ -470,8 +602,8 @@ "task.touhou_little_maid.snow.desc": "女仆会主动清理周围的雪,持有铲子会掉落雪球", "task.touhou_little_maid.feed.desc": "女仆会主动投喂周围饥饿的主人", "task.touhou_little_maid.shears.desc": "女仆会主动“剪”周围的生物", - "task.touhou_little_maid.milk.desc": "女仆会主动用桶收集周围牛的牛奶", - "task.touhou_little_maid.milk.condition.has_bucket": "背包内有桶", + "task.touhou_little_maid.milk.desc": "女仆会主动用铁桶收集周围牛的奶", + "task.touhou_little_maid.milk.condition.has_bucket": "背包内有铁桶", "task.touhou_little_maid.torch.desc": "女仆会主动在周围暗处放置火把", "task.touhou_little_maid.torch.condition.has_torch": "背包内有火把", "task.touhou_little_maid.feed_animal.desc": "女仆尝试繁殖周围的动物,有可配置的繁殖上限", @@ -480,8 +612,10 @@ "task.touhou_little_maid.extinguishing.desc": "女仆会主动扑灭周围的火", "task.touhou_little_maid.extinguishing.condition.has_extinguisher": "主手持有灭火器", "task.touhou_little_maid.board_games.desc": "女仆会寻找周围的五子棋盘", - "task.touhou_little_maid.gun_attack.desc": "女仆可以使用 TacZ(永恒枪械工坊:零)的枪械", - "task.touhou_little_maid.gun_attack.condition.has_tacz_gun": "主手持有一把 TacZ 的枪械", + "task.touhou_little_maid.gun_attack.desc": "女仆会使用永恒枪械工坊:零的枪械", + "task.touhou_little_maid.gun_attack.condition.has_tacz_gun": "主手持有永恒枪械工坊:零的枪械", + "task.touhou_little_maid.fishing.desc": "女仆会寻找椅子并坐在上面,然后开始钓鱼", + "task.touhou_little_maid.fishing.condition.has_fishing_rod": "主手持有钓鱼竿", "task.touhou_little_maid.advanced.id": "工作模式 ID:%s", "button.touhou_little_maid.maid.mode.idle": "空闲", "button.touhou_little_maid.maid.mode.attack": "攻击", @@ -490,7 +624,7 @@ "button.touhou_little_maid.maid.mode.farm": "农场", "button.touhou_little_maid.maid.mode.feed": "喂养", "button.touhou_little_maid.maid.mode.shears": "剪刀", - "button.touhou_little_maid.maid.mode.milk": "获取牛奶", + "button.touhou_little_maid.maid.mode.milk": "获取奶", "button.touhou_little_maid.maid.mode.torch": "火把", "button.touhou_little_maid.maid.mode.feed_animal": "繁殖动物", "button.touhou_little_maid.maid.mode.extinguishing": "灭火", @@ -520,7 +654,7 @@ "subtitle.touhou_little_maid.maid.mode.farm": "女仆:农场", "subtitle.touhou_little_maid.maid.mode.feed": "女仆:喂养", "subtitle.touhou_little_maid.maid.mode.shears": "女仆:剪刀", - "subtitle.touhou_little_maid.maid.mode.milk": "女仆:获取牛奶", + "subtitle.touhou_little_maid.maid.mode.milk": "女仆:获取奶", "subtitle.touhou_little_maid.maid.mode.torch": "女仆:火把", "subtitle.touhou_little_maid.maid.mode.feed_animal": "女仆:繁殖动物", "subtitle.touhou_little_maid.maid.mode.extinguishing": "女仆:灭火", @@ -542,16 +676,16 @@ "subtitle.touhou_little_maid.maid.environment.morning": "女仆:早上", "subtitle.touhou_little_maid.maid.environment.night": "女仆:傍晚", "subtitle.touhou_little_maid.other.credit": "备注说明", - "subtitle.touhou_little_maid.item.camera_use": "相机咔哒声", + "subtitle.touhou_little_maid.item.camera_use": "相机:咔哒", "subtitle.touhou_little_maid.item.album_open": "相册:打开", "subtitle.touhou_little_maid.block.altar_craft": "祭坛:合成", "subtitle.touhou_little_maid.block.gomoku": "五子棋:落子", "subtitle.touhou_little_maid.block.gomoku_reset": "五子棋:重置", "subtitle.touhou_little_maid.entity.box": "盒子:打开", "subtitle.touhou_little_maid.item.compass": "罗盘:选择点", - "touhou_little_maid.subtitles.entity.fairy.ambient": "妖精女仆:吱吱", - "touhou_little_maid.subtitles.entity.fairy.death": "妖精女仆:死亡", - "touhou_little_maid.subtitles.entity.fairy.hurt": "妖精女仆:受伤", + "touhou_little_maid.subtitles.entity.fairy.ambient": "女仆妖精:吱吱", + "touhou_little_maid.subtitles.entity.fairy.death": "女仆妖精:死亡", + "touhou_little_maid.subtitles.entity.fairy.hurt": "女仆妖精:受伤", "emi.category.touhou_little_maid.altar": "祭坛合成", "jei.touhou_little_maid.altar_craft.title": "祭坛合成", "jei.touhou_little_maid.altar_craft.result": "结果:%s", @@ -633,11 +767,15 @@ "patchouli.touhou_little_maid.book.entries.maid.maid_meal.name": "女仆用餐", "patchouli.touhou_little_maid.book.entries.maid.maid_meal.pages.0.text": "女仆在工作或者受伤时可以进食,从而提升好感度或者恢复血量。$(br2)请给她们的主手或副手放上食物!", "patchouli.touhou_little_maid.book.entries.maid.maid_meal.pages.1.text": "女仆在空闲日程时,会寻找周围的野餐垫进食,这会大幅度提升她们的好感度。$(br2)请给她们放上美味的大餐吧!", + "patchouli.touhou_little_maid.book.entries.maid.servant_bell.name": "仆人铃", + "patchouli.touhou_little_maid.book.entries.maid.servant_bell.pages.0.text": "仆人铃可以一对一的召唤回女仆,如果女仆在卸载区块上,它也能提示你女仆所处的位置。$(br2)手持此物品右击女仆即可进行绑定!", + "patchouli.touhou_little_maid.book.entries.maid.monster_list.name": "妖怪名单", + "patchouli.touhou_little_maid.book.entries.maid.monster_list.pages.0.text": "妖怪名单用于女仆的攻击模式,可以设置女仆应当攻击什么样的生物,只需要在她的副手放上这个物品即可。$(br2)注意:女仆不会攻击任何玩家!或者是有主人的宠物!", "patchouli.touhou_little_maid.book.entries.other.chisel_and_statues.name": "雕刻刀与雕像", - "patchouli.touhou_little_maid.book.entries.other.chisel_and_statues.pages.0.text": "雕刻刀右击粘土可以做成不同尺寸大小的雕像,目前支持 1x1x1,1x1x2,2x2x4,3x3x6 大小尺寸。", + "patchouli.touhou_little_maid.book.entries.other.chisel_and_statues.pages.0.text": "雕刻刀右击黏土可以做成不同尺寸大小的雕像,目前支持 1x1x1、1x1x2、2x2x4、3x3x6 大小尺寸。", "patchouli.touhou_little_maid.book.entries.other.chisel_and_statues.pages.1.text": "玩家副手持有女仆照片,主手持有雕刻刀,右击多方块结构的左下角,即可雕刻出照片中的女仆。", "patchouli.touhou_little_maid.book.entries.other.garage_kit.name": "手办", - "patchouli.touhou_little_maid.book.entries.other.garage_kit.pages.0.text": "火烤 1x1 大小的雕像可以转换成它.", + "patchouli.touhou_little_maid.book.entries.other.garage_kit.pages.0.text": "火烤 1x1 大小的雕像可以转换成它。", "patchouli.touhou_little_maid.book.entries.other.maid_beacon.name": "神社庭灯", "patchouli.touhou_little_maid.book.entries.other.maid_beacon.pages.0.text": "神社庭灯既是一个不错的装饰物,还具有一定的实用功能。右击神社庭灯的上部能够打开 GUI,存储玩家的 P 点。$(br2)庭灯同样也是一个拥有攻击力的武器。", "patchouli.touhou_little_maid.book.entries.other.maid_beacon.pages.1.text": "同时还能点击按钮选择相应的效果,这些效果会消耗 P 点来为周围范围的女仆带来对应增益效果。$(br2)神社庭灯还是一个自动收集 P 点的好工具,它能够自动收集其 6 格范围内的 P 点,并将其存储起来。", @@ -654,18 +792,20 @@ "patchouli.touhou_little_maid.book.entries.other.maid_bed.pages.0.text": "玩家可以睡觉,自然而然女仆也可以睡觉。在睡觉的日程中,女仆会寻找周围的床睡觉。$(br2)睡着状态的女仆不会再被敌对性生物攻击,此时女仆的 GUI 也无法打开。", "patchouli.touhou_little_maid.book.entries.other.maid_bed.pages.1.text": "睡在床上的女仆。", "patchouli.touhou_little_maid.book.entries.other.power_point.name": "P 点", - "patchouli.touhou_little_maid.book.entries.other.power_point.pages.0.text": "右键丢出,能够掉落实体 P 点。$(br2)你可在地牢战利品箱内发现物品形态的 P 点。", + "patchouli.touhou_little_maid.book.entries.other.power_point.pages.0.text": "右击丢出,能够掉落实体 P 点。$(br2)你可在地牢战利品箱内发现物品形态的 P 点。", "patchouli.touhou_little_maid.book.entries.other.camera_and_photo.name": "相机与照片", "patchouli.touhou_little_maid.book.entries.other.camera_and_photo.pages.0.text": "在跨维度或者远距离携带女仆是一个麻烦的事情,相机就是为此设计的。$(br2)只需要用相机对着自己的女仆拍摄就能将其变成照片,之后拿着照片对着方块右击又可以将其释放出来。", "patchouli.touhou_little_maid.book.entries.other.model_switcher.name": "模型切换器", "patchouli.touhou_little_maid.book.entries.other.model_switcher.pages.0.text": "用于创造模式,主要面向服务器设计,可以用于展示女仆模型。", - "patchouli.touhou_little_maid.book.entries.other.model_switcher.pages.1.text": "首先你需要手持此方块右击女仆。然后将其放置在地上,并右键打开 GUI 来设置你想展示的模型。$(br2)接下来在其左右两侧输入红石信号,即可切换此女仆的模型。", + "patchouli.touhou_little_maid.book.entries.other.model_switcher.pages.1.text": "首先你需要手持此方块右击女仆。然后将其放置在地上,并右击打开 GUI 来设置你想展示的模型。$(br2)接下来在其左右两侧输入红石信号,即可切换此女仆的模型。", "patchouli.touhou_little_maid.book.entries.other.chair_show.name": "坐垫显示器", "patchouli.touhou_little_maid.book.entries.other.chair_show.pages.0.text": "当手持并按下潜行键时,所有的坐垫都会显示碰撞箱。", "patchouli.touhou_little_maid.book.entries.other.favorability_tool.name": "好感度工具", "patchouli.touhou_little_maid.book.entries.other.favorability_tool.pages.0.text": "右击女仆改变女仆的好感度,仅限创造模式。", "patchouli.touhou_little_maid.book.entries.other.fox_scroll.name": "狐狸卷轴", "patchouli.touhou_little_maid.book.entries.other.fox_scroll.pages.0.text": "用来寻找女仆或者女仆墓碑。", + "patchouli.touhou_little_maid.book.entries.other.granite_inari_fox.name": "麻石狐像", + "patchouli.touhou_little_maid.book.entries.other.granite_inari_fox.pages.0.text": "麻石狐像可以阻止一定范围内女仆妖精的生成,不会影响其他生物的生成$(br2)限制范围是一个矩形范围,Y 方向则是从最低点到最高点全部覆盖!", "patchouli.touhou_little_maid.book.entries.other.gomoku.name": "五子棋", "patchouli.touhou_little_maid.book.entries.other.gomoku.pages.0.text": "你可以和女仆一起玩五子棋,获胜能够增加女仆的好感度。$(br2)在玩家多次取得胜利后,女仆的五子棋技术也会上升。", "patchouli.touhou_little_maid.book.entries.other.maid_joy.name": "女仆娱乐", @@ -673,7 +813,7 @@ "patchouli.touhou_little_maid.book.entries.other.shrine.name": "神龛", "patchouli.touhou_little_maid.book.entries.other.shrine.pages.0.text": "有很低概率在战利品箱中发现。能够通过消耗玩家血量来复活胶片中的女仆。", "patchouli.touhou_little_maid.book.entries.other.broom.name": "扫帚", - "patchouli.touhou_little_maid.book.entries.other.broom.pages.0.text": "扫帚是一个便携的交通工具,但是需要你和女仆共同来使用。$(br2)通过鼠标来控制扫帚拉升或者下降, WASD 控制前后左右移动。", + "patchouli.touhou_little_maid.book.entries.other.broom.pages.0.text": "扫帚是一个便携的交通工具,但是需要你和女仆共同来使用。$(br2)通过鼠标来控制扫帚拉升或者下降,WASD 控制前后左右移动。", "patchouli.touhou_little_maid.book.entries.other.picnic_basket.name": "野餐篮", "patchouli.touhou_little_maid.book.entries.other.picnic_basket.pages.0.text": "野餐篮可以存储食物,右击放置在地上即可变成野餐垫。", "patchouli.touhou_little_maid.book.entries.overview.gohei_and_danmaku.name": "御币与弹幕", @@ -695,7 +835,7 @@ "patchouli.touhou_little_maid.book.entries.overview.world_spawn.pages.1.text": "在任意群系的夜晚生成,会以飞行状态弹幕攻击玩家或铁傀儡。", "patchouli.touhou_little_maid.book.entries.overview.world_spawn.pages.2.text": "女仆有概率在掠夺者前哨站的笼子里生成", "patchouli.touhou_little_maid.book.entries.overview.make_custom_model.name": "制作自定义模型", - "patchouli.touhou_little_maid.book.entries.overview.make_custom_model.pages.0.text": "制作一个自定义模型包非常简单,你只需要 Blockbech。 Blockbench 是一个免费开源的软件,而且非常易于上手。$(br2)自定义模型也支持基岩版动画,并且提供了大量 molang 参数可用。", + "patchouli.touhou_little_maid.book.entries.overview.make_custom_model.pages.0.text": "制作一个自定义模型包非常简单,你只需要 Blockbech。Blockbench 是一个免费开源的软件,而且非常易于上手。$(br2)自定义模型也支持基岩版动画,并且提供了大量 molang 参数可用。", "patchouli.touhou_little_maid.book.entries.overview.make_custom_model.pages.1.text": "我特意设计了一个 Blockbench 插件用于制作模型包,访问下方链接学习如何安装此插件。", "patchouli.touhou_little_maid.book.entries.overview.make_custom_model.pages.1.link_text": "打开链接", "patchouli.touhou_little_maid.book.entries.overview.download_custom_model.name": "下载自定义模型", @@ -713,11 +853,5 @@ "patchouli.touhou_little_maid.book.entries.overview.make_custom_chatbubble_text.pages.2.text": "但是每页的第一行必须要有类型名称,它指明了该台本在什么情况下显示。$(br2)可用的类型名称有这些:$(br)日程相关:$(li)work:任意工作日程时显示$(li)idle:休息或空闲状态时显示$(li)sleep:睡觉时显示", "patchouli.touhou_little_maid.book.entries.overview.make_custom_chatbubble_text.pages.3.text": "其他情况:$(li)morning:早上时显示$(li)night:傍晚时显示$(li)rain:下雨时显示$(li)snow:下雪时显示$(li)cold:处于寒冷的群系时显示$(li)hot:处于炎热的群系时显示$(li)hurt:受伤时显示$(li)beg:祈求状态时显示", "patchouli.touhou_little_maid.book.entries.overview.make_custom_chatbubble_text.pages.4.text": "工作模式:$(li)会在特定的工作模式时显示,比如 attack,farm 等。$(br2)当你写好了台本,只需要对着女仆右击即可写入台本。$(br)如果你是在按下 Shift 键时,手持书与笔(或者成书)右击女仆,那么就可以清除女仆的台本。$(br)如果你是拿着空白的书与笔右击已经有台本的女仆,可以将女仆的台本复制到书上。", - "patchouli.touhou_little_maid.book.entries.overview.make_custom_chatbubble_text.pages.5.text": "当开启了高级文本提示功能时(F3+H),你可以在工作模式切换界面的文本提示上看到这些名称。", - "patchouli.touhou_little_maid.book.entries.maid.servant_bell.name": "仆人铃", - "patchouli.touhou_little_maid.book.entries.maid.servant_bell.pages.0.text": "仆人铃可以一对一的召唤回女仆,如果女仆在卸载区块上,它也能提示你女仆所处的位置。$(br2)手持此物品右击女仆即可进行绑定!", - "patchouli.touhou_little_maid.book.entries.maid.monster_list.name": "妖怪名单", - "patchouli.touhou_little_maid.book.entries.maid.monster_list.pages.0.text": "妖怪名单用于女仆的攻击模式,可以设置女仆应当攻击什么样的生物,只需要在她的副手放上这个物品即可。$(br2)注意:女仆不会攻击任何玩家!或者是有主人的宠物!", - "patchouli.touhou_little_maid.book.entries.other.granite_inari_fox.name": "麻石狐像", - "patchouli.touhou_little_maid.book.entries.other.granite_inari_fox.pages.0.text": "麻石狐像可以阻止一定范围内妖精女仆的生成,不会影响其他生物的生成$(br2)限制范围是一个矩形范围,Y 方向则是从最低点到最高点全部覆盖!" + "patchouli.touhou_little_maid.book.entries.overview.make_custom_chatbubble_text.pages.5.text": "当开启了高级文本提示功能时(F3+H),你可以在工作模式切换界面的文本提示上看到这些名称。" } \ No newline at end of file diff --git a/src/main/resources/assets/touhou_little_maid/models/block/cchess.json b/src/main/resources/assets/touhou_little_maid/models/block/cchess.json new file mode 100644 index 000000000..9406a8491 --- /dev/null +++ b/src/main/resources/assets/touhou_little_maid/models/block/cchess.json @@ -0,0 +1,5 @@ +{ + "textures": { + "particle": "minecraft:block/oak_planks" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/touhou_little_maid/models/block/wchess.json b/src/main/resources/assets/touhou_little_maid/models/block/wchess.json new file mode 100644 index 000000000..9406a8491 --- /dev/null +++ b/src/main/resources/assets/touhou_little_maid/models/block/wchess.json @@ -0,0 +1,5 @@ +{ + "textures": { + "particle": "minecraft:block/oak_planks" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/touhou_little_maid/models/entity/cchess_pieces.json b/src/main/resources/assets/touhou_little_maid/models/entity/cchess_pieces.json new file mode 100644 index 000000000..becc9db48 --- /dev/null +++ b/src/main/resources/assets/touhou_little_maid/models/entity/cchess_pieces.json @@ -0,0 +1,4564 @@ +{ + "format_version": "1.12.0", + "minecraft:geometry": [ + { + "description": { + "identifier": "geometry.unknown", + "texture_width": 512, + "texture_height": 512, + "visible_bounds_width": 3, + "visible_bounds_height": 6, + "visible_bounds_offset": [0, 2, 0] + }, + "bones": [ + { + "name": "ShuaiRed", + "pivot": [0, 0.5, 0] + }, + { + "name": "bone37", + "parent": "ShuaiRed", + "pivot": [0, 0, 0], + "cubes": [ + {"origin": [-32, 31.9, -32], "size": [64, 0, 64], "inflate": -30.75, "uv": [0, 0]} + ] + }, + { + "name": "bone", + "parent": "bone37", + "pivot": [0, 0.2, 0] + }, + { + "name": "bone2", + "parent": "bone", + "pivot": [0, 0.2, 0], + "rotation": [10, 0, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone3", + "parent": "bone", + "pivot": [0, 0.2, 0], + "rotation": [10, -45, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone4", + "parent": "bone", + "pivot": [0, 0.2, 0], + "rotation": [10, -90, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone5", + "parent": "bone", + "pivot": [0, 0.2, 0], + "rotation": [10, -135, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone6", + "parent": "bone", + "pivot": [0, 0.2, 0], + "rotation": [10, -180, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone7", + "parent": "bone", + "pivot": [0, 0.2, 0], + "rotation": [10, -225, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone8", + "parent": "bone", + "pivot": [0, 0.2, 0], + "rotation": [10, -270, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone9", + "parent": "bone", + "pivot": [0, 0.2, 0], + "rotation": [10, -315, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone10", + "parent": "bone37", + "pivot": [0, 1, 0], + "rotation": [0, 0, -180] + }, + { + "name": "bone11", + "parent": "bone10", + "pivot": [0, 1, 0], + "rotation": [10, 0, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone12", + "parent": "bone10", + "pivot": [0, 1, 0], + "rotation": [10, -45, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone13", + "parent": "bone10", + "pivot": [0, 1, 0], + "rotation": [10, -90, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone14", + "parent": "bone10", + "pivot": [0, 1, 0], + "rotation": [10, -135, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone15", + "parent": "bone10", + "pivot": [0, 1, 0], + "rotation": [10, -180, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone16", + "parent": "bone10", + "pivot": [0, 1, 0], + "rotation": [10, -225, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone17", + "parent": "bone10", + "pivot": [0, 1, 0], + "rotation": [10, -270, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone18", + "parent": "bone10", + "pivot": [0, 1, 0], + "rotation": [10, -315, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone19", + "parent": "bone37", + "pivot": [0, 0.1, 0] + }, + { + "name": "bone20", + "parent": "bone19", + "pivot": [0, 0.1, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone21", + "parent": "bone19", + "pivot": [0, 0.1, 0], + "rotation": [0, -45, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone22", + "parent": "bone19", + "pivot": [0, 0.1, 0], + "rotation": [0, -90, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone23", + "parent": "bone19", + "pivot": [0, 0.1, 0], + "rotation": [0, -135, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone24", + "parent": "bone19", + "pivot": [0, 0.1, 0], + "rotation": [0, -180, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone25", + "parent": "bone19", + "pivot": [0, 0.1, 0], + "rotation": [0, -225, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone26", + "parent": "bone19", + "pivot": [0, 0.1, 0], + "rotation": [0, -270, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone27", + "parent": "bone19", + "pivot": [0, 0.1, 0], + "rotation": [0, -315, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone28", + "parent": "bone37", + "pivot": [0, 0.1, 0] + }, + { + "name": "bone29", + "parent": "bone28", + "pivot": [0, 0.1, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone30", + "parent": "bone28", + "pivot": [0, 0.1, 0], + "rotation": [0, -45, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone31", + "parent": "bone28", + "pivot": [0, 0.1, 0], + "rotation": [0, -90, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone32", + "parent": "bone28", + "pivot": [0, 0.1, 0], + "rotation": [0, -135, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone33", + "parent": "bone28", + "pivot": [0, 0.1, 0], + "rotation": [0, -180, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone34", + "parent": "bone28", + "pivot": [0, 0.1, 0], + "rotation": [0, -225, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone35", + "parent": "bone28", + "pivot": [0, 0.1, 0], + "rotation": [0, -270, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone36", + "parent": "bone28", + "pivot": [0, 0.1, 0], + "rotation": [0, -315, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "ShiRed", + "pivot": [0, 0.5, 0] + }, + { + "name": "bone47", + "parent": "ShiRed", + "pivot": [0, 0, 0], + "cubes": [ + {"origin": [-32, 32, -32], "size": [64, 0, 64], "inflate": -30.85, "uv": [161, 0]} + ] + }, + { + "name": "bone48", + "parent": "bone47", + "pivot": [0, 0.2, 0] + }, + { + "name": "bone49", + "parent": "bone48", + "pivot": [0, 0.2, 0], + "rotation": [10, 0, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone50", + "parent": "bone48", + "pivot": [0, 0.2, 0], + "rotation": [10, -45, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone51", + "parent": "bone48", + "pivot": [0, 0.2, 0], + "rotation": [10, -90, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone52", + "parent": "bone48", + "pivot": [0, 0.2, 0], + "rotation": [10, -135, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone53", + "parent": "bone48", + "pivot": [0, 0.2, 0], + "rotation": [10, -180, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone54", + "parent": "bone48", + "pivot": [0, 0.2, 0], + "rotation": [10, -225, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone55", + "parent": "bone48", + "pivot": [0, 0.2, 0], + "rotation": [10, -270, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone56", + "parent": "bone48", + "pivot": [0, 0.2, 0], + "rotation": [10, -315, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone57", + "parent": "bone47", + "pivot": [0, 1, 0], + "rotation": [0, 0, -180] + }, + { + "name": "bone58", + "parent": "bone57", + "pivot": [0, 1, 0], + "rotation": [10, 0, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone59", + "parent": "bone57", + "pivot": [0, 1, 0], + "rotation": [10, -45, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone60", + "parent": "bone57", + "pivot": [0, 1, 0], + "rotation": [10, -90, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone61", + "parent": "bone57", + "pivot": [0, 1, 0], + "rotation": [10, -135, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone62", + "parent": "bone57", + "pivot": [0, 1, 0], + "rotation": [10, -180, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone63", + "parent": "bone57", + "pivot": [0, 1, 0], + "rotation": [10, -225, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone64", + "parent": "bone57", + "pivot": [0, 1, 0], + "rotation": [10, -270, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone65", + "parent": "bone57", + "pivot": [0, 1, 0], + "rotation": [10, -315, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone66", + "parent": "bone47", + "pivot": [0, 0.1, 0] + }, + { + "name": "bone67", + "parent": "bone66", + "pivot": [0, 0.1, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone68", + "parent": "bone66", + "pivot": [0, 0.1, 0], + "rotation": [0, -45, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone69", + "parent": "bone66", + "pivot": [0, 0.1, 0], + "rotation": [0, -90, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone70", + "parent": "bone66", + "pivot": [0, 0.1, 0], + "rotation": [0, -135, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone71", + "parent": "bone66", + "pivot": [0, 0.1, 0], + "rotation": [0, -180, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone72", + "parent": "bone66", + "pivot": [0, 0.1, 0], + "rotation": [0, -225, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone73", + "parent": "bone66", + "pivot": [0, 0.1, 0], + "rotation": [0, -270, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone74", + "parent": "bone66", + "pivot": [0, 0.1, 0], + "rotation": [0, -315, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone75", + "parent": "bone47", + "pivot": [0, 0.1, 0] + }, + { + "name": "bone76", + "parent": "bone75", + "pivot": [0, 0.1, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone77", + "parent": "bone75", + "pivot": [0, 0.1, 0], + "rotation": [0, -45, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone78", + "parent": "bone75", + "pivot": [0, 0.1, 0], + "rotation": [0, -90, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone79", + "parent": "bone75", + "pivot": [0, 0.1, 0], + "rotation": [0, -135, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone80", + "parent": "bone75", + "pivot": [0, 0.1, 0], + "rotation": [0, -180, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone81", + "parent": "bone75", + "pivot": [0, 0.1, 0], + "rotation": [0, -225, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone82", + "parent": "bone75", + "pivot": [0, 0.1, 0], + "rotation": [0, -270, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone83", + "parent": "bone75", + "pivot": [0, 0.1, 0], + "rotation": [0, -315, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "XiangRed", + "pivot": [0, 0.5, 0] + }, + { + "name": "bone84", + "parent": "XiangRed", + "pivot": [0, 0, 0], + "cubes": [ + {"origin": [-32, 32, -32], "size": [64, 0, 64], "inflate": -30.85, "uv": [320, 0]} + ] + }, + { + "name": "bone85", + "parent": "bone84", + "pivot": [0, 0.2, 0] + }, + { + "name": "bone86", + "parent": "bone85", + "pivot": [0, 0.2, 0], + "rotation": [10, 0, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone87", + "parent": "bone85", + "pivot": [0, 0.2, 0], + "rotation": [10, -45, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone88", + "parent": "bone85", + "pivot": [0, 0.2, 0], + "rotation": [10, -90, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone89", + "parent": "bone85", + "pivot": [0, 0.2, 0], + "rotation": [10, -135, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone90", + "parent": "bone85", + "pivot": [0, 0.2, 0], + "rotation": [10, -180, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone91", + "parent": "bone85", + "pivot": [0, 0.2, 0], + "rotation": [10, -225, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone92", + "parent": "bone85", + "pivot": [0, 0.2, 0], + "rotation": [10, -270, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone93", + "parent": "bone85", + "pivot": [0, 0.2, 0], + "rotation": [10, -315, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone94", + "parent": "bone84", + "pivot": [0, 1, 0], + "rotation": [0, 0, -180] + }, + { + "name": "bone95", + "parent": "bone94", + "pivot": [0, 1, 0], + "rotation": [10, 0, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone96", + "parent": "bone94", + "pivot": [0, 1, 0], + "rotation": [10, -45, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone97", + "parent": "bone94", + "pivot": [0, 1, 0], + "rotation": [10, -90, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone98", + "parent": "bone94", + "pivot": [0, 1, 0], + "rotation": [10, -135, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone99", + "parent": "bone94", + "pivot": [0, 1, 0], + "rotation": [10, -180, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone100", + "parent": "bone94", + "pivot": [0, 1, 0], + "rotation": [10, -225, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone101", + "parent": "bone94", + "pivot": [0, 1, 0], + "rotation": [10, -270, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone102", + "parent": "bone94", + "pivot": [0, 1, 0], + "rotation": [10, -315, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone103", + "parent": "bone84", + "pivot": [0, 0.1, 0] + }, + { + "name": "bone104", + "parent": "bone103", + "pivot": [0, 0.1, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone105", + "parent": "bone103", + "pivot": [0, 0.1, 0], + "rotation": [0, -45, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone106", + "parent": "bone103", + "pivot": [0, 0.1, 0], + "rotation": [0, -90, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone107", + "parent": "bone103", + "pivot": [0, 0.1, 0], + "rotation": [0, -135, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone108", + "parent": "bone103", + "pivot": [0, 0.1, 0], + "rotation": [0, -180, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone109", + "parent": "bone103", + "pivot": [0, 0.1, 0], + "rotation": [0, -225, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone110", + "parent": "bone103", + "pivot": [0, 0.1, 0], + "rotation": [0, -270, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone111", + "parent": "bone103", + "pivot": [0, 0.1, 0], + "rotation": [0, -315, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone112", + "parent": "bone84", + "pivot": [0, 0.1, 0] + }, + { + "name": "bone113", + "parent": "bone112", + "pivot": [0, 0.1, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone114", + "parent": "bone112", + "pivot": [0, 0.1, 0], + "rotation": [0, -45, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone115", + "parent": "bone112", + "pivot": [0, 0.1, 0], + "rotation": [0, -90, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone116", + "parent": "bone112", + "pivot": [0, 0.1, 0], + "rotation": [0, -135, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone117", + "parent": "bone112", + "pivot": [0, 0.1, 0], + "rotation": [0, -180, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone118", + "parent": "bone112", + "pivot": [0, 0.1, 0], + "rotation": [0, -225, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone119", + "parent": "bone112", + "pivot": [0, 0.1, 0], + "rotation": [0, -270, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone120", + "parent": "bone112", + "pivot": [0, 0.1, 0], + "rotation": [0, -315, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "MaRed", + "pivot": [0, 0.5, 0] + }, + { + "name": "bone121", + "parent": "MaRed", + "pivot": [0, 0, 0], + "cubes": [ + {"origin": [-32, 32, -32], "size": [64, 0, 64], "inflate": -30.85, "uv": [-64, 72]} + ] + }, + { + "name": "bone122", + "parent": "bone121", + "pivot": [0, 0.2, 0] + }, + { + "name": "bone123", + "parent": "bone122", + "pivot": [0, 0.2, 0], + "rotation": [10, 0, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone124", + "parent": "bone122", + "pivot": [0, 0.2, 0], + "rotation": [10, -45, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone125", + "parent": "bone122", + "pivot": [0, 0.2, 0], + "rotation": [10, -90, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone126", + "parent": "bone122", + "pivot": [0, 0.2, 0], + "rotation": [10, -135, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone127", + "parent": "bone122", + "pivot": [0, 0.2, 0], + "rotation": [10, -180, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone128", + "parent": "bone122", + "pivot": [0, 0.2, 0], + "rotation": [10, -225, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone129", + "parent": "bone122", + "pivot": [0, 0.2, 0], + "rotation": [10, -270, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone130", + "parent": "bone122", + "pivot": [0, 0.2, 0], + "rotation": [10, -315, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone131", + "parent": "bone121", + "pivot": [0, 1, 0], + "rotation": [0, 0, -180] + }, + { + "name": "bone132", + "parent": "bone131", + "pivot": [0, 1, 0], + "rotation": [10, 0, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone133", + "parent": "bone131", + "pivot": [0, 1, 0], + "rotation": [10, -45, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone134", + "parent": "bone131", + "pivot": [0, 1, 0], + "rotation": [10, -90, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone135", + "parent": "bone131", + "pivot": [0, 1, 0], + "rotation": [10, -135, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone136", + "parent": "bone131", + "pivot": [0, 1, 0], + "rotation": [10, -180, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone137", + "parent": "bone131", + "pivot": [0, 1, 0], + "rotation": [10, -225, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone138", + "parent": "bone131", + "pivot": [0, 1, 0], + "rotation": [10, -270, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone139", + "parent": "bone131", + "pivot": [0, 1, 0], + "rotation": [10, -315, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone140", + "parent": "bone121", + "pivot": [0, 0.1, 0] + }, + { + "name": "bone141", + "parent": "bone140", + "pivot": [0, 0.1, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone142", + "parent": "bone140", + "pivot": [0, 0.1, 0], + "rotation": [0, -45, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone143", + "parent": "bone140", + "pivot": [0, 0.1, 0], + "rotation": [0, -90, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone144", + "parent": "bone140", + "pivot": [0, 0.1, 0], + "rotation": [0, -135, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone145", + "parent": "bone140", + "pivot": [0, 0.1, 0], + "rotation": [0, -180, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone146", + "parent": "bone140", + "pivot": [0, 0.1, 0], + "rotation": [0, -225, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone147", + "parent": "bone140", + "pivot": [0, 0.1, 0], + "rotation": [0, -270, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone148", + "parent": "bone140", + "pivot": [0, 0.1, 0], + "rotation": [0, -315, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone149", + "parent": "bone121", + "pivot": [0, 0.1, 0] + }, + { + "name": "bone150", + "parent": "bone149", + "pivot": [0, 0.1, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone151", + "parent": "bone149", + "pivot": [0, 0.1, 0], + "rotation": [0, -45, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone152", + "parent": "bone149", + "pivot": [0, 0.1, 0], + "rotation": [0, -90, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone153", + "parent": "bone149", + "pivot": [0, 0.1, 0], + "rotation": [0, -135, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone154", + "parent": "bone149", + "pivot": [0, 0.1, 0], + "rotation": [0, -180, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone155", + "parent": "bone149", + "pivot": [0, 0.1, 0], + "rotation": [0, -225, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone156", + "parent": "bone149", + "pivot": [0, 0.1, 0], + "rotation": [0, -270, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone157", + "parent": "bone149", + "pivot": [0, 0.1, 0], + "rotation": [0, -315, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "JuRed", + "pivot": [0, 0.5, 0] + }, + { + "name": "bone158", + "parent": "JuRed", + "pivot": [0, 0, 0], + "cubes": [ + {"origin": [-32, 32, -32], "size": [64, 0, 64], "inflate": -30.85, "uv": [116, 74]} + ] + }, + { + "name": "bone159", + "parent": "bone158", + "pivot": [0, 0.2, 0] + }, + { + "name": "bone160", + "parent": "bone159", + "pivot": [0, 0.2, 0], + "rotation": [10, 0, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone161", + "parent": "bone159", + "pivot": [0, 0.2, 0], + "rotation": [10, -45, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone162", + "parent": "bone159", + "pivot": [0, 0.2, 0], + "rotation": [10, -90, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone163", + "parent": "bone159", + "pivot": [0, 0.2, 0], + "rotation": [10, -135, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone164", + "parent": "bone159", + "pivot": [0, 0.2, 0], + "rotation": [10, -180, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone165", + "parent": "bone159", + "pivot": [0, 0.2, 0], + "rotation": [10, -225, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone166", + "parent": "bone159", + "pivot": [0, 0.2, 0], + "rotation": [10, -270, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone167", + "parent": "bone159", + "pivot": [0, 0.2, 0], + "rotation": [10, -315, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone168", + "parent": "bone158", + "pivot": [0, 1, 0], + "rotation": [0, 0, -180] + }, + { + "name": "bone169", + "parent": "bone168", + "pivot": [0, 1, 0], + "rotation": [10, 0, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone170", + "parent": "bone168", + "pivot": [0, 1, 0], + "rotation": [10, -45, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone171", + "parent": "bone168", + "pivot": [0, 1, 0], + "rotation": [10, -90, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone172", + "parent": "bone168", + "pivot": [0, 1, 0], + "rotation": [10, -135, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone173", + "parent": "bone168", + "pivot": [0, 1, 0], + "rotation": [10, -180, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone174", + "parent": "bone168", + "pivot": [0, 1, 0], + "rotation": [10, -225, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone175", + "parent": "bone168", + "pivot": [0, 1, 0], + "rotation": [10, -270, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone176", + "parent": "bone168", + "pivot": [0, 1, 0], + "rotation": [10, -315, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone177", + "parent": "bone158", + "pivot": [0, 0.1, 0] + }, + { + "name": "bone178", + "parent": "bone177", + "pivot": [0, 0.1, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone179", + "parent": "bone177", + "pivot": [0, 0.1, 0], + "rotation": [0, -45, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone180", + "parent": "bone177", + "pivot": [0, 0.1, 0], + "rotation": [0, -90, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone181", + "parent": "bone177", + "pivot": [0, 0.1, 0], + "rotation": [0, -135, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone182", + "parent": "bone177", + "pivot": [0, 0.1, 0], + "rotation": [0, -180, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone183", + "parent": "bone177", + "pivot": [0, 0.1, 0], + "rotation": [0, -225, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone184", + "parent": "bone177", + "pivot": [0, 0.1, 0], + "rotation": [0, -270, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone185", + "parent": "bone177", + "pivot": [0, 0.1, 0], + "rotation": [0, -315, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone186", + "parent": "bone158", + "pivot": [0, 0.1, 0] + }, + { + "name": "bone187", + "parent": "bone186", + "pivot": [0, 0.1, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone188", + "parent": "bone186", + "pivot": [0, 0.1, 0], + "rotation": [0, -45, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone189", + "parent": "bone186", + "pivot": [0, 0.1, 0], + "rotation": [0, -90, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone190", + "parent": "bone186", + "pivot": [0, 0.1, 0], + "rotation": [0, -135, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone191", + "parent": "bone186", + "pivot": [0, 0.1, 0], + "rotation": [0, -180, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone192", + "parent": "bone186", + "pivot": [0, 0.1, 0], + "rotation": [0, -225, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone193", + "parent": "bone186", + "pivot": [0, 0.1, 0], + "rotation": [0, -270, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone194", + "parent": "bone186", + "pivot": [0, 0.1, 0], + "rotation": [0, -315, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "PaoRed", + "pivot": [0, 0.5, 0] + }, + { + "name": "bone195", + "parent": "PaoRed", + "pivot": [0, 0, 0], + "cubes": [ + {"origin": [-32, 32, -32], "size": [64, 0, 64], "inflate": -30.85, "uv": [320, 71]} + ] + }, + { + "name": "bone196", + "parent": "bone195", + "pivot": [0, 0.2, 0] + }, + { + "name": "bone197", + "parent": "bone196", + "pivot": [0, 0.2, 0], + "rotation": [10, 0, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone198", + "parent": "bone196", + "pivot": [0, 0.2, 0], + "rotation": [10, -45, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone199", + "parent": "bone196", + "pivot": [0, 0.2, 0], + "rotation": [10, -90, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone200", + "parent": "bone196", + "pivot": [0, 0.2, 0], + "rotation": [10, -135, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone201", + "parent": "bone196", + "pivot": [0, 0.2, 0], + "rotation": [10, -180, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone202", + "parent": "bone196", + "pivot": [0, 0.2, 0], + "rotation": [10, -225, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone203", + "parent": "bone196", + "pivot": [0, 0.2, 0], + "rotation": [10, -270, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone204", + "parent": "bone196", + "pivot": [0, 0.2, 0], + "rotation": [10, -315, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone205", + "parent": "bone195", + "pivot": [0, 1, 0], + "rotation": [0, 0, -180] + }, + { + "name": "bone206", + "parent": "bone205", + "pivot": [0, 1, 0], + "rotation": [10, 0, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone207", + "parent": "bone205", + "pivot": [0, 1, 0], + "rotation": [10, -45, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone208", + "parent": "bone205", + "pivot": [0, 1, 0], + "rotation": [10, -90, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone209", + "parent": "bone205", + "pivot": [0, 1, 0], + "rotation": [10, -135, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone210", + "parent": "bone205", + "pivot": [0, 1, 0], + "rotation": [10, -180, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone211", + "parent": "bone205", + "pivot": [0, 1, 0], + "rotation": [10, -225, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone212", + "parent": "bone205", + "pivot": [0, 1, 0], + "rotation": [10, -270, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone213", + "parent": "bone205", + "pivot": [0, 1, 0], + "rotation": [10, -315, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone214", + "parent": "bone195", + "pivot": [0, 0.1, 0] + }, + { + "name": "bone215", + "parent": "bone214", + "pivot": [0, 0.1, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone216", + "parent": "bone214", + "pivot": [0, 0.1, 0], + "rotation": [0, -45, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone217", + "parent": "bone214", + "pivot": [0, 0.1, 0], + "rotation": [0, -90, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone218", + "parent": "bone214", + "pivot": [0, 0.1, 0], + "rotation": [0, -135, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone219", + "parent": "bone214", + "pivot": [0, 0.1, 0], + "rotation": [0, -180, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone220", + "parent": "bone214", + "pivot": [0, 0.1, 0], + "rotation": [0, -225, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone221", + "parent": "bone214", + "pivot": [0, 0.1, 0], + "rotation": [0, -270, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone222", + "parent": "bone214", + "pivot": [0, 0.1, 0], + "rotation": [0, -315, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone223", + "parent": "bone195", + "pivot": [0, 0.1, 0] + }, + { + "name": "bone224", + "parent": "bone223", + "pivot": [0, 0.1, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone225", + "parent": "bone223", + "pivot": [0, 0.1, 0], + "rotation": [0, -45, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone226", + "parent": "bone223", + "pivot": [0, 0.1, 0], + "rotation": [0, -90, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone227", + "parent": "bone223", + "pivot": [0, 0.1, 0], + "rotation": [0, -135, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone228", + "parent": "bone223", + "pivot": [0, 0.1, 0], + "rotation": [0, -180, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone229", + "parent": "bone223", + "pivot": [0, 0.1, 0], + "rotation": [0, -225, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone230", + "parent": "bone223", + "pivot": [0, 0.1, 0], + "rotation": [0, -270, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone231", + "parent": "bone223", + "pivot": [0, 0.1, 0], + "rotation": [0, -315, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "BingRed", + "pivot": [0, 0.5, 0] + }, + { + "name": "bone232", + "parent": "BingRed", + "pivot": [0, 0, 0], + "cubes": [ + {"origin": [-32, 32, -32], "size": [64, 0, 64], "inflate": -30.85, "uv": [-64, 142]} + ] + }, + { + "name": "bone233", + "parent": "bone232", + "pivot": [0, 0.2, 0] + }, + { + "name": "bone234", + "parent": "bone233", + "pivot": [0, 0.2, 0], + "rotation": [10, 0, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone235", + "parent": "bone233", + "pivot": [0, 0.2, 0], + "rotation": [10, -45, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone236", + "parent": "bone233", + "pivot": [0, 0.2, 0], + "rotation": [10, -90, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone237", + "parent": "bone233", + "pivot": [0, 0.2, 0], + "rotation": [10, -135, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone238", + "parent": "bone233", + "pivot": [0, 0.2, 0], + "rotation": [10, -180, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone239", + "parent": "bone233", + "pivot": [0, 0.2, 0], + "rotation": [10, -225, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone240", + "parent": "bone233", + "pivot": [0, 0.2, 0], + "rotation": [10, -270, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone241", + "parent": "bone233", + "pivot": [0, 0.2, 0], + "rotation": [10, -315, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone242", + "parent": "bone232", + "pivot": [0, 1, 0], + "rotation": [0, 0, -180] + }, + { + "name": "bone243", + "parent": "bone242", + "pivot": [0, 1, 0], + "rotation": [10, 0, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone244", + "parent": "bone242", + "pivot": [0, 1, 0], + "rotation": [10, -45, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone245", + "parent": "bone242", + "pivot": [0, 1, 0], + "rotation": [10, -90, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone246", + "parent": "bone242", + "pivot": [0, 1, 0], + "rotation": [10, -135, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone247", + "parent": "bone242", + "pivot": [0, 1, 0], + "rotation": [10, -180, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone248", + "parent": "bone242", + "pivot": [0, 1, 0], + "rotation": [10, -225, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone249", + "parent": "bone242", + "pivot": [0, 1, 0], + "rotation": [10, -270, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone250", + "parent": "bone242", + "pivot": [0, 1, 0], + "rotation": [10, -315, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone251", + "parent": "bone232", + "pivot": [0, 0.1, 0] + }, + { + "name": "bone252", + "parent": "bone251", + "pivot": [0, 0.1, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone253", + "parent": "bone251", + "pivot": [0, 0.1, 0], + "rotation": [0, -45, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone254", + "parent": "bone251", + "pivot": [0, 0.1, 0], + "rotation": [0, -90, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone255", + "parent": "bone251", + "pivot": [0, 0.1, 0], + "rotation": [0, -135, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone256", + "parent": "bone251", + "pivot": [0, 0.1, 0], + "rotation": [0, -180, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone257", + "parent": "bone251", + "pivot": [0, 0.1, 0], + "rotation": [0, -225, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone258", + "parent": "bone251", + "pivot": [0, 0.1, 0], + "rotation": [0, -270, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone259", + "parent": "bone251", + "pivot": [0, 0.1, 0], + "rotation": [0, -315, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone260", + "parent": "bone232", + "pivot": [0, 0.1, 0] + }, + { + "name": "bone261", + "parent": "bone260", + "pivot": [0, 0.1, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone262", + "parent": "bone260", + "pivot": [0, 0.1, 0], + "rotation": [0, -45, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone263", + "parent": "bone260", + "pivot": [0, 0.1, 0], + "rotation": [0, -90, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone264", + "parent": "bone260", + "pivot": [0, 0.1, 0], + "rotation": [0, -135, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone265", + "parent": "bone260", + "pivot": [0, 0.1, 0], + "rotation": [0, -180, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone266", + "parent": "bone260", + "pivot": [0, 0.1, 0], + "rotation": [0, -225, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone267", + "parent": "bone260", + "pivot": [0, 0.1, 0], + "rotation": [0, -270, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone268", + "parent": "bone260", + "pivot": [0, 0.1, 0], + "rotation": [0, -315, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "Selected", + "pivot": [0, -0.4, 0] + }, + { + "name": "bone38", + "parent": "Selected", + "pivot": [0, -0.2, 0] + }, + { + "name": "bone39", + "parent": "bone38", + "pivot": [0, -0.2, 0], + "rotation": [10, 0, 0], + "cubes": [ + {"origin": [-1, -0.2, 2.11421], "size": [2, 1, 1], "inflate": -0.35, "uv": [19, 14]} + ] + }, + { + "name": "bone40", + "parent": "bone38", + "pivot": [0, -0.2, 0], + "rotation": [10, -45, 0], + "cubes": [ + {"origin": [-1, -0.2, 2.11421], "size": [2, 1, 1], "inflate": -0.35, "uv": [19, 14]} + ] + }, + { + "name": "bone41", + "parent": "bone38", + "pivot": [0, -0.2, 0], + "rotation": [10, -90, 0], + "cubes": [ + {"origin": [-1, -0.2, 2.11421], "size": [2, 1, 1], "inflate": -0.35, "uv": [19, 14]} + ] + }, + { + "name": "bone42", + "parent": "bone38", + "pivot": [0, -0.2, 0], + "rotation": [10, -135, 0], + "cubes": [ + {"origin": [-1, -0.2, 2.11421], "size": [2, 1, 1], "inflate": -0.35, "uv": [19, 14]} + ] + }, + { + "name": "bone43", + "parent": "bone38", + "pivot": [0, -0.2, 0], + "rotation": [10, -180, 0], + "cubes": [ + {"origin": [-1, -0.2, 2.11421], "size": [2, 1, 1], "inflate": -0.35, "uv": [19, 14]} + ] + }, + { + "name": "bone44", + "parent": "bone38", + "pivot": [0, -0.2, 0], + "rotation": [10, -225, 0], + "cubes": [ + {"origin": [-1, -0.2, 2.11421], "size": [2, 1, 1], "inflate": -0.35, "uv": [19, 14]} + ] + }, + { + "name": "bone45", + "parent": "bone38", + "pivot": [0, -0.2, 0], + "rotation": [10, -270, 0], + "cubes": [ + {"origin": [-1, -0.2, 2.11421], "size": [2, 1, 1], "inflate": -0.35, "uv": [19, 14]} + ] + }, + { + "name": "bone46", + "parent": "bone38", + "pivot": [0, -0.2, 0], + "rotation": [10, -315, 0], + "cubes": [ + {"origin": [-1, -0.2, 2.11421], "size": [2, 1, 1], "inflate": -0.35, "uv": [19, 14]} + ] + }, + { + "name": "JiangBlack", + "pivot": [0, 0.5, 0] + }, + { + "name": "bone269", + "parent": "JiangBlack", + "pivot": [0, 0, 0], + "cubes": [ + {"origin": [-32, 32, -32], "size": [64, 0, 64], "inflate": -30.85, "uv": [-64, 237]} + ] + }, + { + "name": "bone270", + "parent": "bone269", + "pivot": [0, 0.2, 0] + }, + { + "name": "bone271", + "parent": "bone270", + "pivot": [0, 0.2, 0], + "rotation": [10, 0, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone272", + "parent": "bone270", + "pivot": [0, 0.2, 0], + "rotation": [10, -45, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone273", + "parent": "bone270", + "pivot": [0, 0.2, 0], + "rotation": [10, -90, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone274", + "parent": "bone270", + "pivot": [0, 0.2, 0], + "rotation": [10, -135, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone275", + "parent": "bone270", + "pivot": [0, 0.2, 0], + "rotation": [10, -180, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone276", + "parent": "bone270", + "pivot": [0, 0.2, 0], + "rotation": [10, -225, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone277", + "parent": "bone270", + "pivot": [0, 0.2, 0], + "rotation": [10, -270, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone278", + "parent": "bone270", + "pivot": [0, 0.2, 0], + "rotation": [10, -315, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone279", + "parent": "bone269", + "pivot": [0, 1, 0], + "rotation": [0, 0, -180] + }, + { + "name": "bone280", + "parent": "bone279", + "pivot": [0, 1, 0], + "rotation": [10, 0, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone281", + "parent": "bone279", + "pivot": [0, 1, 0], + "rotation": [10, -45, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone282", + "parent": "bone279", + "pivot": [0, 1, 0], + "rotation": [10, -90, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone283", + "parent": "bone279", + "pivot": [0, 1, 0], + "rotation": [10, -135, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone284", + "parent": "bone279", + "pivot": [0, 1, 0], + "rotation": [10, -180, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone285", + "parent": "bone279", + "pivot": [0, 1, 0], + "rotation": [10, -225, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone286", + "parent": "bone279", + "pivot": [0, 1, 0], + "rotation": [10, -270, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone287", + "parent": "bone279", + "pivot": [0, 1, 0], + "rotation": [10, -315, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone288", + "parent": "bone269", + "pivot": [0, 0.1, 0] + }, + { + "name": "bone289", + "parent": "bone288", + "pivot": [0, 0.1, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone290", + "parent": "bone288", + "pivot": [0, 0.1, 0], + "rotation": [0, -45, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone291", + "parent": "bone288", + "pivot": [0, 0.1, 0], + "rotation": [0, -90, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone292", + "parent": "bone288", + "pivot": [0, 0.1, 0], + "rotation": [0, -135, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone293", + "parent": "bone288", + "pivot": [0, 0.1, 0], + "rotation": [0, -180, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone294", + "parent": "bone288", + "pivot": [0, 0.1, 0], + "rotation": [0, -225, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone295", + "parent": "bone288", + "pivot": [0, 0.1, 0], + "rotation": [0, -270, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone296", + "parent": "bone288", + "pivot": [0, 0.1, 0], + "rotation": [0, -315, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone297", + "parent": "bone269", + "pivot": [0, 0.1, 0] + }, + { + "name": "bone298", + "parent": "bone297", + "pivot": [0, 0.1, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone299", + "parent": "bone297", + "pivot": [0, 0.1, 0], + "rotation": [0, -45, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone300", + "parent": "bone297", + "pivot": [0, 0.1, 0], + "rotation": [0, -90, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone301", + "parent": "bone297", + "pivot": [0, 0.1, 0], + "rotation": [0, -135, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone302", + "parent": "bone297", + "pivot": [0, 0.1, 0], + "rotation": [0, -180, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone303", + "parent": "bone297", + "pivot": [0, 0.1, 0], + "rotation": [0, -225, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone304", + "parent": "bone297", + "pivot": [0, 0.1, 0], + "rotation": [0, -270, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone305", + "parent": "bone297", + "pivot": [0, 0.1, 0], + "rotation": [0, -315, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "ShiBlack", + "pivot": [0, 0.5, 0] + }, + { + "name": "bone306", + "parent": "ShiBlack", + "pivot": [0, 0, 0], + "cubes": [ + {"origin": [-32, 32, -32], "size": [64, 0, 64], "inflate": -30.85, "uv": [-64, 309]} + ] + }, + { + "name": "bone307", + "parent": "bone306", + "pivot": [0, 0.2, 0] + }, + { + "name": "bone308", + "parent": "bone307", + "pivot": [0, 0.2, 0], + "rotation": [10, 0, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone309", + "parent": "bone307", + "pivot": [0, 0.2, 0], + "rotation": [10, -45, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone310", + "parent": "bone307", + "pivot": [0, 0.2, 0], + "rotation": [10, -90, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone311", + "parent": "bone307", + "pivot": [0, 0.2, 0], + "rotation": [10, -135, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone312", + "parent": "bone307", + "pivot": [0, 0.2, 0], + "rotation": [10, -180, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone313", + "parent": "bone307", + "pivot": [0, 0.2, 0], + "rotation": [10, -225, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone314", + "parent": "bone307", + "pivot": [0, 0.2, 0], + "rotation": [10, -270, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone315", + "parent": "bone307", + "pivot": [0, 0.2, 0], + "rotation": [10, -315, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone316", + "parent": "bone306", + "pivot": [0, 1, 0], + "rotation": [0, 0, -180] + }, + { + "name": "bone317", + "parent": "bone316", + "pivot": [0, 1, 0], + "rotation": [10, 0, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone318", + "parent": "bone316", + "pivot": [0, 1, 0], + "rotation": [10, -45, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone319", + "parent": "bone316", + "pivot": [0, 1, 0], + "rotation": [10, -90, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone320", + "parent": "bone316", + "pivot": [0, 1, 0], + "rotation": [10, -135, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone321", + "parent": "bone316", + "pivot": [0, 1, 0], + "rotation": [10, -180, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone322", + "parent": "bone316", + "pivot": [0, 1, 0], + "rotation": [10, -225, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone323", + "parent": "bone316", + "pivot": [0, 1, 0], + "rotation": [10, -270, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone324", + "parent": "bone316", + "pivot": [0, 1, 0], + "rotation": [10, -315, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone325", + "parent": "bone306", + "pivot": [0, 0.1, 0] + }, + { + "name": "bone326", + "parent": "bone325", + "pivot": [0, 0.1, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone327", + "parent": "bone325", + "pivot": [0, 0.1, 0], + "rotation": [0, -45, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone328", + "parent": "bone325", + "pivot": [0, 0.1, 0], + "rotation": [0, -90, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone329", + "parent": "bone325", + "pivot": [0, 0.1, 0], + "rotation": [0, -135, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone330", + "parent": "bone325", + "pivot": [0, 0.1, 0], + "rotation": [0, -180, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone331", + "parent": "bone325", + "pivot": [0, 0.1, 0], + "rotation": [0, -225, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone332", + "parent": "bone325", + "pivot": [0, 0.1, 0], + "rotation": [0, -270, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone333", + "parent": "bone325", + "pivot": [0, 0.1, 0], + "rotation": [0, -315, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone334", + "parent": "bone306", + "pivot": [0, 0.1, 0] + }, + { + "name": "bone335", + "parent": "bone334", + "pivot": [0, 0.1, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone336", + "parent": "bone334", + "pivot": [0, 0.1, 0], + "rotation": [0, -45, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone337", + "parent": "bone334", + "pivot": [0, 0.1, 0], + "rotation": [0, -90, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone338", + "parent": "bone334", + "pivot": [0, 0.1, 0], + "rotation": [0, -135, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone339", + "parent": "bone334", + "pivot": [0, 0.1, 0], + "rotation": [0, -180, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone340", + "parent": "bone334", + "pivot": [0, 0.1, 0], + "rotation": [0, -225, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone341", + "parent": "bone334", + "pivot": [0, 0.1, 0], + "rotation": [0, -270, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone342", + "parent": "bone334", + "pivot": [0, 0.1, 0], + "rotation": [0, -315, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "XiangBlack", + "pivot": [0, 0.5, 0] + }, + { + "name": "bone343", + "parent": "XiangBlack", + "pivot": [0, 0, 0], + "cubes": [ + {"origin": [-32, 32, -32], "size": [64, 0, 64], "inflate": -30.85, "uv": [-64, 379]} + ] + }, + { + "name": "bone344", + "parent": "bone343", + "pivot": [0, 0.2, 0] + }, + { + "name": "bone345", + "parent": "bone344", + "pivot": [0, 0.2, 0], + "rotation": [10, 0, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone346", + "parent": "bone344", + "pivot": [0, 0.2, 0], + "rotation": [10, -45, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone347", + "parent": "bone344", + "pivot": [0, 0.2, 0], + "rotation": [10, -90, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone348", + "parent": "bone344", + "pivot": [0, 0.2, 0], + "rotation": [10, -135, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone349", + "parent": "bone344", + "pivot": [0, 0.2, 0], + "rotation": [10, -180, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone350", + "parent": "bone344", + "pivot": [0, 0.2, 0], + "rotation": [10, -225, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone351", + "parent": "bone344", + "pivot": [0, 0.2, 0], + "rotation": [10, -270, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone352", + "parent": "bone344", + "pivot": [0, 0.2, 0], + "rotation": [10, -315, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone353", + "parent": "bone343", + "pivot": [0, 1, 0], + "rotation": [0, 0, -180] + }, + { + "name": "bone354", + "parent": "bone353", + "pivot": [0, 1, 0], + "rotation": [10, 0, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone355", + "parent": "bone353", + "pivot": [0, 1, 0], + "rotation": [10, -45, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone356", + "parent": "bone353", + "pivot": [0, 1, 0], + "rotation": [10, -90, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone357", + "parent": "bone353", + "pivot": [0, 1, 0], + "rotation": [10, -135, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone358", + "parent": "bone353", + "pivot": [0, 1, 0], + "rotation": [10, -180, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone359", + "parent": "bone353", + "pivot": [0, 1, 0], + "rotation": [10, -225, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone360", + "parent": "bone353", + "pivot": [0, 1, 0], + "rotation": [10, -270, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone361", + "parent": "bone353", + "pivot": [0, 1, 0], + "rotation": [10, -315, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone362", + "parent": "bone343", + "pivot": [0, 0.1, 0] + }, + { + "name": "bone363", + "parent": "bone362", + "pivot": [0, 0.1, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone364", + "parent": "bone362", + "pivot": [0, 0.1, 0], + "rotation": [0, -45, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone365", + "parent": "bone362", + "pivot": [0, 0.1, 0], + "rotation": [0, -90, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone366", + "parent": "bone362", + "pivot": [0, 0.1, 0], + "rotation": [0, -135, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone367", + "parent": "bone362", + "pivot": [0, 0.1, 0], + "rotation": [0, -180, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone368", + "parent": "bone362", + "pivot": [0, 0.1, 0], + "rotation": [0, -225, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone369", + "parent": "bone362", + "pivot": [0, 0.1, 0], + "rotation": [0, -270, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone370", + "parent": "bone362", + "pivot": [0, 0.1, 0], + "rotation": [0, -315, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone371", + "parent": "bone343", + "pivot": [0, 0.1, 0] + }, + { + "name": "bone372", + "parent": "bone371", + "pivot": [0, 0.1, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone373", + "parent": "bone371", + "pivot": [0, 0.1, 0], + "rotation": [0, -45, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone374", + "parent": "bone371", + "pivot": [0, 0.1, 0], + "rotation": [0, -90, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone375", + "parent": "bone371", + "pivot": [0, 0.1, 0], + "rotation": [0, -135, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone376", + "parent": "bone371", + "pivot": [0, 0.1, 0], + "rotation": [0, -180, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone377", + "parent": "bone371", + "pivot": [0, 0.1, 0], + "rotation": [0, -225, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone378", + "parent": "bone371", + "pivot": [0, 0.1, 0], + "rotation": [0, -270, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone379", + "parent": "bone371", + "pivot": [0, 0.1, 0], + "rotation": [0, -315, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "MaBlack", + "pivot": [0, 0.5, 0] + }, + { + "name": "bone380", + "parent": "MaBlack", + "pivot": [0, 0, 0], + "cubes": [ + {"origin": [-32, 32, -32], "size": [64, 0, 64], "inflate": -30.85, "uv": [312, 236]} + ] + }, + { + "name": "bone381", + "parent": "bone380", + "pivot": [0, 0.2, 0] + }, + { + "name": "bone382", + "parent": "bone381", + "pivot": [0, 0.2, 0], + "rotation": [10, 0, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone383", + "parent": "bone381", + "pivot": [0, 0.2, 0], + "rotation": [10, -45, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone384", + "parent": "bone381", + "pivot": [0, 0.2, 0], + "rotation": [10, -90, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone385", + "parent": "bone381", + "pivot": [0, 0.2, 0], + "rotation": [10, -135, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone386", + "parent": "bone381", + "pivot": [0, 0.2, 0], + "rotation": [10, -180, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone387", + "parent": "bone381", + "pivot": [0, 0.2, 0], + "rotation": [10, -225, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone388", + "parent": "bone381", + "pivot": [0, 0.2, 0], + "rotation": [10, -270, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone389", + "parent": "bone381", + "pivot": [0, 0.2, 0], + "rotation": [10, -315, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone390", + "parent": "bone380", + "pivot": [0, 1, 0], + "rotation": [0, 0, -180] + }, + { + "name": "bone391", + "parent": "bone390", + "pivot": [0, 1, 0], + "rotation": [10, 0, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone392", + "parent": "bone390", + "pivot": [0, 1, 0], + "rotation": [10, -45, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone393", + "parent": "bone390", + "pivot": [0, 1, 0], + "rotation": [10, -90, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone394", + "parent": "bone390", + "pivot": [0, 1, 0], + "rotation": [10, -135, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone395", + "parent": "bone390", + "pivot": [0, 1, 0], + "rotation": [10, -180, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone396", + "parent": "bone390", + "pivot": [0, 1, 0], + "rotation": [10, -225, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone397", + "parent": "bone390", + "pivot": [0, 1, 0], + "rotation": [10, -270, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone398", + "parent": "bone390", + "pivot": [0, 1, 0], + "rotation": [10, -315, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone399", + "parent": "bone380", + "pivot": [0, 0.1, 0] + }, + { + "name": "bone400", + "parent": "bone399", + "pivot": [0, 0.1, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone401", + "parent": "bone399", + "pivot": [0, 0.1, 0], + "rotation": [0, -45, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone402", + "parent": "bone399", + "pivot": [0, 0.1, 0], + "rotation": [0, -90, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone403", + "parent": "bone399", + "pivot": [0, 0.1, 0], + "rotation": [0, -135, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone404", + "parent": "bone399", + "pivot": [0, 0.1, 0], + "rotation": [0, -180, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone405", + "parent": "bone399", + "pivot": [0, 0.1, 0], + "rotation": [0, -225, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone406", + "parent": "bone399", + "pivot": [0, 0.1, 0], + "rotation": [0, -270, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone407", + "parent": "bone399", + "pivot": [0, 0.1, 0], + "rotation": [0, -315, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone408", + "parent": "bone380", + "pivot": [0, 0.1, 0] + }, + { + "name": "bone409", + "parent": "bone408", + "pivot": [0, 0.1, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone410", + "parent": "bone408", + "pivot": [0, 0.1, 0], + "rotation": [0, -45, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone411", + "parent": "bone408", + "pivot": [0, 0.1, 0], + "rotation": [0, -90, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone412", + "parent": "bone408", + "pivot": [0, 0.1, 0], + "rotation": [0, -135, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone413", + "parent": "bone408", + "pivot": [0, 0.1, 0], + "rotation": [0, -180, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone414", + "parent": "bone408", + "pivot": [0, 0.1, 0], + "rotation": [0, -225, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone415", + "parent": "bone408", + "pivot": [0, 0.1, 0], + "rotation": [0, -270, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone416", + "parent": "bone408", + "pivot": [0, 0.1, 0], + "rotation": [0, -315, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "JuBlack", + "pivot": [0, 0.5, 0] + }, + { + "name": "bone417", + "parent": "JuBlack", + "pivot": [0, 0, 0], + "cubes": [ + {"origin": [-32, 32, -32], "size": [64, 0, 64], "inflate": -30.85, "uv": [100, 237]} + ] + }, + { + "name": "bone418", + "parent": "bone417", + "pivot": [0, 0.2, 0] + }, + { + "name": "bone419", + "parent": "bone418", + "pivot": [0, 0.2, 0], + "rotation": [10, 0, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone420", + "parent": "bone418", + "pivot": [0, 0.2, 0], + "rotation": [10, -45, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone421", + "parent": "bone418", + "pivot": [0, 0.2, 0], + "rotation": [10, -90, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone422", + "parent": "bone418", + "pivot": [0, 0.2, 0], + "rotation": [10, -135, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone423", + "parent": "bone418", + "pivot": [0, 0.2, 0], + "rotation": [10, -180, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone424", + "parent": "bone418", + "pivot": [0, 0.2, 0], + "rotation": [10, -225, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone425", + "parent": "bone418", + "pivot": [0, 0.2, 0], + "rotation": [10, -270, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone426", + "parent": "bone418", + "pivot": [0, 0.2, 0], + "rotation": [10, -315, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone427", + "parent": "bone417", + "pivot": [0, 1, 0], + "rotation": [0, 0, -180] + }, + { + "name": "bone428", + "parent": "bone427", + "pivot": [0, 1, 0], + "rotation": [10, 0, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone429", + "parent": "bone427", + "pivot": [0, 1, 0], + "rotation": [10, -45, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone430", + "parent": "bone427", + "pivot": [0, 1, 0], + "rotation": [10, -90, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone431", + "parent": "bone427", + "pivot": [0, 1, 0], + "rotation": [10, -135, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone432", + "parent": "bone427", + "pivot": [0, 1, 0], + "rotation": [10, -180, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone433", + "parent": "bone427", + "pivot": [0, 1, 0], + "rotation": [10, -225, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone434", + "parent": "bone427", + "pivot": [0, 1, 0], + "rotation": [10, -270, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone435", + "parent": "bone427", + "pivot": [0, 1, 0], + "rotation": [10, -315, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone436", + "parent": "bone417", + "pivot": [0, 0.1, 0] + }, + { + "name": "bone437", + "parent": "bone436", + "pivot": [0, 0.1, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone438", + "parent": "bone436", + "pivot": [0, 0.1, 0], + "rotation": [0, -45, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone439", + "parent": "bone436", + "pivot": [0, 0.1, 0], + "rotation": [0, -90, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone440", + "parent": "bone436", + "pivot": [0, 0.1, 0], + "rotation": [0, -135, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone441", + "parent": "bone436", + "pivot": [0, 0.1, 0], + "rotation": [0, -180, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone442", + "parent": "bone436", + "pivot": [0, 0.1, 0], + "rotation": [0, -225, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone443", + "parent": "bone436", + "pivot": [0, 0.1, 0], + "rotation": [0, -270, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone444", + "parent": "bone436", + "pivot": [0, 0.1, 0], + "rotation": [0, -315, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone445", + "parent": "bone417", + "pivot": [0, 0.1, 0] + }, + { + "name": "bone446", + "parent": "bone445", + "pivot": [0, 0.1, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone447", + "parent": "bone445", + "pivot": [0, 0.1, 0], + "rotation": [0, -45, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone448", + "parent": "bone445", + "pivot": [0, 0.1, 0], + "rotation": [0, -90, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone449", + "parent": "bone445", + "pivot": [0, 0.1, 0], + "rotation": [0, -135, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone450", + "parent": "bone445", + "pivot": [0, 0.1, 0], + "rotation": [0, -180, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone451", + "parent": "bone445", + "pivot": [0, 0.1, 0], + "rotation": [0, -225, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone452", + "parent": "bone445", + "pivot": [0, 0.1, 0], + "rotation": [0, -270, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone453", + "parent": "bone445", + "pivot": [0, 0.1, 0], + "rotation": [0, -315, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "PaoBlack", + "pivot": [0, 0.5, 0] + }, + { + "name": "bone454", + "parent": "PaoBlack", + "pivot": [0, 0, 0], + "cubes": [ + {"origin": [-32, 32, -32], "size": [64, 0, 64], "inflate": -30.85, "uv": [100, 305]} + ] + }, + { + "name": "bone455", + "parent": "bone454", + "pivot": [0, 0.2, 0] + }, + { + "name": "bone456", + "parent": "bone455", + "pivot": [0, 0.2, 0], + "rotation": [10, 0, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone457", + "parent": "bone455", + "pivot": [0, 0.2, 0], + "rotation": [10, -45, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone458", + "parent": "bone455", + "pivot": [0, 0.2, 0], + "rotation": [10, -90, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone459", + "parent": "bone455", + "pivot": [0, 0.2, 0], + "rotation": [10, -135, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone460", + "parent": "bone455", + "pivot": [0, 0.2, 0], + "rotation": [10, -180, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone461", + "parent": "bone455", + "pivot": [0, 0.2, 0], + "rotation": [10, -225, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone462", + "parent": "bone455", + "pivot": [0, 0.2, 0], + "rotation": [10, -270, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone463", + "parent": "bone455", + "pivot": [0, 0.2, 0], + "rotation": [10, -315, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone464", + "parent": "bone454", + "pivot": [0, 1, 0], + "rotation": [0, 0, -180] + }, + { + "name": "bone465", + "parent": "bone464", + "pivot": [0, 1, 0], + "rotation": [10, 0, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone466", + "parent": "bone464", + "pivot": [0, 1, 0], + "rotation": [10, -45, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone467", + "parent": "bone464", + "pivot": [0, 1, 0], + "rotation": [10, -90, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone468", + "parent": "bone464", + "pivot": [0, 1, 0], + "rotation": [10, -135, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone469", + "parent": "bone464", + "pivot": [0, 1, 0], + "rotation": [10, -180, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone470", + "parent": "bone464", + "pivot": [0, 1, 0], + "rotation": [10, -225, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone471", + "parent": "bone464", + "pivot": [0, 1, 0], + "rotation": [10, -270, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone472", + "parent": "bone464", + "pivot": [0, 1, 0], + "rotation": [10, -315, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone473", + "parent": "bone454", + "pivot": [0, 0.1, 0] + }, + { + "name": "bone474", + "parent": "bone473", + "pivot": [0, 0.1, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone475", + "parent": "bone473", + "pivot": [0, 0.1, 0], + "rotation": [0, -45, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone476", + "parent": "bone473", + "pivot": [0, 0.1, 0], + "rotation": [0, -90, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone477", + "parent": "bone473", + "pivot": [0, 0.1, 0], + "rotation": [0, -135, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone478", + "parent": "bone473", + "pivot": [0, 0.1, 0], + "rotation": [0, -180, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone479", + "parent": "bone473", + "pivot": [0, 0.1, 0], + "rotation": [0, -225, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone480", + "parent": "bone473", + "pivot": [0, 0.1, 0], + "rotation": [0, -270, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone481", + "parent": "bone473", + "pivot": [0, 0.1, 0], + "rotation": [0, -315, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone482", + "parent": "bone454", + "pivot": [0, 0.1, 0] + }, + { + "name": "bone483", + "parent": "bone482", + "pivot": [0, 0.1, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone484", + "parent": "bone482", + "pivot": [0, 0.1, 0], + "rotation": [0, -45, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone485", + "parent": "bone482", + "pivot": [0, 0.1, 0], + "rotation": [0, -90, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone486", + "parent": "bone482", + "pivot": [0, 0.1, 0], + "rotation": [0, -135, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone487", + "parent": "bone482", + "pivot": [0, 0.1, 0], + "rotation": [0, -180, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone488", + "parent": "bone482", + "pivot": [0, 0.1, 0], + "rotation": [0, -225, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone489", + "parent": "bone482", + "pivot": [0, 0.1, 0], + "rotation": [0, -270, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone490", + "parent": "bone482", + "pivot": [0, 0.1, 0], + "rotation": [0, -315, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "ZuBlack", + "pivot": [0, 0.5, 0] + }, + { + "name": "bone491", + "parent": "ZuBlack", + "pivot": [0, 0, 0], + "cubes": [ + {"origin": [-32, 32, -32], "size": [64, 0, 64], "inflate": -30.85, "uv": [100, 374]} + ] + }, + { + "name": "bone492", + "parent": "bone491", + "pivot": [0, 0.2, 0] + }, + { + "name": "bone493", + "parent": "bone492", + "pivot": [0, 0.2, 0], + "rotation": [10, 0, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone494", + "parent": "bone492", + "pivot": [0, 0.2, 0], + "rotation": [10, -45, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone495", + "parent": "bone492", + "pivot": [0, 0.2, 0], + "rotation": [10, -90, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone496", + "parent": "bone492", + "pivot": [0, 0.2, 0], + "rotation": [10, -135, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone497", + "parent": "bone492", + "pivot": [0, 0.2, 0], + "rotation": [10, -180, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone498", + "parent": "bone492", + "pivot": [0, 0.2, 0], + "rotation": [10, -225, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone499", + "parent": "bone492", + "pivot": [0, 0.2, 0], + "rotation": [10, -270, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone500", + "parent": "bone492", + "pivot": [0, 0.2, 0], + "rotation": [10, -315, 0], + "cubes": [ + {"origin": [-1, 0.2, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 0]} + ] + }, + { + "name": "bone501", + "parent": "bone491", + "pivot": [0, 1, 0], + "rotation": [0, 0, -180] + }, + { + "name": "bone502", + "parent": "bone501", + "pivot": [0, 1, 0], + "rotation": [10, 0, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone503", + "parent": "bone501", + "pivot": [0, 1, 0], + "rotation": [10, -45, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone504", + "parent": "bone501", + "pivot": [0, 1, 0], + "rotation": [10, -90, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone505", + "parent": "bone501", + "pivot": [0, 1, 0], + "rotation": [10, -135, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone506", + "parent": "bone501", + "pivot": [0, 1, 0], + "rotation": [10, -180, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone507", + "parent": "bone501", + "pivot": [0, 1, 0], + "rotation": [10, -225, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone508", + "parent": "bone501", + "pivot": [0, 1, 0], + "rotation": [10, -270, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone509", + "parent": "bone501", + "pivot": [0, 1, 0], + "rotation": [10, -315, 0], + "cubes": [ + {"origin": [-1, 1, 1.11421], "size": [2, 1, 1], "inflate": -0.3, "uv": [0, 19]} + ] + }, + { + "name": "bone510", + "parent": "bone491", + "pivot": [0, 0.1, 0] + }, + { + "name": "bone511", + "parent": "bone510", + "pivot": [0, 0.1, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone512", + "parent": "bone510", + "pivot": [0, 0.1, 0], + "rotation": [0, -45, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone513", + "parent": "bone510", + "pivot": [0, 0.1, 0], + "rotation": [0, -90, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone514", + "parent": "bone510", + "pivot": [0, 0.1, 0], + "rotation": [0, -135, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone515", + "parent": "bone510", + "pivot": [0, 0.1, 0], + "rotation": [0, -180, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone516", + "parent": "bone510", + "pivot": [0, 0.1, 0], + "rotation": [0, -225, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone517", + "parent": "bone510", + "pivot": [0, 0.1, 0], + "rotation": [0, -270, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone518", + "parent": "bone510", + "pivot": [0, 0.1, 0], + "rotation": [0, -315, 0], + "cubes": [ + {"origin": [-1, 0.1, 1.01421], "size": [2, 1, 1], "inflate": -0.275, "uv": [0, 10]} + ] + }, + { + "name": "bone519", + "parent": "bone491", + "pivot": [0, 0.1, 0] + }, + { + "name": "bone520", + "parent": "bone519", + "pivot": [0, 0.1, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone521", + "parent": "bone519", + "pivot": [0, 0.1, 0], + "rotation": [0, -45, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone522", + "parent": "bone519", + "pivot": [0, 0.1, 0], + "rotation": [0, -90, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone523", + "parent": "bone519", + "pivot": [0, 0.1, 0], + "rotation": [0, -135, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone524", + "parent": "bone519", + "pivot": [0, 0.1, 0], + "rotation": [0, -180, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone525", + "parent": "bone519", + "pivot": [0, 0.1, 0], + "rotation": [0, -225, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone526", + "parent": "bone519", + "pivot": [0, 0.1, 0], + "rotation": [0, -270, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + }, + { + "name": "bone527", + "parent": "bone519", + "pivot": [0, 0.1, 0], + "rotation": [0, -315, 0], + "cubes": [ + {"origin": [-1, -0.4, -0.98579], "size": [2, 2, 3], "inflate": -0.475, "uv": [16, 0]} + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/touhou_little_maid/models/item/all_netherite_equipment.json b/src/main/resources/assets/touhou_little_maid/models/item/all_netherite_equipment.json new file mode 100644 index 000000000..83097141c --- /dev/null +++ b/src/main/resources/assets/touhou_little_maid/models/item/all_netherite_equipment.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "touhou_little_maid:item/all_netherite_equipment" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/touhou_little_maid/models/item/cchess.json b/src/main/resources/assets/touhou_little_maid/models/item/cchess.json new file mode 100644 index 000000000..ad88c447d --- /dev/null +++ b/src/main/resources/assets/touhou_little_maid/models/item/cchess.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "touhou_little_maid:item/cchess" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/touhou_little_maid/models/item/change_chair_model.json b/src/main/resources/assets/touhou_little_maid/models/item/change_chair_model.json new file mode 100644 index 000000000..9042d47a1 --- /dev/null +++ b/src/main/resources/assets/touhou_little_maid/models/item/change_chair_model.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "touhou_little_maid:item/change_chair_model" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/touhou_little_maid/models/item/change_maid_model.json b/src/main/resources/assets/touhou_little_maid/models/item/change_maid_model.json new file mode 100644 index 000000000..8e1e4c4a0 --- /dev/null +++ b/src/main/resources/assets/touhou_little_maid/models/item/change_maid_model.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "touhou_little_maid:item/change_maid_model" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/touhou_little_maid/models/item/kill_dragon.json b/src/main/resources/assets/touhou_little_maid/models/item/kill_dragon.json new file mode 100644 index 000000000..814a3ab3c --- /dev/null +++ b/src/main/resources/assets/touhou_little_maid/models/item/kill_dragon.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "touhou_little_maid:item/kill_dragon" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/touhou_little_maid/models/item/kill_slime_300.json b/src/main/resources/assets/touhou_little_maid/models/item/kill_slime_300.json new file mode 100644 index 000000000..b64866be5 --- /dev/null +++ b/src/main/resources/assets/touhou_little_maid/models/item/kill_slime_300.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "touhou_little_maid:item/kill_slime_300" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/touhou_little_maid/models/item/kill_wither.json b/src/main/resources/assets/touhou_little_maid/models/item/kill_wither.json new file mode 100644 index 000000000..26902ff8f --- /dev/null +++ b/src/main/resources/assets/touhou_little_maid/models/item/kill_wither.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "touhou_little_maid:item/kill_wither" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/touhou_little_maid/models/item/maid_100_healthy.json b/src/main/resources/assets/touhou_little_maid/models/item/maid_100_healthy.json new file mode 100644 index 000000000..a2a5c44a5 --- /dev/null +++ b/src/main/resources/assets/touhou_little_maid/models/item/maid_100_healthy.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "touhou_little_maid:item/maid_100_healthy" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/touhou_little_maid/models/item/wchess.json b/src/main/resources/assets/touhou_little_maid/models/item/wchess.json new file mode 100644 index 000000000..00cc05772 --- /dev/null +++ b/src/main/resources/assets/touhou_little_maid/models/item/wchess.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "touhou_little_maid:item/wchess" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/touhou_little_maid/textures/advancements/backgrounds/stone.png b/src/main/resources/assets/touhou_little_maid/textures/advancements/backgrounds/stone.png new file mode 100644 index 0000000000000000000000000000000000000000..3ae59d49137dfb9d1f4e56cec81073635a6e3d48 GIT binary patch literal 427 zcmV;c0aX5pP)#mu6K1aG}C28Fw=S zz&JzC!PUq|ku5g6pm6k2<{3o+fQ0n}v(iNeH45gZjd$tR7HtsjA+7E|?)|()xqcWy zH$R+X*E&y-a77tOtTEHcHl=|L?#JIKtm82V4#cC)P_1LDtXQg=WQ5fC0hxPU6;J7J zLI?R(5RqwsEaOo$RnrCFA^=K13BKS8Ky7D860+Fh%=8LM@#Z_(O~+(i)A!To4*)ix z-nS2t4B*BdaVXc^2yc%)^m~$96ps`7ZS~7rBeuc~stSA=72jDwrYkfUR8y#G={Q?xi VHxj)7v4j8s002ovPDHLkV1k$Wyp{j} literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/touhou_little_maid/textures/entity/cchess.png b/src/main/resources/assets/touhou_little_maid/textures/entity/cchess.png new file mode 100644 index 0000000000000000000000000000000000000000..a3eb5f2cdf36d59a7c72d28e27702564da946c39 GIT binary patch literal 66708 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/touhou_little_maid/textures/entity/wchess.png b/src/main/resources/assets/touhou_little_maid/textures/entity/wchess.png new file mode 100644 index 0000000000000000000000000000000000000000..e69e9a06b7a37665524c5465a41463637e45668d GIT binary patch literal 680 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/touhou_little_maid/textures/item/cchess.png b/src/main/resources/assets/touhou_little_maid/textures/item/cchess.png new file mode 100644 index 0000000000000000000000000000000000000000..8d7b72494dd16fb5a587913ca28d1f543bfa963f GIT binary patch literal 278 zcmV+x0qOpUP)* zpcRl2;r)+}(bZrDFvah#?D_xh#1b&Rv!devyB#fr4MNrk(u9sdh6I?(VmAb)8C}yt zbKC!`6STqX<9#vzrzM->F#u>YvIb-}+!a7I7_NY6hAEn?r3%M)CMTd8u&*D}6(9~a zr^5|Fvb`!$8@B;4C&M&enH&S>gV>-jY6#W+-xQ{g-2i0gWAi)AcC29l3Sndo$cBK^ z11{T<4FSb7vOzG7Ae&*DF>FUR03-h#|8zUTR!b5AVxFQwygM+EOb62@k$?-q-rLB0Y}j6Cn`2E(mE_IvL$h`M1EM3cOQ zs59otbnQyjhUKYr*|pmp*Xxd=0X)!wPN-0+TL_ZLS6}af2h4P*n9;Mvnw=8gksxgy zKq8s5LUg;`pH4KNFKx0X2#Nnc0h~^k5QN}91Q0}Kx-c@QAHp4G&JaKl?Eo{~4u`Ad z1dEL{BOb=%nL+#@<(t(m+AIk|v5d;!nkDTc7{R)q=mB6WRDNIHdx!u4002ovPDHLk FV1j!UhCToQ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/touhou_little_maid/textures/item/kill_dragon.png b/src/main/resources/assets/touhou_little_maid/textures/item/kill_dragon.png new file mode 100644 index 0000000000000000000000000000000000000000..6ba161fe860298683e318e92709126b0eddc29f1 GIT binary patch literal 291 zcmV+;0o?wHP)K%8;v?T1Fi`uv0;3QSbO6i6 zx;P)UhVgLjCW)qCR7ASVL_Hcz-JWE3i5iiBUbk;(HQNrFBzXkR?@w^+Je|?6)g&3f z1t}oxtbkgzVKo;T1t5fG8A15O$$-$fnasYs1Bu!wBW7tlXYv*N5blDmOeT$&iY6d{ p-* zpe5i`)cp^_FgCh8P5{$b`S|{SouW1{`@e+++%UWVS+QNjp8skJ31Bu+nn3_;K%+TW zgJ0ph|2p;%7r^Au)uRBg=KD!-8<7nF;rna+@w)`32xQ3r_nROz5QD^S&DQ_FAxRCl z0myzofAcS`g8*}q7+&1 z|8b}yAiyx-IK+i8gHR0sIUl3|iecV>J0BztQiHA;t08X+;ogAT4irN+99=&cfFzJH l2*3W`Ic4wA3_Az%oJK(u>Z%ga#~q+4{bFcRsl& z{<%U~wz5a$dgeBAxh5}1n5%1RW<4oInxEhbN~jX;LUc|0hX(E(g6c?0N$6k zj_80w4!{gFc~w;x+UxnEtIjhW00@A*y1J83k=_|V*RBBjiR>qH$ri#Tp9xs*_X4!I g(4NcsY1WVH1MTp59b4UI#sB~S07*qoM6N<$f`XHIg8%>k literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/touhou_little_maid/textures/item/maid_100_healthy.png b/src/main/resources/assets/touhou_little_maid/textures/item/maid_100_healthy.png new file mode 100644 index 0000000000000000000000000000000000000000..a9fe205524be973ed8e24cc9cb7027ff58f313ae GIT binary patch literal 311 zcmV-70m%M|P)bWcm{jDfSr}0HLjeY + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + {description} + Copyright (C) {year} {fullname} + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + {signature of Ty Coon}, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/src/main/resources/licenses/xqwlight b/src/main/resources/licenses/xqwlight new file mode 100644 index 000000000..d7f105139 --- /dev/null +++ b/src/main/resources/licenses/xqwlight @@ -0,0 +1,339 @@ +GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + {description} + Copyright (C) {year} {fullname} + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + {signature of Ty Coon}, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/src/main/resources/touhou_little_maid.mixins.json b/src/main/resources/touhou_little_maid.mixins.json index ba17d35af..a621f2eb5 100644 --- a/src/main/resources/touhou_little_maid.mixins.json +++ b/src/main/resources/touhou_little_maid.mixins.json @@ -9,7 +9,7 @@ ], "client": [ "client.HumanoidModelMixin", "client.ItemPropertiesMixin", "client.LanguageMixin", - "client.LivingEntityRendererMixin", "client.RenderSystemMixin" + "client.LivingEntityRendererMixin" ], "injectors": { "defaultRequire": 1