From 9fa75e11c2fb0f5d050c0910f4695238185f3872 Mon Sep 17 00:00:00 2001 From: Majrusz Date: Thu, 8 Jun 2023 12:49:07 +0200 Subject: [PATCH] Merged 1.2.0 release --- build.gradle | 25 +++-- gradle.properties | 13 ++- ...0.jar => majrusz-library-1.19.2-4.3.0.jar} | Bin 380681 -> 385984 bytes .../majruszsaccessories/AccessoryHolder.java | 88 ++++++++++++------ .../com/majruszsaccessories/Registries.java | 25 +++-- .../accessories/AccessoryBase.java | 84 +++++++---------- .../{items => accessories}/AccessoryItem.java | 6 +- .../accessories/AdventurersGuide.java | 11 +-- .../accessories/AnglersTrophy.java | 35 +++---- .../accessories/CertificateOfTaming.java | 13 ++- .../accessories/IdolOfFertility.java | 11 +-- .../accessories/LuckyRock.java | 10 +- .../accessories/OverworldRune.java | 3 +- .../accessories/SecretIngredient.java | 10 +- .../accessories/TamedPotatoBeetle.java | 10 +- .../accessories/WhiteFlag.java | 11 ++- .../components/AccessoryComponent.java | 31 ++++++ .../components/DoubleCrops.java | 6 +- .../components/EnhanceTamedAnimal.java | 8 +- .../components/EnhancedPotions.java | 8 +- .../components/ExtraStoneLoot.java | 6 +- .../components/FishingLuckBonus.java | 6 +- .../components/FishingLureBonus.java | 42 +++++++++ .../components/MoreChestLoot.java | 10 +- .../components/ReduceDamageDealt.java | 8 +- .../components/ReduceDamageReceived.java | 8 +- .../components/SpawnTwins.java | 6 +- .../components/TradeOffer.java | 16 +++- .../boosters/BoosterBase.java | 53 +++++++++++ .../boosters/BoosterItem.java | 35 +++++++ .../majruszsaccessories/boosters/Dice.java | 45 +++++++++ .../boosters/GoldenDice.java | 15 +++ .../boosters/GoldenHorseshoe.java | 15 +++ .../boosters/Horseshoe.java | 46 +++++++++ .../boosters/OwlFeather.java | 45 +++++++++ .../components/AccessoryDropChance.java | 36 +++++++ .../boosters/components/BoosterComponent.java | 17 ++++ .../boosters/components/ExperienceBonus.java | 44 +++++++++ .../boosters/components/LuckBonus.java | 45 +++++++++ .../ComponentBase.java} | 29 ++---- .../majruszsaccessories/common/ItemBase.java | 71 ++++++++++++++ .../gamemodifiers/CustomConditions.java | 21 ++++- .../contexts/OnAccessoryDropChance.java | 36 +++++++ .../contexts/OnAccessoryTooltip.java | 30 ++++++ .../contexts/OnBoosterTooltip.java | 29 ++++++ .../gamemodifiers/contexts/OnItemRender.java | 41 ++++++++ ...ater.java => AccessoryTooltipUpdater.java} | 21 ++--- .../gamemodifiers/list/BoosterDropper.java | 64 +++++++++++++ .../list/BoosterTooltipUpdater.java | 40 ++++++++ .../list/VillagerTradeUpdater.java | 51 ---------- .../items/BoosterOverlay.java | 15 +++ .../recipes/AccessoryRecipe.java | 45 +++------ .../recipes/BoostAccessoriesRecipe.java | 50 ++++++++++ .../recipes/CombineAccessoriesRecipe.java | 47 ++-------- .../recipes/RecipeData.java | 86 +++++++++++------ .../tooltip/ITooltipProvider.java | 3 +- .../tooltip/TooltipHelper.java | 29 +++++- src/main/resources/META-INF/mods.toml | 12 +-- .../majruszsaccessories/lang/en_us.json | 17 +++- .../majruszsaccessories/lang/pl_pl.json | 17 +++- .../models/item/booster_icon.json | 6 ++ .../majruszsaccessories/models/item/dice.json | 6 ++ .../models/item/golden_dice.json | 6 ++ .../models/item/golden_horseshoe.json | 6 ++ .../models/item/horseshoe.json | 6 ++ .../models/item/owl_feather.json | 6 ++ .../textures/item/anglers_trophy.png | Bin 408 -> 419 bytes .../textures/item/booster_icon.png | Bin 0 -> 135 bytes .../textures/item/dice.png | Bin 0 -> 279 bytes .../textures/item/essence_sparks.png | Bin 147 -> 0 bytes .../textures/item/essence_sparks.png.mcmeta | 22 ----- .../textures/item/golden_dice.png | Bin 0 -> 270 bytes .../textures/item/golden_horseshoe.png | Bin 0 -> 324 bytes .../textures/item/horseshoe.png | Bin 0 -> 278 bytes .../textures/item/owl_feather.png | Bin 0 -> 291 bytes .../advancements/booster_dropped.json | 45 +++++++++ .../advancements/booster_used.json | 35 +++++++ .../recipes/misc/golden_dice.json | 34 +++++++ .../recipes/misc/golden_horseshoe.json | 34 +++++++ .../gameplay/nether_accessories.json | 22 +++++ .../recipes/boost_accessories.json | 3 + .../recipes/golden_dice.json | 20 ++++ .../recipes/golden_horseshoe.json | 20 ++++ 83 files changed, 1517 insertions(+), 414 deletions(-) rename libs/{majrusz-library-1.19.2-4.0.0.jar => majrusz-library-1.19.2-4.3.0.jar} (81%) rename src/main/java/com/majruszsaccessories/{items => accessories}/AccessoryItem.java (85%) create mode 100644 src/main/java/com/majruszsaccessories/accessories/components/AccessoryComponent.java rename src/main/java/com/majruszsaccessories/{ => accessories}/components/DoubleCrops.java (92%) rename src/main/java/com/majruszsaccessories/{ => accessories}/components/EnhanceTamedAnimal.java (93%) rename src/main/java/com/majruszsaccessories/{ => accessories}/components/EnhancedPotions.java (93%) rename src/main/java/com/majruszsaccessories/{ => accessories}/components/ExtraStoneLoot.java (95%) rename src/main/java/com/majruszsaccessories/{ => accessories}/components/FishingLuckBonus.java (92%) create mode 100644 src/main/java/com/majruszsaccessories/accessories/components/FishingLureBonus.java rename src/main/java/com/majruszsaccessories/{ => accessories}/components/MoreChestLoot.java (93%) rename src/main/java/com/majruszsaccessories/{ => accessories}/components/ReduceDamageDealt.java (84%) rename src/main/java/com/majruszsaccessories/{ => accessories}/components/ReduceDamageReceived.java (84%) rename src/main/java/com/majruszsaccessories/{ => accessories}/components/SpawnTwins.java (93%) rename src/main/java/com/majruszsaccessories/{ => accessories}/components/TradeOffer.java (68%) create mode 100644 src/main/java/com/majruszsaccessories/boosters/BoosterBase.java create mode 100644 src/main/java/com/majruszsaccessories/boosters/BoosterItem.java create mode 100644 src/main/java/com/majruszsaccessories/boosters/Dice.java create mode 100644 src/main/java/com/majruszsaccessories/boosters/GoldenDice.java create mode 100644 src/main/java/com/majruszsaccessories/boosters/GoldenHorseshoe.java create mode 100644 src/main/java/com/majruszsaccessories/boosters/Horseshoe.java create mode 100644 src/main/java/com/majruszsaccessories/boosters/OwlFeather.java create mode 100644 src/main/java/com/majruszsaccessories/boosters/components/AccessoryDropChance.java create mode 100644 src/main/java/com/majruszsaccessories/boosters/components/BoosterComponent.java create mode 100644 src/main/java/com/majruszsaccessories/boosters/components/ExperienceBonus.java create mode 100644 src/main/java/com/majruszsaccessories/boosters/components/LuckBonus.java rename src/main/java/com/majruszsaccessories/{components/AccessoryComponent.java => common/ComponentBase.java} (57%) create mode 100644 src/main/java/com/majruszsaccessories/common/ItemBase.java create mode 100644 src/main/java/com/majruszsaccessories/gamemodifiers/contexts/OnAccessoryDropChance.java create mode 100644 src/main/java/com/majruszsaccessories/gamemodifiers/contexts/OnAccessoryTooltip.java create mode 100644 src/main/java/com/majruszsaccessories/gamemodifiers/contexts/OnBoosterTooltip.java create mode 100644 src/main/java/com/majruszsaccessories/gamemodifiers/contexts/OnItemRender.java rename src/main/java/com/majruszsaccessories/gamemodifiers/list/{TooltipUpdater.java => AccessoryTooltipUpdater.java} (86%) create mode 100644 src/main/java/com/majruszsaccessories/gamemodifiers/list/BoosterDropper.java create mode 100644 src/main/java/com/majruszsaccessories/gamemodifiers/list/BoosterTooltipUpdater.java delete mode 100644 src/main/java/com/majruszsaccessories/gamemodifiers/list/VillagerTradeUpdater.java create mode 100644 src/main/java/com/majruszsaccessories/items/BoosterOverlay.java create mode 100644 src/main/java/com/majruszsaccessories/recipes/BoostAccessoriesRecipe.java rename src/main/java/com/majruszsaccessories/{accessories => }/tooltip/ITooltipProvider.java (75%) rename src/main/java/com/majruszsaccessories/{accessories => }/tooltip/TooltipHelper.java (75%) create mode 100644 src/main/resources/assets/majruszsaccessories/models/item/booster_icon.json create mode 100644 src/main/resources/assets/majruszsaccessories/models/item/dice.json create mode 100644 src/main/resources/assets/majruszsaccessories/models/item/golden_dice.json create mode 100644 src/main/resources/assets/majruszsaccessories/models/item/golden_horseshoe.json create mode 100644 src/main/resources/assets/majruszsaccessories/models/item/horseshoe.json create mode 100644 src/main/resources/assets/majruszsaccessories/models/item/owl_feather.json create mode 100644 src/main/resources/assets/majruszsaccessories/textures/item/booster_icon.png create mode 100644 src/main/resources/assets/majruszsaccessories/textures/item/dice.png delete mode 100644 src/main/resources/assets/majruszsaccessories/textures/item/essence_sparks.png delete mode 100644 src/main/resources/assets/majruszsaccessories/textures/item/essence_sparks.png.mcmeta create mode 100644 src/main/resources/assets/majruszsaccessories/textures/item/golden_dice.png create mode 100644 src/main/resources/assets/majruszsaccessories/textures/item/golden_horseshoe.png create mode 100644 src/main/resources/assets/majruszsaccessories/textures/item/horseshoe.png create mode 100644 src/main/resources/assets/majruszsaccessories/textures/item/owl_feather.png create mode 100644 src/main/resources/data/majruszsaccessories/advancements/booster_dropped.json create mode 100644 src/main/resources/data/majruszsaccessories/advancements/booster_used.json create mode 100644 src/main/resources/data/majruszsaccessories/advancements/recipes/misc/golden_dice.json create mode 100644 src/main/resources/data/majruszsaccessories/advancements/recipes/misc/golden_horseshoe.json create mode 100644 src/main/resources/data/majruszsaccessories/loot_tables/gameplay/nether_accessories.json create mode 100644 src/main/resources/data/majruszsaccessories/recipes/boost_accessories.json create mode 100644 src/main/resources/data/majruszsaccessories/recipes/golden_dice.json create mode 100644 src/main/resources/data/majruszsaccessories/recipes/golden_horseshoe.json diff --git a/build.gradle b/build.gradle index eff6cecf..69c7f2fe 100644 --- a/build.gradle +++ b/build.gradle @@ -14,9 +14,9 @@ apply plugin: 'eclipse' apply plugin: 'maven-publish' apply plugin: 'org.spongepowered.mixin' -version = '1.1.5' -group = 'com.majruszsaccessories' // http://maven.apache.org/guides/mini/guide-naming-conventions.html -archivesBaseName = 'majruszs-accessories-1.19.2' +version = versions_mod +group = 'com.majruszsaccessories' +archivesBaseName = "majruszs-accessories-${versions_minecraft}" // Mojang ships Java 16 to end users in 1.17+ instead of Java 8 in 1.16 or lower, so your mod should target Java 16. java.toolchain.languageVersion = JavaLanguageVersion.of(17) @@ -25,7 +25,7 @@ compileJava { } minecraft { - mappings channel: 'official', version: '1.19.2' + mappings channel: 'official', version: versions_minecraft accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg') // Currently, this location cannot be changed from the default. @@ -80,12 +80,19 @@ repositories { } } +processResources { + filesMatching('META-INF/mods.toml') { + expand project.properties + } + outputs.upToDateWhen { false } +} + dependencies { - minecraft 'net.minecraftforge:forge:1.19.2-43.2.0' - implementation fg.deobf( 'com.mlib:majrusz-library-1.19.2:4.0.0' ) - implementation fg.deobf( 'com.mlib:majruszs-difficulty-1.19.2:1.7.4' ) - runtimeOnly fg.deobf( "top.theillusivec4.curios:curios-forge:1.19.2-5.1.1.0" ) - compileOnly fg.deobf( "top.theillusivec4.curios:curios-forge:1.19.2-5.1.1.0:api" ) + minecraft "net.minecraftforge:forge:${versions_minecraft}-${versions_forge}" + implementation fg.deobf( "com.mlib:majrusz-library-${versions_minecraft}:${versions_mlib}" ) + implementation fg.deobf( "com.mlib:majruszs-difficulty-${versions_minecraft}:${versions_difficulty}" ) + runtimeOnly fg.deobf( "top.theillusivec4.curios:curios-forge:${versions_curios}" ) + compileOnly fg.deobf( "top.theillusivec4.curios:curios-forge:${versions_curios}:api" ) } jar { diff --git a/gradle.properties b/gradle.properties index 878bf1f7..7e100351 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,15 @@ # Sets default memory used for gradle commands. Can be overridden by user or command line properties. # This is required to provide enough memory for the Minecraft decompilation process. org.gradle.jvmargs=-Xmx3G -org.gradle.daemon=false \ No newline at end of file +org.gradle.daemon=false +versions_minecraft=1.19.2 +versions_minecraft_range=[1.19.2,1.20) +versions_forge=43.2.0 +versions_forge_range=[43.2.0,) +versions_mod=1.2.0 +versions_mlib=4.3.0 +versions_mlib_range=[4.3.0,5.0.0) +versions_difficulty=1.7.4 +versions_difficulty_range=[1.7.4,) +versions_curios=1.19.2-5.1.1.0 +versions_curios_range=[1.19.2-5.1.1.0,) \ No newline at end of file diff --git a/libs/majrusz-library-1.19.2-4.0.0.jar b/libs/majrusz-library-1.19.2-4.3.0.jar similarity index 81% rename from libs/majrusz-library-1.19.2-4.0.0.jar rename to libs/majrusz-library-1.19.2-4.3.0.jar index 94e9d3b3409546608b48db51a60f5be71e557d15..b3208a575f029b0da63dcd8809cb69a51783ae36 100644 GIT binary patch delta 34829 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 Az5oCK delta 29849 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 xcueT2HAN1WyBp1{kE) diff --git a/src/main/java/com/majruszsaccessories/AccessoryHolder.java b/src/main/java/com/majruszsaccessories/AccessoryHolder.java index 27ac4c9b..ee792a07 100644 --- a/src/main/java/com/majruszsaccessories/AccessoryHolder.java +++ b/src/main/java/com/majruszsaccessories/AccessoryHolder.java @@ -1,8 +1,9 @@ package com.majruszsaccessories; -import com.majruszsaccessories.accessories.AccessoryBase; -import com.majruszsaccessories.items.AccessoryItem; +import com.majruszsaccessories.accessories.AccessoryItem; +import com.majruszsaccessories.boosters.BoosterItem; import com.mlib.Random; +import com.mlib.Utility; import com.mlib.config.DoubleConfig; import com.mlib.config.IntegerConfig; import com.mlib.math.Range; @@ -16,21 +17,22 @@ import top.theillusivec4.curios.api.SlotResult; import java.util.Optional; +import java.util.function.Predicate; public class AccessoryHolder { public static final Range< Float > BONUS_RANGE = new Range<>( -0.6f, 0.6f ); final ItemStack itemStack; final AccessoryItem item; - public static AccessoryHolder find( LivingEntity entity, AccessoryItem item ) { + public static AccessoryHolder find( LivingEntity entity, Predicate< ItemStack > predicate ) { if( Integration.isCuriosInstalled() ) { - Optional< SlotResult > slotResult = CuriosApi.getCuriosHelper().findFirstCurio( entity, item ); + Optional< SlotResult > slotResult = CuriosApi.getCuriosHelper().findFirstCurio( entity, predicate ); if( slotResult.isPresent() ) { return new AccessoryHolder( slotResult.get().stack() ); } } else { ItemStack itemStack = entity.getOffhandItem(); - if( itemStack.is( item ) ) { + if( predicate.test( itemStack ) ) { return new AccessoryHolder( itemStack ); } } @@ -38,20 +40,24 @@ public static AccessoryHolder find( LivingEntity entity, AccessoryItem item ) { return new AccessoryHolder( ItemStack.EMPTY ); } - public static boolean hasAccessory( LivingEntity entity, AccessoryItem item ) { - return find( entity, item ).isValid(); + public static AccessoryHolder find( LivingEntity entity, AccessoryItem item ) { + return find( entity, itemStack->itemStack.is( item ) ); } - public static AccessoryHolder create( AccessoryItem item ) { - return new AccessoryHolder( new ItemStack( item ) ); + public static AccessoryHolder find( LivingEntity entity, BoosterItem item ) { + return find( entity, itemStack->AccessoryHolder.create( itemStack ).hasBoosterTag( item ) ); } - public static AccessoryHolder create( AccessoryItem item, float bonus ) { - return new AccessoryHolder( new ItemStack( item ) ).setBonus( bonus ); + public static boolean hasAccessory( LivingEntity entity, AccessoryItem item ) { + return find( entity, item ).isValid(); } - public static AccessoryHolder create( AccessoryItem item, Range< Float > bonus ) { - return new AccessoryHolder( new ItemStack( item ) ).setBonus( bonus ); + public static boolean hasBooster( LivingEntity entity, BoosterItem item ) { + return find( entity, item ).isValid(); + } + + public static AccessoryHolder create( AccessoryItem item ) { + return new AccessoryHolder( new ItemStack( item ) ); } public static AccessoryHolder create( ItemStack itemStack ) { @@ -79,8 +85,8 @@ public static Rarity getItemRarity( float bonus ) { } public static float randomBonus() { - float gaussianRandom = ( float )Mth.clamp( Random.nextGaussian() / 3.0f, -1.0f, 1.0f ); // random value from range [-1.0; 1.0] with mean ~= 0.0 and standard deviation ~= 0.3333.. - float ratio = ( gaussianRandom + 1.0f ) / 2.0f; // random value from range [0.0; 1.0] with mean ~= 0.5 and standard deviation ~= 0.1666.. + float gaussianRandom = ( float )Mth.clamp( Random.nextGaussian() / 4.0f, -1.0f, 1.0f ); // random value from range [-1.0; 1.0] with mean ~= 0.0 and standard deviation ~= 0.25 + float ratio = ( gaussianRandom + 1.0f ) / 2.0f; // random value from range [0.0; 1.0] with mean ~= 0.5 and standard deviation ~= 0.125 return Mth.lerp( ratio, BONUS_RANGE.from, BONUS_RANGE.to ); } @@ -90,6 +96,13 @@ private AccessoryHolder( ItemStack itemStack ) { this.item = itemStack.getItem() instanceof AccessoryItem item ? item : null; } + public AccessoryHolder copy() { + AccessoryHolder copy = new AccessoryHolder( new ItemStack( this.item ) ); + copy.setBonus( this.getBonus() ); + + return copy; + } + public int apply( IntegerConfig config, int multiplier ) { return config.getRange().clamp( Math.round( ( 1.0f + multiplier * this.getBonus() ) * config.get() ) ); } @@ -108,8 +121,8 @@ public float apply( DoubleConfig config ) { public AccessoryHolder setRandomBonus() { if( this.hasBonusRangeTag() ) { - float minBonus = this.getTagValue( Tags.VALUE_MIN ); - float maxBonus = this.getTagValue( Tags.VALUE_MAX ); + float minBonus = this.getFloatTag( Tags.VALUE_MIN ); + float maxBonus = this.getFloatTag( Tags.VALUE_MAX ); return this.setTagValue( Tags.VALUE, Mth.lerp( Random.nextFloat( 0.0f, 1.0f ), minBonus, maxBonus ) ); } else { @@ -122,23 +135,23 @@ public AccessoryHolder setBonus( float bonus ) { } public AccessoryHolder setBonus( Range< Float > bonus ) { - return this.setTagValue( Tags.VALUE_MIN, bonus.from ).setTagValue( Tags.VALUE_MAX, bonus.to ); + if( ( bonus.to - bonus.from ) > 1e-5f ) { + return this.setTagValue( Tags.VALUE_MIN, bonus.from ).setTagValue( Tags.VALUE_MAX, bonus.to ); + } else { + return this.setBonus( bonus.from ); + } } - public Optional< AccessoryBase > findAccessoryBase() { - return Registries.OBJECTS.stream() - .filter( obj->obj instanceof AccessoryBase ) - .map( obj->( AccessoryBase )obj ) - .filter( base->base.is( this.item ) ) - .findAny(); + public AccessoryHolder setBooster( BoosterItem item ) { + return this.setTagValue( Tags.BOOSTER, Utility.getRegistryString( item ) ); } public float getBonus() { - return this.getTagValue( Tags.VALUE ); + return this.getFloatTag( Tags.VALUE ); } public Range< Float > getBonusRange() { - return new Range<>( this.getTagValue( Tags.VALUE_MIN ), this.getTagValue( Tags.VALUE_MAX ) ); + return new Range<>( this.getFloatTag( Tags.VALUE_MIN ), this.getFloatTag( Tags.VALUE_MAX ) ); } public ItemStack getItemStack() { @@ -177,22 +190,43 @@ public boolean hasMaxBonus() { return this.getBonus() == BONUS_RANGE.to; } + public boolean hasBoosterTag( BoosterItem item ) { + return Utility.getRegistryString( item ).equals( this.getStringTag( Tags.BOOSTER ) ); + } + + public boolean hasBoosterTag() { + return !this.getStringTag( Tags.BOOSTER ).isEmpty(); + } + private AccessoryHolder setTagValue( String tag, float value ) { this.itemStack.getOrCreateTagElement( Tags.BONUS ).putFloat( tag, Math.round( 100.0f * value ) / 100.0f ); return this; } - private float getTagValue( String tag ) { + private AccessoryHolder setTagValue( String tag, String value ) { + this.itemStack.getOrCreateTagElement( Tags.BONUS ).putString( tag, value ); + + return this; + } + + private float getFloatTag( String tag ) { CompoundTag itemTag = this.itemStack.getTagElement( Tags.BONUS ); return itemTag != null ? itemTag.getFloat( tag ) : 0.0f; } + private String getStringTag( String tag ) { + CompoundTag itemTag = this.itemStack.getTagElement( Tags.BONUS ); + + return itemTag != null ? itemTag.getString( tag ) : ""; + } + static final class Tags { static final String BONUS = "Bonus"; static final String VALUE = "Value"; static final String VALUE_MIN = "ValueMin"; static final String VALUE_MAX = "ValueMax"; + static final String BOOSTER = "Booster"; } } diff --git a/src/main/java/com/majruszsaccessories/Registries.java b/src/main/java/com/majruszsaccessories/Registries.java index f78cb966..7479d04c 100644 --- a/src/main/java/com/majruszsaccessories/Registries.java +++ b/src/main/java/com/majruszsaccessories/Registries.java @@ -1,13 +1,17 @@ package com.majruszsaccessories; -import com.majruszsaccessories.items.*; +import com.majruszsaccessories.accessories.AccessoryItem; +import com.majruszsaccessories.boosters.BoosterItem; +import com.majruszsaccessories.items.BoosterOverlay; import com.majruszsaccessories.recipes.AccessoryRecipe; +import com.majruszsaccessories.recipes.BoostAccessoriesRecipe; import com.majruszsaccessories.recipes.CombineAccessoriesRecipe; import com.mlib.annotations.AnnotationHandler; import com.mlib.gamemodifiers.ModConfigs; import com.mlib.items.CreativeModeTabHelper; import com.mlib.registries.RegistryHelper; import net.minecraft.client.renderer.texture.TextureAtlas; +import com.mlib.triggers.BasicTrigger; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.inventory.InventoryMenu; import net.minecraft.world.item.CreativeModeTab; @@ -28,8 +32,6 @@ import top.theillusivec4.curios.api.CuriosApi; import top.theillusivec4.curios.api.SlotTypeMessage; -import java.util.List; - import static com.majruszsaccessories.MajruszsAccessories.SERVER_CONFIG; public class Registries { @@ -37,6 +39,8 @@ public class Registries { static { ModConfigs.init( SERVER_CONFIG, Groups.DEFAULT ); + ModConfigs.init( SERVER_CONFIG, Groups.ACCESSORIES ).name( "Accessories" ); + ModConfigs.init( SERVER_CONFIG, Groups.BOOSTERS ).name( "Boosters" ); } // Groups @@ -47,8 +51,13 @@ public class Registries { public static final RegistryObject< AccessoryItem > ADVENTURERS_GUIDE = ITEMS.register( "adventurers_guide", AccessoryItem::new ); public static final RegistryObject< AccessoryItem > ANGLERS_TROPHY = ITEMS.register( "anglers_trophy", AccessoryItem::new ); public static final RegistryObject< AccessoryItem > CERTIFICATE_OF_TAMING = ITEMS.register( "certificate_of_taming", AccessoryItem::new ); + public static final RegistryObject< BoosterItem > DICE = ITEMS.register( "dice", BoosterItem.basic() ); + public static final RegistryObject< BoosterItem > GOLDEN_DICE = ITEMS.register( "golden_dice", BoosterItem.rare() ); + public static final RegistryObject< BoosterItem > GOLDEN_HORSESHOE = ITEMS.register( "golden_horseshoe", BoosterItem.rare() ); + public static final RegistryObject< BoosterItem > HORSESHOE = ITEMS.register( "horseshoe", BoosterItem.basic() ); public static final RegistryObject< AccessoryItem > IDOL_OF_FERTILITY = ITEMS.register( "idol_of_fertility", AccessoryItem::new ); public static final RegistryObject< AccessoryItem > LUCKY_ROCK = ITEMS.register( "lucky_rock", AccessoryItem::new ); + public static final RegistryObject< BoosterItem > OWL_FEATHER = ITEMS.register( "owl_feather", BoosterItem.basic() ); public static final RegistryObject< AccessoryItem > OVERWORLD_RUNE = ITEMS.register( "overworld_rune", AccessoryItem::new ); public static final RegistryObject< AccessoryItem > SECRET_INGREDIENT = ITEMS.register( "secret_ingredient", AccessoryItem::new ); public static final RegistryObject< AccessoryItem > TAMED_POTATO_BEETLE = ITEMS.register( "tamed_potato_beetle", AccessoryItem::new ); @@ -57,16 +66,16 @@ public class Registries { // Recipes public static final RegistryObject< RecipeSerializer< ? > > ACCESSORY_RECIPE = RECIPES.register( "crafting_accessory", AccessoryRecipe.create() ); public static final RegistryObject< RecipeSerializer< ? > > COMBINE_ACCESSORIES_RECIPE = RECIPES.register( "crafting_combine_accessories", CombineAccessoriesRecipe.create() ); + public static final RegistryObject< RecipeSerializer< ? > > BOOST_ACCESSORIES_RECIPE = RECIPES.register( "crafting_boost_accessories", BoostAccessoriesRecipe.create() ); // Misc public static final ResourceLocation ACCESSORY_SLOT_TEXTURE = Registries.getLocation( "item/empty_accessory_slot" ); public static final CreativeModeTab ITEM_GROUP = CreativeModeTabHelper.newTab( "majruszsaccessories.primary", LUCKY_ROCK ); - - // Game Modifiers - public static final List< Object > OBJECTS; + public static final RegistryObject< Item > BOOSTER_OVERLAY = ITEMS.register( "booster_icon", BoosterOverlay::new ); + public static final BasicTrigger BASIC_TRIGGER = HELPER.registerBasicTrigger(); static { - OBJECTS = new AnnotationHandler( MajruszsAccessories.MOD_ID ).getInstances(); + new AnnotationHandler( MajruszsAccessories.MOD_ID ); } public static void initialize() { @@ -109,5 +118,7 @@ private static void onTextureStitch( TextureStitchEvent.Pre event ) { public static class Groups { public static final String DEFAULT = Registries.getLocationString( "default" ); + public static final String ACCESSORIES = Registries.getLocationString( "accessories" ); + public static final String BOOSTERS = Registries.getLocationString( "boosters" ); } } diff --git a/src/main/java/com/majruszsaccessories/accessories/AccessoryBase.java b/src/main/java/com/majruszsaccessories/accessories/AccessoryBase.java index bbae5bd6..688098b4 100644 --- a/src/main/java/com/majruszsaccessories/accessories/AccessoryBase.java +++ b/src/main/java/com/majruszsaccessories/accessories/AccessoryBase.java @@ -1,66 +1,48 @@ package com.majruszsaccessories.accessories; import com.majruszsaccessories.AccessoryHolder; -import com.majruszsaccessories.components.AccessoryComponent; -import com.majruszsaccessories.items.AccessoryItem; -import com.mlib.client.ClientHelper; -import com.mlib.config.ConfigGroup; -import com.mlib.gamemodifiers.ModConfigs; -import net.minecraft.ChatFormatting; -import net.minecraft.network.chat.Component; +import com.majruszsaccessories.Registries; +import com.majruszsaccessories.accessories.components.AccessoryComponent; +import com.majruszsaccessories.accessories.components.TradeOffer; +import com.majruszsaccessories.common.ItemBase; +import com.majruszsaccessories.gamemodifiers.contexts.OnAccessoryTooltip; +import com.majruszsaccessories.gamemodifiers.contexts.OnItemRender; +import com.mlib.gamemodifiers.Condition; +import com.mlib.gamemodifiers.contexts.OnTradeSetup; +import net.minecraft.client.gui.Font; +import net.minecraft.world.item.ItemStack; +import net.minecraftforge.client.IItemDecorator; import net.minecraftforge.registries.RegistryObject; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.function.Supplier; -import java.util.stream.Stream; - -import static com.majruszsaccessories.MajruszsAccessories.SERVER_CONFIG; - -public class AccessoryBase { - protected final List< AccessoryComponent > components = new ArrayList<>(); - protected final Supplier< AccessoryItem > item; - protected final ConfigGroup group; - +public class AccessoryBase extends ItemBase< AccessoryItem, AccessoryComponent, AccessoryComponent.ISupplier > { public AccessoryBase( RegistryObject< AccessoryItem > item ) { - this.item = item; - this.group = ModConfigs.init( SERVER_CONFIG, item.getId().toString() ); - } - - public AccessoryBase name( String name ) { - this.group.name( name ); + super( item, Registries.Groups.ACCESSORIES ); - return this; - } - - public AccessoryBase add( AccessoryComponent.ISupplier supplier ) { - this.components.add( supplier.accept( this.item, this.group ) ); + OnAccessoryTooltip.listen( this::addTooltip ) + .addCondition( Condition.predicate( data->data.holder.getItem().equals( this.item.get() ) ) ) + .insertTo( this.group ); - return this; - } - - public List< Component > buildTooltip( AccessoryHolder holder ) { - return this.components.stream() - .map( AccessoryComponent::getTooltipProviders ) - .flatMap( List::stream ) - .map( provider->ClientHelper.isShiftDown() ? provider.getDetailedTooltip( holder ) : provider.getTooltip( holder ) ) - .map( component->( Component )component.withStyle( ChatFormatting.GRAY ) ) - .toList(); - } + OnTradeSetup.listen( this::addTrades ) + .insertTo( this.group ); - public boolean is( AccessoryItem item ) { - return this.item.get().equals( item ); + OnItemRender.listen( this::addBoosterIcon ); } - public List< AccessoryComponent > getComponents() { - return Collections.unmodifiableList( this.components ); + private void addTrades( OnTradeSetup.Data data ) { + this.components.stream() + .filter( TradeOffer.class::isInstance ) + .map( TradeOffer.class::cast ) + .filter( offer->offer.getProfession() == data.profession ) + .forEach( offer->data.getTrades( offer.getTier() ).add( ( trader, random )->offer.toMerchantOffer() ) ); } - public < Type > List< Type > getComponents( Class< Type > clazz ) { - return Stream.of( this.components ) - .filter( clazz::isInstance ) - .map( clazz::cast ) - .toList(); + private void addBoosterIcon( OnItemRender.Data data ) { + data.addDecoration( this.item, new IItemDecorator() { + @Override + public boolean render( Font font, ItemStack itemStack, int xOffset, int yOffset, float blitOffset ) { + return AccessoryHolder.create( itemStack ).hasBoosterTag() + && AccessoryBase.this.renderBoosterIcon( xOffset, yOffset, blitOffset ); + } + } ); } } diff --git a/src/main/java/com/majruszsaccessories/items/AccessoryItem.java b/src/main/java/com/majruszsaccessories/accessories/AccessoryItem.java similarity index 85% rename from src/main/java/com/majruszsaccessories/items/AccessoryItem.java rename to src/main/java/com/majruszsaccessories/accessories/AccessoryItem.java index 58908492..4b4bf615 100644 --- a/src/main/java/com/majruszsaccessories/items/AccessoryItem.java +++ b/src/main/java/com/majruszsaccessories/accessories/AccessoryItem.java @@ -1,8 +1,9 @@ -package com.majruszsaccessories.items; +package com.majruszsaccessories.accessories; import com.majruszsaccessories.AccessoryHolder; import com.majruszsaccessories.Registries; import net.minecraft.core.NonNullList; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.util.Mth; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.CreativeModeTab; @@ -22,6 +23,9 @@ public void onCraftedBy( ItemStack itemStack, Level level, Player player ) { if( holder.hasBonusRangeTag() && !holder.hasBonusTag() ) { holder.setRandomBonus(); } + if( holder.hasBoosterTag() && player instanceof ServerPlayer serverPlayer ) { + Registries.BASIC_TRIGGER.trigger( serverPlayer, "booster_used" ); + } } @Override diff --git a/src/main/java/com/majruszsaccessories/accessories/AdventurersGuide.java b/src/main/java/com/majruszsaccessories/accessories/AdventurersGuide.java index 708bbea4..e516c7c6 100644 --- a/src/main/java/com/majruszsaccessories/accessories/AdventurersGuide.java +++ b/src/main/java/com/majruszsaccessories/accessories/AdventurersGuide.java @@ -1,14 +1,13 @@ package com.majruszsaccessories.accessories; import com.majruszsaccessories.Registries; -import com.majruszsaccessories.components.AccessoryComponent; -import com.majruszsaccessories.components.MoreChestLoot; -import com.majruszsaccessories.components.TradeOffer; -import com.majruszsaccessories.items.AccessoryItem; +import com.majruszsaccessories.accessories.components.AccessoryComponent; +import com.majruszsaccessories.accessories.components.MoreChestLoot; +import com.majruszsaccessories.accessories.components.TradeOffer; +import com.majruszsaccessories.gamemodifiers.CustomConditions; import com.mlib.annotations.AutoInstance; import com.mlib.config.ConfigGroup; import com.mlib.config.DoubleConfig; -import com.mlib.gamemodifiers.Condition; import com.mlib.math.Range; import net.minecraft.world.entity.npc.VillagerProfession; @@ -37,7 +36,7 @@ protected DropChance( Supplier< AccessoryItem > item, ConfigGroup group ) { chance.name( "spawn_chance" ).comment( "Chance for Adventurer's Guide to spawn in any chest." ); MoreChestLoot.OnChestOpened.listen( this::addToGeneratedLoot ) - .addCondition( Condition.chance( chance ) ) + .addCondition( CustomConditions.dropChance( chance, data->data.entity ) ) .insertTo( group ); } } diff --git a/src/main/java/com/majruszsaccessories/accessories/AnglersTrophy.java b/src/main/java/com/majruszsaccessories/accessories/AnglersTrophy.java index bc92922b..409af158 100644 --- a/src/main/java/com/majruszsaccessories/accessories/AnglersTrophy.java +++ b/src/main/java/com/majruszsaccessories/accessories/AnglersTrophy.java @@ -1,21 +1,17 @@ package com.majruszsaccessories.accessories; -import com.majruszsaccessories.Integration; import com.majruszsaccessories.Registries; -import com.majruszsaccessories.components.AccessoryComponent; -import com.majruszsaccessories.components.FishingLuckBonus; -import com.majruszsaccessories.components.TradeOffer; -import com.majruszsaccessories.items.AccessoryItem; -import com.majruszsdifficulty.items.TreasureBagItem; +import com.majruszsaccessories.accessories.components.AccessoryComponent; +import com.majruszsaccessories.accessories.components.FishingLuckBonus; +import com.majruszsaccessories.accessories.components.FishingLureBonus; +import com.majruszsaccessories.accessories.components.TradeOffer; +import com.majruszsaccessories.gamemodifiers.CustomConditions; import com.mlib.annotations.AutoInstance; import com.mlib.config.ConfigGroup; import com.mlib.config.DoubleConfig; -import com.mlib.gamemodifiers.Condition; import com.mlib.gamemodifiers.contexts.OnItemFished; -import com.mlib.gamemodifiers.contexts.OnLootTableCustomLoad; import com.mlib.math.Range; import net.minecraft.world.entity.npc.VillagerProfession; -import net.minecraft.world.level.storage.loot.predicates.LootItemRandomChanceCondition; import java.util.function.Supplier; @@ -26,6 +22,7 @@ public AnglersTrophy() { this.name( "AnglersTrophy" ) .add( FishingLuckBonus.create() ) + .add( FishingLureBonus.create() ) .add( TradeOffer.create( VillagerProfession.FISHERMAN, 5 ) ) .add( DropChance.create() ); } @@ -38,22 +35,12 @@ public static AccessoryComponent.ISupplier create() { protected DropChance( Supplier< AccessoryItem > item, ConfigGroup group ) { super( item ); - if( Integration.isProgressiveDifficultyInstalled() ) { - OnLootTableCustomLoad.listen( this::addToTreasureBag ) - .addCondition( Condition.predicate( data->TreasureBagItem.Fishing.LOCATION.equals( data.name ) ) ) - .insertTo( group ); - } else { - DoubleConfig chance = new DoubleConfig( 0.015, Range.CHANCE ); - chance.name( "drop_chance" ).comment( "Chance to drop Angler's Trophy when fishing." ); - - OnItemFished.listen( this::onFished ) - .addCondition( Condition.chance( chance ) ) - .insertTo( group ); - } - } + DoubleConfig chance = new DoubleConfig( 0.015, Range.CHANCE ); + chance.name( "drop_chance" ).comment( "Chance to drop Angler's Trophy when fishing." ); - private void addToTreasureBag( OnLootTableCustomLoad.Data data ) { - data.addEntry( data.addPool(), this.item.get(), 1, 4, LootItemRandomChanceCondition.randomChance( 0.30f ) ); + OnItemFished.listen( this::onFished ) + .addCondition( CustomConditions.dropChance( chance, data->data.player ) ) + .insertTo( group ); } private void onFished( OnItemFished.Data data ) { diff --git a/src/main/java/com/majruszsaccessories/accessories/CertificateOfTaming.java b/src/main/java/com/majruszsaccessories/accessories/CertificateOfTaming.java index c28a407b..a0d9ee8d 100644 --- a/src/main/java/com/majruszsaccessories/accessories/CertificateOfTaming.java +++ b/src/main/java/com/majruszsaccessories/accessories/CertificateOfTaming.java @@ -1,14 +1,13 @@ package com.majruszsaccessories.accessories; import com.majruszsaccessories.Registries; -import com.majruszsaccessories.components.AccessoryComponent; -import com.majruszsaccessories.components.EnhanceTamedAnimal; -import com.majruszsaccessories.components.TradeOffer; -import com.majruszsaccessories.items.AccessoryItem; +import com.majruszsaccessories.accessories.components.AccessoryComponent; +import com.majruszsaccessories.accessories.components.EnhanceTamedAnimal; +import com.majruszsaccessories.accessories.components.TradeOffer; +import com.majruszsaccessories.gamemodifiers.CustomConditions; import com.mlib.annotations.AutoInstance; import com.mlib.config.ConfigGroup; import com.mlib.config.DoubleConfig; -import com.mlib.gamemodifiers.Condition; import com.mlib.gamemodifiers.contexts.OnAnimalTame; import com.mlib.math.Range; import net.minecraft.world.entity.npc.VillagerProfession; @@ -34,11 +33,11 @@ public static AccessoryComponent.ISupplier create() { protected DropChance( Supplier< AccessoryItem > item, ConfigGroup group ) { super( item ); - DoubleConfig chance = new DoubleConfig( 0.02, Range.CHANCE ); + DoubleConfig chance = new DoubleConfig( 0.04, Range.CHANCE ); chance.name( "drop_chance" ).comment( "Chance for Certificate of Taming to drop when taming animals." ); OnAnimalTame.listen( this::spawnCertificate ) - .addCondition( Condition.chance( chance ) ) + .addCondition( CustomConditions.dropChance( chance, data->data.tamer ) ) .insertTo( group ); } diff --git a/src/main/java/com/majruszsaccessories/accessories/IdolOfFertility.java b/src/main/java/com/majruszsaccessories/accessories/IdolOfFertility.java index 88c23a63..e0ebacf2 100644 --- a/src/main/java/com/majruszsaccessories/accessories/IdolOfFertility.java +++ b/src/main/java/com/majruszsaccessories/accessories/IdolOfFertility.java @@ -1,14 +1,13 @@ package com.majruszsaccessories.accessories; import com.majruszsaccessories.Registries; -import com.majruszsaccessories.components.AccessoryComponent; -import com.majruszsaccessories.components.SpawnTwins; -import com.majruszsaccessories.components.TradeOffer; -import com.majruszsaccessories.items.AccessoryItem; +import com.majruszsaccessories.accessories.components.AccessoryComponent; +import com.majruszsaccessories.accessories.components.SpawnTwins; +import com.majruszsaccessories.accessories.components.TradeOffer; +import com.majruszsaccessories.gamemodifiers.CustomConditions; import com.mlib.annotations.AutoInstance; import com.mlib.config.ConfigGroup; import com.mlib.config.DoubleConfig; -import com.mlib.gamemodifiers.Condition; import com.mlib.gamemodifiers.contexts.OnBabySpawn; import com.mlib.math.Range; import net.minecraft.world.entity.npc.VillagerProfession; @@ -38,7 +37,7 @@ protected DropChance( Supplier< AccessoryItem > item, ConfigGroup group ) { chance.name( "drop_chance" ).comment( "Chance for Idol of Fertility to drop when breeding animals." ); SpawnTwins.OnTwinsSpawn.listen( this::spawnTotem ) - .addCondition( Condition.chance( chance ) ) + .addCondition( CustomConditions.dropChance( chance, data->data.player ) ) .insertTo( group ); } diff --git a/src/main/java/com/majruszsaccessories/accessories/LuckyRock.java b/src/main/java/com/majruszsaccessories/accessories/LuckyRock.java index 96677aa6..751402d2 100644 --- a/src/main/java/com/majruszsaccessories/accessories/LuckyRock.java +++ b/src/main/java/com/majruszsaccessories/accessories/LuckyRock.java @@ -2,10 +2,10 @@ import com.majruszsaccessories.Integration; import com.majruszsaccessories.Registries; -import com.majruszsaccessories.components.AccessoryComponent; -import com.majruszsaccessories.components.ExtraStoneLoot; -import com.majruszsaccessories.components.TradeOffer; -import com.majruszsaccessories.items.AccessoryItem; +import com.majruszsaccessories.accessories.components.AccessoryComponent; +import com.majruszsaccessories.accessories.components.ExtraStoneLoot; +import com.majruszsaccessories.accessories.components.TradeOffer; +import com.majruszsaccessories.gamemodifiers.CustomConditions; import com.mlib.annotations.AutoInstance; import com.mlib.config.ConfigGroup; import com.mlib.config.DoubleConfig; @@ -40,7 +40,7 @@ protected DropChance( Supplier< AccessoryItem > item, ConfigGroup group ) { chance.name( "drop_chance" ).comment( "Chance for Lucky Rock to drop when mining stone." ); ExtraStoneLoot.OnStoneMined.listen( this::addToGeneratedLoot ) - .addCondition( Condition.chance( chance ) ) + .addCondition( CustomConditions.dropChance( chance, data->data.entity ) ) .insertTo( group ); } } diff --git a/src/main/java/com/majruszsaccessories/accessories/OverworldRune.java b/src/main/java/com/majruszsaccessories/accessories/OverworldRune.java index 0f2a7468..bed9b7e3 100644 --- a/src/main/java/com/majruszsaccessories/accessories/OverworldRune.java +++ b/src/main/java/com/majruszsaccessories/accessories/OverworldRune.java @@ -1,7 +1,7 @@ package com.majruszsaccessories.accessories; import com.majruszsaccessories.Registries; -import com.majruszsaccessories.components.*; +import com.majruszsaccessories.accessories.components.*; import com.mlib.annotations.AutoInstance; import net.minecraft.world.entity.npc.VillagerProfession; @@ -13,6 +13,7 @@ public OverworldRune() { this.name( "OverworldRune" ) .add( MoreChestLoot.create( 1.5 ) ) .add( FishingLuckBonus.create( 4 ) ) + .add( FishingLureBonus.create( 0.5 ) ) .add( EnhanceTamedAnimal.create( 0.25 ) ) .add( SpawnTwins.create( 0.3 ) ) .add( ExtraStoneLoot.create( 0.04 ) ) diff --git a/src/main/java/com/majruszsaccessories/accessories/SecretIngredient.java b/src/main/java/com/majruszsaccessories/accessories/SecretIngredient.java index 172a6fbb..3ce9c280 100644 --- a/src/main/java/com/majruszsaccessories/accessories/SecretIngredient.java +++ b/src/main/java/com/majruszsaccessories/accessories/SecretIngredient.java @@ -1,10 +1,10 @@ package com.majruszsaccessories.accessories; import com.majruszsaccessories.Registries; -import com.majruszsaccessories.components.AccessoryComponent; -import com.majruszsaccessories.components.EnhancedPotions; -import com.majruszsaccessories.components.TradeOffer; -import com.majruszsaccessories.items.AccessoryItem; +import com.majruszsaccessories.accessories.components.AccessoryComponent; +import com.majruszsaccessories.accessories.components.EnhancedPotions; +import com.majruszsaccessories.accessories.components.TradeOffer; +import com.majruszsaccessories.gamemodifiers.CustomConditions; import com.mlib.annotations.AutoInstance; import com.mlib.config.ConfigGroup; import com.mlib.config.DoubleConfig; @@ -40,7 +40,7 @@ protected DropChance( Supplier< AccessoryItem > item, ConfigGroup group ) { OnLoot.listen( this::addToGeneratedLoot ) .addCondition( Condition.isServer() ) - .addCondition( Condition.chance( chance ) ) + .addCondition( CustomConditions.dropChance( chance, data->data.killer ) ) .addCondition( OnLoot.hasLastDamagePlayer() ) .addCondition( Condition.predicate( data->data.entity instanceof Witch ) ) .insertTo( group ); diff --git a/src/main/java/com/majruszsaccessories/accessories/TamedPotatoBeetle.java b/src/main/java/com/majruszsaccessories/accessories/TamedPotatoBeetle.java index cb097598..5d2a0035 100644 --- a/src/main/java/com/majruszsaccessories/accessories/TamedPotatoBeetle.java +++ b/src/main/java/com/majruszsaccessories/accessories/TamedPotatoBeetle.java @@ -1,10 +1,10 @@ package com.majruszsaccessories.accessories; import com.majruszsaccessories.Registries; -import com.majruszsaccessories.components.AccessoryComponent; -import com.majruszsaccessories.components.DoubleCrops; -import com.majruszsaccessories.components.TradeOffer; -import com.majruszsaccessories.items.AccessoryItem; +import com.majruszsaccessories.accessories.components.AccessoryComponent; +import com.majruszsaccessories.accessories.components.DoubleCrops; +import com.majruszsaccessories.accessories.components.TradeOffer; +import com.majruszsaccessories.gamemodifiers.contexts.OnAccessoryDropChance; import com.mlib.Random; import com.mlib.annotations.AutoInstance; import com.mlib.config.ConfigGroup; @@ -52,7 +52,7 @@ private static Condition< OnLoot.Data > chance() { finalChance *= chanceMultiplier.getOrDefault(); } - return Random.tryChance( finalChance ); + return Random.tryChance( OnAccessoryDropChance.dispatch( finalChance, data.entity ).getChance() ); }; return Condition.predicate( predicate ) diff --git a/src/main/java/com/majruszsaccessories/accessories/WhiteFlag.java b/src/main/java/com/majruszsaccessories/accessories/WhiteFlag.java index 439efdf5..8c698ded 100644 --- a/src/main/java/com/majruszsaccessories/accessories/WhiteFlag.java +++ b/src/main/java/com/majruszsaccessories/accessories/WhiteFlag.java @@ -1,8 +1,11 @@ package com.majruszsaccessories.accessories; import com.majruszsaccessories.Registries; -import com.majruszsaccessories.components.*; -import com.majruszsaccessories.items.AccessoryItem; +import com.majruszsaccessories.accessories.components.AccessoryComponent; +import com.majruszsaccessories.accessories.components.ReduceDamageDealt; +import com.majruszsaccessories.accessories.components.ReduceDamageReceived; +import com.majruszsaccessories.accessories.components.TradeOffer; +import com.majruszsaccessories.gamemodifiers.CustomConditions; import com.mlib.Utility; import com.mlib.annotations.AutoInstance; import com.mlib.blocks.BlockHelper; @@ -44,7 +47,7 @@ protected SwingBehavior( Supplier< AccessoryItem > item, ConfigGroup group ) { super( item ); OnPlayerInteract.listen( this::swing ) - .addCondition( Condition.predicate( data->data.itemStack.getItem().equals( item ) ) ) + .addCondition( Condition.predicate( data->data.itemStack.getItem().equals( item.get() ) ) ) .addCondition( Condition.predicate( data->!data.player.getCooldowns().isOnCooldown( data.itemStack.getItem() ) ) ) .insertTo( group ); } @@ -89,7 +92,7 @@ protected AddToVillageChests( Supplier< AccessoryItem > item, ConfigGroup group OnLoot.listen( this::addToGeneratedLoot ) .addCondition( Condition.isServer() ) - .addCondition( Condition.chance( chance ) ) + .addCondition( CustomConditions.dropChance( chance, data->data.entity ) ) .addCondition( OnLoot.is( villageIds ) ) .addCondition( OnLoot.hasOrigin() ) .addCondition( Condition.predicate( data->BlockHelper.getBlockEntity( data.getLevel(), data.origin ) instanceof RandomizableContainerBlockEntity ) ) diff --git a/src/main/java/com/majruszsaccessories/accessories/components/AccessoryComponent.java b/src/main/java/com/majruszsaccessories/accessories/components/AccessoryComponent.java new file mode 100644 index 00000000..2817a95a --- /dev/null +++ b/src/main/java/com/majruszsaccessories/accessories/components/AccessoryComponent.java @@ -0,0 +1,31 @@ +package com.majruszsaccessories.accessories.components; + +import com.majruszsaccessories.AccessoryHolder; +import com.majruszsaccessories.accessories.AccessoryItem; +import com.majruszsaccessories.common.ComponentBase; +import com.mlib.config.ConfigGroup; +import com.mlib.levels.LevelHelper; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.Vec3; + +import java.util.function.BiFunction; +import java.util.function.Supplier; + +public class AccessoryComponent extends ComponentBase< AccessoryItem > { + public AccessoryComponent( Supplier< AccessoryItem > item ) { + super( item ); + } + + @Override + protected ItemStack constructItemStack() { + return AccessoryHolder.create( this.item.get() ).setRandomBonus().getItemStack(); + } + + protected void spawnFlyingItem( Level level, Vec3 from, Vec3 to ) { + LevelHelper.spawnItemEntityFlyingTowardsDirection( this.constructItemStack(), level, from, to ); + } + + @FunctionalInterface + public interface ISupplier extends BiFunction< Supplier< AccessoryItem >, ConfigGroup, AccessoryComponent > {} +} diff --git a/src/main/java/com/majruszsaccessories/components/DoubleCrops.java b/src/main/java/com/majruszsaccessories/accessories/components/DoubleCrops.java similarity index 92% rename from src/main/java/com/majruszsaccessories/components/DoubleCrops.java rename to src/main/java/com/majruszsaccessories/accessories/components/DoubleCrops.java index 9420b86e..e0c5902f 100644 --- a/src/main/java/com/majruszsaccessories/components/DoubleCrops.java +++ b/src/main/java/com/majruszsaccessories/accessories/components/DoubleCrops.java @@ -1,8 +1,8 @@ -package com.majruszsaccessories.components; +package com.majruszsaccessories.accessories.components; -import com.majruszsaccessories.accessories.tooltip.TooltipHelper; +import com.majruszsaccessories.accessories.AccessoryItem; import com.majruszsaccessories.gamemodifiers.CustomConditions; -import com.majruszsaccessories.items.AccessoryItem; +import com.majruszsaccessories.tooltip.TooltipHelper; import com.mlib.blocks.BlockHelper; import com.mlib.config.ConfigGroup; import com.mlib.config.DoubleConfig; diff --git a/src/main/java/com/majruszsaccessories/components/EnhanceTamedAnimal.java b/src/main/java/com/majruszsaccessories/accessories/components/EnhanceTamedAnimal.java similarity index 93% rename from src/main/java/com/majruszsaccessories/components/EnhanceTamedAnimal.java rename to src/main/java/com/majruszsaccessories/accessories/components/EnhanceTamedAnimal.java index 229ed425..ec029e62 100644 --- a/src/main/java/com/majruszsaccessories/components/EnhanceTamedAnimal.java +++ b/src/main/java/com/majruszsaccessories/accessories/components/EnhanceTamedAnimal.java @@ -1,9 +1,9 @@ -package com.majruszsaccessories.components; +package com.majruszsaccessories.accessories.components; import com.majruszsaccessories.AccessoryHolder; -import com.majruszsaccessories.accessories.tooltip.TooltipHelper; +import com.majruszsaccessories.accessories.AccessoryItem; import com.majruszsaccessories.gamemodifiers.CustomConditions; -import com.majruszsaccessories.items.AccessoryItem; +import com.majruszsaccessories.tooltip.TooltipHelper; import com.mlib.attributes.AttributeHandler; import com.mlib.config.ConfigGroup; import com.mlib.config.DoubleConfig; @@ -38,7 +38,7 @@ protected EnhanceTamedAnimal( Supplier< AccessoryItem > item, ConfigGroup group, this.bonus = new DoubleConfig( bonus, new Range<>( 0.0, 10.0 ) ); OnAnimalTame.listen( this::enhanceAnimal ) - .addCondition( CustomConditions.has( item, data->data.tamer ) ) + .addCondition( CustomConditions.hasAccessory( item, data->data.tamer ) ) .addConfig( this.bonus.name( "animal_bonus" ).comment( "Bonus health, damage, movement speed and jump height for tamed animals." ) ) .insertTo( group ); diff --git a/src/main/java/com/majruszsaccessories/components/EnhancedPotions.java b/src/main/java/com/majruszsaccessories/accessories/components/EnhancedPotions.java similarity index 93% rename from src/main/java/com/majruszsaccessories/components/EnhancedPotions.java rename to src/main/java/com/majruszsaccessories/accessories/components/EnhancedPotions.java index 87df90fe..a21e9c8e 100644 --- a/src/main/java/com/majruszsaccessories/components/EnhancedPotions.java +++ b/src/main/java/com/majruszsaccessories/accessories/components/EnhancedPotions.java @@ -1,9 +1,9 @@ -package com.majruszsaccessories.components; +package com.majruszsaccessories.accessories.components; import com.majruszsaccessories.AccessoryHolder; -import com.majruszsaccessories.accessories.tooltip.TooltipHelper; +import com.majruszsaccessories.accessories.AccessoryItem; import com.majruszsaccessories.gamemodifiers.CustomConditions; -import com.majruszsaccessories.items.AccessoryItem; +import com.majruszsaccessories.tooltip.TooltipHelper; import com.mlib.Utility; import com.mlib.config.ConfigGroup; import com.mlib.config.DoubleConfig; @@ -43,7 +43,7 @@ protected EnhancedPotions( Supplier< AccessoryItem > item, ConfigGroup group, do OnPotionBrewed.listen( this::enhancePotion ) .addCondition( Condition.predicate( data->PotionUtils.getMobEffects( data.itemStack ).size() > 0 ) ) .addCondition( Condition.predicate( data->!data.itemStack.getOrCreateTag().contains( TAG_CUSTOM_POTION_EFFECTS ) ) ) - .addCondition( CustomConditions.has( item, data->data.player ) ) + .addCondition( CustomConditions.hasAccessory( item, data->data.player ) ) .addConfig( this.duration.name( "potion_duration_penalty" ).comment( "Duration penalty for created enhanced potions." ) ) .addConfig( this.amplifier.name( "potion_extra_amplifier" ).comment( "Extra potion level for created enhanced potions." ) ) .insertTo( group ); diff --git a/src/main/java/com/majruszsaccessories/components/ExtraStoneLoot.java b/src/main/java/com/majruszsaccessories/accessories/components/ExtraStoneLoot.java similarity index 95% rename from src/main/java/com/majruszsaccessories/components/ExtraStoneLoot.java rename to src/main/java/com/majruszsaccessories/accessories/components/ExtraStoneLoot.java index 4b7f0e44..c02bc882 100644 --- a/src/main/java/com/majruszsaccessories/components/ExtraStoneLoot.java +++ b/src/main/java/com/majruszsaccessories/accessories/components/ExtraStoneLoot.java @@ -1,9 +1,9 @@ -package com.majruszsaccessories.components; +package com.majruszsaccessories.accessories.components; import com.majruszsaccessories.Registries; -import com.majruszsaccessories.accessories.tooltip.TooltipHelper; +import com.majruszsaccessories.accessories.AccessoryItem; import com.majruszsaccessories.gamemodifiers.CustomConditions; -import com.majruszsaccessories.items.AccessoryItem; +import com.majruszsaccessories.tooltip.TooltipHelper; import com.mlib.config.ConfigGroup; import com.mlib.config.DoubleConfig; import com.mlib.effects.ParticleHandler; diff --git a/src/main/java/com/majruszsaccessories/components/FishingLuckBonus.java b/src/main/java/com/majruszsaccessories/accessories/components/FishingLuckBonus.java similarity index 92% rename from src/main/java/com/majruszsaccessories/components/FishingLuckBonus.java rename to src/main/java/com/majruszsaccessories/accessories/components/FishingLuckBonus.java index 6e7e1dad..845fe441 100644 --- a/src/main/java/com/majruszsaccessories/components/FishingLuckBonus.java +++ b/src/main/java/com/majruszsaccessories/accessories/components/FishingLuckBonus.java @@ -1,8 +1,8 @@ -package com.majruszsaccessories.components; +package com.majruszsaccessories.accessories.components; import com.majruszsaccessories.AccessoryHolder; -import com.majruszsaccessories.accessories.tooltip.TooltipHelper; -import com.majruszsaccessories.items.AccessoryItem; +import com.majruszsaccessories.accessories.AccessoryItem; +import com.majruszsaccessories.tooltip.TooltipHelper; import com.mlib.attributes.AttributeHandler; import com.mlib.config.ConfigGroup; import com.mlib.config.IntegerConfig; diff --git a/src/main/java/com/majruszsaccessories/accessories/components/FishingLureBonus.java b/src/main/java/com/majruszsaccessories/accessories/components/FishingLureBonus.java new file mode 100644 index 00000000..55ddacd1 --- /dev/null +++ b/src/main/java/com/majruszsaccessories/accessories/components/FishingLureBonus.java @@ -0,0 +1,42 @@ +package com.majruszsaccessories.accessories.components; + +import com.majruszsaccessories.AccessoryHolder; +import com.majruszsaccessories.accessories.AccessoryItem; +import com.majruszsaccessories.tooltip.TooltipHelper; +import com.mlib.config.ConfigGroup; +import com.mlib.config.DoubleConfig; +import com.mlib.gamemodifiers.contexts.OnFishingTimeSet; +import com.mlib.math.Range; + +import java.util.function.Supplier; + +public class FishingLureBonus extends AccessoryComponent { + final DoubleConfig timeMultiplier; + + public static ISupplier create( double bonus ) { + return ( item, group )->new FishingLureBonus( item, group, bonus ); + } + + public static ISupplier create() { + return create( 0.4 ); + } + + protected FishingLureBonus( Supplier< AccessoryItem > item, ConfigGroup group, double bonus ) { + super( item ); + + this.timeMultiplier = new DoubleConfig( bonus, new Range<>( 0.01, 0.99 ) ); + + OnFishingTimeSet.listen( this::decreaseFishingTime ) + .addCondition( OnFishingTimeSet.hasPlayer() ) + .addConfig( this.timeMultiplier.name( "time_multiplier" ).comment( "Time reduction multiplier when fishing." ) ) + .insertTo( group ); + + this.addTooltip( "majruszsaccessories.bonuses.fishing_lure", TooltipHelper.asPercent( this.timeMultiplier ) ); + } + + private void decreaseFishingTime( OnFishingTimeSet.Data data ) { + AccessoryHolder holder = AccessoryHolder.find( data.player, this.item.get() ); + float multiplier = holder.isValid() ? holder.apply( this.timeMultiplier ) : 0.0f; + data.ticks = Math.round( data.ticks * ( 1.0f - multiplier ) ); + } +} diff --git a/src/main/java/com/majruszsaccessories/components/MoreChestLoot.java b/src/main/java/com/majruszsaccessories/accessories/components/MoreChestLoot.java similarity index 93% rename from src/main/java/com/majruszsaccessories/components/MoreChestLoot.java rename to src/main/java/com/majruszsaccessories/accessories/components/MoreChestLoot.java index 9f56c6a4..091b063a 100644 --- a/src/main/java/com/majruszsaccessories/components/MoreChestLoot.java +++ b/src/main/java/com/majruszsaccessories/accessories/components/MoreChestLoot.java @@ -1,10 +1,10 @@ -package com.majruszsaccessories.components; +package com.majruszsaccessories.accessories.components; import com.majruszsaccessories.AccessoryHolder; -import com.majruszsaccessories.accessories.tooltip.ITooltipProvider; -import com.majruszsaccessories.accessories.tooltip.TooltipHelper; +import com.majruszsaccessories.accessories.AccessoryItem; import com.majruszsaccessories.gamemodifiers.CustomConditions; -import com.majruszsaccessories.items.AccessoryItem; +import com.majruszsaccessories.tooltip.ITooltipProvider; +import com.majruszsaccessories.tooltip.TooltipHelper; import com.mlib.Random; import com.mlib.blocks.BlockHelper; import com.mlib.config.ConfigGroup; @@ -49,7 +49,7 @@ protected MoreChestLoot( Supplier< AccessoryItem > item, ConfigGroup group, doub this.sizeMultiplier.name( "chest_size_bonus" ).comment( "Extra multiplier for number of items acquired from chests." ); OnChestOpened.listen( this::increaseLoot ) - .addCondition( CustomConditions.has( this.item, data->( LivingEntity )data.entity ) ) + .addCondition( CustomConditions.hasAccessory( this.item, data->( LivingEntity )data.entity ) ) .addConfig( this.sizeMultiplier ) .insertTo( group ); diff --git a/src/main/java/com/majruszsaccessories/components/ReduceDamageDealt.java b/src/main/java/com/majruszsaccessories/accessories/components/ReduceDamageDealt.java similarity index 84% rename from src/main/java/com/majruszsaccessories/components/ReduceDamageDealt.java rename to src/main/java/com/majruszsaccessories/accessories/components/ReduceDamageDealt.java index 05f08dda..ce199a7a 100644 --- a/src/main/java/com/majruszsaccessories/components/ReduceDamageDealt.java +++ b/src/main/java/com/majruszsaccessories/accessories/components/ReduceDamageDealt.java @@ -1,9 +1,9 @@ -package com.majruszsaccessories.components; +package com.majruszsaccessories.accessories.components; import com.majruszsaccessories.AccessoryHolder; -import com.majruszsaccessories.accessories.tooltip.TooltipHelper; +import com.majruszsaccessories.accessories.AccessoryItem; import com.majruszsaccessories.gamemodifiers.CustomConditions; -import com.majruszsaccessories.items.AccessoryItem; +import com.majruszsaccessories.tooltip.TooltipHelper; import com.mlib.config.ConfigGroup; import com.mlib.config.DoubleConfig; import com.mlib.gamemodifiers.contexts.OnDamaged; @@ -28,7 +28,7 @@ protected ReduceDamageDealt( Supplier< AccessoryItem > item, ConfigGroup group, this.penalty = new DoubleConfig( penalty, new Range<>( 0.01, 0.99 ) ); OnDamaged.listen( this::reduceDamage ) - .addCondition( CustomConditions.has( item, data->data.attacker ) ) + .addCondition( CustomConditions.hasAccessory( item, data->data.attacker ) ) .addConfig( this.penalty.name( "damage_dealt_penalty" ).comment( "Ratio of damage ignored when attacking." ) ) .insertTo( group ); diff --git a/src/main/java/com/majruszsaccessories/components/ReduceDamageReceived.java b/src/main/java/com/majruszsaccessories/accessories/components/ReduceDamageReceived.java similarity index 84% rename from src/main/java/com/majruszsaccessories/components/ReduceDamageReceived.java rename to src/main/java/com/majruszsaccessories/accessories/components/ReduceDamageReceived.java index 7f344cb3..75b68df1 100644 --- a/src/main/java/com/majruszsaccessories/components/ReduceDamageReceived.java +++ b/src/main/java/com/majruszsaccessories/accessories/components/ReduceDamageReceived.java @@ -1,9 +1,9 @@ -package com.majruszsaccessories.components; +package com.majruszsaccessories.accessories.components; import com.majruszsaccessories.AccessoryHolder; -import com.majruszsaccessories.accessories.tooltip.TooltipHelper; +import com.majruszsaccessories.accessories.AccessoryItem; import com.majruszsaccessories.gamemodifiers.CustomConditions; -import com.majruszsaccessories.items.AccessoryItem; +import com.majruszsaccessories.tooltip.TooltipHelper; import com.mlib.config.ConfigGroup; import com.mlib.config.DoubleConfig; import com.mlib.gamemodifiers.contexts.OnDamaged; @@ -28,7 +28,7 @@ protected ReduceDamageReceived( Supplier< AccessoryItem > item, ConfigGroup grou this.reduction = new DoubleConfig( reduction, new Range<>( 0.01, 0.99 ) ); OnDamaged.listen( this::reduceDamage ) - .addCondition( CustomConditions.has( item, data->data.target ) ) + .addCondition( CustomConditions.hasAccessory( item, data->data.target ) ) .addConfig( this.reduction.name( "damage_received_reduction" ).comment( "Ratio of damage ignored while being attacked." ) ) .insertTo( group ); diff --git a/src/main/java/com/majruszsaccessories/components/SpawnTwins.java b/src/main/java/com/majruszsaccessories/accessories/components/SpawnTwins.java similarity index 93% rename from src/main/java/com/majruszsaccessories/components/SpawnTwins.java rename to src/main/java/com/majruszsaccessories/accessories/components/SpawnTwins.java index 8df1ff7d..8f8e3965 100644 --- a/src/main/java/com/majruszsaccessories/components/SpawnTwins.java +++ b/src/main/java/com/majruszsaccessories/accessories/components/SpawnTwins.java @@ -1,8 +1,8 @@ -package com.majruszsaccessories.components; +package com.majruszsaccessories.accessories.components; -import com.majruszsaccessories.accessories.tooltip.TooltipHelper; +import com.majruszsaccessories.accessories.AccessoryItem; import com.majruszsaccessories.gamemodifiers.CustomConditions; -import com.majruszsaccessories.items.AccessoryItem; +import com.majruszsaccessories.tooltip.TooltipHelper; import com.mlib.config.ConfigGroup; import com.mlib.config.DoubleConfig; import com.mlib.effects.ParticleHandler; diff --git a/src/main/java/com/majruszsaccessories/components/TradeOffer.java b/src/main/java/com/majruszsaccessories/accessories/components/TradeOffer.java similarity index 68% rename from src/main/java/com/majruszsaccessories/components/TradeOffer.java rename to src/main/java/com/majruszsaccessories/accessories/components/TradeOffer.java index 694af695..d81387e5 100644 --- a/src/main/java/com/majruszsaccessories/components/TradeOffer.java +++ b/src/main/java/com/majruszsaccessories/accessories/components/TradeOffer.java @@ -1,10 +1,13 @@ -package com.majruszsaccessories.components; +package com.majruszsaccessories.accessories.components; -import com.majruszsaccessories.items.AccessoryItem; +import com.majruszsaccessories.accessories.AccessoryItem; import com.mlib.config.ConfigGroup; import com.mlib.config.IntegerConfig; import com.mlib.math.Range; import net.minecraft.world.entity.npc.VillagerProfession; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.world.item.trading.MerchantOffer; import java.util.function.Supplier; @@ -31,6 +34,15 @@ protected TradeOffer( Supplier< AccessoryItem > item, ConfigGroup group, Village group.addConfig( this.price.name( "trade_price" ).comment( "Price the villager will pay for this accessory." ).requiresWorldRestart( true ) ); } + public MerchantOffer toMerchantOffer() { + return new MerchantOffer( new ItemStack( this.getItem(), 1 ), new ItemStack( Items.EMERALD, this.getPrice() ), 2, 40, 0.05f ) { + @Override + public boolean satisfiedBy( ItemStack itemStack1, ItemStack itemStack2 ) { + return itemStack1.is( TradeOffer.this.getItem() ) && itemStack2.isEmpty(); + } + }; + } + public VillagerProfession getProfession() { return this.profession; } diff --git a/src/main/java/com/majruszsaccessories/boosters/BoosterBase.java b/src/main/java/com/majruszsaccessories/boosters/BoosterBase.java new file mode 100644 index 00000000..e6404cd3 --- /dev/null +++ b/src/main/java/com/majruszsaccessories/boosters/BoosterBase.java @@ -0,0 +1,53 @@ +package com.majruszsaccessories.boosters; + +import com.majruszsaccessories.AccessoryHolder; +import com.majruszsaccessories.Registries; +import com.majruszsaccessories.boosters.components.BoosterComponent; +import com.majruszsaccessories.common.ComponentBase; +import com.majruszsaccessories.common.ItemBase; +import com.majruszsaccessories.gamemodifiers.contexts.OnAccessoryTooltip; +import com.majruszsaccessories.gamemodifiers.contexts.OnBoosterTooltip; +import com.majruszsaccessories.gamemodifiers.contexts.OnItemRender; +import com.mlib.gamemodifiers.Condition; +import net.minecraft.ChatFormatting; +import net.minecraft.client.gui.Font; +import net.minecraft.network.chat.Component; +import net.minecraft.world.item.ItemStack; +import net.minecraftforge.client.IItemDecorator; +import net.minecraftforge.registries.RegistryObject; + +import java.util.List; + +public class BoosterBase extends ItemBase< BoosterItem, BoosterComponent, BoosterComponent.ISupplier > { + public BoosterBase( RegistryObject< BoosterItem > item ) { + super( item, Registries.Groups.BOOSTERS ); + + OnAccessoryTooltip.listen( this::addTooltip ) + .addCondition( Condition.predicate( data->data.holder.hasBoosterTag( item.get() ) ) ) + .insertTo( this.group ); + + OnBoosterTooltip.listen( this::addBoosterTooltip ) + .addCondition( Condition.predicate( data->data.item.equals( item.get() ) ) ) + .insertTo( this.group ); + + OnItemRender.listen( this::addBoosterIcon ); + } + + private void addBoosterTooltip( OnBoosterTooltip.Data data ) { + this.components.stream() + .map( ComponentBase::getTooltipProviders ) + .flatMap( List::stream ) + .map( provider->provider.getTooltip( AccessoryHolder.create( ItemStack.EMPTY ) ) ) + .map( component->( Component )component.withStyle( ChatFormatting.GRAY ) ) + .forEach( data.components::add ); + } + + private void addBoosterIcon( OnItemRender.Data data ) { + data.addDecoration( this.item, new IItemDecorator() { + @Override + public boolean render( Font font, ItemStack itemStack, int xOffset, int yOffset, float blitOffset ) { + return BoosterBase.this.renderBoosterIcon( xOffset, yOffset, blitOffset ); + } + } ); + } +} diff --git a/src/main/java/com/majruszsaccessories/boosters/BoosterItem.java b/src/main/java/com/majruszsaccessories/boosters/BoosterItem.java new file mode 100644 index 00000000..ebe87301 --- /dev/null +++ b/src/main/java/com/majruszsaccessories/boosters/BoosterItem.java @@ -0,0 +1,35 @@ +package com.majruszsaccessories.boosters; + +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Rarity; + +import java.util.function.Supplier; + +public class BoosterItem extends Item { + final Rarity rarity; + + public static Supplier< BoosterItem > basic() { + return ()->new BoosterItem( Rarity.UNCOMMON ); + } + + public static Supplier< BoosterItem > rare() { + return ()->new BoosterItem( Rarity.RARE ); + } + + private BoosterItem( Rarity rarity ) { + super( new Properties().stacksTo( 1 ) ); + + this.rarity = rarity; + } + + @Override + public boolean isFoil( ItemStack itemStack ) { + return true; + } + + @Override + public Rarity getRarity( ItemStack itemStack ) { + return this.rarity; + } +} \ No newline at end of file diff --git a/src/main/java/com/majruszsaccessories/boosters/Dice.java b/src/main/java/com/majruszsaccessories/boosters/Dice.java new file mode 100644 index 00000000..f1d5df77 --- /dev/null +++ b/src/main/java/com/majruszsaccessories/boosters/Dice.java @@ -0,0 +1,45 @@ +package com.majruszsaccessories.boosters; + +import com.majruszsaccessories.Registries; +import com.majruszsaccessories.boosters.components.AccessoryDropChance; +import com.majruszsaccessories.boosters.components.BoosterComponent; +import com.mlib.annotations.AutoInstance; +import com.mlib.config.ConfigGroup; +import com.mlib.config.DoubleConfig; +import com.mlib.gamemodifiers.Condition; +import com.mlib.gamemodifiers.contexts.OnLoot; +import com.mlib.math.Range; +import net.minecraft.world.entity.monster.Guardian; + +import java.util.function.Supplier; + +@AutoInstance +public class Dice extends BoosterBase { + public Dice() { + super( Registries.DICE ); + + this.name( "Dice" ) + .add( AccessoryDropChance.create( 0.2 ) ) + .add( DropChance.create() ); + } + + static class DropChance extends BoosterComponent { + public static ISupplier create() { + return DropChance::new; + } + + protected DropChance( Supplier< BoosterItem > item, ConfigGroup group ) { + super( item ); + + DoubleConfig chance = new DoubleConfig( 0.05, Range.CHANCE ); + chance.name( "drop_chance" ).comment( "Chance for Dice to drop from Guardian." ); + + OnLoot.listen( this::addToGeneratedLoot ) + .addCondition( Condition.isServer() ) + .addCondition( Condition.chance( chance ) ) + .addCondition( OnLoot.hasLastDamagePlayer() ) + .addCondition( Condition.predicate( data->data.entity instanceof Guardian ) ) + .insertTo( group ); + } + } +} diff --git a/src/main/java/com/majruszsaccessories/boosters/GoldenDice.java b/src/main/java/com/majruszsaccessories/boosters/GoldenDice.java new file mode 100644 index 00000000..429132e6 --- /dev/null +++ b/src/main/java/com/majruszsaccessories/boosters/GoldenDice.java @@ -0,0 +1,15 @@ +package com.majruszsaccessories.boosters; + +import com.majruszsaccessories.Registries; +import com.majruszsaccessories.boosters.components.AccessoryDropChance; +import com.mlib.annotations.AutoInstance; + +@AutoInstance +public class GoldenDice extends BoosterBase { + public GoldenDice() { + super( Registries.GOLDEN_DICE ); + + this.name( "GoldenDice" ) + .add( AccessoryDropChance.create( 0.4 ) ); + } +} diff --git a/src/main/java/com/majruszsaccessories/boosters/GoldenHorseshoe.java b/src/main/java/com/majruszsaccessories/boosters/GoldenHorseshoe.java new file mode 100644 index 00000000..8b55a2f2 --- /dev/null +++ b/src/main/java/com/majruszsaccessories/boosters/GoldenHorseshoe.java @@ -0,0 +1,15 @@ +package com.majruszsaccessories.boosters; + +import com.majruszsaccessories.Registries; +import com.majruszsaccessories.boosters.components.LuckBonus; +import com.mlib.annotations.AutoInstance; + +@AutoInstance +public class GoldenHorseshoe extends BoosterBase { + public GoldenHorseshoe() { + super( Registries.GOLDEN_HORSESHOE ); + + this.name( "GoldenHorseshoe" ) + .add( LuckBonus.create( 2 ) ); + } +} diff --git a/src/main/java/com/majruszsaccessories/boosters/Horseshoe.java b/src/main/java/com/majruszsaccessories/boosters/Horseshoe.java new file mode 100644 index 00000000..5a4029b7 --- /dev/null +++ b/src/main/java/com/majruszsaccessories/boosters/Horseshoe.java @@ -0,0 +1,46 @@ +package com.majruszsaccessories.boosters; + +import com.majruszsaccessories.Registries; +import com.majruszsaccessories.boosters.components.BoosterComponent; +import com.majruszsaccessories.boosters.components.LuckBonus; +import com.mlib.annotations.AutoInstance; +import com.mlib.config.ConfigGroup; +import com.mlib.config.DoubleConfig; +import com.mlib.gamemodifiers.Condition; +import com.mlib.gamemodifiers.contexts.OnLoot; +import com.mlib.math.Range; +import net.minecraft.world.entity.animal.horse.SkeletonHorse; +import net.minecraft.world.entity.monster.Skeleton; + +import java.util.function.Supplier; + +@AutoInstance +public class Horseshoe extends BoosterBase { + public Horseshoe() { + super( Registries.HORSESHOE ); + + this.name( "Horseshoe" ) + .add( LuckBonus.create( 1 ) ) + .add( DropChance.create() ); + } + + static class DropChance extends BoosterComponent { + public static ISupplier create() { + return DropChance::new; + } + + protected DropChance( Supplier< BoosterItem > item, ConfigGroup group ) { + super( item ); + + DoubleConfig chance = new DoubleConfig( 0.334, Range.CHANCE ); + chance.name( "drop_chance" ).comment( "Chance for Horseshoe to drop from Skeleton Horseman." ); + + OnLoot.listen( this::addToGeneratedLoot ) + .addCondition( Condition.isServer() ) + .addCondition( Condition.chance( chance ) ) + .addCondition( OnLoot.hasLastDamagePlayer() ) + .addCondition( Condition.predicate( data->data.entity instanceof Skeleton skeleton && skeleton.getRootVehicle() instanceof SkeletonHorse ) ) + .insertTo( group ); + } + } +} diff --git a/src/main/java/com/majruszsaccessories/boosters/OwlFeather.java b/src/main/java/com/majruszsaccessories/boosters/OwlFeather.java new file mode 100644 index 00000000..12bab677 --- /dev/null +++ b/src/main/java/com/majruszsaccessories/boosters/OwlFeather.java @@ -0,0 +1,45 @@ +package com.majruszsaccessories.boosters; + +import com.majruszsaccessories.Registries; +import com.majruszsaccessories.boosters.components.BoosterComponent; +import com.majruszsaccessories.boosters.components.ExperienceBonus; +import com.mlib.annotations.AutoInstance; +import com.mlib.config.ConfigGroup; +import com.mlib.config.DoubleConfig; +import com.mlib.gamemodifiers.Condition; +import com.mlib.gamemodifiers.contexts.OnLoot; +import com.mlib.math.Range; +import net.minecraft.world.entity.monster.Vex; + +import java.util.function.Supplier; + +@AutoInstance +public class OwlFeather extends BoosterBase { + public OwlFeather() { + super( Registries.OWL_FEATHER ); + + this.name( "OwlFeather" ) + .add( ExperienceBonus.create( 0.15 ) ) + .add( DropChance.create() ); + } + + static class DropChance extends BoosterComponent { + public static ISupplier create() { + return DropChance::new; + } + + protected DropChance( Supplier< BoosterItem > item, ConfigGroup group ) { + super( item ); + + DoubleConfig chance = new DoubleConfig( 0.1, Range.CHANCE ); + chance.name( "drop_chance" ).comment( "Chance for Owl Feather to drop from Vex." ); + + OnLoot.listen( this::addToGeneratedLoot ) + .addCondition( Condition.isServer() ) + .addCondition( Condition.chance( chance ) ) + .addCondition( OnLoot.hasLastDamagePlayer() ) + .addCondition( Condition.predicate( data->data.entity instanceof Vex ) ) + .insertTo( group ); + } + } +} diff --git a/src/main/java/com/majruszsaccessories/boosters/components/AccessoryDropChance.java b/src/main/java/com/majruszsaccessories/boosters/components/AccessoryDropChance.java new file mode 100644 index 00000000..1d69bf9a --- /dev/null +++ b/src/main/java/com/majruszsaccessories/boosters/components/AccessoryDropChance.java @@ -0,0 +1,36 @@ +package com.majruszsaccessories.boosters.components; + +import com.majruszsaccessories.boosters.BoosterItem; +import com.majruszsaccessories.gamemodifiers.CustomConditions; +import com.majruszsaccessories.gamemodifiers.contexts.OnAccessoryDropChance; +import com.majruszsaccessories.tooltip.TooltipHelper; +import com.mlib.config.ConfigGroup; +import com.mlib.config.DoubleConfig; +import com.mlib.math.Range; + +import java.util.function.Supplier; + +public class AccessoryDropChance extends BoosterComponent { + final DoubleConfig chanceExtraMultiplier; + + public static ISupplier create( double chance ) { + return ( item, group )->new AccessoryDropChance( item, group, chance ); + } + + protected AccessoryDropChance( Supplier< BoosterItem > item, ConfigGroup group, double extraChanceMultiplier ) { + super( item ); + + this.chanceExtraMultiplier = new DoubleConfig( extraChanceMultiplier, new Range<>( 0.01, 10.0 ) ); + + OnAccessoryDropChance.listen( this::increaseChance ) + .addCondition( CustomConditions.hasBooster( item, data->data.player ) ) + .addConfig( this.chanceExtraMultiplier.name( "extra_chance_multiplier" ).comment( "Extra chance multiplier to drop accessories." ) ) + .insertTo( group ); + + this.addTooltip( "majruszsaccessories.boosters.drop_chance", TooltipHelper.asItem( item ), TooltipHelper.asFixedPercent( this.chanceExtraMultiplier ) ); + } + + private void increaseChance( OnAccessoryDropChance.Data data ) { + data.chance *= 1.0 + this.chanceExtraMultiplier.get(); + } +} diff --git a/src/main/java/com/majruszsaccessories/boosters/components/BoosterComponent.java b/src/main/java/com/majruszsaccessories/boosters/components/BoosterComponent.java new file mode 100644 index 00000000..8809b6ee --- /dev/null +++ b/src/main/java/com/majruszsaccessories/boosters/components/BoosterComponent.java @@ -0,0 +1,17 @@ +package com.majruszsaccessories.boosters.components; + +import com.majruszsaccessories.boosters.BoosterItem; +import com.majruszsaccessories.common.ComponentBase; +import com.mlib.config.ConfigGroup; + +import java.util.function.BiFunction; +import java.util.function.Supplier; + +public class BoosterComponent extends ComponentBase< BoosterItem > { + public BoosterComponent( Supplier< BoosterItem > item ) { + super( item ); + } + + @FunctionalInterface + public interface ISupplier extends BiFunction< Supplier< BoosterItem >, ConfigGroup, BoosterComponent > {} +} diff --git a/src/main/java/com/majruszsaccessories/boosters/components/ExperienceBonus.java b/src/main/java/com/majruszsaccessories/boosters/components/ExperienceBonus.java new file mode 100644 index 00000000..460245df --- /dev/null +++ b/src/main/java/com/majruszsaccessories/boosters/components/ExperienceBonus.java @@ -0,0 +1,44 @@ +package com.majruszsaccessories.boosters.components; + +import com.majruszsaccessories.AccessoryHolder; +import com.majruszsaccessories.boosters.BoosterItem; +import com.majruszsaccessories.gamemodifiers.CustomConditions; +import com.majruszsaccessories.tooltip.TooltipHelper; +import com.mlib.Random; +import com.mlib.config.ConfigGroup; +import com.mlib.config.DoubleConfig; +import com.mlib.gamemodifiers.contexts.OnPickupXp; +import com.mlib.math.Range; + +import java.util.function.Supplier; + +public class ExperienceBonus extends BoosterComponent { + final DoubleConfig experienceExtraMultiplier; + + public static ISupplier create( double chance ) { + return ( item, group )->new ExperienceBonus( item, group, chance ); + } + + protected ExperienceBonus( Supplier< BoosterItem > item, ConfigGroup group, double experienceExtraMultiplier ) { + super( item ); + + this.experienceExtraMultiplier = new DoubleConfig( experienceExtraMultiplier, new Range<>( 0.01, 10.0 ) ); + + OnPickupXp.listen( this::increaseExperience ) + .addCondition( CustomConditions.hasBooster( item, data->data.player ) ) + .addConfig( this.experienceExtraMultiplier.name( "experience_extra_multiplier" ).comment( "Extra experience multiplier from all sources." ) ) + .insertTo( group ); + + this.addTooltip( "majruszsaccessories.boosters.experience_bonus", TooltipHelper.asItem( item ), TooltipHelper.asFixedPercent( this.experienceExtraMultiplier ) ); + } + + private void increaseExperience( OnPickupXp.Data data ) { + AccessoryHolder holder = AccessoryHolder.find( data.player, this.item.get() ); + if( holder.isValid() ) { + int experiencePoints = Random.roundRandomly( this.experienceExtraMultiplier.get() * data.event.getOrb().getValue() ); + if( experiencePoints > 0 ) { + data.player.giveExperiencePoints( experiencePoints ); + } + } + } +} diff --git a/src/main/java/com/majruszsaccessories/boosters/components/LuckBonus.java b/src/main/java/com/majruszsaccessories/boosters/components/LuckBonus.java new file mode 100644 index 00000000..174f6a61 --- /dev/null +++ b/src/main/java/com/majruszsaccessories/boosters/components/LuckBonus.java @@ -0,0 +1,45 @@ +package com.majruszsaccessories.boosters.components; + +import com.majruszsaccessories.AccessoryHolder; +import com.majruszsaccessories.boosters.BoosterItem; +import com.majruszsaccessories.tooltip.TooltipHelper; +import com.mlib.attributes.AttributeHandler; +import com.mlib.config.ConfigGroup; +import com.mlib.config.IntegerConfig; +import com.mlib.gamemodifiers.Condition; +import com.mlib.gamemodifiers.contexts.OnPlayerTick; +import com.mlib.math.Range; +import net.minecraft.world.entity.ai.attributes.AttributeModifier; +import net.minecraft.world.entity.ai.attributes.Attributes; +import net.minecraftforge.api.distmarker.Dist; + +import java.util.function.Supplier; + +public class LuckBonus extends BoosterComponent { + static final AttributeHandler LUCK_ATTRIBUTE = new AttributeHandler( "ad04ffd5-fb72-4e53-83e7-a388bd7e1e1f", "HorseshoeLuckBonus", Attributes.LUCK, AttributeModifier.Operation.ADDITION ); + final IntegerConfig luckBonus; + + public static ISupplier create( int luck ) { + return ( item, group )->new LuckBonus( item, group, luck ); + } + + protected LuckBonus( Supplier< BoosterItem > item, ConfigGroup group, int luck ) { + super( item ); + + this.luckBonus = new IntegerConfig( luck, new Range<>( 1, 10 ) ); + + OnPlayerTick.listen( this::updateLuck ) + .addCondition( Condition.< OnPlayerTick.Data > cooldown( 4, Dist.DEDICATED_SERVER ).configurable( false ) ) + .addConfig( this.luckBonus.name( "luck" ).comment( "Extra luck bonus." ) ) + .insertTo( group ); + + this.addTooltip( "majruszsaccessories.boosters.luck_bonus", TooltipHelper.asItem( item ), TooltipHelper.asFixedValue( this.luckBonus ) ); + } + + private void updateLuck( OnPlayerTick.Data data ) { + AccessoryHolder holder = AccessoryHolder.find( data.player, this.item.get() ); + int luck = holder.isValid() ? holder.apply( this.luckBonus ) : 0; + + LUCK_ATTRIBUTE.setValue( luck ).apply( data.player ); + } +} diff --git a/src/main/java/com/majruszsaccessories/components/AccessoryComponent.java b/src/main/java/com/majruszsaccessories/common/ComponentBase.java similarity index 57% rename from src/main/java/com/majruszsaccessories/components/AccessoryComponent.java rename to src/main/java/com/majruszsaccessories/common/ComponentBase.java index 143aaad9..abd989a5 100644 --- a/src/main/java/com/majruszsaccessories/components/AccessoryComponent.java +++ b/src/main/java/com/majruszsaccessories/common/ComponentBase.java @@ -1,16 +1,12 @@ -package com.majruszsaccessories.components; +package com.majruszsaccessories.common; import com.majruszsaccessories.AccessoryHolder; -import com.majruszsaccessories.accessories.tooltip.ITooltipProvider; -import com.majruszsaccessories.items.AccessoryItem; -import com.mlib.config.ConfigGroup; +import com.majruszsaccessories.tooltip.ITooltipProvider; import com.mlib.gamemodifiers.contexts.OnLoot; -import com.mlib.levels.LevelHelper; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.MutableComponent; +import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.Level; -import net.minecraft.world.phys.Vec3; import java.util.ArrayList; import java.util.Collections; @@ -18,15 +14,15 @@ import java.util.function.Supplier; import java.util.stream.Stream; -public class AccessoryComponent { - protected final Supplier< AccessoryItem > item; +public class ComponentBase< ItemType extends Item > { + protected final Supplier< ItemType > item; final List< ITooltipProvider > tooltipProviders = new ArrayList<>(); - public AccessoryComponent( Supplier< AccessoryItem > item ) { + public ComponentBase( Supplier< ItemType > item ) { this.item = item; } - public AccessoryComponent addTooltip( String key, ITooltipProvider... providers ) { + public ComponentBase< ItemType > addTooltip( String key, ITooltipProvider... providers ) { this.tooltipProviders.add( new ITooltipProvider() { @Override public MutableComponent getTooltip( AccessoryHolder holder ) { @@ -50,16 +46,7 @@ protected void addToGeneratedLoot( OnLoot.Data data ) { data.generatedLoot.add( this.constructItemStack() ); } - protected void spawnFlyingItem( Level level, Vec3 from, Vec3 to ) { - LevelHelper.spawnItemEntityFlyingTowardsDirection( this.constructItemStack(), level, from, to ); - } - protected ItemStack constructItemStack() { - return AccessoryHolder.create( this.item.get() ).setRandomBonus().getItemStack(); - } - - @FunctionalInterface - public interface ISupplier { - AccessoryComponent accept( Supplier< AccessoryItem > item, ConfigGroup group ); + return new ItemStack( this.item.get() ); } } diff --git a/src/main/java/com/majruszsaccessories/common/ItemBase.java b/src/main/java/com/majruszsaccessories/common/ItemBase.java new file mode 100644 index 00000000..497b0f48 --- /dev/null +++ b/src/main/java/com/majruszsaccessories/common/ItemBase.java @@ -0,0 +1,71 @@ +package com.majruszsaccessories.common; + +import com.majruszsaccessories.Registries; +import com.majruszsaccessories.gamemodifiers.contexts.OnAccessoryTooltip; +import com.mlib.client.ClientHelper; +import com.mlib.config.ConfigGroup; +import com.mlib.gamemodifiers.ModConfigs; +import net.minecraft.ChatFormatting; +import net.minecraft.client.Minecraft; +import net.minecraft.network.chat.Component; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.fml.DistExecutor; +import net.minecraftforge.registries.RegistryObject; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.function.BiFunction; +import java.util.function.Supplier; + +public class ItemBase< ItemType extends Item, ComponentType extends ComponentBase< ItemType >, SupplierType extends BiFunction< Supplier< ItemType >, ConfigGroup, ComponentType > > { + protected final List< ComponentType > components = new ArrayList<>(); + protected final Supplier< ItemType > item; + protected final ConfigGroup group; + + public ItemBase( RegistryObject< ItemType > item, String groupId ) { + this.item = item; + this.group = ModConfigs.init( groupId, item.getId().toString() ); + } + + public ItemBase< ItemType, ComponentType, SupplierType > name( String name ) { + this.group.name( name ); + + return this; + } + + public ItemBase< ItemType, ComponentType, SupplierType > add( SupplierType supplier ) { + this.components.add( supplier.apply( this.item, this.group ) ); + + return this; + } + + public List< ComponentType > getComponents() { + return Collections.unmodifiableList( this.components ); + } + + public Supplier< ItemType > getItem() { + return this.item; + } + + protected void addTooltip( OnAccessoryTooltip.Data data ) { + this.components.stream() + .map( ComponentBase::getTooltipProviders ) + .flatMap( List::stream ) + .map( provider->ClientHelper.isShiftDown() ? provider.getDetailedTooltip( data.holder ) : provider.getTooltip( data.holder ) ) + .map( component->( Component )component.withStyle( ChatFormatting.GRAY ) ) + .forEach( data.components::add ); + } + + protected boolean renderBoosterIcon( int xOffset, int yOffset, float blitOffset ) { + return DistExecutor.unsafeCallWhenOn( Dist.CLIENT, ()->()->{ + Minecraft.getInstance() + .getItemRenderer() + .renderAndDecorateItem( new ItemStack( Registries.BOOSTER_OVERLAY.get() ), xOffset, yOffset, 0, 111 ); + + return true; + } ); + } +} diff --git a/src/main/java/com/majruszsaccessories/gamemodifiers/CustomConditions.java b/src/main/java/com/majruszsaccessories/gamemodifiers/CustomConditions.java index b667dece..3b092467 100644 --- a/src/main/java/com/majruszsaccessories/gamemodifiers/CustomConditions.java +++ b/src/main/java/com/majruszsaccessories/gamemodifiers/CustomConditions.java @@ -1,19 +1,28 @@ package com.majruszsaccessories.gamemodifiers; import com.majruszsaccessories.AccessoryHolder; -import com.majruszsaccessories.items.AccessoryItem; +import com.majruszsaccessories.accessories.AccessoryItem; +import com.majruszsaccessories.boosters.BoosterItem; +import com.majruszsaccessories.gamemodifiers.contexts.OnAccessoryDropChance; import com.mlib.Random; +import com.mlib.config.DoubleConfig; import com.mlib.gamemodifiers.Condition; +import com.mlib.gamemodifiers.Priority; +import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.LivingEntity; import java.util.function.Function; import java.util.function.Supplier; public class CustomConditions { - public static < DataType > Condition< DataType > has( Supplier< AccessoryItem > item, Function< DataType, LivingEntity > entity ) { + public static < DataType > Condition< DataType > hasAccessory( Supplier< AccessoryItem > item, Function< DataType, LivingEntity > entity ) { return Condition.predicate( data->entity.apply( data ) != null && AccessoryHolder.hasAccessory( entity.apply( data ), item.get() ) ); } + public static < DataType > Condition< DataType > hasBooster( Supplier< BoosterItem > item, Function< DataType, LivingEntity > entity ) { + return Condition.predicate( data->entity.apply( data ) != null && AccessoryHolder.hasBooster( entity.apply( data ), item.get() ) ); + } + public static < DataType > Condition< DataType > chance( Supplier< AccessoryItem > item, Function< DataType, LivingEntity > entity, Function< AccessoryHolder, Float > chance ) { @@ -23,4 +32,12 @@ public static < DataType > Condition< DataType > chance( Supplier< AccessoryItem return holder.isValid() && Random.tryChance( chance.apply( holder ) ); } ); } + + public static < DataType > Condition< DataType > dropChance( DoubleConfig chance, Function< DataType, Entity > entity ) { + return Condition.< DataType > predicate( data->Random.tryChance( OnAccessoryDropChance.dispatch( chance.getOrDefault(), entity.apply( data ) ) + .getChance() ) ) + .priority( Priority.HIGH ) + .configurable( true ) + .addConfig( chance ); + } } diff --git a/src/main/java/com/majruszsaccessories/gamemodifiers/contexts/OnAccessoryDropChance.java b/src/main/java/com/majruszsaccessories/gamemodifiers/contexts/OnAccessoryDropChance.java new file mode 100644 index 00000000..5e6df285 --- /dev/null +++ b/src/main/java/com/majruszsaccessories/gamemodifiers/contexts/OnAccessoryDropChance.java @@ -0,0 +1,36 @@ +package com.majruszsaccessories.gamemodifiers.contexts; + +import com.mlib.gamemodifiers.Context; +import com.mlib.gamemodifiers.Contexts; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; + +import javax.annotation.Nullable; +import java.util.function.Consumer; + +public class OnAccessoryDropChance { + public static Context< Data > listen( Consumer< Data > consumer ) { + return Contexts.get( Data.class ).add( consumer ); + } + + public static Data dispatch( double chance, @Nullable Entity entity ) { + return Contexts.get( Data.class ).dispatch( new Data( chance, entity ) ); + } + + public static class Data { + public final double original; + public double chance; + @Nullable + public final Player player; + + public Data( double chance, @Nullable Entity entity ) { + this.original = this.chance = chance; + this.player = entity instanceof Player player ? player : null; + } + + public double getChance() { + return Mth.clamp( this.chance, 0.0, 1.0 ); + } + } +} diff --git a/src/main/java/com/majruszsaccessories/gamemodifiers/contexts/OnAccessoryTooltip.java b/src/main/java/com/majruszsaccessories/gamemodifiers/contexts/OnAccessoryTooltip.java new file mode 100644 index 00000000..0686b434 --- /dev/null +++ b/src/main/java/com/majruszsaccessories/gamemodifiers/contexts/OnAccessoryTooltip.java @@ -0,0 +1,30 @@ +package com.majruszsaccessories.gamemodifiers.contexts; + +import com.majruszsaccessories.AccessoryHolder; +import com.mlib.gamemodifiers.Context; +import com.mlib.gamemodifiers.Contexts; +import net.minecraft.network.chat.Component; +import net.minecraft.world.item.ItemStack; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; + +public class OnAccessoryTooltip { + public static Context< Data > listen( Consumer< Data > consumer ) { + return Contexts.get( Data.class ).add( consumer ); + } + + public static Data dispatch( ItemStack itemStack ) { + return Contexts.get( Data.class ).dispatch( new Data( itemStack ) ); + } + + public static class Data { + public final List< Component > components = new ArrayList<>(); + public final AccessoryHolder holder; + + public Data( ItemStack itemStack ) { + this.holder = AccessoryHolder.create( itemStack ); + } + } +} diff --git a/src/main/java/com/majruszsaccessories/gamemodifiers/contexts/OnBoosterTooltip.java b/src/main/java/com/majruszsaccessories/gamemodifiers/contexts/OnBoosterTooltip.java new file mode 100644 index 00000000..4426dbb7 --- /dev/null +++ b/src/main/java/com/majruszsaccessories/gamemodifiers/contexts/OnBoosterTooltip.java @@ -0,0 +1,29 @@ +package com.majruszsaccessories.gamemodifiers.contexts; + +import com.majruszsaccessories.boosters.BoosterItem; +import com.mlib.gamemodifiers.Context; +import com.mlib.gamemodifiers.Contexts; +import net.minecraft.network.chat.Component; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; + +public class OnBoosterTooltip { + public static Context< Data > listen( Consumer< Data > consumer ) { + return Contexts.get( Data.class ).add( consumer ); + } + + public static Data dispatch( BoosterItem item ) { + return Contexts.get( Data.class ).dispatch( new Data( item ) ); + } + + public static class Data { + public final List< Component > components = new ArrayList<>(); + public final BoosterItem item; + + public Data( BoosterItem item ) { + this.item = item; + } + } +} diff --git a/src/main/java/com/majruszsaccessories/gamemodifiers/contexts/OnItemRender.java b/src/main/java/com/majruszsaccessories/gamemodifiers/contexts/OnItemRender.java new file mode 100644 index 00000000..f844d842 --- /dev/null +++ b/src/main/java/com/majruszsaccessories/gamemodifiers/contexts/OnItemRender.java @@ -0,0 +1,41 @@ +package com.majruszsaccessories.gamemodifiers.contexts; + +import com.mlib.gamemodifiers.Context; +import com.mlib.gamemodifiers.Contexts; +import net.minecraft.world.item.Item; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.client.IItemDecorator; +import net.minecraftforge.client.event.RegisterItemDecorationsEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; + +import java.util.function.Consumer; +import java.util.function.Supplier; + +@Mod.EventBusSubscriber( value = Dist.CLIENT, bus = Mod.EventBusSubscriber.Bus.MOD ) +public class OnItemRender { + public static Context< Data > listen( Consumer< Data > consumer ) { + return Contexts.get( Data.class ).add( consumer ); + } + + public static Data dispatch( RegisterItemDecorationsEvent item ) { + return Contexts.get( Data.class ).dispatch( new Data( item ) ); + } + + @SubscribeEvent + public static void onDecorator( RegisterItemDecorationsEvent event ) { + OnItemRender.dispatch( event ); + } + + public static class Data { + private final RegisterItemDecorationsEvent event; + + public Data( RegisterItemDecorationsEvent event ) { + this.event = event; + } + + public < Type extends Item > void addDecoration( Supplier< Type > item, IItemDecorator decorator ) { + this.event.register( item.get(), decorator ); + } + } +} diff --git a/src/main/java/com/majruszsaccessories/gamemodifiers/list/TooltipUpdater.java b/src/main/java/com/majruszsaccessories/gamemodifiers/list/AccessoryTooltipUpdater.java similarity index 86% rename from src/main/java/com/majruszsaccessories/gamemodifiers/list/TooltipUpdater.java rename to src/main/java/com/majruszsaccessories/gamemodifiers/list/AccessoryTooltipUpdater.java index 87e52586..ec403e6b 100644 --- a/src/main/java/com/majruszsaccessories/gamemodifiers/list/TooltipUpdater.java +++ b/src/main/java/com/majruszsaccessories/gamemodifiers/list/AccessoryTooltipUpdater.java @@ -2,7 +2,8 @@ import com.majruszsaccessories.AccessoryHolder; import com.majruszsaccessories.Integration; -import com.majruszsaccessories.items.AccessoryItem; +import com.majruszsaccessories.accessories.AccessoryItem; +import com.majruszsaccessories.gamemodifiers.contexts.OnAccessoryTooltip; import com.mlib.Utility; import com.mlib.annotations.AutoInstance; import com.mlib.gamemodifiers.Condition; @@ -19,10 +20,10 @@ import java.util.List; @AutoInstance -public class TooltipUpdater { - static final int PAGE_SIZE = 4; +public class AccessoryTooltipUpdater { + static final int PAGE_SIZE = 7; - public TooltipUpdater() { + public AccessoryTooltipUpdater() { OnItemTooltip.listen( this::addTooltip ) .addCondition( Condition.predicate( data->data.itemStack.getItem() instanceof AccessoryItem ) ); } @@ -78,20 +79,18 @@ private ChatFormatting getUseFormatting( OnItemTooltip.Data data ) { } private List< Component > buildEffectsInfo( OnItemTooltip.Data data ) { - List< Component > components = new ArrayList<>(); - AccessoryHolder holder = AccessoryHolder.create( data.itemStack ); - holder.findAccessoryBase().ifPresent( base->components.addAll( base.buildTooltip( holder ) ) ); - boolean cannotFitSinglePage = components.size() > PAGE_SIZE; + OnAccessoryTooltip.Data tooltipData = OnAccessoryTooltip.dispatch( data.itemStack ); + boolean cannotFitSinglePage = tooltipData.components.size() > PAGE_SIZE; if( cannotFitSinglePage ) { - return this.convertToEffectsInfoPage( components ); + return this.convertToEffectsInfoPage( tooltipData.components ); } else { - return components; + return tooltipData.components; } } private List< Component > convertToEffectsInfoPage( List< Component > components ) { int totalPages = ( int )Math.ceil( ( double )components.size() / PAGE_SIZE ); - int currentPage = ( int )( Math.floor( ( double )TimeHelper.getClientTicks() / Utility.secondsToTicks( 7.5 ) ) % totalPages ); + int currentPage = ( int )( Math.floor( ( double )TimeHelper.getClientTicks() / Utility.secondsToTicks( PAGE_SIZE * 2 ) ) % totalPages ); List< Component > pageComponents = new ArrayList<>( components.subList( currentPage * PAGE_SIZE, Math.min( ( currentPage + 1 ) * PAGE_SIZE, components.size() ) ) ); pageComponents.add( Component.translatable( Tooltips.PAGE, currentPage + 1, totalPages ).withStyle( ChatFormatting.DARK_GRAY ) ); diff --git a/src/main/java/com/majruszsaccessories/gamemodifiers/list/BoosterDropper.java b/src/main/java/com/majruszsaccessories/gamemodifiers/list/BoosterDropper.java new file mode 100644 index 00000000..ea0b0302 --- /dev/null +++ b/src/main/java/com/majruszsaccessories/gamemodifiers/list/BoosterDropper.java @@ -0,0 +1,64 @@ +package com.majruszsaccessories.gamemodifiers.list; + +import com.majruszsaccessories.Registries; +import com.mlib.annotations.AutoInstance; +import com.mlib.blocks.BlockHelper; +import com.mlib.config.ConfigGroup; +import com.mlib.config.DoubleConfig; +import com.mlib.gamemodifiers.Condition; +import com.mlib.gamemodifiers.ModConfigs; +import com.mlib.gamemodifiers.contexts.OnLoot; +import com.mlib.levels.LevelHelper; +import com.mlib.loot.LootHelper; +import com.mlib.math.Range; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.RandomizableContainerBlockEntity; + +@AutoInstance +public class BoosterDropper { + static final ResourceLocation LOOT_TABLE = Registries.getLocation( "gameplay/nether_accessories" ); + + public BoosterDropper() { + ConfigGroup group = ModConfigs.getGroup( Registries.Groups.BOOSTERS ); + + DoubleConfig chestChance = new DoubleConfig( 0.1, Range.CHANCE ); + chestChance.name( "chest_chance" ).comment( "Chance for random booster to spawn in any Nether chest." ); + + OnLoot.listen( this::spawnBoosterInChest ) + .addCondition( Condition.isServer() ) + .addCondition( Condition.chance( chestChance ) ) + .addCondition( OnLoot.hasOrigin() ) + .addCondition( Condition.predicate( data->BlockHelper.getBlockEntity( data.getLevel(), data.origin ) instanceof RandomizableContainerBlockEntity ) ) + .addCondition( Condition.predicate( data->data.entity instanceof ServerPlayer ) ) + .addCondition( Condition.predicate( data->LevelHelper.isEntityIn( data.entity, Level.NETHER ) ) ) + .insertTo( group ); + + DoubleConfig mobChance = new DoubleConfig( 0.001, Range.CHANCE ); + mobChance.name( "mob_chance" ).comment( "Chance for random booster to drop from any Nether mob." ); + + OnLoot.listen( this::dropBoosterFromMonster ) + .addCondition( Condition.isServer() ) + .addCondition( Condition.chance( mobChance ) ) + .addCondition( OnLoot.hasEntity() ) + .addCondition( OnLoot.hasKiller() ) + .addCondition( Condition.predicate( data->LevelHelper.isEntityIn( data.killer, Level.NETHER ) ) ) + .insertTo( group ); + } + + private void spawnBoosterInChest( OnLoot.Data data ) { + this.addBooster( data, data.entity ); + } + + private void dropBoosterFromMonster( OnLoot.Data data ) { + this.addBooster( data, data.killer ); + } + + private void addBooster( OnLoot.Data data, Entity entity ) { + LootHelper.getLootTable( LOOT_TABLE ) + .getRandomItems( LootHelper.toGiftContext( entity ) ) + .forEach( data.generatedLoot::add ); + } +} diff --git a/src/main/java/com/majruszsaccessories/gamemodifiers/list/BoosterTooltipUpdater.java b/src/main/java/com/majruszsaccessories/gamemodifiers/list/BoosterTooltipUpdater.java new file mode 100644 index 00000000..351685a0 --- /dev/null +++ b/src/main/java/com/majruszsaccessories/gamemodifiers/list/BoosterTooltipUpdater.java @@ -0,0 +1,40 @@ +package com.majruszsaccessories.gamemodifiers.list; + +import com.majruszsaccessories.boosters.BoosterItem; +import com.majruszsaccessories.gamemodifiers.contexts.OnBoosterTooltip; +import com.mlib.annotations.AutoInstance; +import com.mlib.gamemodifiers.Condition; +import com.mlib.gamemodifiers.contexts.OnItemTooltip; +import net.minecraft.ChatFormatting; +import net.minecraft.network.chat.Component; + +import java.util.ArrayList; +import java.util.List; + +@AutoInstance +public class BoosterTooltipUpdater { + public BoosterTooltipUpdater() { + OnItemTooltip.listen( this::addTooltip ) + .addCondition( Condition.predicate( data->data.itemStack.getItem() instanceof BoosterItem ) ); + } + + private void addTooltip( OnItemTooltip.Data data ) { + List< Component > components = new ArrayList<>(); + components.addAll( this.buildGenericInfo() ); + components.addAll( this.buildEffectsInfo( data ) ); + + data.tooltip.addAll( 1, components ); + } + + private List< Component > buildGenericInfo() { + return List.of( Component.translatable( Tooltips.INFO ).withStyle( ChatFormatting.GOLD ) ); + } + + private List< Component > buildEffectsInfo( OnItemTooltip.Data data ) { + return OnBoosterTooltip.dispatch( ( BoosterItem )data.itemStack.getItem() ).components; + } + + static final class Tooltips { + static final String INFO = "majruszsaccessories.items.booster_tooltip"; + } +} diff --git a/src/main/java/com/majruszsaccessories/gamemodifiers/list/VillagerTradeUpdater.java b/src/main/java/com/majruszsaccessories/gamemodifiers/list/VillagerTradeUpdater.java deleted file mode 100644 index 0ad8b39a..00000000 --- a/src/main/java/com/majruszsaccessories/gamemodifiers/list/VillagerTradeUpdater.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.majruszsaccessories.gamemodifiers.list; - -import com.majruszsaccessories.Registries; -import com.majruszsaccessories.accessories.AccessoryBase; -import com.majruszsaccessories.components.TradeOffer; -import com.majruszsaccessories.items.AccessoryItem; -import com.mlib.annotations.AutoInstance; -import com.mlib.gamemodifiers.contexts.OnTradeSetup; -import net.minecraft.world.entity.npc.VillagerTrades; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.Items; -import net.minecraft.world.item.trading.MerchantOffer; - -import java.util.List; - -@AutoInstance -public class VillagerTradeUpdater { - public VillagerTradeUpdater() { - OnTradeSetup.listen( this::addTrades ); - } - - private void addTrades( OnTradeSetup.Data data ) { - Registries.OBJECTS.stream() - .filter( object->object instanceof AccessoryBase ) - .map( object->( AccessoryBase )object ) - .forEach( accessory->accessory.getComponents( TradeOffer.class ).forEach( offer->this.addTrades( data, offer ) ) ); - } - - private void addTrades( OnTradeSetup.Data data, TradeOffer offer ) { - if( offer.getProfession() != data.profession ) { - return; - } - - List< VillagerTrades.ItemListing > trades = data.getTrades( offer.getTier() ); - trades.add( ( trader, random )->new AccessoryMerchantOffer( offer ) ); - } - - static class AccessoryMerchantOffer extends MerchantOffer { - final AccessoryItem item; - - public AccessoryMerchantOffer( TradeOffer offer ) { - super( new ItemStack( offer.getItem(), 1 ), new ItemStack( Items.EMERALD, offer.getPrice() ), 2, 40, 0.05f ); - this.item = offer.getItem(); - } - - @Override - public boolean satisfiedBy( ItemStack itemStack1, ItemStack itemStack2 ) { - return itemStack1.is( this.item ) && itemStack2.isEmpty(); - } - } -} diff --git a/src/main/java/com/majruszsaccessories/items/BoosterOverlay.java b/src/main/java/com/majruszsaccessories/items/BoosterOverlay.java new file mode 100644 index 00000000..95f4a14d --- /dev/null +++ b/src/main/java/com/majruszsaccessories/items/BoosterOverlay.java @@ -0,0 +1,15 @@ +package com.majruszsaccessories.items; + +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; + +public class BoosterOverlay extends Item { + public BoosterOverlay() { + super( new Item.Properties().stacksTo( 1 ) ); + } + + @Override + public boolean isFoil( ItemStack itemStack ) { + return true; + } +} diff --git a/src/main/java/com/majruszsaccessories/recipes/AccessoryRecipe.java b/src/main/java/com/majruszsaccessories/recipes/AccessoryRecipe.java index fe51ce12..e801dced 100644 --- a/src/main/java/com/majruszsaccessories/recipes/AccessoryRecipe.java +++ b/src/main/java/com/majruszsaccessories/recipes/AccessoryRecipe.java @@ -5,7 +5,8 @@ import com.google.gson.JsonParseException; import com.majruszsaccessories.AccessoryHolder; import com.majruszsaccessories.Registries; -import com.majruszsaccessories.items.AccessoryItem; +import com.majruszsaccessories.accessories.AccessoryItem; +import com.mlib.math.Range; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.resources.ResourceLocation; import net.minecraft.util.GsonHelper; @@ -16,14 +17,12 @@ import net.minecraft.world.level.Level; import java.util.ArrayList; -import java.util.Iterator; import java.util.List; import java.util.function.Supplier; import static com.majruszsaccessories.AccessoryHolder.BONUS_RANGE; public class AccessoryRecipe extends CustomRecipe { - public static float BONUS_OFFSET = 0.05f; final AccessoryItem result; final List< AccessoryItem > ingredients; @@ -33,49 +32,27 @@ public class AccessoryRecipe extends CustomRecipe { public AccessoryRecipe( ResourceLocation id, AccessoryItem result, List< AccessoryItem > ingredients ) { super( id ); + this.result = result; this.ingredients = ingredients; } @Override public boolean matches( CraftingContainer container, Level level ) { - List< AccessoryItem > ingredients = new ArrayList<>( this.ingredients ); - for( int i = 0; i < container.getContainerSize(); ++i ) { - ItemStack itemStack = container.getItem( i ); - if( itemStack.isEmpty() ) - continue; - - boolean foundMatch = false; - Iterator< AccessoryItem > iterator = ingredients.iterator(); - while( iterator.hasNext() ) { - if( itemStack.getItem() == iterator.next() ) { - iterator.remove(); - foundMatch = true; - break; - } - } - if( !foundMatch ) { - return false; - } - } + RecipeData data = RecipeData.build( container ); - return ingredients.isEmpty(); + return this.ingredients.stream().allMatch( data::hasAccessory ); } @Override public ItemStack assemble( CraftingContainer container ) { - List< Float > bonuses = new ArrayList<>(); - for( int i = 0; i < container.getContainerSize(); ++i ) { - ItemStack itemStack = container.getItem( i ); - if( !itemStack.isEmpty() ) { - bonuses.add( AccessoryHolder.create( itemStack ).getBonus() ); - } - } - RecipeData data = new RecipeData( this.result, bonuses ); - float minBonus = BONUS_RANGE.clamp( data.getAverageBonus() - BONUS_OFFSET ); - float maxBonus = BONUS_RANGE.clamp( data.getAverageBonus() + BONUS_OFFSET ); + RecipeData data = RecipeData.build( container ); + float average = data.getAverageBonus(); + float std = data.getStandardDeviation(); + float minBonus = BONUS_RANGE.clamp( average - std ); + float maxBonus = BONUS_RANGE.clamp( average + std ); - return data.build( minBonus, maxBonus ); + return AccessoryHolder.create( this.result ).setBonus( new Range<>( minBonus, maxBonus ) ).getItemStack(); } @Override diff --git a/src/main/java/com/majruszsaccessories/recipes/BoostAccessoriesRecipe.java b/src/main/java/com/majruszsaccessories/recipes/BoostAccessoriesRecipe.java new file mode 100644 index 00000000..67f76061 --- /dev/null +++ b/src/main/java/com/majruszsaccessories/recipes/BoostAccessoriesRecipe.java @@ -0,0 +1,50 @@ +package com.majruszsaccessories.recipes; + +import com.majruszsaccessories.AccessoryHolder; +import com.majruszsaccessories.Registries; +import com.majruszsaccessories.boosters.BoosterItem; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.inventory.CraftingContainer; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.crafting.CustomRecipe; +import net.minecraft.world.item.crafting.RecipeSerializer; +import net.minecraft.world.item.crafting.SimpleRecipeSerializer; +import net.minecraft.world.level.Level; + +import java.util.function.Supplier; + +public class BoostAccessoriesRecipe extends CustomRecipe { + public static Supplier< RecipeSerializer< ? > > create() { + return ()->new SimpleRecipeSerializer<>( BoostAccessoriesRecipe::new ); + } + + public BoostAccessoriesRecipe( ResourceLocation id ) { + super( id ); + } + + @Override + public boolean matches( CraftingContainer container, Level level ) { + RecipeData data = RecipeData.build( container ); + + return data.getAccessoriesSize() == 1 && data.getBoostersSize() == 1; + } + + @Override + public ItemStack assemble( CraftingContainer container ) { + RecipeData data = RecipeData.build( container ); + AccessoryHolder holder = data.getAccessory( 0 ); + BoosterItem booster = data.getBooster( 0 ); + + return holder.copy().setBooster( booster ).getItemStack(); + } + + @Override + public boolean canCraftInDimensions( int width, int height ) { + return width * height >= 2; + } + + @Override + public RecipeSerializer< ? > getSerializer() { + return Registries.BOOST_ACCESSORIES_RECIPE.get(); + } +} diff --git a/src/main/java/com/majruszsaccessories/recipes/CombineAccessoriesRecipe.java b/src/main/java/com/majruszsaccessories/recipes/CombineAccessoriesRecipe.java index 0f4cd9a4..9a05f135 100644 --- a/src/main/java/com/majruszsaccessories/recipes/CombineAccessoriesRecipe.java +++ b/src/main/java/com/majruszsaccessories/recipes/CombineAccessoriesRecipe.java @@ -2,7 +2,7 @@ import com.majruszsaccessories.AccessoryHolder; import com.majruszsaccessories.Registries; -import com.majruszsaccessories.items.AccessoryItem; +import com.mlib.math.Range; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.inventory.CraftingContainer; import net.minecraft.world.item.ItemStack; @@ -11,15 +11,11 @@ import net.minecraft.world.item.crafting.SimpleRecipeSerializer; import net.minecraft.world.level.Level; -import java.util.ArrayList; -import java.util.List; import java.util.function.Supplier; import static com.majruszsaccessories.AccessoryHolder.BONUS_RANGE; public class CombineAccessoriesRecipe extends CustomRecipe { - public static float BONUS_OFFSET = 0.04f; - public static Supplier< RecipeSerializer< ? > > create() { return ()->new SimpleRecipeSerializer<>( CombineAccessoriesRecipe::new ); } @@ -30,21 +26,22 @@ public CombineAccessoriesRecipe( ResourceLocation id ) { @Override public boolean matches( CraftingContainer container, Level level ) { - RecipeData data = this.buildCraftingData( container ); + RecipeData data = RecipeData.build( container ); - return data != null && data.getBonusesSize() > 1; + return data.getAccessoriesSize() > 1 + && data.hasIdenticalItemTypes() + && data.getMaxBonus() < AccessoryHolder.BONUS_RANGE.to + && data.getBoostersSize() == 0; } @Override public ItemStack assemble( CraftingContainer container ) { - RecipeData data = this.buildCraftingData( container ); + RecipeData data = RecipeData.build( container ); float craftingMaxBonus = data.getMaxBonus(); - float ratio = data.determineRatio(); - float bonusOffset = data.getBonusesSize() * BONUS_OFFSET; - float minBonus = BONUS_RANGE.clamp( craftingMaxBonus - ( 1.0f - ratio ) * bonusOffset ); - float maxBonus = BONUS_RANGE.clamp( craftingMaxBonus + ratio * bonusOffset ); + float minBonus = BONUS_RANGE.clamp( craftingMaxBonus - 0.01f * ( data.getAccessoriesSize() - 1 ) ); + float maxBonus = BONUS_RANGE.clamp( craftingMaxBonus + 0.03f * ( data.getAccessoriesSize() - 1 ) ); - return data.build( minBonus, maxBonus ); + return AccessoryHolder.create( data.getAccessory( 0 ).getItem() ).setBonus( new Range<>( minBonus, maxBonus ) ).getItemStack(); } @Override @@ -56,28 +53,4 @@ public boolean canCraftInDimensions( int width, int height ) { public RecipeSerializer< ? > getSerializer() { return Registries.COMBINE_ACCESSORIES_RECIPE.get(); } - - private RecipeData buildCraftingData( CraftingContainer container ) { - AccessoryItem accessory = null; - List< Float > bonuses = new ArrayList<>(); - for( int i = 0; i < container.getContainerSize(); ++i ) { - ItemStack itemStack = container.getItem( i ); - if( itemStack.isEmpty() ) - continue; - - if( itemStack.getItem() instanceof AccessoryItem item ) { - if( accessory == null ) { - accessory = item; - } else if( accessory != item ) { - return null; - } - bonuses.add( AccessoryHolder.create( itemStack ).getBonus() ); - } else { - return null; - } - } - - RecipeData data = new RecipeData( accessory, bonuses ); - return accessory != null && data.getMaxBonus() < AccessoryHolder.BONUS_RANGE.to ? data : null; - } } diff --git a/src/main/java/com/majruszsaccessories/recipes/RecipeData.java b/src/main/java/com/majruszsaccessories/recipes/RecipeData.java index 3eaebcc2..c95daef3 100644 --- a/src/main/java/com/majruszsaccessories/recipes/RecipeData.java +++ b/src/main/java/com/majruszsaccessories/recipes/RecipeData.java @@ -1,59 +1,83 @@ package com.majruszsaccessories.recipes; import com.majruszsaccessories.AccessoryHolder; -import com.majruszsaccessories.items.AccessoryItem; -import com.mlib.math.Range; -import net.minecraft.util.Mth; -import net.minecraft.world.item.Item; +import com.majruszsaccessories.accessories.AccessoryItem; +import com.majruszsaccessories.boosters.BoosterItem; +import net.minecraft.world.inventory.CraftingContainer; import net.minecraft.world.item.ItemStack; -import java.util.Collections; +import java.util.ArrayList; import java.util.List; -public record RecipeData( AccessoryItem item, List< Float > bonuses ) { - public RecipeData( AccessoryItem item, List< Float > bonuses ) { - this.item = item; - this.bonuses = bonuses; +public record RecipeData( List< AccessoryHolder > accessories, List< BoosterItem > boosters ) { + public static RecipeData build( CraftingContainer container ) { + RecipeData data = new RecipeData(); + for( int i = 0; i < container.getContainerSize(); ++i ) { + ItemStack itemStack = container.getItem( i ); + if( itemStack.isEmpty() ) { + continue; + } - Collections.sort( this.bonuses ); - } + if( itemStack.getItem() instanceof AccessoryItem ) { + data.accessories.add( AccessoryHolder.create( itemStack ) ); + } else if( itemStack.getItem() instanceof BoosterItem item ) { + data.boosters.add( item ); + } else { + return new RecipeData(); + } + } - ItemStack build( float minBonus, float maxBonus ) { - return AccessoryHolder.create( this.item, new Range<>( minBonus, maxBonus ) ).getItemStack(); + data.accessories.sort( ( left, right )->Float.compare( left.getBonus(), right.getBonus() ) ); + return data; } - Item getItem() { - return this.item; + public RecipeData() { + this( new ArrayList<>(), new ArrayList<>() ); } - List< Float > getBonuses() { - return this.bonuses; + public AccessoryHolder getAccessory( int idx ) { + return this.accessories.get( idx ); } - int getBonusesSize() { - return this.bonuses.size(); + public BoosterItem getBooster( int idx ) { + return this.boosters.get( idx ); } - float getAverageBonus() { - return this.bonuses.stream().reduce( 0.0f, Float::sum ) / this.bonuses.size(); + float getStandardDeviation() { + float average = this.getAverageBonus(); + double variation = this.accessories.stream() + .map( AccessoryHolder::getBonus ) + .reduce( 0.0f, ( sum, bonus )->sum + ( float )Math.pow( bonus - average, 2.0 ) ) / this.accessories.size(); + + return ( float )Math.sqrt( variation ); } float getMaxBonus() { - return this.bonuses.get( this.bonuses.size() - 1 ); + return this.accessories.get( this.accessories.size() - 1 ).getBonus(); } float getMinBonus() { - return this.bonuses.get( 0 ); + return this.accessories.get( 0 ).getBonus(); } - float determineRatio() { - float min = this.getMinBonus(), max = this.getMaxBonus(); - if( min == max ) - return 1.0f; + float getAverageBonus() { + return this.accessories.stream().map( AccessoryHolder::getBonus ).reduce( 0.0f, Float::sum ) / this.accessories.size(); + } - float average = this.getAverageBonus(); - float std = ( float )Math.sqrt( this.bonuses.stream() - .reduce( 0.0f, ( sum, bonus )->sum + ( float )Math.pow( bonus - average, 2.0f ) ) / this.bonuses.size() ); - return Mth.clamp( 1.0f - 2.0f * std / ( AccessoryHolder.BONUS_RANGE.to - AccessoryHolder.BONUS_RANGE.from ), 0.0f, 1.0f ); + int getAccessoriesSize() { + return this.accessories.size(); } + + int getBoostersSize() { + return this.boosters.size(); + } + + boolean hasAccessory( AccessoryItem item ) { + return this.accessories.stream().anyMatch( holder->holder.getItem().equals( item ) ); + } + + boolean hasIdenticalItemTypes() { + return this.accessories.stream().allMatch( holder->holder.getItem().equals( this.accessories.get( 0 ).getItem() ) ); + } + } diff --git a/src/main/java/com/majruszsaccessories/accessories/tooltip/ITooltipProvider.java b/src/main/java/com/majruszsaccessories/tooltip/ITooltipProvider.java similarity index 75% rename from src/main/java/com/majruszsaccessories/accessories/tooltip/ITooltipProvider.java rename to src/main/java/com/majruszsaccessories/tooltip/ITooltipProvider.java index 566d7fc9..667025c9 100644 --- a/src/main/java/com/majruszsaccessories/accessories/tooltip/ITooltipProvider.java +++ b/src/main/java/com/majruszsaccessories/tooltip/ITooltipProvider.java @@ -1,7 +1,6 @@ -package com.majruszsaccessories.accessories.tooltip; +package com.majruszsaccessories.tooltip; import com.majruszsaccessories.AccessoryHolder; -import net.minecraft.network.chat.Component; import net.minecraft.network.chat.MutableComponent; public interface ITooltipProvider { diff --git a/src/main/java/com/majruszsaccessories/accessories/tooltip/TooltipHelper.java b/src/main/java/com/majruszsaccessories/tooltip/TooltipHelper.java similarity index 75% rename from src/main/java/com/majruszsaccessories/accessories/tooltip/TooltipHelper.java rename to src/main/java/com/majruszsaccessories/tooltip/TooltipHelper.java index 2a931818..b13efe01 100644 --- a/src/main/java/com/majruszsaccessories/accessories/tooltip/TooltipHelper.java +++ b/src/main/java/com/majruszsaccessories/tooltip/TooltipHelper.java @@ -1,12 +1,16 @@ -package com.majruszsaccessories.accessories.tooltip; +package com.majruszsaccessories.tooltip; import com.majruszsaccessories.AccessoryHolder; +import com.majruszsaccessories.boosters.BoosterItem; import com.mlib.config.DoubleConfig; import com.mlib.config.IntegerConfig; import com.mlib.text.TextHelper; import net.minecraft.ChatFormatting; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.MutableComponent; +import net.minecraft.world.item.ItemStack; + +import java.util.function.Supplier; public class TooltipHelper { public final static ChatFormatting DEFAULT_FORMAT = ChatFormatting.GRAY; @@ -44,6 +48,10 @@ public static ITooltipProvider asValue( IntegerConfig config ) { return asValue( config, 1 ); } + public static ITooltipProvider asFixedValue( IntegerConfig config ) { + return asValue( config, 0 ); + } + public static ITooltipProvider asPercent( DoubleConfig config, double multiplier ) { return new ITooltipProvider() { @Override @@ -71,4 +79,23 @@ public MutableComponent getDetailedTooltip( AccessoryHolder holder ) { public static ITooltipProvider asPercent( DoubleConfig config ) { return asPercent( config, 1.0 ); } + + public static ITooltipProvider asFixedPercent( DoubleConfig config ) { + return asPercent( config, 0.0 ); + } + + public static ITooltipProvider asItem( Supplier< BoosterItem > item ) { + return new ITooltipProvider() { + @Override + public MutableComponent getTooltip( AccessoryHolder holder ) { + if( !holder.isValid() ) { + return Component.literal( "" ); + } + + return Component.translatable( "majruszsaccessories.items.booster_name", item.get().getDescription() ) + .withStyle( item.get().getRarity( ItemStack.EMPTY ).getStyleModifier() ) + .append( " " ); + } + }; + } } diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/mods.toml index 47711e58..991a608d 100644 --- a/src/main/resources/META-INF/mods.toml +++ b/src/main/resources/META-INF/mods.toml @@ -5,7 +5,7 @@ issueTrackerURL="https://github.com/Majrusz/MajruszsAccessories/issues" [[mods]] modId="majruszsaccessories" - version="1.1.5" + version="${versions_mod}" displayName="Majrusz's Accessories" updateJSONURL="https://raw.githubusercontent.com/Majrusz/MinecraftCommon/main/Accessories/update.json" displayURL="https://www.curseforge.com/minecraft/mc-mods/majruszs-accessories" @@ -17,34 +17,34 @@ issueTrackerURL="https://github.com/Majrusz/MajruszsAccessories/issues" [[dependencies.majruszsaccessories]] modId="forge" mandatory=true - versionRange="[43.2.0,)" + versionRange="${versions_forge_range}" ordering="NONE" side="BOTH" [[dependencies.majruszsaccessories]] modId="minecraft" mandatory=true - versionRange="[1.19.2,1.20)" + versionRange="${versions_minecraft_range}" ordering="NONE" side="BOTH" [[dependencies.majruszsaccessories]] modId="mlib" mandatory=true - versionRange="[4.0.0,5.0.0)" + versionRange="${versions_mlib_range}" ordering="NONE" side="BOTH" [[dependencies.majruszsaccessories]] modId="curios" mandatory=false - versionRange="[1.19.2-5.1.1.0,)" + versionRange="${versions_curios_range}" ordering="AFTER" side="BOTH" [[dependencies.majruszsaccessories]] modId="majruszsdifficulty" mandatory=false - versionRange="[1.7.4,)" + versionRange="${versions_difficulty_range}" ordering="AFTER" side="BOTH" \ No newline at end of file diff --git a/src/main/resources/assets/majruszsaccessories/lang/en_us.json b/src/main/resources/assets/majruszsaccessories/lang/en_us.json index 6373ccc7..aa277160 100644 --- a/src/main/resources/assets/majruszsaccessories/lang/en_us.json +++ b/src/main/resources/assets/majruszsaccessories/lang/en_us.json @@ -9,12 +9,20 @@ "item.majruszsaccessories.tamed_potato_beetle": "Tamed Potato Beetle", "item.majruszsaccessories.white_flag": "White Flag", "item.majruszsaccessories.overworld_rune": "Overworld Rune", + "item.majruszsaccessories.dice": "Dice", + "item.majruszsaccessories.golden_dice": "Golden Dice", + "item.majruszsaccessories.owl_feather": "Owl Feather", + "item.majruszsaccessories.horseshoe": "Horseshoe", + "item.majruszsaccessories.golden_horseshoe": "Golden Horseshoe", "majruszsaccessories.items.accessory_item": "Works when held in the other hand.", "majruszsaccessories.items.bonus": "%1$s efficiency bonus", "majruszsaccessories.items.bonus_range": "Random efficiency bonus from %1$s to %2$s.", "majruszsaccessories.items.formula": "%1$s%2$s", "majruszsaccessories.items.page": "--- Page %1$s/%2$s ---", + "majruszsaccessories.items.booster_tooltip": "Accessory Booster", + "majruszsaccessories.items.booster_name": "[%1$s]", "majruszsaccessories.bonuses.fishing_luck": "Increases luck by %1$s when fishing.", + "majruszsaccessories.bonuses.fishing_lure": "Reduces fishing time by %1$s.", "majruszsaccessories.bonuses.extra_stone_loot": "Gives %1$s chance for extra loot when mining.", "majruszsaccessories.bonuses.spawn_twins": "Gives %1$s chance of twins when breeding animals.", "majruszsaccessories.bonuses.potion_amplifier": "Makes created potions %1$s level(s) stronger.", @@ -24,10 +32,13 @@ "majruszsaccessories.bonuses.animal_damage": "Increases tamed wolf's damage by %1$s.", "majruszsaccessories.bonuses.animal_speed": "Increases tamed horse's movement speed by %1$s.", "majruszsaccessories.bonuses.animal_jump_height": "Increases tamed horse's jump height by %1$s.", - "majruszsaccessories.bonuses.more_chest_loot": "All structure chests contain %1$s more loot for every %2$s blocks further from home, up to %3$s.", + "majruszsaccessories.bonuses.more_chest_loot": "Increases loot by %1$s in all chests for every %2$s blocks further from home, up to %3$s.", "majruszsaccessories.bonuses.double_crops": "Gives %1$s chance to double crops when harvesting.", "majruszsaccessories.bonuses.reduce_damage_received": "Decreases damage received by %1$s.", "majruszsaccessories.bonuses.reduce_damage_dealt": "Decreases damage dealt by %1$s.", + "majruszsaccessories.boosters.drop_chance": "%1$sIncreases accessories drop chance by %2$s.", + "majruszsaccessories.boosters.experience_bonus": "%1$sIncreases experience gained by %2$s.", + "majruszsaccessories.boosters.luck_bonus": "%1$sIncreases luck by %2$s.", "advancements.majruszsaccessories.adventurers_guide.title": "Adventure Time", "advancements.majruszsaccessories.adventurers_guide.description": "Acquire an Adventurer's Guide", "advancements.majruszsaccessories.anglers_trophy.title": "What a Slimy Specimen of Beauty", @@ -46,5 +57,9 @@ "advancements.majruszsaccessories.white_flag.description": "Acquire a White Flag", "advancements.majruszsaccessories.overworld_rune.title": "Overworld Holds No Secrets", "advancements.majruszsaccessories.overworld_rune.description": "Acquire an Overworld Rune", + "advancements.majruszsaccessories.booster_dropped.title": "It Is Time For an Upgrade, Isn't It?", + "advancements.majruszsaccessories.booster_dropped.description": "Acquire Any Accessory Booster", + "advancements.majruszsaccessories.booster_used.title": "What a Boost!", + "advancements.majruszsaccessories.booster_used.description": "Use Any Accessory Booster", "curios.identifier.pocket": "Pocket" } \ No newline at end of file diff --git a/src/main/resources/assets/majruszsaccessories/lang/pl_pl.json b/src/main/resources/assets/majruszsaccessories/lang/pl_pl.json index d7b63c84..3074bd44 100644 --- a/src/main/resources/assets/majruszsaccessories/lang/pl_pl.json +++ b/src/main/resources/assets/majruszsaccessories/lang/pl_pl.json @@ -9,12 +9,20 @@ "item.majruszsaccessories.tamed_potato_beetle": "Oswojona stonka ziemniaczana", "item.majruszsaccessories.white_flag": "Biała flaga", "item.majruszsaccessories.overworld_rune": "Runa Ziemi", + "item.majruszsaccessories.dice": "Kostka", + "item.majruszsaccessories.golden_dice": "Złota kostka", + "item.majruszsaccessories.owl_feather": "Pióro sowy", + "item.majruszsaccessories.horseshoe": "Podkowa", + "item.majruszsaccessories.golden_horseshoe": "Złota podkowa", "majruszsaccessories.items.accessory_item": "Działa gdy trzymany w drugiej ręce.", "majruszsaccessories.items.bonus": "%1$s bonusu do wydajności", "majruszsaccessories.items.bonus_range": "Losowy bonus do wydajności od %1$s do %2$s.", "majruszsaccessories.items.formula": "%1$s%2$s", "majruszsaccessories.items.page": "--- Strona %1$s/%2$s ---", + "majruszsaccessories.items.booster_tooltip": "Wzmacniacz akcesoriów", + "majruszsaccessories.items.booster_name": "[%1$s]", "majruszsaccessories.bonuses.fishing_luck": "Zwiększa szczęście o %1$s podczas łowienia.", + "majruszsaccessories.bonuses.fishing_lure": "Redukuje czas łowienia o %1$s.", "majruszsaccessories.bonuses.extra_stone_loot": "Daje %1$s szansy na dodatkowe przedmioty podczas kopania.", "majruszsaccessories.bonuses.spawn_twins": "Daje %1$s szansy na bliźniaki podczas rozmnażania zwierząt.", "majruszsaccessories.bonuses.potion_amplifier": "Wzmacnia mikstury o %1$s poziom(y).", @@ -28,6 +36,9 @@ "majruszsaccessories.bonuses.double_crops": "Daje %1$s szansy na podwójne plony podczas zbiorów.", "majruszsaccessories.bonuses.reduce_damage_received": "Zmniejsza otrzymywane obrażenia o %1$s.", "majruszsaccessories.bonuses.reduce_damage_dealt": "Zmniejsza zadawane obrażenia o %1$s.", + "majruszsaccessories.boosters.drop_chance": "%1$sZwiększa szansę zdobycia akcesoriów o %2$s.", + "majruszsaccessories.boosters.experience_bonus": "%1$sZwiększa zdobywane doświadczenie o %2$s.", + "majruszsaccessories.boosters.luck_bonus": "%1$sZwiększa szczęście o %2$s.", "advancements.majruszsaccessories.adventurers_guide.title": "Pora na przygodę", "advancements.majruszsaccessories.adventurers_guide.description": "Zdobądź przewodnik podróżniczy", "advancements.majruszsaccessories.anglers_trophy.title": "Co za obślizgły okaz piękna", @@ -46,5 +57,9 @@ "advancements.majruszsaccessories.white_flag.description": "Zdobądź białą flagę", "advancements.majruszsaccessories.overworld_rune.title": "Ziemia nie skrywa już tajemnic", "advancements.majruszsaccessories.overworld_rune.description": "Zdobądź runę Ziemi", - "curios.identifier.pocket": "Pocket" + "advancements.majruszsaccessories.booster_dropped.title": "Czy to nie czas na wzmocnienie?", + "advancements.majruszsaccessories.booster_dropped.description": "Zdobądź dowolny wzmacniacz akcesoriów", + "advancements.majruszsaccessories.booster_used.title": "Co za wzmocnienie!", + "advancements.majruszsaccessories.booster_used.description": "Wykorzystaj dowolny wzmacniacz akcesoriów", + "curios.identifier.pocket": "Kieszeń" } \ No newline at end of file diff --git a/src/main/resources/assets/majruszsaccessories/models/item/booster_icon.json b/src/main/resources/assets/majruszsaccessories/models/item/booster_icon.json new file mode 100644 index 00000000..88a25d0a --- /dev/null +++ b/src/main/resources/assets/majruszsaccessories/models/item/booster_icon.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "majruszsaccessories:item/booster_icon" + } +} diff --git a/src/main/resources/assets/majruszsaccessories/models/item/dice.json b/src/main/resources/assets/majruszsaccessories/models/item/dice.json new file mode 100644 index 00000000..c4acf659 --- /dev/null +++ b/src/main/resources/assets/majruszsaccessories/models/item/dice.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "majruszsaccessories:item/dice" + } +} diff --git a/src/main/resources/assets/majruszsaccessories/models/item/golden_dice.json b/src/main/resources/assets/majruszsaccessories/models/item/golden_dice.json new file mode 100644 index 00000000..395b3b9c --- /dev/null +++ b/src/main/resources/assets/majruszsaccessories/models/item/golden_dice.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "majruszsaccessories:item/golden_dice" + } +} diff --git a/src/main/resources/assets/majruszsaccessories/models/item/golden_horseshoe.json b/src/main/resources/assets/majruszsaccessories/models/item/golden_horseshoe.json new file mode 100644 index 00000000..f37cf770 --- /dev/null +++ b/src/main/resources/assets/majruszsaccessories/models/item/golden_horseshoe.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "majruszsaccessories:item/golden_horseshoe" + } +} diff --git a/src/main/resources/assets/majruszsaccessories/models/item/horseshoe.json b/src/main/resources/assets/majruszsaccessories/models/item/horseshoe.json new file mode 100644 index 00000000..bb272906 --- /dev/null +++ b/src/main/resources/assets/majruszsaccessories/models/item/horseshoe.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "majruszsaccessories:item/horseshoe" + } +} diff --git a/src/main/resources/assets/majruszsaccessories/models/item/owl_feather.json b/src/main/resources/assets/majruszsaccessories/models/item/owl_feather.json new file mode 100644 index 00000000..28d14a57 --- /dev/null +++ b/src/main/resources/assets/majruszsaccessories/models/item/owl_feather.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "majruszsaccessories:item/owl_feather" + } +} diff --git a/src/main/resources/assets/majruszsaccessories/textures/item/anglers_trophy.png b/src/main/resources/assets/majruszsaccessories/textures/item/anglers_trophy.png index c0dac6853c7cb307c63377854a9997e744ddcf54..55f231a1935bfc390a10520a6e8e16bc511ea679 100644 GIT binary patch delta 379 zcmV->0fhdT1ET|wF@If2L_t(Ijm?q2O9F8i#y`g0pr;VZi3f+$5cm&NB++6+O$}|~ z9}v`DG)YtK2CYGaOM_D_Eh34zH3<=tNJ@4QT&IJ=HQ0T*AMW)`Umo7)d7tO|!e1ja zi!9_ddlr9n-wVup2uB!IWagEaXYk81dF_t?xP2Ui0tSV=W`FC+ctA89jRA;+WdOdd zF@`x2CX!p+eg6bNPsVxsn7(t_B>)~;O`LQ9*|cJ}I#x*XcRD^PaaufJXCsHIr5W@( zs9G9Lm+5uKR2p?Msj!%zbH{aXR4jSKgIFdb@udio@>{hZBNaY*$LcmI$qpV0oYzy6+A#9CSjNp zF)z-zwXE8iRM-tH@iI^l(w);a`9V_H9faz%f7E%!*aMx@1hX6txFz_4s;THZM Z`~W-*hEaI*U_}4`002ovPDHLkV1ls*s!{*| delta 368 zcmV-$0gwKp1DFGlF@I7?L_t(Ijm?q0O9EjW$3GX|U{-{1;sb|Hf`33SB++6^lY?9M z2Q;)7P101mL#q(s;^5TOB9fR+O@cHe(nV&3mpOQF4R#Or;$GkB;mhy)`Mo^w*HRXl zg{-g_`PX+wpx$FR!Ig;0dSum8_&G6oew_kv`!G}jfI?Q-dVee$2z^gy04#@90KO(O zMy4epA$NH2_5pw%i}Lb5e`nI00Ni)mIMV^76A`=HpC}>!PG{#OE{ezG_cLfB!O-ZV zi3CDdF$ObgttQEMSk^DO$8~gCEP291qfhRniqKVmzxfIy(~_eB)GK9#u9Dh4{B;`C zF7s$2u^8ZJWNBK|D`je}CP(@ny~d5F__6&Y54jKk$Q`e$bpUePJJJV8#={-5F|G8_Q-L4LV||3^QcCx&%sGO(Zk O0000PfQhWYuz%}OQ9e*g_*@O1TaS?83{1OOh3EYbh~ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/majruszsaccessories/textures/item/dice.png b/src/main/resources/assets/majruszsaccessories/textures/item/dice.png new file mode 100644 index 0000000000000000000000000000000000000000..01b23322122b2a18773568b85a8dcac08b27c47a GIT binary patch literal 279 zcmV+y0qFjTP)Px#(Md!>R5*>zlQ9m0KoCVAhD(@eVQXhWgTb28-Xm}X5(*O&FW>=etSzb8U}Irt zO9Ccvi?uLIfL)Np#$Qc-=KY;XX5p_@WI`61kV8FI9|$m=EdeNBPXOi%PwTgaz^+U| zbx~wOcEQIz24Lm*n(w$f3&2*UNK(Abr&d8G5a1f$YR|?XHL40yph=UiA(FHe)P$Qa z_Xc>IwbrD-t?zyhFiC-JSQ6R%8 d82k%A>kWLCTJtu(LM8wJ002ovPDHLkV1l51ZN>lq literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/majruszsaccessories/textures/item/essence_sparks.png b/src/main/resources/assets/majruszsaccessories/textures/item/essence_sparks.png deleted file mode 100644 index 60402719374244f9f487f8ce55d68eb1fdce6a12..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 147 zcmeAS@N?(olHy`uVBq!ia0vp^0ziC#gAF8d_OTz3Vk{1FcVbv~PUa<$I??6gZaL@Aj5)jvUL75EyVwzopr0Ay}w6#xJL literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/majruszsaccessories/textures/item/golden_horseshoe.png b/src/main/resources/assets/majruszsaccessories/textures/item/golden_horseshoe.png new file mode 100644 index 0000000000000000000000000000000000000000..230607e5e03c0dd189faba5e5409efc82651b8b8 GIT binary patch literal 324 zcmV-K0lWT*P)Px#{z*hZR5*>zk};0LFc3w5EP7>2+zU$%iyE3u2F3*c9gjLcm1AQ6a@npDM(2);Km+m zN^acVc114_bBXGpp@#$X=d&QHt!-C?^;IVUpeeb@s|=5yU$EOf0I=H~q$HO6De4h3 z0l=Mf-dwypSnMb{Z!Xbf0pLIB;ov=hl#IszOVI>*m3hxrkC@4;tTl87^w1G02`*BI zf}uXOm$lqaUuII$J0E-&QM94BNCU7sXdF)u?-@OSjXN3lVL?_ga};19v3l419eM(0 WCT$ESw|b!f0000Px#&`Cr=R5*>zlD!ebAPj|{bJ@k`P7O-d> z(9frL0^rx0%0WbOo!GW*s_*ae_d3YTAR?F<0OV36BDv13>pHe0BDtuZSmH6p?3}we zxz$CgihbXaQtIF-C72n!_h=z6K#Z}Q{>jCyE&QZ;o-g;y5}(WaN<#;#dU-bITvk;8 z==O6*BQpaLfte9P$N=EIe>Jx*yU)VR001KDz{hbQgn;urry-!&U6us}R5WTH0t#dl cZ=3%^5Bn5~q{s$23;+NC07*qoM6N<$f+taRJ^%m! literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/majruszsaccessories/textures/item/owl_feather.png b/src/main/resources/assets/majruszsaccessories/textures/item/owl_feather.png new file mode 100644 index 0000000000000000000000000000000000000000..16c98a98f402bb619467c7ea5ed755cb3b26bee4 GIT binary patch literal 291 zcmV+;0o?wHP)Px#-AP12R5*>*k)aNPP#A?jorx-pf;LDNH>1hqW+V6tHjB~h3($N7izYUc$!;-0 zQwjqs^_uvH0~O~Co^