diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 26beb378..28833c84 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -10,8 +10,8 @@ on: env: MINECRAFT_VERSION: 1.20.1 JAVA_VERSION: 17 - VERSION: 4.1.8+1.20.1 - VERSION_TYPE: beta + VERSION: 4.1.9+1.20.1 + VERSION_TYPE: alpha permissions: contents: write diff --git a/CHANGELOG.md b/CHANGELOG.md index fb96e9a0..b98278dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,2 @@ -- Fixed evokers always being replaced by illusioners in raids. - - Note that this spell is not affected by havens right now. -- \ No newline at end of file +- Spells now decay over time +- Fixed turboChickens being utterly broken \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 384decbd..69c1bca9 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,7 +6,7 @@ minecraft_version=1.20.1 yarn_mappings=1.20.1+build.10 loader_version=0.15.0 # Mod Properties -mod_version=4.1.8+1.20.1 +mod_version=4.1.9+1.20.1 maven_group=com.skycat archives_base_name=mystical modid=mystical diff --git a/src/main/generated/assets/mystical/lang/en_us.json b/src/main/generated/assets/mystical/lang/en_us.json index f9d69962..bed96608 100644 --- a/src/main/generated/assets/mystical/lang/en_us.json +++ b/src/main/generated/assets/mystical/lang/en_us.json @@ -25,22 +25,28 @@ "text.config.mysticalConfig.enum.logLevel.info": "Info", "text.config.mysticalConfig.enum.logLevel.off": "No logging", "text.config.mysticalConfig.enum.logLevel.warn": "Warn", + "text.config.mysticalConfig.option.aggressiveGolems.change": "% chance", "text.config.mysticalConfig.option.aggressiveGolems.enabled": "Enable?", "text.config.mysticalConfig.option.aggressiveGolems.logLevel": "Logging", "text.config.mysticalConfig.option.aggressiveGolems.weight": "Weight", + "text.config.mysticalConfig.option.bigCreeperExplosion.change": "% chance", "text.config.mysticalConfig.option.bigCreeperExplosion.enabled": "Enable?", "text.config.mysticalConfig.option.bigCreeperExplosion.logLevel": "Logging", "text.config.mysticalConfig.option.bigCreeperExplosion.weight": "Weight", + "text.config.mysticalConfig.option.catVariantChange.change": "% chance", "text.config.mysticalConfig.option.catVariantChange.enabled": "Enable?", "text.config.mysticalConfig.option.catVariantChange.logLevel": "Logging", "text.config.mysticalConfig.option.catVariantChange.weight": "Weight", "text.config.mysticalConfig.option.devMode": "Dev mode", + "text.config.mysticalConfig.option.disableDaylightBurning.change": "% chance", "text.config.mysticalConfig.option.disableDaylightBurning.enabled": "Enable?", "text.config.mysticalConfig.option.disableDaylightBurning.logLevel": "Logging", "text.config.mysticalConfig.option.disableDaylightBurning.weight": "Weight", + "text.config.mysticalConfig.option.enderTypeChange.change": "% chance", "text.config.mysticalConfig.option.enderTypeChange.enabled": "Enable?", "text.config.mysticalConfig.option.enderTypeChange.logLevel": "Logging", "text.config.mysticalConfig.option.enderTypeChange.weight": "Weight", + "text.config.mysticalConfig.option.explosionsInfest.change": "% chance", "text.config.mysticalConfig.option.explosionsInfest.enabled": "Enable?", "text.config.mysticalConfig.option.explosionsInfest.logLevel": "Logging", "text.config.mysticalConfig.option.explosionsInfest.weight": "Weight", @@ -49,56 +55,75 @@ "text.config.mysticalConfig.option.failedToLoadSpellHandlerLogLevel": "Failed to load spell handler", "text.config.mysticalConfig.option.failedToSaveSpellHandlerLogLevel": "Failed to save spell manager", "text.config.mysticalConfig.option.failedToSetNightTimerLogLevel": "Failed to set night timer", + "text.config.mysticalConfig.option.fishingRodLaunch.change": "% chance", "text.config.mysticalConfig.option.fishingRodLaunch.enabled": "Enable?", "text.config.mysticalConfig.option.fishingRodLaunch.logLevel": "Logging", "text.config.mysticalConfig.option.fishingRodLaunch.weight": "Weight", + "text.config.mysticalConfig.option.illusionersReplaceEvokers.change": "% chance", "text.config.mysticalConfig.option.illusionersReplaceEvokers.enabled": "Enable?", "text.config.mysticalConfig.option.illusionersReplaceEvokers.logLevel": "Logging", "text.config.mysticalConfig.option.illusionersReplaceEvokers.weight": "Weight", + "text.config.mysticalConfig.option.levitate.change": "% chance", "text.config.mysticalConfig.option.levitate.enabled": "Enable?", "text.config.mysticalConfig.option.levitate.logLevel": "Logging", "text.config.mysticalConfig.option.levitate.weight": "Weight", + "text.config.mysticalConfig.option.mobSpawnSwap.change": "% chance", "text.config.mysticalConfig.option.mobSpawnSwap.enabled": "Enable?", "text.config.mysticalConfig.option.mobSpawnSwap.logLevel": "Logging", "text.config.mysticalConfig.option.mobSpawnSwap.weight": "Weight", "text.config.mysticalConfig.option.newSpellCommandBroadcast": "New spell command (in-game)", "text.config.mysticalConfig.option.newSpellCommandLogLevel": "New spell command (console)", + "text.config.mysticalConfig.option.noFuse.change": "% chance", "text.config.mysticalConfig.option.noFuse.enabled": "Enable?", "text.config.mysticalConfig.option.noFuse.logLevel": "Logging", "text.config.mysticalConfig.option.noFuse.weight": "Weight", + "text.config.mysticalConfig.option.oneStrikeWardens.change": "% chance", "text.config.mysticalConfig.option.oneStrikeWardens.enabled": "Enable?", "text.config.mysticalConfig.option.oneStrikeWardens.logLevel": "Logging", "text.config.mysticalConfig.option.oneStrikeWardens.weight": "Weight", + "text.config.mysticalConfig.option.randomCreeperEffectClouds.change": "% chance", "text.config.mysticalConfig.option.randomCreeperEffectClouds.enabled": "Enable?", "text.config.mysticalConfig.option.randomCreeperEffectClouds.logLevel": "Logging", "text.config.mysticalConfig.option.randomCreeperEffectClouds.weight": "Weight", + "text.config.mysticalConfig.option.randomEvokerSummons.change": "% chance", "text.config.mysticalConfig.option.randomEvokerSummons.enabled": "Enable?", "text.config.mysticalConfig.option.randomEvokerSummons.logLevel": "Logging", "text.config.mysticalConfig.option.randomEvokerSummons.weight": "Weight", + "text.config.mysticalConfig.option.randomTreeType.change": "% chance", "text.config.mysticalConfig.option.randomTreeType.enabled": "Enable?", "text.config.mysticalConfig.option.randomTreeType.logLevel": "Logging", "text.config.mysticalConfig.option.randomTreeType.weight": "Weight", + "text.config.mysticalConfig.option.sheepColorChange.change": "% chance", "text.config.mysticalConfig.option.sheepColorChange.enabled": "Enable?", "text.config.mysticalConfig.option.sheepColorChange.logLevel": "Logging", "text.config.mysticalConfig.option.sheepColorChange.weight": "Weight", + "text.config.mysticalConfig.option.skeletonTypeChange.change": "% chance", "text.config.mysticalConfig.option.skeletonTypeChange.enabled": "Enable?", "text.config.mysticalConfig.option.skeletonTypeChange.logLevel": "Logging", "text.config.mysticalConfig.option.skeletonTypeChange.weight": "Weight", "text.config.mysticalConfig.option.spellContributionLogLevel": "Spell contribution", + "text.config.mysticalConfig.option.spellDecay": "Spell decay (%)", + "text.config.mysticalConfig.option.spellDecay.tooltip": "How much spells will decay each night.", + "text.config.mysticalConfig.option.spellDecayLinear": "Decay spells linearly?", + "text.config.mysticalConfig.option.spellDecayLinear.tooltip": "If true, spells will decay based on the full requirement of the spell.\nIf false, they will decay based on what's left.", "text.config.mysticalConfig.option.spellMaxHard": "Max spells (Hard)", "text.config.mysticalConfig.option.spellMaxHard.tooltip": "The maximum number of spells active at a time.\nMystical will not delete extra spells, but won't make any past this point.", "text.config.mysticalConfig.option.spellMinHard": "Min spells (Hard)", "text.config.mysticalConfig.option.spellMinHard.tooltip": "The minimum number of spells active at a time.\nMystical will make sure there are this many spells active whenever spell rewards are paid out.", "text.config.mysticalConfig.option.timeOfDayAtStartupLogLevel": "Time of day at startup", + "text.config.mysticalConfig.option.turboChickens.change": "% chance", "text.config.mysticalConfig.option.turboChickens.enabled": "Enable?", "text.config.mysticalConfig.option.turboChickens.logLevel": "Logging", "text.config.mysticalConfig.option.turboChickens.weight": "Weight", + "text.config.mysticalConfig.option.turboMobs.change": "% chance", "text.config.mysticalConfig.option.turboMobs.enabled": "Enable?", "text.config.mysticalConfig.option.turboMobs.logLevel": "Logging", "text.config.mysticalConfig.option.turboMobs.weight": "Weight", + "text.config.mysticalConfig.option.unbreakableLocation.change": "% chance", "text.config.mysticalConfig.option.unbreakableLocation.enabled": "Enable?", "text.config.mysticalConfig.option.unbreakableLocation.logLevel": "Logging", "text.config.mysticalConfig.option.unbreakableLocation.weight": "Weight", + "text.config.mysticalConfig.option.zombieTypeChange.change": "% chance", "text.config.mysticalConfig.option.zombieTypeChange.enabled": "Enable?", "text.config.mysticalConfig.option.zombieTypeChange.logLevel": "Logging", "text.config.mysticalConfig.option.zombieTypeChange.weight": "Weight", @@ -195,6 +220,11 @@ "text.mystical.consequence.zombieTypeChange.fired": "Spell zombieTypeChange: Zombie type changed..", "text.mystical.consequence.zombieTypeChange.longName": "Zombie Type Change", "text.mystical.consequence.zombieTypeChange.shortName": "zombieTypeChange", + "text.mystical.events.cureSpell": "1 spell was cured this night.", + "text.mystical.events.cureSpells": "%d spells were cured this night.", + "text.mystical.events.newSpell": "1 new spell fell over the world.", + "text.mystical.events.newSpells": "%d new spells fell over the world.", + "text.mystical.events.spellsChange": "The world shifts...", "text.mystical.logging.failedToGetRandomBlock": "Failed to get random block, using a command block instead.", "text.mystical.logging.failedToLoadHavenManager": "Failed to load haven manager, making a new one instead.", "text.mystical.logging.failedToLoadSpellHandler": "Failed to load spell handler, making a new one instead.", diff --git a/src/main/generated/data/mystical/lang/en_us.json b/src/main/generated/data/mystical/lang/en_us.json deleted file mode 100644 index f9d69962..00000000 --- a/src/main/generated/data/mystical/lang/en_us.json +++ /dev/null @@ -1,206 +0,0 @@ -{ - "text.config.mysticalConfig.category.aggressiveGolems": "Aggressive golems", - "text.config.mysticalConfig.category.bigCreeperExplosion": "Bigger Creeper Explosions", - "text.config.mysticalConfig.category.catVariantChange": "Cat Variant Change", - "text.config.mysticalConfig.category.disableDaylightBurning": "Disable Daylight Burning", - "text.config.mysticalConfig.category.enderTypeChange": "Ender Type Change", - "text.config.mysticalConfig.category.explosionsInfest": "Explosions Infest Blocks", - "text.config.mysticalConfig.category.fishingRodLaunch": "Fishing Rod Launch", - "text.config.mysticalConfig.category.illusionersReplaceEvokers": "Illusioners Replace Evokers", - "text.config.mysticalConfig.category.levitate": "Levitation", - "text.config.mysticalConfig.category.mobSpawnSwap": "Swap Overworld Mobs With Nether Mobs", - "text.config.mysticalConfig.category.noFuse": "No Fuses", - "text.config.mysticalConfig.category.oneStrikeWardens": "One Strike Wardens", - "text.config.mysticalConfig.category.randomCreeperEffectClouds": "Creepers leave random effect clouds", - "text.config.mysticalConfig.category.randomEvokerSummons": "Evokers Summon Random Mobs", - "text.config.mysticalConfig.category.randomTreeType": "Random Tree Types", - "text.config.mysticalConfig.category.sheepColorChange": "Sheep Color Change", - "text.config.mysticalConfig.category.skeletonTypeChange": "Skeleton Type Change", - "text.config.mysticalConfig.category.turboChickens": "Chickens lay eggs faster", - "text.config.mysticalConfig.category.turboMobs": "Turbo Mobs", - "text.config.mysticalConfig.category.unbreakableLocation": "Unbreakable Block (location)", - "text.config.mysticalConfig.category.zombieTypeChange": "Zombie Type Change", - "text.config.mysticalConfig.enum.logLevel.debug": "Debug", - "text.config.mysticalConfig.enum.logLevel.error": "Error", - "text.config.mysticalConfig.enum.logLevel.info": "Info", - "text.config.mysticalConfig.enum.logLevel.off": "No logging", - "text.config.mysticalConfig.enum.logLevel.warn": "Warn", - "text.config.mysticalConfig.option.aggressiveGolems.enabled": "Enable?", - "text.config.mysticalConfig.option.aggressiveGolems.logLevel": "Logging", - "text.config.mysticalConfig.option.aggressiveGolems.weight": "Weight", - "text.config.mysticalConfig.option.bigCreeperExplosion.enabled": "Enable?", - "text.config.mysticalConfig.option.bigCreeperExplosion.logLevel": "Logging", - "text.config.mysticalConfig.option.bigCreeperExplosion.weight": "Weight", - "text.config.mysticalConfig.option.catVariantChange.enabled": "Enable?", - "text.config.mysticalConfig.option.catVariantChange.logLevel": "Logging", - "text.config.mysticalConfig.option.catVariantChange.weight": "Weight", - "text.config.mysticalConfig.option.devMode": "Dev mode", - "text.config.mysticalConfig.option.disableDaylightBurning.enabled": "Enable?", - "text.config.mysticalConfig.option.disableDaylightBurning.logLevel": "Logging", - "text.config.mysticalConfig.option.disableDaylightBurning.weight": "Weight", - "text.config.mysticalConfig.option.enderTypeChange.enabled": "Enable?", - "text.config.mysticalConfig.option.enderTypeChange.logLevel": "Logging", - "text.config.mysticalConfig.option.enderTypeChange.weight": "Weight", - "text.config.mysticalConfig.option.explosionsInfest.enabled": "Enable?", - "text.config.mysticalConfig.option.explosionsInfest.logLevel": "Logging", - "text.config.mysticalConfig.option.explosionsInfest.weight": "Weight", - "text.config.mysticalConfig.option.failedToGetRandomBlockLogLevel": "Failed to get random block", - "text.config.mysticalConfig.option.failedToLoadHavenManagerLogLevel": "Failed to load haven manager", - "text.config.mysticalConfig.option.failedToLoadSpellHandlerLogLevel": "Failed to load spell handler", - "text.config.mysticalConfig.option.failedToSaveSpellHandlerLogLevel": "Failed to save spell manager", - "text.config.mysticalConfig.option.failedToSetNightTimerLogLevel": "Failed to set night timer", - "text.config.mysticalConfig.option.fishingRodLaunch.enabled": "Enable?", - "text.config.mysticalConfig.option.fishingRodLaunch.logLevel": "Logging", - "text.config.mysticalConfig.option.fishingRodLaunch.weight": "Weight", - "text.config.mysticalConfig.option.illusionersReplaceEvokers.enabled": "Enable?", - "text.config.mysticalConfig.option.illusionersReplaceEvokers.logLevel": "Logging", - "text.config.mysticalConfig.option.illusionersReplaceEvokers.weight": "Weight", - "text.config.mysticalConfig.option.levitate.enabled": "Enable?", - "text.config.mysticalConfig.option.levitate.logLevel": "Logging", - "text.config.mysticalConfig.option.levitate.weight": "Weight", - "text.config.mysticalConfig.option.mobSpawnSwap.enabled": "Enable?", - "text.config.mysticalConfig.option.mobSpawnSwap.logLevel": "Logging", - "text.config.mysticalConfig.option.mobSpawnSwap.weight": "Weight", - "text.config.mysticalConfig.option.newSpellCommandBroadcast": "New spell command (in-game)", - "text.config.mysticalConfig.option.newSpellCommandLogLevel": "New spell command (console)", - "text.config.mysticalConfig.option.noFuse.enabled": "Enable?", - "text.config.mysticalConfig.option.noFuse.logLevel": "Logging", - "text.config.mysticalConfig.option.noFuse.weight": "Weight", - "text.config.mysticalConfig.option.oneStrikeWardens.enabled": "Enable?", - "text.config.mysticalConfig.option.oneStrikeWardens.logLevel": "Logging", - "text.config.mysticalConfig.option.oneStrikeWardens.weight": "Weight", - "text.config.mysticalConfig.option.randomCreeperEffectClouds.enabled": "Enable?", - "text.config.mysticalConfig.option.randomCreeperEffectClouds.logLevel": "Logging", - "text.config.mysticalConfig.option.randomCreeperEffectClouds.weight": "Weight", - "text.config.mysticalConfig.option.randomEvokerSummons.enabled": "Enable?", - "text.config.mysticalConfig.option.randomEvokerSummons.logLevel": "Logging", - "text.config.mysticalConfig.option.randomEvokerSummons.weight": "Weight", - "text.config.mysticalConfig.option.randomTreeType.enabled": "Enable?", - "text.config.mysticalConfig.option.randomTreeType.logLevel": "Logging", - "text.config.mysticalConfig.option.randomTreeType.weight": "Weight", - "text.config.mysticalConfig.option.sheepColorChange.enabled": "Enable?", - "text.config.mysticalConfig.option.sheepColorChange.logLevel": "Logging", - "text.config.mysticalConfig.option.sheepColorChange.weight": "Weight", - "text.config.mysticalConfig.option.skeletonTypeChange.enabled": "Enable?", - "text.config.mysticalConfig.option.skeletonTypeChange.logLevel": "Logging", - "text.config.mysticalConfig.option.skeletonTypeChange.weight": "Weight", - "text.config.mysticalConfig.option.spellContributionLogLevel": "Spell contribution", - "text.config.mysticalConfig.option.spellMaxHard": "Max spells (Hard)", - "text.config.mysticalConfig.option.spellMaxHard.tooltip": "The maximum number of spells active at a time.\nMystical will not delete extra spells, but won't make any past this point.", - "text.config.mysticalConfig.option.spellMinHard": "Min spells (Hard)", - "text.config.mysticalConfig.option.spellMinHard.tooltip": "The minimum number of spells active at a time.\nMystical will make sure there are this many spells active whenever spell rewards are paid out.", - "text.config.mysticalConfig.option.timeOfDayAtStartupLogLevel": "Time of day at startup", - "text.config.mysticalConfig.option.turboChickens.enabled": "Enable?", - "text.config.mysticalConfig.option.turboChickens.logLevel": "Logging", - "text.config.mysticalConfig.option.turboChickens.weight": "Weight", - "text.config.mysticalConfig.option.turboMobs.enabled": "Enable?", - "text.config.mysticalConfig.option.turboMobs.logLevel": "Logging", - "text.config.mysticalConfig.option.turboMobs.weight": "Weight", - "text.config.mysticalConfig.option.unbreakableLocation.enabled": "Enable?", - "text.config.mysticalConfig.option.unbreakableLocation.logLevel": "Logging", - "text.config.mysticalConfig.option.unbreakableLocation.weight": "Weight", - "text.config.mysticalConfig.option.zombieTypeChange.enabled": "Enable?", - "text.config.mysticalConfig.option.zombieTypeChange.logLevel": "Logging", - "text.config.mysticalConfig.option.zombieTypeChange.weight": "Weight", - "text.config.mysticalConfig.section.General": "General", - "text.config.mysticalConfig.section.Logging": "Logging", - "text.config.mysticalConfig.section.Spells": "Spells", - "text.config.mysticalConfig.title": "Mystical Config", - "text.mystical.command.mystical.reload.success": "Successfully reloaded config and set night timer.", - "text.mystical.command.mystical.spell.delete.noSpells": "There are no active spells.", - "text.mystical.command.mystical.spell.list.noSpells": "There are no active spells.", - "text.mystical.command.mystical.spell.new.spell.warnDisabled": "Warning: Randomly generating this spell is disabled, or its weight is zero.", - "text.mystical.command.mystical.spell.new.success": "Successfully created new %s spell.", - "text.mystical.consequence.aggressiveGolems.description": "Iron + Pumpkin says \"Here, have pain!\"", - "text.mystical.consequence.aggressiveGolems.fired": "Spell aggressiveGolems: Golem is aggressive.", - "text.mystical.consequence.aggressiveGolems.longName": "Aggressive golems", - "text.mystical.consequence.aggressiveGolems.shortName": "aggressiveGolems", - "text.mystical.consequence.bigCreeperExplosion.description": "Creepers go boom. But more.", - "text.mystical.consequence.bigCreeperExplosion.fired": "Spell bigCreeperExplosion: Creeper explosion multiplied..", - "text.mystical.consequence.bigCreeperExplosion.longName": "Bigger Creeper Explosions", - "text.mystical.consequence.bigCreeperExplosion.shortName": "bigCreeperExplosion", - "text.mystical.consequence.catVariantChange.description": "We change coats, so why can't cats do the same?", - "text.mystical.consequence.catVariantChange.fired": "Spell catVariantChange: Changed cat variant.", - "text.mystical.consequence.catVariantChange.longName": "Cat Variant Change", - "text.mystical.consequence.catVariantChange.shortName": "catVariantChange", - "text.mystical.consequence.disableDaylightBurning.description": "Mobs bought some sunscreen", - "text.mystical.consequence.disableDaylightBurning.fired": "Spell disableDaylightBurning: Said no this mob doesn't burn.", - "text.mystical.consequence.disableDaylightBurning.longName": "Disable Daylight Burning", - "text.mystical.consequence.disableDaylightBurning.shortName": "disableDaylightBurning", - "text.mystical.consequence.enderTypeChange.description": "Of mites and men", - "text.mystical.consequence.enderTypeChange.fired": "Spell enderTypeChange: Swapped ender entity type.", - "text.mystical.consequence.enderTypeChange.longName": "Ender Type Change", - "text.mystical.consequence.enderTypeChange.shortName": "enderTypeChange", - "text.mystical.consequence.explosionsInfest.description": "ssss... delayed ssss!", - "text.mystical.consequence.explosionsInfest.fired": "Spell explosionsInfest: Infested blocks.", - "text.mystical.consequence.explosionsInfest.longName": "Explosions Infest Blocks", - "text.mystical.consequence.explosionsInfest.shortName": "explosionsInfest", - "text.mystical.consequence.fishingRodLaunch.description": "Hehe. Rod make cow go zoom.", - "text.mystical.consequence.fishingRodLaunch.fired": "Spell fishingRodLaunch: Fishing rod power multiplied.", - "text.mystical.consequence.fishingRodLaunch.longName": "Fishing Rod Launch", - "text.mystical.consequence.fishingRodLaunch.shortName": "fishingRodLaunch", - "text.mystical.consequence.illusionersReplaceEvokers.description": "But it was all an illusion!", - "text.mystical.consequence.illusionersReplaceEvokers.fired": "Spell illusionersReplaceEvokers: Replaced an evoker with an illusioner..", - "text.mystical.consequence.illusionersReplaceEvokers.longName": "Illusioners Replace Evokers", - "text.mystical.consequence.illusionersReplaceEvokers.shortName": "illusionersReplaceEvokers", - "text.mystical.consequence.levitate.description": "Are you a balloon?", - "text.mystical.consequence.levitate.fired": "Spell levitate: Levitating entity.", - "text.mystical.consequence.levitate.longName": "Levitation", - "text.mystical.consequence.levitate.shortName": "levitate", - "text.mystical.consequence.mobSpawnSwap.description": "Hot guy cold, cold guy hot.", - "text.mystical.consequence.mobSpawnSwap.fired": "Spell mobSpawnSwap: Nether mob <-> overworld mob.", - "text.mystical.consequence.mobSpawnSwap.longName": "Swap Overworld Mobs With Nether Mobs", - "text.mystical.consequence.mobSpawnSwap.shortName": "mobSpawnSwap", - "text.mystical.consequence.noFuse.description": "Creepers don't hesitate anymore.", - "text.mystical.consequence.noFuse.fired": "Spell noFuse: Destroyed a fuse.", - "text.mystical.consequence.noFuse.longName": "No Fuses", - "text.mystical.consequence.noFuse.shortName": "noFuse", - "text.mystical.consequence.oneStrikeWardens.description": "Mr. Clompy Shoes returns!", - "text.mystical.consequence.oneStrikeWardens.fired": "Spell oneStrikeWardens: Hah. New warden, nerd..", - "text.mystical.consequence.oneStrikeWardens.longName": "One Strike Wardens", - "text.mystical.consequence.oneStrikeWardens.shortName": "oneStrikeWardens", - "text.mystical.consequence.randomCreeperEffectClouds.description": "Hissss... Bubbles?", - "text.mystical.consequence.randomCreeperEffectClouds.fired": "Spell randomCreeperEffectClouds: Random effect cloud made.", - "text.mystical.consequence.randomCreeperEffectClouds.longName": "Creepers leave random effect clouds", - "text.mystical.consequence.randomCreeperEffectClouds.shortName": "randomCreeperEffectClouds", - "text.mystical.consequence.randomEvokerSummons.description": "Evokers found some new friends!", - "text.mystical.consequence.randomEvokerSummons.fired": "Spell randomEvokerSummons: Evoker summoned random mob.", - "text.mystical.consequence.randomEvokerSummons.longName": "Evokers Summon Random Mobs", - "text.mystical.consequence.randomEvokerSummons.shortName": "randomEvokerSummons", - "text.mystical.consequence.randomTreeType.description": "The saplings are spies!", - "text.mystical.consequence.randomTreeType.fired": "Spell randomTreeType: Random tree generated.", - "text.mystical.consequence.randomTreeType.longName": "Random Tree Types", - "text.mystical.consequence.randomTreeType.shortName": "randomTreeType", - "text.mystical.consequence.sheepColorChange.description": "The fluffy marshmallows got jealous of _jeb.", - "text.mystical.consequence.sheepColorChange.fired": "Spell sheepColorChange: Sheep color changed.", - "text.mystical.consequence.sheepColorChange.longName": "Sheep Color Change", - "text.mystical.consequence.sheepColorChange.shortName": "sheepColorChange", - "text.mystical.consequence.skeletonTypeChange.description": "Skeletons are having a wardrobe crisis too!", - "text.mystical.consequence.skeletonTypeChange.fired": "Spell skeletonTypeChange: Skeleton type changed.", - "text.mystical.consequence.skeletonTypeChange.longName": "Skeleton Type Change", - "text.mystical.consequence.skeletonTypeChange.shortName": "skeletonTypeChange", - "text.mystical.consequence.turboChickens.description": "Turbo chickens", - "text.mystical.consequence.turboChickens.fired": "Spell turboChickens: Turbo chicken activated.", - "text.mystical.consequence.turboChickens.longName": "Chickens lay eggs faster", - "text.mystical.consequence.turboChickens.shortName": "turboChickens", - "text.mystical.consequence.turboMobs.description": "%s go zoom", - "text.mystical.consequence.turboMobs.fired": "Spell turboMobs: Gave a mob extra speed..", - "text.mystical.consequence.turboMobs.longName": "Turbo Mobs", - "text.mystical.consequence.turboMobs.shortName": "turboMobs", - "text.mystical.consequence.unbreakableLocation.description": "WorldGuard but awful", - "text.mystical.consequence.unbreakableLocation.fired": "Spell unbreakableLocation: Prevented a block from being broken..", - "text.mystical.consequence.unbreakableLocation.longName": "Unbreakable Block (location)", - "text.mystical.consequence.unbreakableLocation.shortName": "unbreakableLocation", - "text.mystical.consequence.zombieTypeChange.description": "Zombies are having a wardrobe crisis", - "text.mystical.consequence.zombieTypeChange.fired": "Spell zombieTypeChange: Zombie type changed..", - "text.mystical.consequence.zombieTypeChange.longName": "Zombie Type Change", - "text.mystical.consequence.zombieTypeChange.shortName": "zombieTypeChange", - "text.mystical.logging.failedToGetRandomBlock": "Failed to get random block, using a command block instead.", - "text.mystical.logging.failedToLoadHavenManager": "Failed to load haven manager, making a new one instead.", - "text.mystical.logging.failedToLoadSpellHandler": "Failed to load spell handler, making a new one instead.", - "text.mystical.logging.failedToSaveSpellHandler": "Failed to save spell manager.", - "text.mystical.logging.failedToSetNightTimer": "Failed to set night timer because %s", - "text.mystical.logging.newSpellCommand": "New spell created using command", - "text.mystical.logging.spellContribution": "Spell contribution by %s. Amount: %d.", - "text.mystical.logging.timeOfDayAtStartup": "Time of day at startup: %l." -} \ No newline at end of file diff --git a/src/main/java/com/skycat/mystical/Mystical.java b/src/main/java/com/skycat/mystical/Mystical.java index 40ba211a..a7e92564 100644 --- a/src/main/java/com/skycat/mystical/Mystical.java +++ b/src/main/java/com/skycat/mystical/Mystical.java @@ -38,6 +38,7 @@ import java.util.Random; import java.util.UUID; +// WARNING: Package structure looks like split-sources structure. It's not. I'm working on it. @Getter public class Mystical implements ModInitializer, ServerWorldEvents.Load { @Getter public static final Logger LOGGER = LoggerFactory.getLogger("mystical"); diff --git a/src/main/java/com/skycat/mystical/common/ConfigModel.java b/src/main/java/com/skycat/mystical/common/ConfigModel.java index a90cc67c..63e8cb50 100644 --- a/src/main/java/com/skycat/mystical/common/ConfigModel.java +++ b/src/main/java/com/skycat/mystical/common/ConfigModel.java @@ -10,6 +10,8 @@ public class ConfigModel { public boolean devMode = false; // Not implemented public int spellMaxHard = 3; public int spellMinHard = 0; + public double spellDecay = 10.0; + public boolean spellDecayLinear = false; @SectionHeader("Spells") @Nest public BigCreeperExplosionConfig bigCreeperExplosion = new BigCreeperExplosionConfig(); @@ -371,7 +373,9 @@ public static boolean chancePredicate(double value) { public static boolean weightPredicate(double value) { return value >= 0; } - + public static boolean percentPredicate(double value) { + return value >= 0 && value <= 100; + } public static boolean positivePredicate(double value) { return value >= 0; } diff --git a/src/main/java/com/skycat/mystical/common/spell/SpellHandler.java b/src/main/java/com/skycat/mystical/common/spell/SpellHandler.java index 847c7c89..3e1dd308 100644 --- a/src/main/java/com/skycat/mystical/common/spell/SpellHandler.java +++ b/src/main/java/com/skycat/mystical/common/spell/SpellHandler.java @@ -7,6 +7,7 @@ import com.skycat.mystical.common.spell.cure.SpellCure; import com.skycat.mystical.common.spell.cure.StatBackedSpellCure; import com.skycat.mystical.common.util.Utils; +import com.skycat.mystical.event.CatEntityEvents; import lombok.Getter; import net.fabricmc.fabric.api.entity.event.v1.EntitySleepEvents; import net.fabricmc.fabric.api.entity.event.v1.ServerEntityCombatEvents; @@ -17,7 +18,9 @@ import net.minecraft.block.entity.BlockEntity; import net.minecraft.entity.Entity; import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.passive.CatEntity; import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemStack; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.world.ServerWorld; import net.minecraft.stat.Stat; @@ -36,6 +39,7 @@ import java.util.ListIterator; import java.util.Scanner; +import static com.skycat.mystical.Mystical.CONFIG; import static com.skycat.mystical.Mystical.GSON; public class SpellHandler implements EntitySleepEvents.StartSleeping, @@ -44,7 +48,8 @@ public class SpellHandler implements EntitySleepEvents.StartSleeping, PlayerBlockBreakEvents.After, ServerPlayerEvents.AfterRespawn, ServerEntityCombatEvents.AfterKilledOtherEntity, - AttackBlockCallback { + AttackBlockCallback, + CatEntityEvents.Eat { /** * @implNote Saving/loading does not ensure that the order of spells will be retained. */ @@ -75,6 +80,15 @@ public static SpellHandler loadOrNew() { } } + public void decaySpells() { + double amount = CONFIG.spellDecay() / 100; + for (Spell spell : activeSpells) { + SpellCure cure = spell.getCure(); + // If linear, base decay on the goal. Otherwise, base it on how much is left. + cure.contribute(null, (int) Math.ceil((CONFIG.spellDecayLinear() ? cure.getContributionGoal() : cure.getContributionsLeft()) * amount)); + } + } + @Override public ActionResult interact(PlayerEntity player, World world, Hand hand, BlockPos pos, Direction direction) { boolean fail = false; @@ -90,6 +104,7 @@ public boolean isConsequenceActive(Class consequence return !spellsOfConsequenceType(consequence).isEmpty(); } + /** * Used for finding active spells with a particular consequence type. * This is not the same as a handler. @@ -124,6 +139,13 @@ public void afterBlockBreak(World world, PlayerEntity player, BlockPos pos, Bloc } } + @Override + public void onEat(CatEntity cat, PlayerEntity player, Hand hand, ItemStack stack) { + for (Spell spell : spellsOfHandler(CatEntityEvents.Eat.class)) { + ((CatEntityEvents.Eat) spell.getConsequence()).onEat(cat, player, hand, stack); + } + } + @Override public void afterKilledOtherEntity(ServerWorld world, Entity entity, LivingEntity killedEntity) { for (Spell spell : spellsOfHandler(ServerEntityCombatEvents.AfterKilledOtherEntity.class)) { diff --git a/src/main/java/com/skycat/mystical/common/spell/consequence/CatVariantChangeConsequence.java b/src/main/java/com/skycat/mystical/common/spell/consequence/CatVariantChangeConsequence.java index 7a44db77..b16ccd75 100644 --- a/src/main/java/com/skycat/mystical/common/spell/consequence/CatVariantChangeConsequence.java +++ b/src/main/java/com/skycat/mystical/common/spell/consequence/CatVariantChangeConsequence.java @@ -2,13 +2,25 @@ import com.mojang.serialization.Codec; import com.skycat.mystical.Mystical; +import com.skycat.mystical.common.util.Utils; +import com.skycat.mystical.event.CatEntityEvents; import lombok.NonNull; +import net.minecraft.entity.passive.CatEntity; +import net.minecraft.entity.passive.CatVariant; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.registry.Registries; +import net.minecraft.util.Hand; +import net.minecraft.util.Util; import org.jetbrains.annotations.NotNull; +import java.util.ArrayList; import java.util.Random; -public class CatVariantChangeConsequence extends SpellConsequence { +public class CatVariantChangeConsequence extends SpellConsequence implements CatEntityEvents.Eat { public static final Factory FACTORY = new Factory(); + private static final ArrayList VARIANTS = new ArrayList<>(); + @Override public @NotNull ConsequenceFactory getFactory() { @@ -16,7 +28,22 @@ public class CatVariantChangeConsequence extends SpellConsequence { } public CatVariantChangeConsequence() { // TODO: Config on variants - super(CatVariantChangeConsequence.class, null, 1d); // TODO: Scaling + super(CatVariantChangeConsequence.class, CatEntityEvents.Eat.class, 1d); // TODO: Scaling + } + + @Override + public void onEat(CatEntity cat, PlayerEntity player, Hand hand, ItemStack stack) { + if (VARIANTS.isEmpty()) { // Should this be in static? Seems like delaying initialization might be good though. + for (CatVariant catVariant : Registries.CAT_VARIANT) { + VARIANTS.add(catVariant); + } + } + if (Mystical.getSpellHandler().isConsequenceActive(CatVariantChangeConsequence.class) && + !Mystical.getHavenManager().isInHaven(player) && + Utils.percentChance(Mystical.CONFIG.catVariantChange.chance())) { + cat.setVariant(Util.getRandom(VARIANTS, Mystical.MC_RANDOM)); + Utils.log(Utils.translateString("text.mystical.consequence.catVariantChange.fired"), Mystical.CONFIG.catVariantChange.logLevel()); + } } public static class Factory extends ConsequenceFactory { diff --git a/src/main/java/com/skycat/mystical/common/spell/cure/SpellCure.java b/src/main/java/com/skycat/mystical/common/spell/cure/SpellCure.java index ea214220..bfbd5f49 100644 --- a/src/main/java/com/skycat/mystical/common/spell/cure/SpellCure.java +++ b/src/main/java/com/skycat/mystical/common/spell/cure/SpellCure.java @@ -62,6 +62,9 @@ public void sumContributions() { } public void contribute(@Nullable UUID uuid, int amount) { + if (uuid == null) { + uuid = UUID.fromString("09b4c37c-1dd6-4eb4-8adf-f660dd111410"); // This better not collide with anything. + } if (contributions.containsKey(uuid)) { contributions.put(uuid, contributions.get(uuid) + amount); } else { @@ -69,11 +72,7 @@ public void contribute(@Nullable UUID uuid, int amount) { } contributionTotal += amount; String contributor; - if (uuid != null) { - contributor = uuid.toString(); - } else { - contributor = "unknown"; - } + contributor = uuid.toString(); Utils.log(Utils.translateString("text.mystical.logging.spellContribution", contributor, amount), Mystical.CONFIG.spellContributionLogLevel()); Mystical.saveUpdated(); } @@ -104,6 +103,10 @@ public void awardPower(int totalPower, int max) { } } + public int getContributionsLeft() { + return getContributionGoal() - getContributionTotal(); + } + public static class Serializer implements JsonSerializer, JsonDeserializer { @Override public SpellCure deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { diff --git a/src/main/java/com/skycat/mystical/datagen/EnglishLangProvider.java b/src/main/java/com/skycat/mystical/datagen/EnglishLangProvider.java index f9bab1d1..98970e31 100644 --- a/src/main/java/com/skycat/mystical/datagen/EnglishLangProvider.java +++ b/src/main/java/com/skycat/mystical/datagen/EnglishLangProvider.java @@ -18,9 +18,13 @@ public void generateTranslations(TranslationBuilder tb) { addConfigSection(tb, "General"); addConfigOption(tb, "devMode", "Dev mode"); addConfigOption(tb, "spellMaxHard", "Max spells (Hard)"); - addConfigOption(tb, "spellMinHard", "Min spells (Hard)"); addConfigOptionTooltip(tb, "spellMaxHard", "The maximum number of spells active at a time.\nMystical will not delete extra spells, but won't make any past this point."); + addConfigOption(tb, "spellMinHard", "Min spells (Hard)"); addConfigOptionTooltip(tb, "spellMinHard", "The minimum number of spells active at a time.\nMystical will make sure there are this many spells active whenever spell rewards are paid out."); + addConfigOption(tb, "spellDecay", "Spell decay (%)"); + addConfigOptionTooltip(tb, "spellDecay", "How much spells will decay each night."); + addConfigOption(tb, "spellDecayLinear", "Decay spells linearly?"); + addConfigOptionTooltip(tb, "spellDecayLinear", "If true, spells will decay based on the full requirement of the spell.\nIf false, they will decay based on what's left."); addConfigSection(tb, "Logging"); addLoggingOption(tb, "newSpellCommand", "New spell created using command", "New spell command (console)"); diff --git a/src/main/java/com/skycat/mystical/event/CatEntityEvents.java b/src/main/java/com/skycat/mystical/event/CatEntityEvents.java new file mode 100644 index 00000000..ef299c8f --- /dev/null +++ b/src/main/java/com/skycat/mystical/event/CatEntityEvents.java @@ -0,0 +1,21 @@ +package com.skycat.mystical.event; + +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; +import net.minecraft.entity.passive.CatEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.util.Hand; + +public class CatEntityEvents { + public static final Event EAT = EventFactory.createArrayBacked(Eat.class, (callbacks) -> (cat, player, hand, stack) -> { + for (Eat eat : callbacks) { + eat.onEat(cat, player, hand, stack); + } + }); + + @FunctionalInterface + public interface Eat { + void onEat(CatEntity cat, PlayerEntity player, Hand hand, ItemStack stack); + } +} diff --git a/src/main/java/com/skycat/mystical/mixin/CatEntityMixin.java b/src/main/java/com/skycat/mystical/mixin/CatEntityMixin.java index bc6c4d26..5bc5cc8e 100644 --- a/src/main/java/com/skycat/mystical/mixin/CatEntityMixin.java +++ b/src/main/java/com/skycat/mystical/mixin/CatEntityMixin.java @@ -1,41 +1,22 @@ package com.skycat.mystical.mixin; -import com.skycat.mystical.Mystical; -import com.skycat.mystical.common.spell.consequence.CatVariantChangeConsequence; -import com.skycat.mystical.common.util.Utils; +import com.skycat.mystical.event.CatEntityEvents; import net.minecraft.entity.passive.CatEntity; -import net.minecraft.entity.passive.CatVariant; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; -import net.minecraft.registry.Registries; import net.minecraft.util.Hand; -import net.minecraft.util.Util; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import java.util.ArrayList; - @Mixin(CatEntity.class) -public abstract class CatEntityMixin { // I could probably turn this into an event - @Unique private static final ArrayList VARIANTS = new ArrayList<>(); - @Shadow public abstract void setVariant(CatVariant variant); - +public abstract class CatEntityMixin { + /** + * Fire the {@link CatEntityEvents.Eat} event. + */ @Inject(method = "eat", at = @At("HEAD")) public void eat(PlayerEntity entity, Hand hand, ItemStack stack, CallbackInfo ci) { - if (VARIANTS.isEmpty()) { // Should this be in static? Seems like delaying initialization might be good though. - for (CatVariant catVariant : Registries.CAT_VARIANT) { - VARIANTS.add(catVariant); - } - } - if ((Mystical.isClientWorld() && Mystical.getSpellHandler().isConsequenceActive(CatVariantChangeConsequence.class)) && - !(Mystical.isClientWorld() && Mystical.getHavenManager().isInHaven(entity)) && - Utils.percentChance(Mystical.CONFIG.catVariantChange.chance())) { - setVariant(Util.getRandom(VARIANTS, Mystical.MC_RANDOM)); - Utils.log(Utils.translateString("text.mystical.consequence.catVariantChange.fired"), Mystical.CONFIG.catVariantChange.logLevel()); - } + CatEntityEvents.EAT.invoker().onEat((CatEntity) (Object) this, entity, hand, stack); } } diff --git a/src/main/java/com/skycat/mystical/mixin/ChickenEntityMixin.java b/src/main/java/com/skycat/mystical/mixin/ChickenEntityMixin.java index 14e6b362..f218828a 100644 --- a/src/main/java/com/skycat/mystical/mixin/ChickenEntityMixin.java +++ b/src/main/java/com/skycat/mystical/mixin/ChickenEntityMixin.java @@ -12,7 +12,7 @@ public abstract class ChickenEntityMixin { @Redirect(method = "tickMovement", at = @At(value = "FIELD", target = "Lnet/minecraft/entity/passive/ChickenEntity;eggLayTime:I", opcode = Opcodes.PUTFIELD, ordinal = 1)) private void shortenEggLayTime(ChickenEntity instance, int value) { - if (Mystical.isClientWorld() && + if (!Mystical.isClientWorld() && Mystical.getSpellHandler().isConsequenceActive(TurboChickensConsequence.class) && Mystical.getHavenManager().isInHaven(instance)) { instance.eggLayTime = (int) (value / Mystical.CONFIG.turboChickens.speed()); diff --git a/src/main/java/com/skycat/mystical/server/MysticalEventHandler.java b/src/main/java/com/skycat/mystical/server/MysticalEventHandler.java index 62f194ed..3300e16d 100644 --- a/src/main/java/com/skycat/mystical/server/MysticalEventHandler.java +++ b/src/main/java/com/skycat/mystical/server/MysticalEventHandler.java @@ -1,6 +1,7 @@ package com.skycat.mystical.server; import com.skycat.mystical.Mystical; +import com.skycat.mystical.common.spell.SpellHandler; import com.skycat.mystical.common.util.Utils; import lombok.Getter; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; @@ -35,7 +36,9 @@ public void doNighttimeEvents() { * Do all the nighttime events - changing spells and setting the night timer. */ public void doNighttimeEvents(MinecraftServer server) { - int spellsCured = Mystical.getSpellHandler().removeCuredSpells(); + SpellHandler spellHandler = Mystical.getSpellHandler(); + spellHandler.decaySpells(); + int spellsCured = spellHandler.removeCuredSpells(); Stack messageStack = new Stack<>(); // Done this way because it seemed best to get the spell changing message out on top if (spellsCured == 1) { messageStack.push(Utils.translatable("text.mystical.events.cureSpell")); @@ -44,12 +47,12 @@ public void doNighttimeEvents(MinecraftServer server) { messageStack.push(Utils.translatable("text.mystical.events.cureSpells", spellsCured)); } int newSpells = 0; - if (Mystical.getSpellHandler().getActiveSpells().size() < Mystical.CONFIG.spellMaxHard()) { // Make sure we don't go past the max number of spells - Mystical.getSpellHandler().activateNewSpell(); + if (spellHandler.getActiveSpells().size() < Mystical.CONFIG.spellMaxHard()) { // Make sure we don't go past the max number of spells + spellHandler.activateNewSpell(); newSpells++; } - while (Mystical.getSpellHandler().getActiveSpells().size() < Mystical.CONFIG.spellMinHard()) { // Make sure we have the minimum number of spells - Mystical.getSpellHandler().activateNewSpell(); + while (spellHandler.getActiveSpells().size() < Mystical.CONFIG.spellMinHard()) { // Make sure we have the minimum number of spells + spellHandler.activateNewSpell(); newSpells++; } if (newSpells == 1) {