From 2075fa5be33b034ba19086b2e859766feb8917ca Mon Sep 17 00:00:00 2001 From: WayofTime Date: Sat, 28 Nov 2020 12:04:11 -0500 Subject: [PATCH] First stab at Living Armour reimplementation. Added a lot of the upgrades, but there's still more testing/upgrades to be done/reimplemented. --- src/generated/resources/.cache/cache | 7 +- .../assets/bloodmagic/lang/en_us.json | 48 ++++ .../bloodmagic/models/item/livingboots.json | 6 + .../bloodmagic/models/item/livinghelmet.json | 6 + .../models/item/livingleggings.json | 6 + .../bloodmagic/models/item/livingplate.json | 6 + .../bloodmagic/models/item/upgradetome.json | 6 + .../java/wayoftime/bloodmagic/BloodMagic.java | 3 + .../common/data/GeneratorLanguage.java | 53 ++++ .../common/item/ArmorMaterialLiving.java | 59 ++++ .../common/item/BloodMagicItems.java | 10 +- .../bloodmagic/common/item/ExpandedArmor.java | 20 ++ .../common/item/ItemLivingArmor.java | 163 +++++++++++ .../common/item/ItemLivingTome.java | 101 +++++++ .../common/item/ItemLivingTrainer.java | 28 ++ .../impl/LivingUpgradeDeferredRegister.java | 25 ++ .../impl/LivingUpgradeRegistryObject.java | 13 + .../bloodmagic/core/LivingArmorRegistrar.java | 182 ++++++++++++ .../core/living/ILivingContainer.java | 60 ++++ .../bloodmagic/core/living/LivingStats.java | 150 ++++++++++ .../bloodmagic/core/living/LivingUpgrade.java | 267 ++++++++++++++++++ .../bloodmagic/core/living/LivingUtil.java | 176 ++++++++++++ .../core/living/ProjectileArmorProvider.java | 15 + .../bloodmagic/core/util/PlayerUtil.java | 57 ++++ .../bloodmagic/core/util/ResourceUtil.java | 78 +++++ .../wayoftime/bloodmagic/core/util/Value.java | 27 ++ .../event/LivingEquipmentEvent.java | 96 +++++++ .../bloodmagic/event/LivingEvent.java | 30 ++ .../java/wayoftime/bloodmagic/util/Utils.java | 108 +++++++ .../util/handler/event/GenericHandler.java | 185 ++++++++++++ .../living_armor/arrow_protect.json | 29 ++ .../bloodmagic/living_armor/arrow_shot.json | 10 + .../living_armor/critical_strike.json | 19 ++ .../data/bloodmagic/living_armor/digging.json | 53 ++++ .../bloodmagic/living_armor/experienced.json | 29 ++ .../bloodmagic/living_armor/fall_protect.json | 19 ++ .../bloodmagic/living_armor/fire_resist.json | 26 ++ .../data/bloodmagic/living_armor/health.json | 29 ++ .../data/bloodmagic/living_armor/jump.json | 41 +++ .../living_armor/self_sacrifice.json | 29 ++ .../data/bloodmagic/living_armor/speed.json | 53 ++++ .../living_armor/sprint_attack.json | 26 ++ 42 files changed, 2352 insertions(+), 2 deletions(-) create mode 100644 src/generated/resources/assets/bloodmagic/models/item/livingboots.json create mode 100644 src/generated/resources/assets/bloodmagic/models/item/livinghelmet.json create mode 100644 src/generated/resources/assets/bloodmagic/models/item/livingleggings.json create mode 100644 src/generated/resources/assets/bloodmagic/models/item/livingplate.json create mode 100644 src/generated/resources/assets/bloodmagic/models/item/upgradetome.json create mode 100644 src/main/java/wayoftime/bloodmagic/common/item/ArmorMaterialLiving.java create mode 100644 src/main/java/wayoftime/bloodmagic/common/item/ExpandedArmor.java create mode 100644 src/main/java/wayoftime/bloodmagic/common/item/ItemLivingArmor.java create mode 100644 src/main/java/wayoftime/bloodmagic/common/item/ItemLivingTome.java create mode 100644 src/main/java/wayoftime/bloodmagic/common/item/ItemLivingTrainer.java create mode 100644 src/main/java/wayoftime/bloodmagic/common/registration/impl/LivingUpgradeDeferredRegister.java create mode 100644 src/main/java/wayoftime/bloodmagic/common/registration/impl/LivingUpgradeRegistryObject.java create mode 100644 src/main/java/wayoftime/bloodmagic/core/LivingArmorRegistrar.java create mode 100644 src/main/java/wayoftime/bloodmagic/core/living/ILivingContainer.java create mode 100644 src/main/java/wayoftime/bloodmagic/core/living/LivingStats.java create mode 100644 src/main/java/wayoftime/bloodmagic/core/living/LivingUpgrade.java create mode 100644 src/main/java/wayoftime/bloodmagic/core/living/LivingUtil.java create mode 100644 src/main/java/wayoftime/bloodmagic/core/living/ProjectileArmorProvider.java create mode 100644 src/main/java/wayoftime/bloodmagic/core/util/PlayerUtil.java create mode 100644 src/main/java/wayoftime/bloodmagic/core/util/ResourceUtil.java create mode 100644 src/main/java/wayoftime/bloodmagic/core/util/Value.java create mode 100644 src/main/java/wayoftime/bloodmagic/event/LivingEquipmentEvent.java create mode 100644 src/main/java/wayoftime/bloodmagic/event/LivingEvent.java create mode 100644 src/main/resources/data/bloodmagic/living_armor/arrow_protect.json create mode 100644 src/main/resources/data/bloodmagic/living_armor/arrow_shot.json create mode 100644 src/main/resources/data/bloodmagic/living_armor/critical_strike.json create mode 100644 src/main/resources/data/bloodmagic/living_armor/digging.json create mode 100644 src/main/resources/data/bloodmagic/living_armor/experienced.json create mode 100644 src/main/resources/data/bloodmagic/living_armor/fall_protect.json create mode 100644 src/main/resources/data/bloodmagic/living_armor/fire_resist.json create mode 100644 src/main/resources/data/bloodmagic/living_armor/health.json create mode 100644 src/main/resources/data/bloodmagic/living_armor/jump.json create mode 100644 src/main/resources/data/bloodmagic/living_armor/self_sacrifice.json create mode 100644 src/main/resources/data/bloodmagic/living_armor/speed.json create mode 100644 src/main/resources/data/bloodmagic/living_armor/sprint_attack.json diff --git a/src/generated/resources/.cache/cache b/src/generated/resources/.cache/cache index d938ef2c..97e8d160 100644 --- a/src/generated/resources/.cache/cache +++ b/src/generated/resources/.cache/cache @@ -56,7 +56,7 @@ e6d9cf699667aaa47efff37b2b033895dee29c15 assets/bloodmagic/blockstates/waterritu 42f26f715bddd16c069f9b51e3767b36477c8908 assets/bloodmagic/blockstates/woodtilepath.json 3c6ce233dae6c1307d9016406c324bbe844b4e1e assets/bloodmagic/blockstates/wornstonebrickpath.json d59655f12d1724b73b77c373fb6864fcff69db12 assets/bloodmagic/blockstates/wornstonetilepath.json -c220fc49d1981be98283901bf1b50702f5c021cd assets/bloodmagic/lang/en_us.json +0529422020c4a1669969bd3ee63aee063de4954d assets/bloodmagic/lang/en_us.json 34445195b9f2459475cde53454bc8e37d32865d7 assets/bloodmagic/models/block/accelerationrune.json bcdbccc49d4509571be6988762ab87126275a4c8 assets/bloodmagic/models/block/airritualstone.json adf6c0b1e25451609486dc8c8cfbd9cf0f8c67f4 assets/bloodmagic/models/block/alchemicalreactionchamber.json @@ -269,6 +269,10 @@ ccbcba6e4a6450bb67f91ba17754d668ba64c0ac assets/bloodmagic/models/item/ironfragm 413fa378c40dec89cb765a7d5c8bfc9cdef1d828 assets/bloodmagic/models/item/lavacrystal.json 588c5208e3f4ef941cd8375aeceeed44484d85d3 assets/bloodmagic/models/item/lavasigil.json 5a76914a87fc9b99079bb6afed1d4cfe3e4a532e assets/bloodmagic/models/item/lightritualstone.json +bd4db65caffbc68b312607bae4258fc1b67f60fd assets/bloodmagic/models/item/livingboots.json +c80cdacad2c4b6e995fe846c11cb2124a1813d79 assets/bloodmagic/models/item/livinghelmet.json +a64aa9003209d9eeca67cd7d3f1e2f05795c8f1a assets/bloodmagic/models/item/livingleggings.json +c0c9c72a8e31c9fa2d12eb870495407255431c8b assets/bloodmagic/models/item/livingplate.json 15d8178b626da912334774142d40d1012fb21fa0 assets/bloodmagic/models/item/magicianbloodorb.json 0a3566d3c86403f24c22977dd32ffaec727a9ad3 assets/bloodmagic/models/item/masterbloodorb.json 9e377ab2c131993f96ab6fb544bda4dbba0ab87e assets/bloodmagic/models/item/masterritualstone.json @@ -322,6 +326,7 @@ fe2b201007c974229509f6900c6eb8b03d158b0a assets/bloodmagic/models/item/soulsword 29009ca92dc30e1ec4ae1d454cd3f8726d8edc3c assets/bloodmagic/models/item/stonebrickpath.json 2dc28b0e2b7ae7bb0bcf8c8e74b9ba7c800446ff assets/bloodmagic/models/item/stonetilepath.json 26cb0aae63ea4f27efd5337c90c580ddd7481b99 assets/bloodmagic/models/item/sulfur.json +1e735651ebcc0087d38dfce304e5d722d219870e assets/bloodmagic/models/item/upgradetome.json e8fe01c5cddc268538681889f3161472a8f1c8ad assets/bloodmagic/models/item/variants/growthsigil_activated.json 20c802279de4df496057795c2e891fa54a21376f assets/bloodmagic/models/item/variants/growthsigil_deactivated.json 2778ea3a62ce6dd718a557beee7b5329bb185ff9 assets/bloodmagic/models/item/variants/icesigil_activated.json diff --git a/src/generated/resources/assets/bloodmagic/lang/en_us.json b/src/generated/resources/assets/bloodmagic/lang/en_us.json index 739326b8..de046a6b 100644 --- a/src/generated/resources/assets/bloodmagic/lang/en_us.json +++ b/src/generated/resources/assets/bloodmagic/lang/en_us.json @@ -60,6 +60,7 @@ "block.bloodmagic.wornstonebrickpath": "Worn Stone Path", "block.bloodmagic.wornstonetilepath": "Tiled Worn Stone Path", "chat.bloodmagic.damageSource": "%s's soul became too weak", + "chat.bloodmagic.living_upgrade_level_increase": "%s has leveled up to %d", "chat.bloodmagic.ritual.activate": "A rush of energy flows through the ritual!", "chat.bloodmagic.ritual.notValid": "You feel that these runes are not configured correctly...", "chat.bloodmagic.ritual.prevent": "The ritual is actively resisting you!", @@ -112,6 +113,10 @@ "item.bloodmagic.lavacrystal": "Lava Crystal", "item.bloodmagic.lavasigil": "Lava Sigil", "item.bloodmagic.life_essence_bucket": "Bucket of Life", + "item.bloodmagic.livingboots": "Living Boots", + "item.bloodmagic.livinghelmet": "Living Helmet", + "item.bloodmagic.livingleggings": "Living Leggings", + "item.bloodmagic.livingplate": "Living Chestplate", "item.bloodmagic.magicianbloodorb": "Magician Blood Orb", "item.bloodmagic.masterbloodorb": "Master Blood Orb", "item.bloodmagic.miningsigil": "Sigil of the Fast Miner", @@ -150,6 +155,7 @@ "item.bloodmagic.soulsword": "Sentient Sword", "item.bloodmagic.steadfastcrystal": "Steadfast Will Crystal", "item.bloodmagic.sulfur": "Sulfur", + "item.bloodmagic.upgradetome": "Living Armour Upgrade Tome", "item.bloodmagic.vengefulcrystal": "Vengeful Will Crystal", "item.bloodmagic.voidsigil": "Void Sigil", "item.bloodmagic.waterscribetool": "Inscription Tool: Water", @@ -170,6 +176,41 @@ "jei.bloodmagic.recipe.requiredtier": "Tier: %d", "jei.bloodmagic.recipe.soulforge": "Hellfire Forge", "jei.bloodmagic.recipe.soulsdrained": "Drained: %s Will", + "living_upgrade.bloodmagic.arrowShot": "Trick Shot", + "living_upgrade.bloodmagic.arrow_protect": "Pin Cushion", + "living_upgrade.bloodmagic.battleHunger": "Battle Hungry", + "living_upgrade.bloodmagic.crippledArm": "Crippled Arm", + "living_upgrade.bloodmagic.criticalStrike": "True Strike", + "living_upgrade.bloodmagic.digSlowdown": "Weakened Pick", + "living_upgrade.bloodmagic.digging": "Dwarven Might", + "living_upgrade.bloodmagic.disoriented": "Disoriented", + "living_upgrade.bloodmagic.elytra": "Elytra", + "living_upgrade.bloodmagic.experienced": "Experienced", + "living_upgrade.bloodmagic.fallProtect": "Soft Fall", + "living_upgrade.bloodmagic.fireResist": "Gift of Ignis", + "living_upgrade.bloodmagic.graveDigger": "Grave Digger", + "living_upgrade.bloodmagic.grimReaper": "Grim Reaper's Sprint", + "living_upgrade.bloodmagic.health": "Healthy", + "living_upgrade.bloodmagic.jump": "Strong Legs", + "living_upgrade.bloodmagic.knockback": "Body Builder", + "living_upgrade.bloodmagic.meleeDamage": "Fierce Strike", + "living_upgrade.bloodmagic.meleeDecrease": "Dulled Blade", + "living_upgrade.bloodmagic.nightSight": "Nocturnal Prowess", + "living_upgrade.bloodmagic.physicalProtect": "Tough", + "living_upgrade.bloodmagic.poisonResist": "Poison Resistance", + "living_upgrade.bloodmagic.quenched": "Quenched", + "living_upgrade.bloodmagic.repair": "Repairing", + "living_upgrade.bloodmagic.revealing": "Revealing", + "living_upgrade.bloodmagic.self_sacrifice": "Tough Palms", + "living_upgrade.bloodmagic.slippery": "Loose Traction", + "living_upgrade.bloodmagic.slowHeal": "Diseased", + "living_upgrade.bloodmagic.slowness": "Limp Leg", + "living_upgrade.bloodmagic.solarPowered": "Solar Powered", + "living_upgrade.bloodmagic.speed": "Quick Feet", + "living_upgrade.bloodmagic.sprint_attack": "Charging Strike", + "living_upgrade.bloodmagic.stepAssist": "Step Assist", + "living_upgrade.bloodmagic.stormTrooper": "Storm Trooper", + "living_upgrade.bloodmagic.thaumRunicShielding": "Runic Shielding", "ritual.bloodmagic.altarBuilderRitual": "The Assembly of the High Altar", "ritual.bloodmagic.altarBuilderRitual.info": "Builds an altar out of the components inside of the connected inventory.", "ritual.bloodmagic.animalGrowthRitual": "Ritual of the Shepherd", @@ -203,8 +244,10 @@ "ritual.bloodmagic.crushingRitual.info": "Breaks blocks within its crushing range and places the items into the linked chest.", "ritual.bloodmagic.crushingRitual.steadfast.info": "(Steadfast) Causes all blocks that are broken to be picked up with silk touch. Overrides Fortune where applicable.", "ritual.bloodmagic.crushingRitual.vengeful.info": "(Vengeful) Compresses the inventory on successful operation. Currently only does one compression per operation.", + "ritual.bloodmagic.crystalHarvestRitual": "Crack of the Fractured Crystal", "ritual.bloodmagic.crystalHarvestRitual.crystal.info": "(Crystal) All Demon Will crystal clusters have a single crystal broken off, spawning the crystal into the world. If there is only one crystal on the cluster, it will not break it.", "ritual.bloodmagic.crystalHarvestRitual.info": "Breaks Demon Will crystal clusters within its range, dropping the results on top of the crystals.", + "ritual.bloodmagic.crystalSplitRitual": "Resonance of the Faceted Crystal", "ritual.bloodmagic.crystalSplitRitual.info": "Splits apart a well-grown Raw crystal cluster into seperal aspected crystal clusters.", "ritual.bloodmagic.ellipseRitual.chest.info": "(Chest) The location of the inventory that the ritual will grab blocks from to place in the world.", "ritual.bloodmagic.ellipseRitual.info": "Creates a hollow spheroid around the ritual using the blocks in the attached chest.", @@ -226,6 +269,7 @@ "ritual.bloodmagic.fellingRitual.chest.info": "(Chest) The location of the inventory that the ritual will place the results into.", "ritual.bloodmagic.fellingRitual.fellingRange.info": "(Cutting) The range that the ritual will search out logs and leaves in order to cut down.", "ritual.bloodmagic.fellingRitual.info": "A standard tree-cutting machine, this ritual will cut down all trees and leaves within its area and collect the drops.", + "ritual.bloodmagic.forsakenSoulRitual": "Gathering of the Forsaken Souls", "ritual.bloodmagic.forsakenSoulRitual.crystal.info": "(Crystal) Demon Crystals in this range receive an increase in growth speed when a mob is killed by the ritual.", "ritual.bloodmagic.forsakenSoulRitual.damage.info": "(Damage) Mobs within this range will be slowly damaged, and when killed will grow the crystals.", "ritual.bloodmagic.forsakenSoulRitual.info": "Damages mobs within its damage range and when the mob dies a demon crystal within its crystal range will be grown.", @@ -360,6 +404,10 @@ "tooltip.bloodmagic.extraInfo": "&9-Hold shift for more info-", "tooltip.bloodmagic.holdShiftForInfo": "Press shift for extra info", "tooltip.bloodmagic.inscriber.desc": "The writing is on the wall...", + "tooltip.bloodmagic.livingarmour.extraExtraInfo": "&9-Hold shift + M for progress info-", + "tooltip.bloodmagic.livingarmour.upgrade.level": "%s (Level %d)", + "tooltip.bloodmagic.livingarmour.upgrade.points": "Upgrade points: %s / %s", + "tooltip.bloodmagic.livingarmour.upgrade.progress": "%s (%d/100)", "tooltip.bloodmagic.orb.desc": "Stores raw Life Essence", "tooltip.bloodmagic.orb.owner": "Added by: %s", "tooltip.bloodmagic.ritualReader.currentState": "Current mode: %s", diff --git a/src/generated/resources/assets/bloodmagic/models/item/livingboots.json b/src/generated/resources/assets/bloodmagic/models/item/livingboots.json new file mode 100644 index 00000000..44ac054b --- /dev/null +++ b/src/generated/resources/assets/bloodmagic/models/item/livingboots.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/handheld", + "textures": { + "layer0": "bloodmagic:item/livingboots" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/bloodmagic/models/item/livinghelmet.json b/src/generated/resources/assets/bloodmagic/models/item/livinghelmet.json new file mode 100644 index 00000000..38ca8c70 --- /dev/null +++ b/src/generated/resources/assets/bloodmagic/models/item/livinghelmet.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/handheld", + "textures": { + "layer0": "bloodmagic:item/livinghelmet" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/bloodmagic/models/item/livingleggings.json b/src/generated/resources/assets/bloodmagic/models/item/livingleggings.json new file mode 100644 index 00000000..2df3b839 --- /dev/null +++ b/src/generated/resources/assets/bloodmagic/models/item/livingleggings.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/handheld", + "textures": { + "layer0": "bloodmagic:item/livingleggings" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/bloodmagic/models/item/livingplate.json b/src/generated/resources/assets/bloodmagic/models/item/livingplate.json new file mode 100644 index 00000000..69aace1a --- /dev/null +++ b/src/generated/resources/assets/bloodmagic/models/item/livingplate.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/handheld", + "textures": { + "layer0": "bloodmagic:item/livingplate" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/bloodmagic/models/item/upgradetome.json b/src/generated/resources/assets/bloodmagic/models/item/upgradetome.json new file mode 100644 index 00000000..7839a726 --- /dev/null +++ b/src/generated/resources/assets/bloodmagic/models/item/upgradetome.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/handheld", + "textures": { + "layer0": "bloodmagic:item/upgradetome" + } +} \ No newline at end of file diff --git a/src/main/java/wayoftime/bloodmagic/BloodMagic.java b/src/main/java/wayoftime/bloodmagic/BloodMagic.java index d9d6dfd2..aa513ef7 100644 --- a/src/main/java/wayoftime/bloodmagic/BloodMagic.java +++ b/src/main/java/wayoftime/bloodmagic/BloodMagic.java @@ -49,6 +49,7 @@ import wayoftime.bloodmagic.common.data.recipe.BloodMagicRecipeProvider; import wayoftime.bloodmagic.common.item.BloodMagicItems; import wayoftime.bloodmagic.common.registries.BloodMagicEntityTypes; import wayoftime.bloodmagic.common.registries.BloodMagicRecipeSerializers; +import wayoftime.bloodmagic.core.LivingArmorRegistrar; import wayoftime.bloodmagic.core.recipe.IngredientBloodOrb; import wayoftime.bloodmagic.core.registry.OrbRegistry; import wayoftime.bloodmagic.impl.BloodMagicAPI; @@ -96,6 +97,7 @@ public class BloodMagic BloodMagicItems.ITEMS.register(modBus); // RegistrarBloodMagic.BLOOD_ORBS.createAndRegister(modBus, "bloodorbs"); BloodMagicItems.BLOOD_ORBS.createAndRegister(modBus, "bloodorbs"); + LivingArmorRegistrar.UPGRADES.createAndRegister(modBus, "upgrades"); BloodMagicItems.BASICITEMS.register(modBus); BloodMagicBlocks.BASICBLOCKS.register(modBus); BloodMagicBlocks.DUNGEONBLOCKS.register(modBus); @@ -165,6 +167,7 @@ public class BloodMagic BloodMagicCorePlugin.INSTANCE.register(BloodMagicAPI.INSTANCE); RITUAL_MANAGER.discover(); ModRituals.initHarvestHandlers(); + LivingArmorRegistrar.register(); } public void registerTileEntityTypes(RegistryEvent.Register> event) diff --git a/src/main/java/wayoftime/bloodmagic/common/data/GeneratorLanguage.java b/src/main/java/wayoftime/bloodmagic/common/data/GeneratorLanguage.java index ea83f623..21f531c9 100644 --- a/src/main/java/wayoftime/bloodmagic/common/data/GeneratorLanguage.java +++ b/src/main/java/wayoftime/bloodmagic/common/data/GeneratorLanguage.java @@ -297,6 +297,52 @@ public class GeneratorLanguage extends LanguageProvider add("tooltip.bloodmagic.ritualReader.desc.information", "Right click on an active Master Ritual Stone to gather basic information about the ritual."); add("tooltip.bloodmagic.ritualReader.desc.set_will_types", "Set the types of demon will that the ritual will consume from the aura by right clicking on the MRS with the same types of crystals on your hotbar."); + // Living Armour - the 'u' is important, TehNut! + add("living_upgrade.bloodmagic.arrow_protect", "Pin Cushion"); + add("living_upgrade.bloodmagic.speed", "Quick Feet"); + add("living_upgrade.bloodmagic.digging", "Dwarven Might"); + add("living_upgrade.bloodmagic.poisonResist", "Poison Resistance"); + add("living_upgrade.bloodmagic.fireResist", "Gift of Ignis"); + add("living_upgrade.bloodmagic.self_sacrifice", "Tough Palms"); + add("living_upgrade.bloodmagic.knockback", "Body Builder"); + add("living_upgrade.bloodmagic.physicalProtect", "Tough"); + add("living_upgrade.bloodmagic.health", "Healthy"); + add("living_upgrade.bloodmagic.meleeDamage", "Fierce Strike"); + add("living_upgrade.bloodmagic.arrowShot", "Trick Shot"); + add("living_upgrade.bloodmagic.stepAssist", "Step Assist"); + add("living_upgrade.bloodmagic.grimReaper", "Grim Reaper's Sprint"); + add("living_upgrade.bloodmagic.solarPowered", "Solar Powered"); + add("living_upgrade.bloodmagic.thaumRunicShielding", "Runic Shielding"); + add("living_upgrade.bloodmagic.revealing", "Revealing"); + add("living_upgrade.bloodmagic.experienced", "Experienced"); + add("living_upgrade.bloodmagic.jump", "Strong Legs"); + add("living_upgrade.bloodmagic.fallProtect", "Soft Fall"); + add("living_upgrade.bloodmagic.graveDigger", "Grave Digger"); + add("living_upgrade.bloodmagic.sprint_attack", "Charging Strike"); + add("living_upgrade.bloodmagic.criticalStrike", "True Strike"); + add("living_upgrade.bloodmagic.elytra", "Elytra"); + add("living_upgrade.bloodmagic.nightSight", "Nocturnal Prowess"); + add("living_upgrade.bloodmagic.repair", "Repairing"); + + add("living_upgrade.bloodmagic.slowness", "Limp Leg"); + add("living_upgrade.bloodmagic.crippledArm", "Crippled Arm"); + add("living_upgrade.bloodmagic.slippery", "Loose Traction"); + add("living_upgrade.bloodmagic.battleHunger", "Battle Hungry"); + add("living_upgrade.bloodmagic.quenched", "Quenched"); + add("living_upgrade.bloodmagic.meleeDecrease", "Dulled Blade"); + add("living_upgrade.bloodmagic.digSlowdown", "Weakened Pick"); + add("living_upgrade.bloodmagic.stormTrooper", "Storm Trooper"); + add("living_upgrade.bloodmagic.slowHeal", "Diseased"); + add("living_upgrade.bloodmagic.disoriented", "Disoriented"); + + add("tooltip.bloodmagic.livingarmour.upgrade.level", "%s (Level %d)"); + add("tooltip.bloodmagic.livingarmour.upgrade.progress", "%s (%d/100)"); + add("tooltip.bloodmagic.livingarmour.upgrade.points", "Upgrade points: %s / %s"); + + add("tooltip.bloodmagic.livingarmour.extraExtraInfo", "&9-Hold shift + M for progress info-"); + + add("chat.bloodmagic.living_upgrade_level_increase", "%s has leveled up to %d"); + // Guide add("guide.bloodmagic.name", "Sanguine Scientiem"); add("guide.bloodmagic.landing_text", "\"It is my dear hope that by holding this tome in your hands, I may impart the knowledge of the lost art that is Blood Magic\"$(br)$(o)- Magus Arcana$()"); @@ -464,6 +510,13 @@ public class GeneratorLanguage extends LanguageProvider addItem(BloodMagicItems.EXPERIENCE_TOME, "Tome of Peritia"); + addItem(BloodMagicItems.LIVING_HELMET, "Living Helmet"); + addItem(BloodMagicItems.LIVING_PLATE, "Living Chestplate"); + addItem(BloodMagicItems.LIVING_LEGGINGS, "Living Leggings"); + addItem(BloodMagicItems.LIVING_BOOTS, "Living Boots"); + + addItem(BloodMagicItems.LIVING_TOME, "Living Armour Upgrade Tome"); + // Alchemy Items addItem(BloodMagicItems.PLANT_OIL, "Plant Oil"); diff --git a/src/main/java/wayoftime/bloodmagic/common/item/ArmorMaterialLiving.java b/src/main/java/wayoftime/bloodmagic/common/item/ArmorMaterialLiving.java new file mode 100644 index 00000000..20f04529 --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/common/item/ArmorMaterialLiving.java @@ -0,0 +1,59 @@ +package wayoftime.bloodmagic.common.item; + +import net.minecraft.inventory.EquipmentSlotType; +import net.minecraft.item.ArmorMaterial; +import net.minecraft.item.IArmorMaterial; +import net.minecraft.item.crafting.Ingredient; + +public class ArmorMaterialLiving implements IArmorMaterial +{ + public static final IArmorMaterial INSTANCE = new ArmorMaterialLiving(); + + @Override + public int getDurability(EquipmentSlotType slot) + { + return ArmorMaterial.IRON.getDurability(slot); + } + + @Override + public int getDamageReductionAmount(EquipmentSlotType slot) + { + return ArmorMaterial.IRON.getDamageReductionAmount(slot); + } + + @Override + public int getEnchantability() + { + return ArmorMaterial.IRON.getEnchantability(); + } + + @Override + public net.minecraft.util.SoundEvent getSoundEvent() + { + return ArmorMaterial.IRON.getSoundEvent(); + } + + @Override + public Ingredient getRepairMaterial() + { + return ArmorMaterial.IRON.getRepairMaterial(); + } + + @Override + public String getName() + { + return "livingarmour"; + } + + @Override + public float getToughness() + { + return ArmorMaterial.IRON.getToughness(); + } + + @Override + public float getKnockbackResistance() + { + return ArmorMaterial.IRON.getKnockbackResistance(); + } +} \ No newline at end of file diff --git a/src/main/java/wayoftime/bloodmagic/common/item/BloodMagicItems.java b/src/main/java/wayoftime/bloodmagic/common/item/BloodMagicItems.java index bc80ed56..2e029f58 100644 --- a/src/main/java/wayoftime/bloodmagic/common/item/BloodMagicItems.java +++ b/src/main/java/wayoftime/bloodmagic/common/item/BloodMagicItems.java @@ -1,5 +1,6 @@ package wayoftime.bloodmagic.common.item; +import net.minecraft.inventory.EquipmentSlotType; import net.minecraft.item.BlockItem; import net.minecraft.item.Item; import net.minecraft.util.ResourceLocation; @@ -7,6 +8,7 @@ import net.minecraftforge.fml.RegistryObject; import net.minecraftforge.registries.DeferredRegister; import net.minecraftforge.registries.ForgeRegistries; import wayoftime.bloodmagic.BloodMagic; +import wayoftime.bloodmagic.api.compat.EnumDemonWillType; import wayoftime.bloodmagic.common.block.BloodMagicBlocks; import wayoftime.bloodmagic.common.item.arc.ItemARCToolBase; import wayoftime.bloodmagic.common.item.block.ItemBlockAlchemyTable; @@ -32,7 +34,6 @@ import wayoftime.bloodmagic.common.registration.impl.BloodOrbDeferredRegister; import wayoftime.bloodmagic.common.registration.impl.BloodOrbRegistryObject; import wayoftime.bloodmagic.ritual.EnumRuneType; import wayoftime.bloodmagic.structures.ItemDungeonTester; -import wayoftime.bloodmagic.api.compat.EnumDemonWillType; public class BloodMagicItems { @@ -129,6 +130,13 @@ public class BloodMagicItems public static final RegistryObject WEAK_BLOOD_SHARD = BASICITEMS.register("weakbloodshard", () -> new ItemBase()); public static final RegistryObject EXPERIENCE_TOME = BASICITEMS.register("experiencebook", () -> new ItemExperienceBook()); + public static final RegistryObject LIVING_HELMET = BASICITEMS.register("livinghelmet", () -> new ItemLivingArmor(EquipmentSlotType.HEAD)); + public static final RegistryObject LIVING_PLATE = BASICITEMS.register("livingplate", () -> new ItemLivingArmor(EquipmentSlotType.CHEST)); + public static final RegistryObject LIVING_LEGGINGS = BASICITEMS.register("livingleggings", () -> new ItemLivingArmor(EquipmentSlotType.LEGS)); + public static final RegistryObject LIVING_BOOTS = BASICITEMS.register("livingboots", () -> new ItemLivingArmor(EquipmentSlotType.FEET)); + + public static final RegistryObject LIVING_TOME = BASICITEMS.register("upgradetome", () -> new ItemLivingTome()); + // Ritual stuffs public static final RegistryObject WEAK_ACTIVATION_CRYSTAL = BASICITEMS.register("activationcrystalweak", () -> new ItemActivationCrystal(ItemActivationCrystal.CrystalType.WEAK)); public static final RegistryObject AWAKENED_ACTIVATION_CRYSTAL = BASICITEMS.register("activationcrystalawakened", () -> new ItemActivationCrystal(ItemActivationCrystal.CrystalType.AWAKENED)); diff --git a/src/main/java/wayoftime/bloodmagic/common/item/ExpandedArmor.java b/src/main/java/wayoftime/bloodmagic/common/item/ExpandedArmor.java new file mode 100644 index 00000000..39a45a5f --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/common/item/ExpandedArmor.java @@ -0,0 +1,20 @@ +package wayoftime.bloodmagic.common.item; + +import com.google.common.collect.Multimap; + +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.ai.attributes.Attribute; +import net.minecraft.entity.ai.attributes.AttributeModifier; +import net.minecraft.inventory.EquipmentSlotType; +import net.minecraft.item.ItemStack; +import net.minecraft.util.DamageSource; + +public interface ExpandedArmor +{ + +// Multimap getAttributeModifiers(EquipmentSlotType slot, ItemStack stack); + + void damageArmor(LivingEntity livingEntity, ItemStack stack, DamageSource source, float damage, EquipmentSlotType slot); + + Multimap getAttributeModifiers(EquipmentSlotType slot, ItemStack stack); +} diff --git a/src/main/java/wayoftime/bloodmagic/common/item/ItemLivingArmor.java b/src/main/java/wayoftime/bloodmagic/common/item/ItemLivingArmor.java new file mode 100644 index 00000000..5a2cb76c --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/common/item/ItemLivingArmor.java @@ -0,0 +1,163 @@ +package wayoftime.bloodmagic.common.item; + +import java.util.List; +import java.util.UUID; + +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; + +import net.minecraft.client.util.ITooltipFlag; +import net.minecraft.entity.Entity; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.ai.attributes.Attribute; +import net.minecraft.entity.ai.attributes.AttributeModifier; +import net.minecraft.inventory.EquipmentSlotType; +import net.minecraft.item.ArmorItem; +import net.minecraft.item.Item; +import net.minecraft.item.ItemGroup; +import net.minecraft.item.ItemStack; +import net.minecraft.util.DamageSource; +import net.minecraft.util.NonNullList; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.world.World; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import wayoftime.bloodmagic.BloodMagic; +import wayoftime.bloodmagic.core.living.ILivingContainer; +import wayoftime.bloodmagic.core.living.LivingStats; + +public class ItemLivingArmor extends ArmorItem implements ILivingContainer, ExpandedArmor +{ + + private static final int MAX_ABSORPTION = 100000; + + public ItemLivingArmor(EquipmentSlotType slot) + { + super(ArmorMaterialLiving.INSTANCE, slot, new Item.Properties().maxStackSize(1).group(BloodMagic.TAB)); + } + + @Override + public String getArmorTexture(ItemStack stack, Entity entity, EquipmentSlotType slot, String type) + { + if (this == BloodMagicItems.LIVING_PLATE.get() || this == BloodMagicItems.LIVING_HELMET.get() || this == BloodMagicItems.LIVING_BOOTS.get()) + { + return "bloodmagic:models/armor/livingarmour_layer_1.png"; + } + + if (this == BloodMagicItems.LIVING_LEGGINGS.get()) + { + return "bloodmagic:models/armor/livingarmour_layer_2.png"; + } else + { + return null; + } + } + + @Override + public Multimap getAttributeModifiers(EquipmentSlotType slot, ItemStack stack) + { +// Multimap modifiers = super.getAttributeModifiers(slot, stack); + Multimap modifiers = HashMultimap.create(); + modifiers.putAll(super.getAttributeModifiers(slot, stack)); + if (slot != EquipmentSlotType.CHEST) + return modifiers; + + LivingStats stats = getLivingStats(stack); + if (stats == null) + return modifiers; + + stats.getUpgrades().forEach((k, v) -> { + if (k.getAttributeProvider() != null) + k.getAttributeProvider().handleAttributes(stats, modifiers, UUID.nameUUIDFromBytes(k.getKey().toString().getBytes()), k, k.getLevel(v.intValue())); + }); + + return modifiers; + } + +// @Override +// public ArmorProperties getProperties(EntityLivingBase player, @Nonnull ItemStack armor, DamageSource source, double damage, int slot) { +// if (source == DamageSource.DROWN || source == DamageSource.OUT_OF_WORLD) +// return new ArmorProperties(-1, 0D, 0); +// +// double armorReduction; +// double damageAmount = 0.25; +// double armorPenetrationReduction = 0; +// +// if (armor.getItem() == RegistrarBloodMagicItems.LIVING_ARMOR_FEET || armor.getItem() == RegistrarBloodMagicItems.LIVING_ARMOR_HEAD) +// damageAmount = 3d / 20d * 0.6; +// else if (armor.getItem() == RegistrarBloodMagicItems.LIVING_ARMOR_LEGS) +// damageAmount = 6d / 20d * 0.6; +// else if (armor.getItem() == RegistrarBloodMagicItems.LIVING_ARMOR_CHEST) +// damageAmount = 0.64; +// +// if (armor.getItem() == RegistrarBloodMagicItems.LIVING_ARMOR_CHEST) { +// armorReduction = 0.24 / 0.64; // This values puts it at iron level +// +// if (!LivingUtil.hasFullSet((EntityPlayer) player)) +// return new ArmorProperties(-1, damageAmount * armorReduction, MAX_ABSORPTION); +// +// LivingStats stats = getLivingStats(armor); +// double protection = 1.0D; +// if (stats != null) +// for (Map.Entry entry : stats.getUpgrades().entrySet()) +// if (entry.getKey().getArmorProvider() != null) +// protection *= 1 - entry.getKey().getArmorProvider().getProtection((EntityPlayer) player, stats, source, entry.getKey().getLevel(entry.getValue())); +// +// armorReduction += (1 - protection) * (1 - armorReduction); +// damageAmount *= armorReduction; +// return new ArmorProperties(-1, source.isUnblockable() ? 1 - protection : damageAmount, MAX_ABSORPTION); +// } else if (source.isUnblockable()) +// return new ArmorProperties(-1, damageAmount * armorPenetrationReduction, MAX_ABSORPTION); +// +// return new ArmorProperties(-1, damageAmount, MAX_ABSORPTION); +// } + + @Override + public void fillItemGroup(ItemGroup group, NonNullList items) + { + if (!isInGroup(group)) + return; + + ItemStack stack = new ItemStack(this); + if (slot == EquipmentSlotType.CHEST) + updateLivingStats(stack, new LivingStats()); + + items.add(stack); + } + +// @Override +// public void fillItemGroup(ItemGroup group, NonNullList items) +// { +// if (this.isInGroup(group)) +// { +// for (EnumDemonWillType type : EnumDemonWillType.values()) +// { +// ItemStack stack = new ItemStack(this); +// this.setCurrentType(type, stack); +// this.setWill(type, stack, maxWill); +// items.add(stack); +// } +// } +// } + + @Override + public void damageArmor(LivingEntity livingEntity, ItemStack stack, DamageSource source, float damage, EquipmentSlotType slot) + { + if (slot == EquipmentSlotType.CHEST && damage > getMaxDamage() - stack.getDamage()) + { +// livingEntity.attackEntityFrom(source, amount) +// } + livingEntity.attackEntityFrom(DamageSource.MAGIC, 2.0F); + return; + } + +// stack.damage((int) damage, livingEntity, entity -> {}); + } + + @Override + @OnlyIn(Dist.CLIENT) + public void addInformation(ItemStack stack, World world, List tooltip, ITooltipFlag flag) + { + ILivingContainer.appendLivingTooltip(getLivingStats(stack), tooltip, true); + } +} diff --git a/src/main/java/wayoftime/bloodmagic/common/item/ItemLivingTome.java b/src/main/java/wayoftime/bloodmagic/common/item/ItemLivingTome.java new file mode 100644 index 00000000..db045af8 --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/common/item/ItemLivingTome.java @@ -0,0 +1,101 @@ +package wayoftime.bloodmagic.common.item; + +import java.util.List; +import java.util.Map.Entry; + +import net.minecraft.client.util.ITooltipFlag; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.Item; +import net.minecraft.item.ItemGroup; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ActionResult; +import net.minecraft.util.Hand; +import net.minecraft.util.NonNullList; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.world.World; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import wayoftime.bloodmagic.BloodMagic; +import wayoftime.bloodmagic.core.LivingArmorRegistrar; +import wayoftime.bloodmagic.core.living.ILivingContainer; +import wayoftime.bloodmagic.core.living.LivingStats; +import wayoftime.bloodmagic.core.living.LivingUpgrade; +import wayoftime.bloodmagic.core.living.LivingUtil; + +public class ItemLivingTome extends Item implements ILivingContainer +{ + + public ItemLivingTome() + { + super(new Item.Properties().maxStackSize(1).group(BloodMagic.TAB)); + } + + @Override + public ActionResult onItemRightClick(World world, PlayerEntity player, Hand hand) + { + ItemStack held = player.getHeldItem(hand); + + LivingStats armorStats = LivingStats.fromPlayer(player, true); + if (armorStats == null) + return ActionResult.resultPass(held); + + LivingStats tomeStats = getLivingStats(held); + if (tomeStats == null) + return ActionResult.resultPass(held); + + boolean[] flag = new boolean[] { false }; + tomeStats.getUpgrades().forEach((k, v) -> { + if (armorStats.getLevel(k.getKey()) >= tomeStats.getLevel(k.getKey())) + return; + + LivingUtil.applyNewExperience(player, k, v); // FIXME set levels directly, don't add experience + flag[0] = true; + }); +// LivingStats.toPlayer(player, armorStats); + if (flag[0]) + { + held.shrink(1); + return ActionResult.resultSuccess(held); + } else + return ActionResult.resultPass(held); + } + + @Override + public void fillItemGroup(ItemGroup group, NonNullList items) + { + if (!isInGroup(group)) + return; + + for (Entry entry : LivingArmorRegistrar.UPGRADE_MAP.entrySet()) + { + LivingUpgrade upgrade = entry.getValue(); + int exp = 0; + + while ((exp = upgrade.getNextRequirement(exp)) != 0) + { + ItemStack tome = new ItemStack(this); + updateLivingStats(tome, new LivingStats().setMaxPoints(upgrade.getLevelCost(exp)).addExperience(upgrade.getKey(), exp)); + items.add(tome); + } + } + +// LivingArmorRegistrar.UPGRADE_MAP.forEach(upgrade -> { +// int exp = 0; +// +// while ((exp = upgrade.getNextRequirement(exp)) != 0) +// { +// ItemStack tome = new ItemStack(this); +// updateLivingStats(tome, new LivingStats().setMaxPoints(upgrade.getLevelCost(exp)).addExperience(upgrade.getKey(), exp)); +// display.add(tome); +// } +// }); + } + + @Override + @OnlyIn(Dist.CLIENT) + public void addInformation(ItemStack stack, World world, List tooltip, ITooltipFlag flag) + { + ILivingContainer.appendLivingTooltip(getLivingStats(stack), tooltip, false); + } +} diff --git a/src/main/java/wayoftime/bloodmagic/common/item/ItemLivingTrainer.java b/src/main/java/wayoftime/bloodmagic/common/item/ItemLivingTrainer.java new file mode 100644 index 00000000..241dd4dd --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/common/item/ItemLivingTrainer.java @@ -0,0 +1,28 @@ +package wayoftime.bloodmagic.common.item; + +import java.util.List; + +import net.minecraft.client.util.ITooltipFlag; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.world.World; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import wayoftime.bloodmagic.BloodMagic; +import wayoftime.bloodmagic.core.living.ILivingContainer; + +public class ItemLivingTrainer extends Item implements ILivingContainer +{ + public ItemLivingTrainer() + { + super(new Item.Properties().maxStackSize(1).group(BloodMagic.TAB)); + } + + @Override + @OnlyIn(Dist.CLIENT) + public void addInformation(ItemStack stack, World world, List tooltip, ITooltipFlag flag) + { + ILivingContainer.appendLivingTooltip(getLivingStats(stack), tooltip, false); + } +} diff --git a/src/main/java/wayoftime/bloodmagic/common/registration/impl/LivingUpgradeDeferredRegister.java b/src/main/java/wayoftime/bloodmagic/common/registration/impl/LivingUpgradeDeferredRegister.java new file mode 100644 index 00000000..a84c05de --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/common/registration/impl/LivingUpgradeDeferredRegister.java @@ -0,0 +1,25 @@ +package wayoftime.bloodmagic.common.registration.impl; + +import java.util.function.Supplier; + +import wayoftime.bloodmagic.common.registration.WrappedDeferredRegister; +import wayoftime.bloodmagic.core.living.LivingUpgrade; + +public class LivingUpgradeDeferredRegister extends WrappedDeferredRegister +{ + public LivingUpgradeDeferredRegister(String modid) + { + super(modid, LivingUpgrade.class); + } + +// public BloodOrbRegistryObject register(String name, ResourceLocation rl, int tier, int capacity, +// int fillRate) +// { +// return register(name, () -> new BloodOrb(rl, tier, capacity, fillRate)); +// } + + public LivingUpgradeRegistryObject register(String name, Supplier sup) + { + return register(name, sup, LivingUpgradeRegistryObject::new); + } +} diff --git a/src/main/java/wayoftime/bloodmagic/common/registration/impl/LivingUpgradeRegistryObject.java b/src/main/java/wayoftime/bloodmagic/common/registration/impl/LivingUpgradeRegistryObject.java new file mode 100644 index 00000000..c851d6fb --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/common/registration/impl/LivingUpgradeRegistryObject.java @@ -0,0 +1,13 @@ +package wayoftime.bloodmagic.common.registration.impl; + +import net.minecraftforge.fml.RegistryObject; +import wayoftime.bloodmagic.common.registration.WrappedRegistryObject; +import wayoftime.bloodmagic.core.living.LivingUpgrade; + +public class LivingUpgradeRegistryObject extends WrappedRegistryObject +{ + public LivingUpgradeRegistryObject(RegistryObject registryObject) + { + super(registryObject); + } +} diff --git a/src/main/java/wayoftime/bloodmagic/core/LivingArmorRegistrar.java b/src/main/java/wayoftime/bloodmagic/core/LivingArmorRegistrar.java new file mode 100644 index 00000000..c93e8fd9 --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/core/LivingArmorRegistrar.java @@ -0,0 +1,182 @@ +package wayoftime.bloodmagic.core; + +import java.net.URL; +import java.util.HashMap; +import java.util.Map; +import java.util.function.Supplier; + +import com.google.common.base.Charsets; +import com.google.common.io.Resources; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +import net.minecraft.entity.ai.attributes.AttributeModifier; +import net.minecraft.entity.ai.attributes.Attributes; +import net.minecraft.util.ResourceLocation; +import wayoftime.bloodmagic.BloodMagic; +import wayoftime.bloodmagic.common.registration.impl.LivingUpgradeDeferredRegister; +import wayoftime.bloodmagic.common.registration.impl.LivingUpgradeRegistryObject; +import wayoftime.bloodmagic.core.living.LivingUpgrade; +import wayoftime.bloodmagic.gson.Serializers; + +public class LivingArmorRegistrar +{ + + public static final LivingUpgradeDeferredRegister UPGRADES = new LivingUpgradeDeferredRegister(BloodMagic.MODID); + + public static final Map UPGRADE_MAP = new HashMap<>(); + +// public static final DefaultedRegistry UPGRADES = (DefaultedRegistry) createRegistry("livingarmor:upgrades", LivingUpgrade.DUMMY.getKey().toString(), () -> LivingUpgrade.DUMMY); +// private static final Map DEFINITIONS = ((Supplier>) () -> { +// Map def = new HashMap<>(); +// def.put("arrow_protect", Paths.get(MinecraftForge.getInstance().getConfigDirectory().getAbsolutePath(), "livingarmor", "arrow_protect.json")); +// def.put("arrow_shot", Paths.get(FabricLoader.getInstance().getConfigDirectory().getAbsolutePath(), "livingarmor", "arrow_shot.json")); +// def.put("critical_strike", Paths.get(FabricLoader.getInstance().getConfigDirectory().getAbsolutePath(), "livingarmor", "critical_strike.json")); +// def.put("jump", Paths.get(FabricLoader.getInstance().getConfigDirectory().getAbsolutePath(), "livingarmor", "jump.json")); +// return def; +// }).get(); + private static final Map DEFINITIONS = ((Supplier>) () -> { + Map def = new HashMap<>(); + def.put("arrow_protect", BloodMagic.rl("arrow_protect")); + def.put("arrow_shot", BloodMagic.rl("arrow_shot")); + def.put("critical_strike", BloodMagic.rl("critical_strike")); + def.put("jump", BloodMagic.rl("jump")); + def.put("health", BloodMagic.rl("health")); + def.put("experience", BloodMagic.rl("experienced")); + def.put("sprint_attack", BloodMagic.rl("sprint_attack")); + def.put("self_sacrifice", BloodMagic.rl("self_sacrifice")); + def.put("speed", BloodMagic.rl("speed")); + return def; + }).get(); + // private static final Map DEFINITIONS = + // ResourceUtil.gatherResources("/data", "living_armor", p -> + // FilenameUtils.getExtension(p.toFile().getName()).equals("json")) +// .stream() +// .collect(Collectors.toMap(key -> FilenameUtils.getBaseName(key.toFile().getName()), value -> value)); + private static final Gson GSON = new GsonBuilder().serializeNulls().create(); + +// public static final ItemLivingArmor LIVING_HELMET = new ItemLivingArmor(EquipmentSlotType.HEAD); +// public static final ItemLivingArmor LIVING_CHESTPLATE = new ItemLivingArmor(EquipmentSlotType.CHEST); +// public static final ItemLivingArmor LIVING_LEGGINGS = new ItemLivingArmor(EquipmentSlotType.LEGS); +// public static final ItemLivingArmor LIVING_BOOTS = new ItemLivingArmor(EquipmentSlotType.FEET); +// public static final ItemLivingTrainer TRAINER = new ItemLivingTrainer(); +// public static final ItemLivingTome TOME = new ItemLivingTome(); + + public static final LivingUpgradeRegistryObject UPGRADE_ARROW_PROTECT = UPGRADES.register("arrow_protect", () -> parseDefinition("arrow_protect").withArmorProvider((player, stats, source, upgrade, level) -> { + if (source.isProjectile()) + { + return upgrade.getBonusValue("protection", level).doubleValue(); + } + return 0; + })); + + public static final LivingUpgradeRegistryObject UPGRADE_HEALTH = UPGRADES.register("health", () -> parseDefinition("health").withAttributeProvider((stats, attributeMap, uuid, upgrade, level) -> { + attributeMap.put(Attributes.MAX_HEALTH, new AttributeModifier(uuid, "Health Modifier", upgrade.getBonusValue("hp", level).intValue(), AttributeModifier.Operation.ADDITION)); + })); + + public static final LivingUpgradeRegistryObject UPGRADE_EXPERIENCE = UPGRADES.register("experienced", () -> parseDefinition("experienced")); + public static final LivingUpgradeRegistryObject UPGRADE_SPRINT_ATTACK = UPGRADES.register("sprint_attack", () -> parseDefinition("sprint_attack").withDamageProvider((player, weapon, damage, stats, attackedEntity, upgrade, level) -> { + if (player.isSprinting()) + { + return damage * upgrade.getBonusValue("damage_boost", level).doubleValue(); + } + return 0; + })); + public static final LivingUpgradeRegistryObject UPGRADE_SELF_SACRIFICE = UPGRADES.register("self_sacrifice", () -> parseDefinition("self_sacrifice")); + public static final LivingUpgradeRegistryObject UPGRADE_SPEED = UPGRADES.register("speed", () -> parseDefinition("speed")); + +// public static final LivingUpgrade UPGRADE_ARROW_PROTECT = parseDefinition("arrow_protect").withArmorProvider((player, stats, source, upgrade, level) -> { +// if (source.isProjectile()) +// { +// return upgrade.getBonusValue("protection", level).doubleValue(); +// } +// return 0; +// }); +// public static final LivingUpgrade UPGRADE_ARROW_SHOT = parseDefinition("arrow_shot"); +// public static final LivingUpgrade UPGRADE_CRITICAL_STRIKE = parseDefinition("critical_strike").withAttributeProvider((stats, attributeMap, uuid, upgrade, level) -> { +// attributeMap.put(Attributes.ATTACK_DAMAGE, new AttributeModifier(uuid, "Weapon modifier", upgrade.getBonusValue("damage_boost", level).doubleValue(), AttributeModifier.Operation.ADDITION)); +//// attributeMap.put(EntityAttributes.ATTACK_DAMAGE.getId(), AttributeModifiers.create(upgrade, "damage_boost", upgrade.getBonusValue("damage_boost", level).doubleValue(), EntityAttributeModifier.Operation.ADDITION)); +//// attributeMap.put(EntityAttributes.ATTACK_DAMAGE.getId(), AttributeModifiers.create(upgrade, "damage_boost", level, EntityAttributeModifier.Operation.ADDITION)); +// }); +// public static final LivingUpgrade UPGRADE_JUMP = parseDefinition("jump"); + + public static void register() + { + registerUpgrade(UPGRADE_ARROW_PROTECT.get()); + registerUpgrade(UPGRADE_HEALTH.get()); + registerUpgrade(UPGRADE_EXPERIENCE.get()); + registerUpgrade(UPGRADE_SPRINT_ATTACK.get()); + registerUpgrade(UPGRADE_SELF_SACRIFICE.get()); + registerUpgrade(UPGRADE_SPEED.get()); +// Registry.register(UPGRADES, UPGRADE_ARROW_PROTECT.getKey(), UPGRADE_ARROW_PROTECT); +// Registry.register(UPGRADES, UPGRADE_ARROW_SHOT.getKey(), UPGRADE_ARROW_SHOT); +// Registry.register(UPGRADES, UPGRADE_CRITICAL_STRIKE.getKey(), UPGRADE_CRITICAL_STRIKE); +// Registry.register(UPGRADES, UPGRADE_JUMP.getKey(), UPGRADE_JUMP); + +// Registry.register(Registry.ITEM, new ResourceLocation("livingarmor", "living_helmet"), LIVING_HELMET); +// Registry.register(Registry.ITEM, new Identifier("livingarmor", "living_chestplate"), LIVING_CHESTPLATE); +// Registry.register(Registry.ITEM, new Identifier("livingarmor", "living_leggings"), LIVING_LEGGINGS); +// Registry.register(Registry.ITEM, new Identifier("livingarmor", "living_boots"), LIVING_BOOTS); +// Registry.register(Registry.ITEM, new Identifier("livingarmor", "trainer"), TRAINER); +// Registry.register(Registry.ITEM, new Identifier("livingarmor", "tome"), TOME); + } + + public static void registerUpgrade(LivingUpgrade upgrade) + { + UPGRADE_MAP.put(upgrade.getKey(), upgrade); + } + + public static LivingUpgrade parseDefinition(String fileName) + { + ResourceLocation path = DEFINITIONS.get(fileName); + if (path == null) + return LivingUpgrade.DUMMY; + + try + { + URL schematicURL = LivingUpgrade.class.getResource(resLocToResourcePath(path)); + System.out.println("Attempting to load Living Armour Upgrade: " + schematicURL + ", path: " + resLocToResourcePath(path)); + return Serializers.GSON.fromJson(Resources.toString(schematicURL, Charsets.UTF_8), LivingUpgrade.class); +// return GSON.fromJson(IOUtils.toString(path.toUri(), StandardCharsets.UTF_8), LivingUpgrade.class); + } catch (Exception e) + { + e.printStackTrace(); + return LivingUpgrade.DUMMY; + } +// Path path = DEFINITIONS.get(fileName); +// if (path == null) +// return LivingUpgrade.DUMMY; +// +// try +// { +// return GSON.fromJson(IOUtils.toString(path.toUri(), StandardCharsets.UTF_8), LivingUpgrade.class); +// } catch (Exception e) +// { +// e.printStackTrace(); +// return LivingUpgrade.DUMMY; +// } + } + + public static String resLocToResourcePath(ResourceLocation resourceLocation) + { + return "/data/" + resourceLocation.getNamespace() + "/living_armor/" + resourceLocation.getPath() + ".json"; + } + +// private static Registry createRegistry(String registryId, String defaultId, Supplier defaultProvider) +// { +// try +// { +// Method _createRegistry = Registry.class.getDeclaredMethod("create", String.class, String.class, Supplier.class); // FIXME +// // yarn +// // name +// _createRegistry.setAccessible(true); +// return (Registry) _createRegistry.invoke(null, registryId, defaultId, defaultProvider); +// } catch (Exception e) +// { +// e.printStackTrace(); +// MutableRegistry registry = new DefaultedRegistry(defaultId, null, null); +// registry.add(new ResourceLocation(defaultId), defaultProvider.get()); +// return registry; +// } +// } +} diff --git a/src/main/java/wayoftime/bloodmagic/core/living/ILivingContainer.java b/src/main/java/wayoftime/bloodmagic/core/living/ILivingContainer.java new file mode 100644 index 00000000..3f663fff --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/core/living/ILivingContainer.java @@ -0,0 +1,60 @@ +package wayoftime.bloodmagic.core.living; + +import java.util.List; + +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.TextFormatting; +import net.minecraft.util.text.TranslationTextComponent; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +public interface ILivingContainer +{ + default LivingStats getLivingStats(ItemStack stack) + { + if (!stack.hasTag() || !stack.getTag().contains("livingStats")) + return null; + + return LivingStats.fromNBT(stack.getTag().getCompound("livingStats")); + } + + default void updateLivingStats(ItemStack stack, LivingStats stats) + { + if (stats == null) + { + if (stack.hasTag()) + stack.getTag().remove("livingStats"); + return; + } + + if (!stack.hasTag()) + stack.setTag(new CompoundNBT()); + + stack.getTag().put("livingStats", stats.serialize()); + } + + @OnlyIn(Dist.CLIENT) + static void appendLivingTooltip(LivingStats stats, List tooltip, boolean trainable) + { + if (stats != null) + { + if (trainable) + tooltip.add(new TranslationTextComponent("tooltip.bloodmagic.livingarmour.upgrade.points", stats.getUsedPoints(), stats.getMaxPoints()).mergeStyle(TextFormatting.GOLD)); + + stats.getUpgrades().forEach((k, v) -> { + if (k.getLevel(v.intValue()) <= 0) + return; + + boolean sneaking = Screen.hasShiftDown(); +// if (!InputUtil.isKeyPressed(MinecraftClient.getInstance().getWindow().getHandle(), 340) || k.getNextRequirement(v) == 0) + if (!sneaking || k.getNextRequirement(v.intValue()) == 0) + tooltip.add(new TranslationTextComponent("%s %s", new TranslationTextComponent(k.getTranslationKey()), new TranslationTextComponent("enchantment.level." + k.getLevel(v.intValue())))); + else + tooltip.add(new TranslationTextComponent("%s %s", new TranslationTextComponent(k.getTranslationKey()), (": " + v.intValue() + "/" + k.getNextRequirement(v.intValue())))); + }); + } + } +} diff --git a/src/main/java/wayoftime/bloodmagic/core/living/LivingStats.java b/src/main/java/wayoftime/bloodmagic/core/living/LivingStats.java new file mode 100644 index 00000000..d5089cd9 --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/core/living/LivingStats.java @@ -0,0 +1,150 @@ +package wayoftime.bloodmagic.core.living; + +import java.util.Map; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Maps; + +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.inventory.EquipmentSlotType; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.nbt.ListNBT; +import net.minecraft.util.ResourceLocation; +import wayoftime.bloodmagic.core.LivingArmorRegistrar; + +public class LivingStats +{ + + public static final int DEFAULT_UPGRADE_POINTS = 100; + + private final Map upgrades; + private int maxPoints = DEFAULT_UPGRADE_POINTS; + + public LivingStats(Map upgrades) + { + this.upgrades = upgrades; + } + + public LivingStats() + { + this(Maps.newHashMap()); + } + + public Map getUpgrades() + { + return ImmutableMap.copyOf(upgrades); + } + + public LivingStats addExperience(ResourceLocation key, double experience) + { +// LivingUpgrade upgrade = LivingArmorRegistrar.UPGRADES.getOrDefault(key); + LivingUpgrade upgrade = LivingArmorRegistrar.UPGRADE_MAP.getOrDefault(key, LivingUpgrade.DUMMY); + double current = upgrades.getOrDefault(upgrade, 0d); + + System.out.println("Upgrade: " + upgrade); + + if (upgrade.getNextRequirement((int) current) == 0) + return this; + + upgrades.put(upgrade, current + experience); + return this; + } + + public int getLevel(ResourceLocation key) + { + LivingUpgrade upgrade = LivingArmorRegistrar.UPGRADE_MAP.getOrDefault(key, LivingUpgrade.DUMMY); +// LivingUpgrade upgrade = LivingArmorRegistrar.UPGRADES.getOrDefault(key); + return upgrade.getLevel(upgrades.getOrDefault(upgrade, 0d).intValue()); + } + + public int getUsedPoints() + { + int total = 0; + for (Map.Entry applied : upgrades.entrySet()) + { + double experience = applied.getValue(); + int level = applied.getKey().getLevel((int) experience); + int cost = applied.getKey().getLevelCost(level); + total += cost; + } + + return total; + } + + public int getMaxPoints() + { + return maxPoints; + } + + public LivingStats setMaxPoints(int maxPoints) + { + this.maxPoints = maxPoints; + return this; + } + + public CompoundNBT serialize() + { + CompoundNBT compound = new CompoundNBT(); + ListNBT statList = new ListNBT(); + upgrades.forEach((k, v) -> { + CompoundNBT upgrade = new CompoundNBT(); + upgrade.putString("key", k.getKey().toString()); + upgrade.putDouble("exp", v); + statList.add(upgrade); + }); + compound.put("upgrades", statList); + + compound.putInt("maxPoints", maxPoints); + + return compound; + } + + public void deserialize(CompoundNBT nbt) + { + ListNBT statList = nbt.getList("upgrades", 10); + statList.forEach(tag -> { + if (!(tag instanceof CompoundNBT)) + return; + + LivingUpgrade upgrade = LivingArmorRegistrar.UPGRADE_MAP.getOrDefault(new ResourceLocation(((CompoundNBT) tag).getString("key")), LivingUpgrade.DUMMY); + if (upgrade == LivingUpgrade.DUMMY) + return; + double experience = ((CompoundNBT) tag).getDouble("exp"); + upgrades.put(upgrade, experience); + }); + + maxPoints = nbt.getInt("maxPoints"); + } + + public static LivingStats fromNBT(CompoundNBT statTag) + { + LivingStats stats = new LivingStats(); + stats.deserialize(statTag); + return stats; + } + + public static LivingStats fromPlayer(PlayerEntity player) + { + return fromPlayer(player, false); + } + + public static LivingStats fromPlayer(PlayerEntity player, boolean createNew) + { + if (!LivingUtil.hasFullSet(player)) + return null; + + ItemStack chest = player.getItemStackFromSlot(EquipmentSlotType.CHEST); + LivingStats stats = ((ILivingContainer) chest.getItem()).getLivingStats(chest); + return stats == null && createNew ? new LivingStats() : stats; + } + + public static void toPlayer(PlayerEntity player, LivingStats stats) + { + if (!LivingUtil.hasFullSet(player)) + return; + + ItemStack chest = player.getItemStackFromSlot(EquipmentSlotType.CHEST); + ((ILivingContainer) chest.getItem()).updateLivingStats(chest, stats); + } +} diff --git a/src/main/java/wayoftime/bloodmagic/core/living/LivingUpgrade.java b/src/main/java/wayoftime/bloodmagic/core/living/LivingUpgrade.java new file mode 100644 index 00000000..8f6b0e82 --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/core/living/LivingUpgrade.java @@ -0,0 +1,267 @@ +package wayoftime.bloodmagic.core.living; + +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import java.util.UUID; +import java.util.function.Consumer; + +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Multimap; +import com.google.common.collect.Sets; +import com.google.common.reflect.TypeToken; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.annotations.JsonAdapter; +import com.google.gson.annotations.SerializedName; + +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.ai.attributes.Attribute; +import net.minecraft.entity.ai.attributes.AttributeModifier; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.util.DamageSource; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.Util; +import net.minecraftforge.registries.ForgeRegistryEntry; + +@JsonAdapter(LivingUpgrade.Deserializer.class) +public class LivingUpgrade extends ForgeRegistryEntry +{ + public static final LivingUpgrade DUMMY = new LivingUpgrade(new ResourceLocation("dummy"), levels -> levels.add(new Level(0, 0))); + + private final ResourceLocation key; + private final Set incompatible; + private final TreeMap experienceToLevel; + private final Map levelToCost; + private final Map bonuses; + private boolean isNegative; + private String translationKey = null; + private IAttributeProvider attributeProvider; + private IArmorProvider armorProvider; + private IDamageProvider damageProvider; + + public LivingUpgrade(ResourceLocation key, Consumer> experienceMapper) + { + this.key = key; + this.incompatible = Sets.newHashSet(); + this.experienceToLevel = Maps.newTreeMap(); + this.levelToCost = Maps.newHashMap(); + this.bonuses = Maps.newHashMap(); + + List levels = Lists.newArrayList(); + experienceMapper.accept(levels); + + for (int i = 0; i < levels.size(); i++) + { + Level level = levels.get(i); + experienceToLevel.put(level.experienceNeeded, i + 1); + levelToCost.put(i + 1, level.upgradeCost); + } + } + + public LivingUpgrade withBonusSet(String id, Consumer> modifiers) + { +// List values = DefaultedList.of(); + List values = new ArrayList(); + modifiers.accept(values); + if (values.size() != levelToCost.size()) + throw new RuntimeException("Bonus size and level size must be the same."); + + bonuses.put(id, new Bonus(id, values)); + return this; + } + + public Number getBonusValue(String id, int level) + { + List modifiers = bonuses.getOrDefault(id, Bonus.DEFAULT).modifiers; + if (modifiers.isEmpty() || level == 0) + return 0; + + return modifiers.get(level - 1); + } + + public LivingUpgrade withAttributeProvider(IAttributeProvider attributeProvider) + { + this.attributeProvider = attributeProvider; + return this; + } + + public IAttributeProvider getAttributeProvider() + { + return attributeProvider; + } + + public LivingUpgrade withArmorProvider(IArmorProvider armorProvider) + { + this.armorProvider = armorProvider; + return this; + } + + public IArmorProvider getArmorProvider() + { + return armorProvider; + } + + public LivingUpgrade withDamageProvider(IDamageProvider damageProvider) + { + this.damageProvider = damageProvider; + return this; + } + + public IDamageProvider getDamageProvider() + { + return damageProvider; + } + + public String getTranslationKey() + { + return translationKey == null ? translationKey = Util.makeTranslationKey("living_upgrade", key) + : translationKey; + } + + public boolean isNegative() + { + return isNegative; + } + + public boolean isCompatible(ResourceLocation otherUpgrade) + { + return !incompatible.contains(otherUpgrade); + } + + public LivingUpgrade addIncompatibility(ResourceLocation key, ResourceLocation... otherKeys) + { + incompatible.add(key); + Collections.addAll(incompatible, otherKeys); + return this; + } + + public int getLevel(int experience) + { + Map.Entry floor = experienceToLevel.floorEntry(experience); + return floor == null ? 0 : floor.getValue(); + } + + public int getNextRequirement(int experience) + { + Integer ret = experienceToLevel.ceilingKey(experience + 1); + return ret == null ? 0 : ret; + } + + public int getLevelCost(int level) + { + return levelToCost.getOrDefault(level, 0); + } + + public ResourceLocation getKey() + { + return key; + } + + public LivingUpgrade asDowngrade() + { + this.isNegative = true; + return this; + } + + @Override + public String toString() + { + return key.toString(); + } + + public interface IAttributeProvider + { + void handleAttributes(LivingStats stats, Multimap modifiers, UUID uuid, LivingUpgrade upgrade, int level); + } + + public interface IArmorProvider + { + double getProtection(PlayerEntity player, LivingStats stats, DamageSource source, LivingUpgrade upgrade, int level); + } + + public interface IDamageProvider + { + double getAdditionalDamage(PlayerEntity player, ItemStack weapon, double damage, LivingStats stats, LivingEntity attacked, LivingUpgrade upgrade, int level); + } + + public static class Level + { + @SerializedName("xp") + private final int experienceNeeded; + @SerializedName("cost") + private final int upgradeCost; + + public Level(int experienceNeeded, int upgradeCost) + { + this.experienceNeeded = experienceNeeded; + this.upgradeCost = upgradeCost; + } + } + + public static class Bonus + { + + private static final Bonus DEFAULT = new Bonus("null", Collections.emptyList()); + + private final String id; + private final List modifiers; + + public Bonus(String id, List modifiers) + { + this.id = id; + this.modifiers = modifiers; + } + + public String getId() + { + return id; + } + } + + public static class Deserializer implements JsonDeserializer + { + @Override + public LivingUpgrade deserialize(JsonElement element, Type typeOfT, JsonDeserializationContext context) + throws JsonParseException + { + JsonObject json = element.getAsJsonObject(); + ResourceLocation id = new ResourceLocation(json.getAsJsonPrimitive("id").getAsString()); + List levels = context.deserialize(json.getAsJsonArray("levels"), new TypeToken>() + { + }.getType()); + boolean negative = json.has("negative") && json.getAsJsonPrimitive("negative").getAsBoolean(); + + LivingUpgrade upgrade = new LivingUpgrade(id, upgradeLevels -> upgradeLevels.addAll(levels)); + if (negative) + upgrade.asDowngrade(); + + if (json.has("incompatibilities")) + { + String[] incompatibilities = context.deserialize(json.getAsJsonArray("incompatibilities"), String[].class); + for (String incompatible : incompatibilities) + upgrade.addIncompatibility(new ResourceLocation(incompatible)); + } + + if (json.has("bonuses")) + { + Map bonuses = context.deserialize(json.getAsJsonObject("bonuses"), new TypeToken>() + { + }.getType()); + bonuses.forEach((k, v) -> upgrade.withBonusSet(k, numbers -> Collections.addAll(numbers, v))); + } + + return upgrade; + } + } + +} diff --git a/src/main/java/wayoftime/bloodmagic/core/living/LivingUtil.java b/src/main/java/wayoftime/bloodmagic/core/living/LivingUtil.java new file mode 100644 index 00000000..17698252 --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/core/living/LivingUtil.java @@ -0,0 +1,176 @@ +package wayoftime.bloodmagic.core.living; + +import java.util.Map; +import java.util.Map.Entry; + +import com.google.common.collect.Multimap; + +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.ai.attributes.Attribute; +import net.minecraft.entity.ai.attributes.AttributeModifier; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.inventory.EquipmentSlotType; +import net.minecraft.item.ArmorItem; +import net.minecraft.item.ItemStack; +import net.minecraft.util.DamageSource; +import net.minecraft.util.text.TranslationTextComponent; +import net.minecraftforge.common.MinecraftForge; +import wayoftime.bloodmagic.common.item.ItemLivingTrainer; +import wayoftime.bloodmagic.core.util.PlayerUtil; +import wayoftime.bloodmagic.event.LivingEquipmentEvent; + +public class LivingUtil +{ + public static LivingStats applyNewExperience(PlayerEntity player, LivingUpgrade upgrade, double experience) + { + LivingStats stats = LivingStats.fromPlayer(player, true); + if (stats == null) + return null; + + if (!canTrain(player, upgrade, upgrade.getLevel((int) experience))) + return stats; + + LivingEquipmentEvent.GainExperience event = new LivingEquipmentEvent.GainExperience(player, stats, upgrade, experience); +// EventResult result = LivingEquipmentEvent.EXPERIENCE_GAIN.invoker().gainExperience(event); + MinecraftForge.EVENT_BUS.post(event); + if (event.isCanceled()) + return stats; + + experience = event.getExperience(); + + double currentExperience = stats.getUpgrades().getOrDefault(upgrade, 0d); + double requiredForLevel = upgrade.getNextRequirement((int) currentExperience) - currentExperience; + + // If we're going to level up from this, check points + if (requiredForLevel <= experience) + { + int currentPoints = stats.getUsedPoints(); + // If we're already capped or somehow over the cap, we don't want to add + // experience + if (currentPoints >= stats.getMaxPoints()) + return stats; + + int nextPointCost = upgrade.getLevelCost(upgrade.getLevel((int) currentExperience) + 1); + // If there's no more levels in this upgrade, we don't want to add experience + if (nextPointCost == -1) + return stats; + + // If applying this new level will go over our cap, we don't want to add + // experience + if (currentPoints + nextPointCost > stats.getMaxPoints()) + return stats; + } + + int newLevel = upgrade.getLevel((int) (currentExperience + experience)); + if (upgrade.getLevel((int) currentExperience) != newLevel) + { + LivingEquipmentEvent.LevelUp levelUpEvent = new LivingEquipmentEvent.LevelUp(player, stats, upgrade); +// LivingEquipmentEvent.LEVEL_UP.invoker().levelUp(levelUpEvent); + MinecraftForge.EVENT_BUS.post(levelUpEvent); + + player.sendStatusMessage(new TranslationTextComponent("chat.bloodmagic.living_upgrade_level_increase", new TranslationTextComponent(upgrade.getTranslationKey()), newLevel), true); + } + + System.out.println("Adding experience!"); + + stats.addExperience(upgrade.getKey(), experience); + LivingStats.toPlayer(player, stats); + return stats; + } + + public static double getDamageReceivedForArmour(PlayerEntity player, DamageSource source, double damage) + { +// System.out.println("Initial damage from " + source + ": " + damage); + LivingStats stats = LivingStats.fromPlayer(player, true); + if (stats == null) + return damage; + + Map upgrades = stats.getUpgrades(); + for (Entry entry : upgrades.entrySet()) + { + LivingUpgrade upgrade = entry.getKey(); + if (upgrade.getArmorProvider() == null) + { + continue; + } + + int level = upgrade.getLevel(entry.getValue().intValue()); + damage *= 1 - upgrade.getArmorProvider().getProtection(player, stats, source, upgrade, level); + } + +// System.out.println("Final damage: " + damage); + + return damage; + } + + public static double getAdditionalDamage(PlayerEntity player, ItemStack weapon, LivingEntity attackedEntity, double damage) + { +// System.out.println("Initial damage from " + source + ": " + damage); + LivingStats stats = LivingStats.fromPlayer(player, true); + if (stats == null) + return 0; + + double additionalDamage = 0; + + Map upgrades = stats.getUpgrades(); + for (Entry entry : upgrades.entrySet()) + { + LivingUpgrade upgrade = entry.getKey(); + if (upgrade.getArmorProvider() == null) + { + continue; + } + + int level = upgrade.getLevel(entry.getValue().intValue()); + if (upgrade.getDamageProvider() == null) + { + continue; + } + additionalDamage += upgrade.getDamageProvider().getAdditionalDamage(player, weapon, damage, stats, attackedEntity, upgrade, level); + } + +// System.out.println("Final damage: " + damage); + + return additionalDamage; + } + + public static boolean canTrain(PlayerEntity player, LivingUpgrade upgrade, int currentLevel) + { + ItemStack trainer = PlayerUtil.findItem(player, stack -> stack.getItem() instanceof ItemLivingTrainer && stack.hasTag() && stack.getTag().contains("livingStats")); + if (trainer.isEmpty()) + return true; + + String mode = trainer.getTag().getString("livingLock"); + LivingStats stats = ((ILivingContainer) trainer.getItem()).getLivingStats(trainer); + + int levelLimit = stats.getLevel(upgrade.getKey()); + if (mode.equalsIgnoreCase("whitelist")) + { + return levelLimit != 0 && levelLimit > currentLevel; + } else if (mode.equalsIgnoreCase("blacklist")) + { + return levelLimit == 0; + } + + return true; + } + + public static boolean hasFullSet(PlayerEntity player) + { + for (ItemStack stack : player.inventory.armorInventory) + if (stack.isEmpty() || !(stack.getItem() instanceof ILivingContainer)) + return false; + + return true; + } + + public static void applyAttributes(Multimap attributes, ItemStack stack, PlayerEntity player, EquipmentSlotType slot) + { + if (player == null || !hasFullSet(player)) + return; + + Multimap newAttributes = ((ArmorItem) stack.getItem()).getAttributeModifiers(slot, stack); +// newAttributes.values().forEach(e -> e.setSerialize(false)); + attributes.putAll(newAttributes); + } +} \ No newline at end of file diff --git a/src/main/java/wayoftime/bloodmagic/core/living/ProjectileArmorProvider.java b/src/main/java/wayoftime/bloodmagic/core/living/ProjectileArmorProvider.java new file mode 100644 index 00000000..f1b10b44 --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/core/living/ProjectileArmorProvider.java @@ -0,0 +1,15 @@ +package wayoftime.bloodmagic.core.living; + +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.util.DamageSource; + +public class ProjectileArmorProvider implements LivingUpgrade.IArmorProvider +{ + @Override + public double getProtection(PlayerEntity player, LivingStats stats, DamageSource source, LivingUpgrade upgrade, int level) + { + // TODO Auto-generated method stub + return 0; + } + +} diff --git a/src/main/java/wayoftime/bloodmagic/core/util/PlayerUtil.java b/src/main/java/wayoftime/bloodmagic/core/util/PlayerUtil.java new file mode 100644 index 00000000..5c6e2f42 --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/core/util/PlayerUtil.java @@ -0,0 +1,57 @@ +package wayoftime.bloodmagic.core.util; + +import java.util.function.Predicate; + +import com.google.common.collect.Multimap; + +import net.minecraft.entity.ai.attributes.Attribute; +import net.minecraft.entity.ai.attributes.AttributeModifier; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.inventory.EquipmentSlotType; +import net.minecraft.item.ItemStack; +import wayoftime.bloodmagic.common.item.ExpandedArmor; +import wayoftime.bloodmagic.core.living.LivingUtil; + +public class PlayerUtil +{ + + public static ItemStack findItem(PlayerEntity player, Predicate requirements) + { + + // Check offhand first + ItemStack offHand = player.getHeldItemOffhand(); + if (requirements.test(offHand)) + return offHand; + + // Check inventory next + for (int slot = 0; slot < player.inventory.getSizeInventory(); slot++) + { + ItemStack foundStack = player.inventory.getStackInSlot(slot); + if (!foundStack.isEmpty() && requirements.test(foundStack)) + return foundStack; + } + + return ItemStack.EMPTY; + } + + public static Multimap handle(PlayerEntity player, Multimap existing) + { + + ItemStack chest = player.getItemStackFromSlot(EquipmentSlotType.CHEST); + boolean hasFullSet = LivingUtil.hasFullSet(player); + + if (hasFullSet && existing == null) + { + existing = ((ExpandedArmor) chest.getItem()).getAttributeModifiers(EquipmentSlotType.CHEST, chest); + player.getAttributeManager().reapplyModifiers(existing); + } + + if (!hasFullSet && existing != null) + { + player.getAttributeManager().removeModifiers(existing); + existing = null; + } + + return existing; + } +} diff --git a/src/main/java/wayoftime/bloodmagic/core/util/ResourceUtil.java b/src/main/java/wayoftime/bloodmagic/core/util/ResourceUtil.java new file mode 100644 index 00000000..81f6b0d1 --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/core/util/ResourceUtil.java @@ -0,0 +1,78 @@ +package wayoftime.bloodmagic.core.util; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.file.FileSystem; +import java.nio.file.FileSystemAlreadyExistsException; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Collections; +import java.util.Set; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import org.apache.commons.io.IOUtils; + +import net.minecraft.util.ResourceLocation; +import wayoftime.bloodmagic.BloodMagic; + +public class ResourceUtil +{ + public static Set gatherResources(String home, String following, Predicate predicate) + { + FileSystem fileSystem = null; + try + { + URL url = ResourceUtil.class.getResource(home); + if (url != null) + { + URI uri = url.toURI(); + Path path; + if (uri.getScheme().equals("file")) + { + path = Paths.get(ResourceUtil.class.getResource(home + "/" + following).toURI()); + } else + { + if (!uri.getScheme().equals("jar")) + { + BloodMagic.LOGGER.error("Unsupported URI scheme {}", uri.getScheme()); + return Collections.emptySet(); + } + + try + { + fileSystem = FileSystems.newFileSystem(uri, Collections.emptyMap()); + } catch (FileSystemAlreadyExistsException e) + { + fileSystem = FileSystems.getFileSystem(uri); + } + path = fileSystem.getPath(home + "/" + following); + } + + return Files.walk(path).filter(predicate).collect(Collectors.toSet()); + } + } catch (IOException | URISyntaxException e) + { + e.printStackTrace(); + } finally + { + IOUtils.closeQuietly(fileSystem); + } + + return Collections.emptySet(); + } + + public static Set gatherResources(String home, String following) + { + return gatherResources(home, following, p -> true); + } + + public static ResourceLocation addContext(ResourceLocation rl, String context) + { + return new ResourceLocation(rl.getNamespace(), context + rl.getPath()); + } +} diff --git a/src/main/java/wayoftime/bloodmagic/core/util/Value.java b/src/main/java/wayoftime/bloodmagic/core/util/Value.java new file mode 100644 index 00000000..4ffbd20f --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/core/util/Value.java @@ -0,0 +1,27 @@ +package wayoftime.bloodmagic.core.util; + +public final class Value +{ + private T value; + + private Value(T t) + { + this.value = t; + } + + public T get() + { + return value; + } + + public Value set(T t) + { + this.value = t; + return this; + } + + public static Value of(T t) + { + return new Value<>(t); + } +} \ No newline at end of file diff --git a/src/main/java/wayoftime/bloodmagic/event/LivingEquipmentEvent.java b/src/main/java/wayoftime/bloodmagic/event/LivingEquipmentEvent.java new file mode 100644 index 00000000..82d9e007 --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/event/LivingEquipmentEvent.java @@ -0,0 +1,96 @@ +package wayoftime.bloodmagic.event; + +import net.minecraft.entity.player.PlayerEntity; +import net.minecraftforge.eventbus.api.Event; +import wayoftime.bloodmagic.core.living.LivingStats; +import wayoftime.bloodmagic.core.living.LivingUpgrade; + +public class LivingEquipmentEvent extends Event +{ + +// public static final Event EXPERIENCE_GAIN = EventFactory.createArrayBacked(OnExperienceGain.class, handlers -> e -> { +// for (OnExperienceGain gain : handlers) if (gain.gainExperience(e) == EventResult.CANCEL) +// return EventResult.CANCEL; +// +// return EventResult.PASS; +// }); +// public static final Event LEVEL_UP = EventFactory.createArrayBacked(OnLevelUp.class, handlers -> e -> { +// for (OnLevelUp levelUp : handlers) levelUp.levelUp(e); +// }); +// +// public interface OnExperienceGain +// { +// EventResult gainExperience(GainExperience event); +// } +// +// public interface OnLevelUp +// { +// void levelUp(LevelUp event); +// } + + private final PlayerEntity player; + private final LivingStats stats; + + private LivingEquipmentEvent(PlayerEntity player, LivingStats stats) + { + this.player = player; + this.stats = stats; + } + + public PlayerEntity getPlayer() + { + return player; + } + + public LivingStats getStats() + { + return stats; + } + + public static class GainExperience extends LivingEquipmentEvent + { + + private final LivingUpgrade upgrade; + private double experience; + + public GainExperience(PlayerEntity player, LivingStats stats, LivingUpgrade upgrade, double experience) + { + super(player, stats); + this.upgrade = upgrade; + this.experience = experience; + } + + public LivingUpgrade getUpgrade() + { + return upgrade; + } + + public double getExperience() + { + return experience; + } + + public void setExperience(double experience) + { + this.experience = experience; + } + } + + public static class LevelUp extends LivingEquipmentEvent + { + + private final LivingUpgrade upgrade; + + public LevelUp(PlayerEntity player, LivingStats stats, LivingUpgrade upgrade) + { + super(player, stats); + + this.upgrade = upgrade; + } + + public LivingUpgrade getUpgrade() + { + return upgrade; + } + } +} diff --git a/src/main/java/wayoftime/bloodmagic/event/LivingEvent.java b/src/main/java/wayoftime/bloodmagic/event/LivingEvent.java new file mode 100644 index 00000000..57172317 --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/event/LivingEvent.java @@ -0,0 +1,30 @@ +package wayoftime.bloodmagic.event; + +import net.minecraftforge.eventbus.api.Event; + +public class LivingEvent extends Event +{ + +// public static final Event JUMP = EventFactory.createArrayBacked(Jump.class, handlers -> e -> { +// for (Jump handler : handlers) if (handler.onJump(e) == EventResult.CANCEL) +// return EventResult.CANCEL; +// +// return EventResult.PASS; +// }); +// public static final Event DAMAGE = EventFactory.createArrayBacked(Damage.class, handlers -> (e, s, d) -> { +// for (Damage handler : handlers) if (handler.onDamage(e, s, d) == EventResult.CANCEL) +// return EventResult.CANCEL; +// +// return EventResult.PASS; +// }); +// +// public interface Jump +// { +// EventResult onJump(LivingEntity livingEntity); +// } +// +// public interface Damage +// { +// EventResult onDamage(LivingEntity livingEntity, DamageSource source, Value damage); +// } +} diff --git a/src/main/java/wayoftime/bloodmagic/util/Utils.java b/src/main/java/wayoftime/bloodmagic/util/Utils.java index 1a665309..d47d024c 100644 --- a/src/main/java/wayoftime/bloodmagic/util/Utils.java +++ b/src/main/java/wayoftime/bloodmagic/util/Utils.java @@ -623,4 +623,112 @@ public class Utils return added; } + +// public static float getModifiedDamage(LivingEntity attackedEntity, DamageSource source, float amount) +// { +// if (!attackedEntity.isInvulnerableTo(source)) +// { +// if (amount <= 0) +// return 0; +// +// amount = applyArmor(attackedEntity, Iterables.toArray(attackedEntity.getEquipmentAndArmor(), ItemStack.class), source, amount); +// if (amount <= 0) +// return 0; +// amount = applyPotionDamageCalculations(attackedEntity, source, amount); +// +// return amount; +// } +// +// return 0; +// } +// +// public static float applyArmor(LivingEntity entity, ItemStack[] inventory, DamageSource source, double damage) +// { +// damage *= 25; +// ArrayList dmgVals = new ArrayList<>(); +// for (int x = 0; x < inventory.length; x++) +// { +// ItemStack stack = inventory[x]; +// if (stack.isEmpty()) +// { +// continue; +// } +// ArmorProperties prop = null; +// if (stack.getItem() instanceof ISpecialArmor) +// { +// ISpecialArmor armor = (ISpecialArmor) stack.getItem(); +// prop = armor.getProperties(entity, stack, source, damage / 25D, x).copy(); +// } else if (stack.getItem() instanceof ArmorItem && !source.isUnblockable()) +// { +// ArmorItem armor = (ArmorItem) stack.getItem(); +// prop = new ArmorProperties(0, armor.damageReduceAmount / 25D, Integer.MAX_VALUE); +// } +// if (prop != null) +// { +// prop.Slot = x; +// dmgVals.add(prop); +// } +// } +// if (dmgVals.size() > 0) +// { +// ArmorProperties[] props = dmgVals.toArray(new ArmorProperties[dmgVals.size()]); +// int level = props[0].Priority; +// double ratio = 0; +// for (ArmorProperties prop : props) +// { +// if (level != prop.Priority) +// { +// damage -= (damage * ratio); +// ratio = 0; +// level = prop.Priority; +// } +// ratio += prop.AbsorbRatio; +// +// } +// damage -= (damage * ratio); +// } +// +// return (float) (damage / 25.0F); +// } +// +// public static float applyPotionDamageCalculations(LivingEntity attackedEntity, DamageSource source, float damage) +// { +// Effect resistance = Effects.RESISTANCE; +// +// if (source.isDamageAbsolute()) +// { +// return damage; +// } else +// { +// if (attackedEntity.isPotionActive(resistance) && source != DamageSource.OUT_OF_WORLD) +// { +// int i = (attackedEntity.getActivePotionEffect(resistance).getAmplifier() + 1) * 5; +// int j = 25 - i; +// float f = damage * (float) j; +// damage = f / 25.0F; +// } +// +// if (damage <= 0.0F) +// { +// return 0.0F; +// } else +// { +// int k = EnchantmentHelper.getEnchantmentModifierDamage(attackedEntity.getArmorInventoryList(), source); +// +// if (k > 20) +// { +// k = 20; +// } +// +// if (k > 0 && k <= 20) +// { +// int l = 25 - k; +// float f1 = damage * (float) l; +// damage = f1 / 25.0F; +// } +// +// return damage; +// } +// } +// } } diff --git a/src/main/java/wayoftime/bloodmagic/util/handler/event/GenericHandler.java b/src/main/java/wayoftime/bloodmagic/util/handler/event/GenericHandler.java index c8b52550..5a74b833 100644 --- a/src/main/java/wayoftime/bloodmagic/util/handler/event/GenericHandler.java +++ b/src/main/java/wayoftime/bloodmagic/util/handler/event/GenericHandler.java @@ -1,19 +1,30 @@ package wayoftime.bloodmagic.util.handler.event; +import java.util.HashMap; +import java.util.Map; import java.util.Map.Entry; +import java.util.UUID; import net.minecraft.enchantment.EnchantmentHelper; import net.minecraft.enchantment.Enchantments; +import net.minecraft.entity.Entity; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.inventory.EquipmentSlotType; import net.minecraft.item.ItemStack; +import net.minecraft.potion.EffectInstance; +import net.minecraft.potion.Effects; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.vector.Vector3d; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.common.Tags; import net.minecraftforge.common.ToolType; +import net.minecraftforge.event.entity.living.LivingDamageEvent; +import net.minecraftforge.event.entity.living.LivingEvent; import net.minecraftforge.event.entity.living.LivingEvent.LivingUpdateEvent; +import net.minecraftforge.event.entity.living.LivingHealEvent; +import net.minecraftforge.event.entity.living.LivingHurtEvent; import net.minecraftforge.event.entity.player.PlayerInteractEvent; import net.minecraftforge.event.entity.player.PlayerXpEvent; import net.minecraftforge.event.world.BlockEvent.BlockToolInteractEvent; @@ -26,10 +37,14 @@ import wayoftime.bloodmagic.common.item.BloodOrb; import wayoftime.bloodmagic.common.item.IBindable; import wayoftime.bloodmagic.common.item.IBloodOrb; import wayoftime.bloodmagic.common.item.ItemExperienceBook; +import wayoftime.bloodmagic.core.LivingArmorRegistrar; import wayoftime.bloodmagic.core.data.Binding; import wayoftime.bloodmagic.core.data.SoulNetwork; +import wayoftime.bloodmagic.core.living.LivingStats; +import wayoftime.bloodmagic.core.living.LivingUtil; import wayoftime.bloodmagic.demonaura.WorldDemonWillHandler; import wayoftime.bloodmagic.event.ItemBindEvent; +import wayoftime.bloodmagic.event.SacrificeKnifeUsedEvent; import wayoftime.bloodmagic.network.DemonAuraClientPacket; import wayoftime.bloodmagic.potion.BMPotionUtils; import wayoftime.bloodmagic.potion.BloodMagicPotions; @@ -100,6 +115,95 @@ public class GenericHandler // } } + @SubscribeEvent + // Called when an entity is set to be hurt. Called before vanilla armour + // calculations. + public void onLivingHurt(LivingHurtEvent event) + { + Entity sourceEntity = event.getSource().getTrueSource(); + LivingEntity living = event.getEntityLiving(); + + if (sourceEntity instanceof PlayerEntity) + { + PlayerEntity sourcePlayer = (PlayerEntity) sourceEntity; + if (LivingUtil.hasFullSet(sourcePlayer)) + { + ItemStack mainWeapon = sourcePlayer.getActiveItemStack(); + double additionalDamage = LivingUtil.getAdditionalDamage(sourcePlayer, mainWeapon, living, event.getAmount()); + event.setAmount((float) (event.getAmount() + additionalDamage)); + } + } + + if (living instanceof PlayerEntity) + { + PlayerEntity player = (PlayerEntity) living; + if (LivingUtil.hasFullSet(player)) + { + event.setAmount((float) LivingUtil.getDamageReceivedForArmour(player, event.getSource(), event.getAmount())); + } + } + } + + @SubscribeEvent + // Called after armour calculations (including LivingHurtEvent) are parsed. + // Damage that the player should receive after armour/absorption hearts. + public void onLivingDamage(LivingDamageEvent event) + { + Entity sourceEntity = event.getSource().getTrueSource(); + LivingEntity living = event.getEntityLiving(); + + if (sourceEntity instanceof PlayerEntity) + { + PlayerEntity sourcePlayer = (PlayerEntity) sourceEntity; + if (LivingUtil.hasFullSet(sourcePlayer)) + { + if (sourcePlayer.isSprinting()) + { + LivingUtil.applyNewExperience(sourcePlayer, LivingArmorRegistrar.UPGRADE_SPRINT_ATTACK.get(), event.getAmount()); + } + } + } + + if (living instanceof PlayerEntity) + { + PlayerEntity player = (PlayerEntity) living; + if (LivingUtil.hasFullSet(player)) + { + if (event.getSource().isProjectile()) + { +// LivingStats stats = LivingStats.fromPlayer(player); +// stats.addExperience(LivingArmorRegistrar.TEST_UPGRADE.get().getKey(), 10); + LivingUtil.applyNewExperience(player, LivingArmorRegistrar.UPGRADE_ARROW_PROTECT.get(), event.getAmount()); + } + + } + } + } + + @SubscribeEvent(priority = EventPriority.HIGHEST) + public void onExperiencePickupHighest(PlayerXpEvent.PickupXp event) + { + LivingEntity living = event.getEntityLiving(); + if (living instanceof PlayerEntity) + { + PlayerEntity player = (PlayerEntity) living; + if (LivingUtil.hasFullSet(player)) + { + LivingStats stats = LivingStats.fromPlayer(player); + double expModifier = 1 + LivingArmorRegistrar.UPGRADE_EXPERIENCE.get().getBonusValue("exp", stats.getLevel(LivingArmorRegistrar.UPGRADE_EXPERIENCE.get().getKey())).doubleValue(); + System.out.println("Experience modifier: " + expModifier); + + int xp = event.getOrb().xpValue; + + event.getOrb().xpValue = ((int) Math.floor(xp * expModifier) + (player.world.rand.nextDouble() < (xp * expModifier) % 1 + ? 1 + : 0)); + + LivingUtil.applyNewExperience(player, LivingArmorRegistrar.UPGRADE_EXPERIENCE.get(), event.getOrb().getXpValue()); + } + } + } + @SubscribeEvent public void onHoe(BlockToolInteractEvent event) { @@ -185,4 +289,85 @@ public class GenericHandler } } } + + @SubscribeEvent + public void onHeal(LivingHealEvent event) + { + LivingEntity living = event.getEntityLiving(); + if (living instanceof PlayerEntity) + { + PlayerEntity player = (PlayerEntity) living; + if (LivingUtil.hasFullSet(player)) + { + LivingUtil.applyNewExperience(player, LivingArmorRegistrar.UPGRADE_HEALTH.get(), event.getAmount()); + } + } + } + + @SubscribeEvent + public void onSelfSacrifice(SacrificeKnifeUsedEvent event) + { + if (LivingUtil.hasFullSet(event.player)) + { + LivingStats stats = LivingStats.fromPlayer(event.player); + double bonus = LivingArmorRegistrar.UPGRADE_SELF_SACRIFICE.get().getBonusValue("self_mod", stats.getLevel(LivingArmorRegistrar.UPGRADE_SELF_SACRIFICE.get().getKey())).doubleValue(); + event.lpAdded = (int) Math.round(event.lpAdded * (1 + bonus)); + LivingUtil.applyNewExperience(event.player, LivingArmorRegistrar.UPGRADE_SELF_SACRIFICE.get(), event.healthDrained); + } + } + + public static Map posXMap = new HashMap<>(); + public static Map posZMap = new HashMap<>(); + + @SubscribeEvent(priority = EventPriority.HIGHEST) + public void onEntityUpdate(LivingEvent.LivingUpdateEvent event) + { + if (event.getEntity().world.isRemote) + { + return; + } + if (event.getEntityLiving() instanceof PlayerEntity) + { + PlayerEntity player = (PlayerEntity) event.getEntityLiving(); + float percentIncrease = 0; + + if (LivingUtil.hasFullSet(player)) + { + LivingStats stats = LivingStats.fromPlayer(player); + percentIncrease += LivingArmorRegistrar.UPGRADE_SPEED.get().getBonusValue("speed_modifier", stats.getLevel(LivingArmorRegistrar.UPGRADE_SPEED.get().getKey())).doubleValue(); + if (player.isSprinting()) + { + int speedTime = LivingArmorRegistrar.UPGRADE_SPEED.get().getBonusValue("speed_time", stats.getLevel(LivingArmorRegistrar.UPGRADE_SPEED.get().getKey())).intValue(); + if (speedTime > 0) + { + int speedLevel = LivingArmorRegistrar.UPGRADE_SPEED.get().getBonusValue("speed_level", stats.getLevel(LivingArmorRegistrar.UPGRADE_SPEED.get().getKey())).intValue(); + player.addPotionEffect(new EffectInstance(Effects.SPEED, speedTime, speedLevel, true, false)); + } + } + + double distance = 0; + + if (posXMap.containsKey(player.getUniqueID())) + { + distance = Math.sqrt((player.getPosX() - posXMap.get(player.getUniqueID())) * (player.getPosX() - posXMap.get(player.getUniqueID())) + (player.getPosZ() - posZMap.get(player.getUniqueID())) * (player.getPosZ() - posZMap.get(player.getUniqueID()))); + } + +// System.out.println("Distance travelled: " + distance); + if (player.isOnGround() && distance > 0 && distance < 50) + { + distance *= (1 + percentIncrease); + LivingUtil.applyNewExperience(player, LivingArmorRegistrar.UPGRADE_SPEED.get(), distance); + } + } + + if (percentIncrease > 0 && (player.isOnGround()) && (Math.abs(player.moveForward) > 0 || Math.abs(player.moveStrafing) > 0)) + { + player.travel(new Vector3d(player.moveStrafing * percentIncrease, 0, player.moveForward * percentIncrease)); + } + + posXMap.put(player.getUniqueID(), player.getPosX()); + posZMap.put(player.getUniqueID(), player.getPosZ()); + } + } + } diff --git a/src/main/resources/data/bloodmagic/living_armor/arrow_protect.json b/src/main/resources/data/bloodmagic/living_armor/arrow_protect.json new file mode 100644 index 00000000..ae1ea715 --- /dev/null +++ b/src/main/resources/data/bloodmagic/living_armor/arrow_protect.json @@ -0,0 +1,29 @@ +{ + "id": "bloodmagic:arrow_protect", + "levels": [ + { "xp": 30, "cost": 4 }, + { "xp": 200, "cost": 9 }, + { "xp": 400, "cost": 16 }, + { "xp": 800, "cost": 30 }, + { "xp": 1500, "cost": 60 }, + { "xp": 2500, "cost": 90 }, + { "xp": 3500, "cost": 125 }, + { "xp": 5000, "cost": 165 }, + { "xp": 7000, "cost": 210 }, + { "xp": 15000, "cost": 250 } + ], + "bonuses": { + "protection": [ + 0.1, + 0.3, + 0.4, + 0.6, + 0.7, + 0.75, + 0.77, + 0.8, + 0.83, + 0.85 + ] + } +} \ No newline at end of file diff --git a/src/main/resources/data/bloodmagic/living_armor/arrow_shot.json b/src/main/resources/data/bloodmagic/living_armor/arrow_shot.json new file mode 100644 index 00000000..009585b7 --- /dev/null +++ b/src/main/resources/data/bloodmagic/living_armor/arrow_shot.json @@ -0,0 +1,10 @@ +{ + "id": "bloodmagic:arrow_shot", + "levels": [ + { "xp": 50, "cost": 20 }, + { "xp": 200, "cost": 50 }, + { "xp": 700, "cost": 90 }, + { "xp": 1500, "cost": 160 }, + { "xp": 3000, "cost": 290 } + ] +} \ No newline at end of file diff --git a/src/main/resources/data/bloodmagic/living_armor/critical_strike.json b/src/main/resources/data/bloodmagic/living_armor/critical_strike.json new file mode 100644 index 00000000..6089c9be --- /dev/null +++ b/src/main/resources/data/bloodmagic/living_armor/critical_strike.json @@ -0,0 +1,19 @@ +{ + "id": "bloodmagic:critical_strike", + "levels": [ + { "xp": 200, "cost": 5 }, + { "xp": 800, "cost": 12 }, + { "xp": 1300, "cost": 22 }, + { "xp": 2500, "cost": 35 }, + { "xp": 3000, "cost": 49 } + ], + "bonuses": { + "damage_boost": [ + 0.1, + 0.2, + 0.3, + 0.4, + 0.5 + ] + } +} \ No newline at end of file diff --git a/src/main/resources/data/bloodmagic/living_armor/digging.json b/src/main/resources/data/bloodmagic/living_armor/digging.json new file mode 100644 index 00000000..4dda13a3 --- /dev/null +++ b/src/main/resources/data/bloodmagic/living_armor/digging.json @@ -0,0 +1,53 @@ +{ + "id": "bloodmagic:digging", + "levels": [ + { "xp": 128, "cost": 5 }, + { "xp": 512, "cost": 10 }, + { "xp": 1024, "cost": 18 }, + { "xp": 2048, "cost": 32 }, + { "xp": 8192, "cost": 60 }, + { "xp": 16000, "cost": 90 }, + { "xp": 32000, "cost": 140 }, + { "xp": 50000, "cost": 180 }, + { "xp": 80000, "cost": 240 }, + { "xp": 150000, "cost": 300 } + ], + "bonuses": { + "speed_time": [ + 0, + 50, + 60, + 100, + 100, + 100, + 100, + 150, + 150, + 150 + ], + "speed_level": [ + 0, + 0, + 0, + 1, + 1, + 1, + 1, + 1, + 2, + 2 + ], + "speed_modifier": [ + 1.1, + 1.2, + 1.3, + 1.4, + 1.5, + 1.6, + 1.8, + 2, + 2.2, + 2.5 + ] + } +} \ No newline at end of file diff --git a/src/main/resources/data/bloodmagic/living_armor/experienced.json b/src/main/resources/data/bloodmagic/living_armor/experienced.json new file mode 100644 index 00000000..304dd659 --- /dev/null +++ b/src/main/resources/data/bloodmagic/living_armor/experienced.json @@ -0,0 +1,29 @@ +{ + "id": "bloodmagic:experienced", + "levels": [ + { "xp": 100, "cost": 7 }, + { "xp": 400, "cost": 13 }, + { "xp": 1000, "cost": 22 }, + { "xp": 1600, "cost": 40 }, + { "xp": 3200, "cost": 65 }, + { "xp": 5000, "cost": 90 }, + { "xp": 7000, "cost": 130 }, + { "xp": 9200, "cost": 180 }, + { "xp": 11500, "cost": 250 }, + { "xp": 14000, "cost": 350 } + ], + "bonuses": { + "exp": [ + 0.15, + 0.3, + 0.45, + 0.6, + 0.75, + 0.9, + 1.05, + 1.2, + 1.35, + 1.5 + ] + } +} \ No newline at end of file diff --git a/src/main/resources/data/bloodmagic/living_armor/fall_protect.json b/src/main/resources/data/bloodmagic/living_armor/fall_protect.json new file mode 100644 index 00000000..2e30bafa --- /dev/null +++ b/src/main/resources/data/bloodmagic/living_armor/fall_protect.json @@ -0,0 +1,19 @@ +{ + "id": "bloodmagic:fall_protect", + "levels": [ + { "xp": 30, "cost": 2 }, + { "xp": 200, "cost": 5 }, + { "xp": 400, "cost": 9 }, + { "xp": 800, "cost": 15 }, + { "xp": 1500, "cost": 25 } + ], + "bonuses": { + "protection": [ + 0.2, + 0.4, + 0.6, + 0.8, + 1 + ] + } +} \ No newline at end of file diff --git a/src/main/resources/data/bloodmagic/living_armor/fire_resist.json b/src/main/resources/data/bloodmagic/living_armor/fire_resist.json new file mode 100644 index 00000000..6266703d --- /dev/null +++ b/src/main/resources/data/bloodmagic/living_armor/fire_resist.json @@ -0,0 +1,26 @@ +{ + "id": "bloodmagic:fire_resist", + "levels": [ + { "xp": 1200, "cost": 2 }, + { "xp": 3600, "cost": 6 }, + { "xp": 12000, "cost": 14 }, + { "xp": 24000, "cost": 25 }, + { "xp": 30000, "cost": 40 } + ], + "bonuses": { + "cooldown_time": [ + 6000, + 4800, + 4800, + 3600, + 2400 + ], + "resist_duration": [ + 600, + 600, + 800, + 1000, + 1200 + ] + } +} \ No newline at end of file diff --git a/src/main/resources/data/bloodmagic/living_armor/health.json b/src/main/resources/data/bloodmagic/living_armor/health.json new file mode 100644 index 00000000..46debd74 --- /dev/null +++ b/src/main/resources/data/bloodmagic/living_armor/health.json @@ -0,0 +1,29 @@ +{ + "id": "bloodmagic:health", + "levels": [ + { "xp": 80, "cost": 5 }, + { "xp": 200, "cost": 12 }, + { "xp": 340, "cost": 20 }, + { "xp": 540, "cost": 35 }, + { "xp": 800, "cost": 49 }, + { "xp": 1600, "cost": 78 }, + { "xp": 2800, "cost": 110 }, + { "xp": 5000, "cost": 160 }, + { "xp": 7600, "cost": 215 }, + { "xp": 10000, "cost": 320 } + ], + "bonuses": { + "hp": [ + 4, + 8, + 12, + 16, + 20, + 26, + 32, + 38, + 44, + 50 + ] + } +} \ No newline at end of file diff --git a/src/main/resources/data/bloodmagic/living_armor/jump.json b/src/main/resources/data/bloodmagic/living_armor/jump.json new file mode 100644 index 00000000..57865813 --- /dev/null +++ b/src/main/resources/data/bloodmagic/living_armor/jump.json @@ -0,0 +1,41 @@ +{ + "id": "bloodmagic:jump", + "levels": [ + { "xp": 10, "cost": 3 }, + { "xp": 20, "cost": 6 }, + { "xp": 30, "cost": 11 }, + { "xp": 40, "cost": 23 }, + { "xp": 40, "cost": 37 }, + { "xp": 40, "cost": 50 }, + { "xp": 40, "cost": 70 }, + { "xp": 40, "cost": 100 }, + { "xp": 40, "cost": 140 }, + { "xp": 40, "cost": 200 } + ], + "bonuses": { + "jump": [ + 0.1, + 0.2, + 0.3, + 0.4, + 0.5, + 0.7, + 0.75, + 0.9, + 1.1, + 1.3 + ], + "fall": [ + 0.1, + 0.2, + 0.3, + 0.4, + 0.5, + 0.6, + 0.7, + 0.75, + 0.8, + 0.85 + ] + } +} \ No newline at end of file diff --git a/src/main/resources/data/bloodmagic/living_armor/self_sacrifice.json b/src/main/resources/data/bloodmagic/living_armor/self_sacrifice.json new file mode 100644 index 00000000..08ba85f7 --- /dev/null +++ b/src/main/resources/data/bloodmagic/living_armor/self_sacrifice.json @@ -0,0 +1,29 @@ +{ + "id": "bloodmagic:self_sacrifice", + "levels": [ + { "xp": 30, "cost": 7 }, + { "xp": 200, "cost": 13 }, + { "xp": 400, "cost": 22 }, + { "xp": 700, "cost": 40 }, + { "xp": 1100, "cost": 65 }, + { "xp": 1500, "cost": 90 }, + { "xp": 2000, "cost": 130 }, + { "xp": 2800, "cost": 180 }, + { "xp": 3600, "cost": 250 }, + { "xp": 5000, "cost": 350 } + ], + "bonuses": { + "self_mod": [ + 0.15, + 0.3, + 0.45, + 0.6, + 0.75, + 0.9, + 1.05, + 1.2, + 1.35, + 1.5 + ] + } +} \ No newline at end of file diff --git a/src/main/resources/data/bloodmagic/living_armor/speed.json b/src/main/resources/data/bloodmagic/living_armor/speed.json new file mode 100644 index 00000000..717abf5b --- /dev/null +++ b/src/main/resources/data/bloodmagic/living_armor/speed.json @@ -0,0 +1,53 @@ +{ + "id": "bloodmagic:speed", + "levels": [ + { "xp": 200, "cost": 3 }, + { "xp": 1000, "cost": 7 }, + { "xp": 2000, "cost": 13 }, + { "xp": 4000, "cost": 26 }, + { "xp": 7000, "cost": 42 }, + { "xp": 15000, "cost": 60 }, + { "xp": 25000, "cost": 90 }, + { "xp": 35000, "cost": 130 }, + { "xp": 50000, "cost": 180 }, + { "xp": 70000, "cost": 250 } + ], + "bonuses": { + "speed_time": [ + 0, + 0, + 0, + 0, + 0, + 20, + 60, + 60, + 100, + 200 + ], + "speed_level": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + 1, + 2 + ], + "speed_modifier": [ + 0.1, + 0.2, + 0.3, + 0.4, + 0.5, + 0.7, + 0.9, + 1.1, + 1.3, + 1.5 + ] + } +} \ No newline at end of file diff --git a/src/main/resources/data/bloodmagic/living_armor/sprint_attack.json b/src/main/resources/data/bloodmagic/living_armor/sprint_attack.json new file mode 100644 index 00000000..f9c7166c --- /dev/null +++ b/src/main/resources/data/bloodmagic/living_armor/sprint_attack.json @@ -0,0 +1,26 @@ +{ + "id": "bloodmagic:sprint_attack", + "levels": [ + { "xp": 200, "cost": 3 }, + { "xp": 800, "cost": 7 }, + { "xp": 1300, "cost": 15 }, + { "xp": 2500, "cost": 25 }, + { "xp": 3800, "cost": 40 } + ], + "bonuses": { + "damage_boost": [ + 0.5, + 0.75, + 1, + 1.25, + 1.5 + ], + "kb": [ + 1, + 2, + 3, + 4, + 5 + ] + } +} \ No newline at end of file