diff --git a/src/generated/resources/.cache/cache b/src/generated/resources/.cache/cache index 3d4fa05e..79d86fc3 100644 --- a/src/generated/resources/.cache/cache +++ b/src/generated/resources/.cache/cache @@ -1,27 +1,42 @@ cb435652c27b4978d8db83af2fd531ccaa82ada7 assets/bloodmagic/blockstates/accelerationrune.json +43be0406da1c9f7cf734427bea235a65cda073d2 assets/bloodmagic/blockstates/airritualstone.json 4a60c54def00d68368ed0a0d4783979aa63d5f60 assets/bloodmagic/blockstates/altarcapacityrune.json 950fff9f06033741091aa8a66a62857da673efb9 assets/bloodmagic/blockstates/bettercapacityrune.json 8a5edb859a6f4d0adfbe2f608bab6b8c8addf01a assets/bloodmagic/blockstates/blankrune.json 904d9baa649250571bce5f965cf48fbec69c2c1a assets/bloodmagic/blockstates/bloodlight.json 631b579c38652efbcd9e5771d09ad6e476f3ba00 assets/bloodmagic/blockstates/chargingrune.json 6bd58d1d02a40416cec29409dee7ef80038b26d5 assets/bloodmagic/blockstates/dislocationrune.json +ba1cd8a9475212843e3b26232c8a9943fa0d2d20 assets/bloodmagic/blockstates/duskritualstone.json +bb3db171734f511fc0c259d86e869b49aa1d0c77 assets/bloodmagic/blockstates/earthritualstone.json +e780d6d9e891082dc6ce83fde1697ce36281a02a assets/bloodmagic/blockstates/fireritualstone.json +002795212cc7bf2cad2a91f873d85e2204c6367d assets/bloodmagic/blockstates/lightritualstone.json 372ecd737f7082a4c2c70e46745f893b1179f885 assets/bloodmagic/blockstates/orbcapacityrune.json +90daa355e528ab8a6582f796951201882f3c56da assets/bloodmagic/blockstates/ritualstone.json 285618c1a8ec36e36d479f577190579ae7616529 assets/bloodmagic/blockstates/sacrificerune.json b03040d7a168653bf8df3600033b8fde2383db30 assets/bloodmagic/blockstates/selfsacrificerune.json 487ffdc02ab7b65aafcb932e3b5cf6ea0500b21d assets/bloodmagic/blockstates/speedrune.json +e6d9cf699667aaa47efff37b2b033895dee29c15 assets/bloodmagic/blockstates/waterritualstone.json f7a92ca94cbd68344d89b92dc6c26c15cd1b85b5 assets/bloodmagic/lang/en_us.json 34445195b9f2459475cde53454bc8e37d32865d7 assets/bloodmagic/models/block/accelerationrune.json +bcdbccc49d4509571be6988762ab87126275a4c8 assets/bloodmagic/models/block/airritualstone.json 3c98a88c2283ad54f0efb9d7194361bbc3e93c17 assets/bloodmagic/models/block/altarcapacityrune.json 7cd62092c6fb3109e016d42090cf89bfa3ab7fca assets/bloodmagic/models/block/bettercapacityrune.json 1fe0f89895addb7abcacf6ce7e39b6ddc87b0d85 assets/bloodmagic/models/block/blankrune.json 3c83e090a1cff00e2bb2c7eb475785954b6eb980 assets/bloodmagic/models/block/bloodlight.json 320827ad2feaa51a90ebb7064a70bdc6d3765203 assets/bloodmagic/models/block/chargingrune.json 6adbeedc17f649ef47419845a6da0d50cfc76742 assets/bloodmagic/models/block/dislocationrune.json +81313327125e6e7396df0408595228bf0f63e1c9 assets/bloodmagic/models/block/duskritualstone.json +c30064f4aa09c42d23e94d118ae5b148eadb3a6c assets/bloodmagic/models/block/earthritualstone.json +4ff1cab1014cd8f655e5f032ecf60dd371f421c3 assets/bloodmagic/models/block/fireritualstone.json +2e1a81c758bfeec2aee807b48239f23241302268 assets/bloodmagic/models/block/lightritualstone.json c3a813b735cd229f8597e41d04465926b2e65fe1 assets/bloodmagic/models/block/orbcapacityrune.json +9b2bf2a44b788cbaecbe63a3e085e8de76672e1b assets/bloodmagic/models/block/ritualstone.json a8a1d06fcc2f8395530c72d2846133fff37d5537 assets/bloodmagic/models/block/sacrificerune.json 791c9f2e27215ff0a45eed7efe385276bfc09aed assets/bloodmagic/models/block/selfsacrificerune.json 65fe5e01ed2660e45a5c329ff2389a87e4d791ec assets/bloodmagic/models/block/speedrune.json +6041f2e47f5437d90a58586e42d18dadc42df439 assets/bloodmagic/models/block/waterritualstone.json 9462d62d9bc9408359d30728de8651dc104aacf1 assets/bloodmagic/models/item/accelerationrune.json +fe8e3deb3ad0107ca3ebd70694c1fc55a987d912 assets/bloodmagic/models/item/airritualstone.json 17cbe9142ef3950ea1b6be11694b849f55e93f13 assets/bloodmagic/models/item/airsigil.json f150f178edf7d6d250bcfd84af1c28a21cff09c6 assets/bloodmagic/models/item/altarcapacityrune.json 866b8cdd3da56e2e82dbd5f16ab5117b5a503749 assets/bloodmagic/models/item/apprenticebloodorb.json @@ -40,11 +55,15 @@ f404148f9df3a61da3c18175885ffa56b2a85a6a assets/bloodmagic/models/item/daggerofs 9671199681493a396e07d7bcab20137c22d981d5 assets/bloodmagic/models/item/demonslate.json 7af07ab578bbd20e2f834b26d9cafb5fe23bc7d4 assets/bloodmagic/models/item/dislocationrune.json f4531e22aa1db1cff324db5ccb344d3b9fa85c8d assets/bloodmagic/models/item/divinationsigil.json +10aceefca3ad3f0da773cb317c4effc6c06051ea assets/bloodmagic/models/item/duskritualstone.json +4d56efd7fdbf430f49903ce201577047687c3804 assets/bloodmagic/models/item/earthritualstone.json 4c39378f6c14dc243a7d52564e5a21df94683415 assets/bloodmagic/models/item/etherealslate.json +c36bde4f98c0aeb3bf0f369ad3bc067e5f0dc916 assets/bloodmagic/models/item/fireritualstone.json 44663089f348642bcca1c5020b5081c3ab172f92 assets/bloodmagic/models/item/growthsigil.json f68825f667ca73b4373fd5068a47f0d1ca9b2aad assets/bloodmagic/models/item/icesigil.json 109b5485c25d978af55b46682d5bfa7008909458 assets/bloodmagic/models/item/infusedslate.json 588c5208e3f4ef941cd8375aeceeed44484d85d3 assets/bloodmagic/models/item/lavasigil.json +5a76914a87fc9b99079bb6afed1d4cfe3e4a532e assets/bloodmagic/models/item/lightritualstone.json 15d8178b626da912334774142d40d1012fb21fa0 assets/bloodmagic/models/item/magicianbloodorb.json 0a3566d3c86403f24c22977dd32ffaec727a9ad3 assets/bloodmagic/models/item/masterbloodorb.json 7596826c5b40c2809eb0a42eb5f5f2089290e3e5 assets/bloodmagic/models/item/miningsigil.json @@ -58,6 +77,7 @@ baafdb5915c5fbc99b84a54670ed64a6f26cb0fe assets/bloodmagic/models/item/reagentma 95b2925e96a7df71d72568e0ed7b03290293cbe7 assets/bloodmagic/models/item/reagentvoid.json fd1447d943ddc4540a51a72dcbb245d77d45da71 assets/bloodmagic/models/item/reagentwater.json 50bf796adbed412488df48ed9250fc9b0ecd851f assets/bloodmagic/models/item/reinforcedslate.json +2722891c9c40b124d85bf9ff8eb885e175f5e6ff assets/bloodmagic/models/item/ritualstone.json db73abb3bcb1731b6fc389e3577910b6aab87b10 assets/bloodmagic/models/item/sacrificerune.json 9403d6195d4d38d5876c2a42f4edfb9bdcd05210 assets/bloodmagic/models/item/sacrificialdagger.json cc71421e98ee7ee047a4cfbb6cb69529c2b02d4e assets/bloodmagic/models/item/selfsacrificerune.json @@ -102,6 +122,7 @@ ec6f6bf7f520182b2044f3cc5a10f1d4c7a8d7ab assets/bloodmagic/models/item/variants/ 2029220112f89a3f4d432ab4749dff6143846659 assets/bloodmagic/models/item/variants/soulsword_vengeful_activated.json 0f5a3e1e5993a03ccda156eed855b71fbd0be0a2 assets/bloodmagic/models/item/variants/soulsword_vengeful_deactivated.json 836b5a7f19915af809795a72983a23f0d5f9c5b2 assets/bloodmagic/models/item/voidsigil.json +a31019db55828cb937a071ac2f74b125a2d0c955 assets/bloodmagic/models/item/waterritualstone.json 7426fed5f833ce3d08602f727f1467dd3e107991 assets/bloodmagic/models/item/watersigil.json f72efc172699d43405019add97f455bd6b7f452b assets/bloodmagic/models/item/weakbloodorb.json 828c0f89e747d48d37c6a86030a8ec59ca5c29cb data/bloodmagic/advancements/recipes/bloodmagictab/blood_altar.json @@ -116,6 +137,7 @@ e897d6f91e2a0bd12b0da0a50e5c897294989e7c data/bloodmagic/advancements/recipes/bl 2d29dd0c24c4c11d7438cdeeb26b9357d4359e2c data/bloodmagic/advancements/recipes/bloodmagictab/soul_forge.json 7a7f9f995d2414289d07c0a145647c8e735a6b78 data/bloodmagic/advancements/recipes/bloodmagictab/soul_snare.json 639ebb2ccabb2eaece59be96c2e6f28c31f4d2f4 data/bloodmagic/loot_tables/blocks/accelerationrune.json +26e3f34021426def32602e5ae7755e4672878320 data/bloodmagic/loot_tables/blocks/airritualstone.json 443550be9eaf1021b11fd2bbe6afcfe2cee6f7ad data/bloodmagic/loot_tables/blocks/alchemyarray.json 17d8dcc62320d5d2eeb781e925963d9b9d5eec54 data/bloodmagic/loot_tables/blocks/altar.json 05bb6268d7e884c962061a632e162d5baf73271e data/bloodmagic/loot_tables/blocks/altarcapacityrune.json @@ -124,11 +146,17 @@ e897d6f91e2a0bd12b0da0a50e5c897294989e7c data/bloodmagic/advancements/recipes/bl f1a8e3131d85077665563372cad868534a72fb31 data/bloodmagic/loot_tables/blocks/bloodlight.json 779b809a2a51e6dab46f9e6799249f2f14653ebb data/bloodmagic/loot_tables/blocks/chargingrune.json a9fcfc656fab957328c10ee1d9d33807e697b7f7 data/bloodmagic/loot_tables/blocks/dislocationrune.json +26e3f34021426def32602e5ae7755e4672878320 data/bloodmagic/loot_tables/blocks/duskritualstone.json +26e3f34021426def32602e5ae7755e4672878320 data/bloodmagic/loot_tables/blocks/earthritualstone.json +26e3f34021426def32602e5ae7755e4672878320 data/bloodmagic/loot_tables/blocks/fireritualstone.json +26e3f34021426def32602e5ae7755e4672878320 data/bloodmagic/loot_tables/blocks/lightritualstone.json 95442c1bb740fab2eb8ee051f7184813f6023afa data/bloodmagic/loot_tables/blocks/orbcapacityrune.json +26e3f34021426def32602e5ae7755e4672878320 data/bloodmagic/loot_tables/blocks/ritualstone.json e0239eff7762a414a4e4faa0158d844dffb8c1f6 data/bloodmagic/loot_tables/blocks/sacrificerune.json 9b697e37046b6238b3a19eae9113b88010ccff32 data/bloodmagic/loot_tables/blocks/selfsacrificerune.json f748a5ba8838b50de0502f132fe2a65f4726dae6 data/bloodmagic/loot_tables/blocks/soulforge.json 015e07226fd90935f7ec663f4bcf3873a57a82d1 data/bloodmagic/loot_tables/blocks/speedrune.json +26e3f34021426def32602e5ae7755e4672878320 data/bloodmagic/loot_tables/blocks/waterritualstone.json f41b0e9dfab608c42a85c3c5c5bbc050b03f02a1 data/bloodmagic/recipes/altar/apprenticebloodorb.json 2a67e37497a571b5ee944375d315fddccea87697 data/bloodmagic/recipes/altar/daggerofsacrifice.json c5a4a256a7437f2e13c574a6f0c4d75fc2e718cb data/bloodmagic/recipes/altar/demonicslate.json diff --git a/src/generated/resources/assets/bloodmagic/blockstates/airritualstone.json b/src/generated/resources/assets/bloodmagic/blockstates/airritualstone.json new file mode 100644 index 00000000..a64ce156 --- /dev/null +++ b/src/generated/resources/assets/bloodmagic/blockstates/airritualstone.json @@ -0,0 +1,7 @@ +{ + "variants": { + "": { + "model": "bloodmagic:block/airritualstone" + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/bloodmagic/blockstates/duskritualstone.json b/src/generated/resources/assets/bloodmagic/blockstates/duskritualstone.json new file mode 100644 index 00000000..474324b4 --- /dev/null +++ b/src/generated/resources/assets/bloodmagic/blockstates/duskritualstone.json @@ -0,0 +1,7 @@ +{ + "variants": { + "": { + "model": "bloodmagic:block/duskritualstone" + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/bloodmagic/blockstates/earthritualstone.json b/src/generated/resources/assets/bloodmagic/blockstates/earthritualstone.json new file mode 100644 index 00000000..75d2c5eb --- /dev/null +++ b/src/generated/resources/assets/bloodmagic/blockstates/earthritualstone.json @@ -0,0 +1,7 @@ +{ + "variants": { + "": { + "model": "bloodmagic:block/earthritualstone" + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/bloodmagic/blockstates/fireritualstone.json b/src/generated/resources/assets/bloodmagic/blockstates/fireritualstone.json new file mode 100644 index 00000000..33e7f1b2 --- /dev/null +++ b/src/generated/resources/assets/bloodmagic/blockstates/fireritualstone.json @@ -0,0 +1,7 @@ +{ + "variants": { + "": { + "model": "bloodmagic:block/fireritualstone" + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/bloodmagic/blockstates/lightritualstone.json b/src/generated/resources/assets/bloodmagic/blockstates/lightritualstone.json new file mode 100644 index 00000000..d198280b --- /dev/null +++ b/src/generated/resources/assets/bloodmagic/blockstates/lightritualstone.json @@ -0,0 +1,7 @@ +{ + "variants": { + "": { + "model": "bloodmagic:block/lightritualstone" + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/bloodmagic/blockstates/ritualstone.json b/src/generated/resources/assets/bloodmagic/blockstates/ritualstone.json new file mode 100644 index 00000000..8f09bcba --- /dev/null +++ b/src/generated/resources/assets/bloodmagic/blockstates/ritualstone.json @@ -0,0 +1,7 @@ +{ + "variants": { + "": { + "model": "bloodmagic:block/ritualstone" + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/bloodmagic/blockstates/waterritualstone.json b/src/generated/resources/assets/bloodmagic/blockstates/waterritualstone.json new file mode 100644 index 00000000..35b1d3aa --- /dev/null +++ b/src/generated/resources/assets/bloodmagic/blockstates/waterritualstone.json @@ -0,0 +1,7 @@ +{ + "variants": { + "": { + "model": "bloodmagic:block/waterritualstone" + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/bloodmagic/models/block/airritualstone.json b/src/generated/resources/assets/bloodmagic/models/block/airritualstone.json new file mode 100644 index 00000000..428b9552 --- /dev/null +++ b/src/generated/resources/assets/bloodmagic/models/block/airritualstone.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:block/cube_all", + "textures": { + "all": "bloodmagic:block/airritualstone" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/bloodmagic/models/block/duskritualstone.json b/src/generated/resources/assets/bloodmagic/models/block/duskritualstone.json new file mode 100644 index 00000000..ecfcfa10 --- /dev/null +++ b/src/generated/resources/assets/bloodmagic/models/block/duskritualstone.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:block/cube_all", + "textures": { + "all": "bloodmagic:block/duskritualstone" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/bloodmagic/models/block/earthritualstone.json b/src/generated/resources/assets/bloodmagic/models/block/earthritualstone.json new file mode 100644 index 00000000..e0949faa --- /dev/null +++ b/src/generated/resources/assets/bloodmagic/models/block/earthritualstone.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:block/cube_all", + "textures": { + "all": "bloodmagic:block/earthritualstone" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/bloodmagic/models/block/fireritualstone.json b/src/generated/resources/assets/bloodmagic/models/block/fireritualstone.json new file mode 100644 index 00000000..1661fe87 --- /dev/null +++ b/src/generated/resources/assets/bloodmagic/models/block/fireritualstone.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:block/cube_all", + "textures": { + "all": "bloodmagic:block/fireritualstone" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/bloodmagic/models/block/lightritualstone.json b/src/generated/resources/assets/bloodmagic/models/block/lightritualstone.json new file mode 100644 index 00000000..89bce579 --- /dev/null +++ b/src/generated/resources/assets/bloodmagic/models/block/lightritualstone.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:block/cube_all", + "textures": { + "all": "bloodmagic:block/lightritualstone" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/bloodmagic/models/block/ritualstone.json b/src/generated/resources/assets/bloodmagic/models/block/ritualstone.json new file mode 100644 index 00000000..ca5b7b23 --- /dev/null +++ b/src/generated/resources/assets/bloodmagic/models/block/ritualstone.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:block/cube_all", + "textures": { + "all": "bloodmagic:block/ritualstone" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/bloodmagic/models/block/waterritualstone.json b/src/generated/resources/assets/bloodmagic/models/block/waterritualstone.json new file mode 100644 index 00000000..1222a06c --- /dev/null +++ b/src/generated/resources/assets/bloodmagic/models/block/waterritualstone.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:block/cube_all", + "textures": { + "all": "bloodmagic:block/waterritualstone" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/bloodmagic/models/item/airritualstone.json b/src/generated/resources/assets/bloodmagic/models/item/airritualstone.json new file mode 100644 index 00000000..a32ef885 --- /dev/null +++ b/src/generated/resources/assets/bloodmagic/models/item/airritualstone.json @@ -0,0 +1,3 @@ +{ + "parent": "bloodmagic:block/airritualstone" +} \ No newline at end of file diff --git a/src/generated/resources/assets/bloodmagic/models/item/duskritualstone.json b/src/generated/resources/assets/bloodmagic/models/item/duskritualstone.json new file mode 100644 index 00000000..289ff1ee --- /dev/null +++ b/src/generated/resources/assets/bloodmagic/models/item/duskritualstone.json @@ -0,0 +1,3 @@ +{ + "parent": "bloodmagic:block/duskritualstone" +} \ No newline at end of file diff --git a/src/generated/resources/assets/bloodmagic/models/item/earthritualstone.json b/src/generated/resources/assets/bloodmagic/models/item/earthritualstone.json new file mode 100644 index 00000000..3758ede0 --- /dev/null +++ b/src/generated/resources/assets/bloodmagic/models/item/earthritualstone.json @@ -0,0 +1,3 @@ +{ + "parent": "bloodmagic:block/earthritualstone" +} \ No newline at end of file diff --git a/src/generated/resources/assets/bloodmagic/models/item/fireritualstone.json b/src/generated/resources/assets/bloodmagic/models/item/fireritualstone.json new file mode 100644 index 00000000..6eef57c2 --- /dev/null +++ b/src/generated/resources/assets/bloodmagic/models/item/fireritualstone.json @@ -0,0 +1,3 @@ +{ + "parent": "bloodmagic:block/fireritualstone" +} \ No newline at end of file diff --git a/src/generated/resources/assets/bloodmagic/models/item/lightritualstone.json b/src/generated/resources/assets/bloodmagic/models/item/lightritualstone.json new file mode 100644 index 00000000..96ca64a5 --- /dev/null +++ b/src/generated/resources/assets/bloodmagic/models/item/lightritualstone.json @@ -0,0 +1,3 @@ +{ + "parent": "bloodmagic:block/lightritualstone" +} \ No newline at end of file diff --git a/src/generated/resources/assets/bloodmagic/models/item/ritualstone.json b/src/generated/resources/assets/bloodmagic/models/item/ritualstone.json new file mode 100644 index 00000000..4dea1d50 --- /dev/null +++ b/src/generated/resources/assets/bloodmagic/models/item/ritualstone.json @@ -0,0 +1,3 @@ +{ + "parent": "bloodmagic:block/ritualstone" +} \ No newline at end of file diff --git a/src/generated/resources/assets/bloodmagic/models/item/waterritualstone.json b/src/generated/resources/assets/bloodmagic/models/item/waterritualstone.json new file mode 100644 index 00000000..4c02099f --- /dev/null +++ b/src/generated/resources/assets/bloodmagic/models/item/waterritualstone.json @@ -0,0 +1,3 @@ +{ + "parent": "bloodmagic:block/waterritualstone" +} \ No newline at end of file diff --git a/src/generated/resources/data/bloodmagic/loot_tables/blocks/airritualstone.json b/src/generated/resources/data/bloodmagic/loot_tables/blocks/airritualstone.json new file mode 100644 index 00000000..e8935390 --- /dev/null +++ b/src/generated/resources/data/bloodmagic/loot_tables/blocks/airritualstone.json @@ -0,0 +1,19 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1, + "entries": [ + { + "type": "minecraft:item", + "name": "bloodmagic:ritualstone" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/bloodmagic/loot_tables/blocks/duskritualstone.json b/src/generated/resources/data/bloodmagic/loot_tables/blocks/duskritualstone.json new file mode 100644 index 00000000..e8935390 --- /dev/null +++ b/src/generated/resources/data/bloodmagic/loot_tables/blocks/duskritualstone.json @@ -0,0 +1,19 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1, + "entries": [ + { + "type": "minecraft:item", + "name": "bloodmagic:ritualstone" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/bloodmagic/loot_tables/blocks/earthritualstone.json b/src/generated/resources/data/bloodmagic/loot_tables/blocks/earthritualstone.json new file mode 100644 index 00000000..e8935390 --- /dev/null +++ b/src/generated/resources/data/bloodmagic/loot_tables/blocks/earthritualstone.json @@ -0,0 +1,19 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1, + "entries": [ + { + "type": "minecraft:item", + "name": "bloodmagic:ritualstone" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/bloodmagic/loot_tables/blocks/fireritualstone.json b/src/generated/resources/data/bloodmagic/loot_tables/blocks/fireritualstone.json new file mode 100644 index 00000000..e8935390 --- /dev/null +++ b/src/generated/resources/data/bloodmagic/loot_tables/blocks/fireritualstone.json @@ -0,0 +1,19 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1, + "entries": [ + { + "type": "minecraft:item", + "name": "bloodmagic:ritualstone" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/bloodmagic/loot_tables/blocks/lightritualstone.json b/src/generated/resources/data/bloodmagic/loot_tables/blocks/lightritualstone.json new file mode 100644 index 00000000..e8935390 --- /dev/null +++ b/src/generated/resources/data/bloodmagic/loot_tables/blocks/lightritualstone.json @@ -0,0 +1,19 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1, + "entries": [ + { + "type": "minecraft:item", + "name": "bloodmagic:ritualstone" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/bloodmagic/loot_tables/blocks/ritualstone.json b/src/generated/resources/data/bloodmagic/loot_tables/blocks/ritualstone.json new file mode 100644 index 00000000..e8935390 --- /dev/null +++ b/src/generated/resources/data/bloodmagic/loot_tables/blocks/ritualstone.json @@ -0,0 +1,19 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1, + "entries": [ + { + "type": "minecraft:item", + "name": "bloodmagic:ritualstone" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/bloodmagic/loot_tables/blocks/waterritualstone.json b/src/generated/resources/data/bloodmagic/loot_tables/blocks/waterritualstone.json new file mode 100644 index 00000000..e8935390 --- /dev/null +++ b/src/generated/resources/data/bloodmagic/loot_tables/blocks/waterritualstone.json @@ -0,0 +1,19 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1, + "entries": [ + { + "type": "minecraft:item", + "name": "bloodmagic:ritualstone" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ] + } + ] +} \ 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 3ad54158..fb69752f 100644 --- a/src/main/java/WayofTime/bloodmagic/BloodMagic.java +++ b/src/main/java/WayofTime/bloodmagic/BloodMagic.java @@ -49,6 +49,7 @@ import wayoftime.bloodmagic.core.recipe.IngredientBloodOrb; import wayoftime.bloodmagic.core.registry.OrbRegistry; import wayoftime.bloodmagic.network.BloodMagicPacketHandler; import wayoftime.bloodmagic.potion.BloodMagicPotions; +import wayoftime.bloodmagic.ritual.RitualManager; import wayoftime.bloodmagic.tile.TileAlchemyArray; import wayoftime.bloodmagic.tile.TileAltar; import wayoftime.bloodmagic.tile.TileSoulForge; @@ -66,6 +67,7 @@ public class BloodMagic private static Gson GSON = null; public static final BloodMagicPacketHandler packetHandler = new BloodMagicPacketHandler(); + public static final RitualManager RITUAL_MANAGER = new RitualManager(); public BloodMagic() { @@ -134,8 +136,11 @@ public class BloodMagic public void onLoadComplete(FMLLoadCompleteEvent event) { OrbRegistry.tierMap.put(BloodMagicItems.ORB_WEAK.get().getTier(), new ItemStack(BloodMagicItems.WEAK_BLOOD_ORB.get())); + OrbRegistry.tierMap.put(BloodMagicItems.ORB_APPRENTICE.get().getTier(), new ItemStack(BloodMagicItems.APPRENTICE_BLOOD_ORB.get())); + OrbRegistry.tierMap.put(BloodMagicItems.ORB_MAGICIAN.get().getTier(), new ItemStack(BloodMagicItems.MAGICIAN_BLOOD_ORB.get())); + OrbRegistry.tierMap.put(BloodMagicItems.ORB_MASTER.get().getTier(), new ItemStack(BloodMagicItems.MASTER_BLOOD_ORB.get())); BloodMagicCorePlugin.INSTANCE.register(BloodMagicAPI.INSTANCE); - + RITUAL_MANAGER.discover(); } public void registerTileEntityTypes(RegistryEvent.Register> event) diff --git a/src/main/java/wayoftime/bloodmagic/block/enums/EnumRitualController.java b/src/main/java/wayoftime/bloodmagic/block/enums/EnumRitualController.java new file mode 100644 index 00000000..29948a7a --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/block/enums/EnumRitualController.java @@ -0,0 +1,23 @@ +package wayoftime.bloodmagic.block.enums; + +import java.util.Locale; + +import net.minecraft.util.IStringSerializable; + +//TODO: Will want to probably discontinue this due to The Flattening +public enum EnumRitualController implements IStringSerializable +{ + MASTER, IMPERFECT, INVERTED,; + + @Override + public String toString() + { + return name().toLowerCase(Locale.ENGLISH); + } + + @Override + public String getString() + { + return this.toString(); + } +} diff --git a/src/main/java/wayoftime/bloodmagic/common/block/BlockMasterRitualStone.java b/src/main/java/wayoftime/bloodmagic/common/block/BlockMasterRitualStone.java new file mode 100644 index 00000000..7fb09854 --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/common/block/BlockMasterRitualStone.java @@ -0,0 +1,130 @@ +package wayoftime.bloodmagic.common.block; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.SoundType; +import net.minecraft.block.material.Material; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ActionResultType; +import net.minecraft.util.Direction; +import net.minecraft.util.Hand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.BlockRayTraceResult; +import net.minecraft.util.text.TranslationTextComponent; +import net.minecraft.world.Explosion; +import net.minecraft.world.IBlockReader; +import net.minecraft.world.IWorld; +import net.minecraft.world.World; +import net.minecraftforge.common.ToolType; +import wayoftime.bloodmagic.BloodMagic; +import wayoftime.bloodmagic.common.item.ItemActivationCrystal; +import wayoftime.bloodmagic.iface.IBindable; +import wayoftime.bloodmagic.ritual.Ritual; +import wayoftime.bloodmagic.tile.TileMasterRitualStone; +import wayoftime.bloodmagic.util.helper.RitualHelper; + +public class BlockMasterRitualStone extends Block +{ + public final boolean isInverted; + + public BlockMasterRitualStone(boolean isInverted) + { + super(Properties.create(Material.ROCK).sound(SoundType.STONE).hardnessAndResistance(2.0F, 5.0F).harvestTool(ToolType.PICKAXE).harvestLevel(2)); + this.isInverted = isInverted; + } + + @Override + public ActionResultType onBlockActivated(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockRayTraceResult blockRayTraceResult) + { + ItemStack heldItem = player.getHeldItem(hand); + TileEntity tile = world.getTileEntity(pos); + + if (tile instanceof TileMasterRitualStone) + { + if (heldItem.getItem() instanceof ItemActivationCrystal) + { + if (((IBindable) heldItem.getItem()).getBinding(heldItem) == null) + return ActionResultType.FAIL; + + String key = RitualHelper.getValidRitual(world, pos); + if (!key.isEmpty()) + { + Ritual ritual = BloodMagic.RITUAL_MANAGER.getRitual(key); + if (ritual != null) + { + Direction direction = RitualHelper.getDirectionOfRitual(world, pos, ritual); + // TODO: Give a message stating that this ritual is not a valid ritual. + if (direction != null && RitualHelper.checkValidRitual(world, pos, ritual, direction)) + { + if (((TileMasterRitualStone) tile).activateRitual(heldItem, player, BloodMagic.RITUAL_MANAGER.getRitual(key))) + { + ((TileMasterRitualStone) tile).setDirection(direction); + if (isInverted) + ((TileMasterRitualStone) tile).setInverted(true); + } + } else + { + player.sendStatusMessage(new TranslationTextComponent("chat.bloodmagic.ritual.notValid"), true); + } + } else + { + player.sendStatusMessage(new TranslationTextComponent("chat.bloodmagic.ritual.notValid"), true); + } + } else + { + player.sendStatusMessage(new TranslationTextComponent("chat.bloodmagic.ritual.notValid"), true); + } + } + } + + return ActionResultType.FAIL; + } + + @Override + public void onPlayerDestroy(IWorld world, BlockPos blockPos, BlockState blockState) + { + TileMasterRitualStone tile = (TileMasterRitualStone) world.getTileEntity(blockPos); + if (tile != null) + ((TileMasterRitualStone) tile).stopRitual(Ritual.BreakType.BREAK_MRS); + + super.onPlayerDestroy(world, blockPos, blockState); + } + + @Override + public void onReplaced(BlockState state, World worldIn, BlockPos pos, BlockState newState, boolean isMoving) + { + if (!state.isIn(newState.getBlock())) + { + TileEntity tile = worldIn.getTileEntity(pos); + if (tile instanceof TileMasterRitualStone) + { + ((TileMasterRitualStone) tile).stopRitual(Ritual.BreakType.BREAK_MRS); + } + + super.onReplaced(state, worldIn, pos, newState, isMoving); + } + } + + @Override + public void onExplosionDestroy(World world, BlockPos pos, Explosion explosion) + { + TileEntity tile = world.getTileEntity(pos); + + if (tile instanceof TileMasterRitualStone) + ((TileMasterRitualStone) tile).stopRitual(Ritual.BreakType.EXPLOSION); + } + + @Override + public boolean hasTileEntity(BlockState state) + { + return true; + } + + @Override + public TileEntity createTileEntity(BlockState state, IBlockReader world) + { + return new TileMasterRitualStone(); + } +} \ No newline at end of file diff --git a/src/main/java/wayoftime/bloodmagic/common/block/BlockRitualStone.java b/src/main/java/wayoftime/bloodmagic/common/block/BlockRitualStone.java new file mode 100644 index 00000000..d76bfe60 --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/common/block/BlockRitualStone.java @@ -0,0 +1,89 @@ +package wayoftime.bloodmagic.common.block; + +import java.util.List; + +import javax.annotation.Nullable; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.SoundType; +import net.minecraft.block.material.Material; +import net.minecraft.client.util.ITooltipFlag; +import net.minecraft.item.ItemStack; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.TranslationTextComponent; +import net.minecraft.world.IBlockReader; +import net.minecraft.world.World; +import net.minecraftforge.common.ToolType; +import wayoftime.bloodmagic.ritual.EnumRuneType; +import wayoftime.bloodmagic.ritual.IRitualStone; + +public class BlockRitualStone extends Block implements IRitualStone +{ + private final EnumRuneType type; + + public BlockRitualStone(EnumRuneType type) + { + super(Properties.create(Material.ROCK).hardnessAndResistance(2.0F, 5.0F).sound(SoundType.STONE).harvestTool(ToolType.PICKAXE).harvestLevel(2)); + this.type = type; + } + + @Override + public void addInformation(ItemStack stack, @Nullable IBlockReader world, List tooltip, ITooltipFlag flag) + { + tooltip.add(new TranslationTextComponent("tooltip.bloodmagic.decoration.safe")); + super.addInformation(stack, world, tooltip, flag); + } + +// @Override +// public int damageDropped(BlockState state) +// { +// return 0; +// } +// +// @Override +// public boolean canSilkHarvest(World world, BlockPos pos, BlockState state, PlayerEntity player) +// { +// return false; +// } + + @Override + public boolean isRuneType(World world, BlockPos pos, EnumRuneType runeType) + { + return type.equals(runeType); + } + + @Override + public void setRuneType(World world, BlockPos pos, EnumRuneType runeType) + { + Block runeBlock = this; + switch (type) + { + case AIR: + runeBlock = BloodMagicBlocks.AIR_RITUAL_STONE.get(); + break; + case BLANK: + runeBlock = BloodMagicBlocks.BLANK_RITUAL_STONE.get(); + break; + case DAWN: + runeBlock = BloodMagicBlocks.DAWN_RITUAL_STONE.get(); + break; + case DUSK: + runeBlock = BloodMagicBlocks.DUSK_RITUAL_STONE.get(); + break; + case EARTH: + runeBlock = BloodMagicBlocks.EARTH_RITUAL_STONE.get(); + break; + case FIRE: + runeBlock = BloodMagicBlocks.FIRE_RITUAL_STONE.get(); + break; + case WATER: + runeBlock = BloodMagicBlocks.WATER_RITUAL_STONE.get(); + break; + } + + BlockState newState = runeBlock.getDefaultState(); + world.setBlockState(pos, newState); + } +} \ No newline at end of file diff --git a/src/main/java/wayoftime/bloodmagic/common/block/BloodMagicBlocks.java b/src/main/java/wayoftime/bloodmagic/common/block/BloodMagicBlocks.java index 955b36b8..48e0dc40 100644 --- a/src/main/java/wayoftime/bloodmagic/common/block/BloodMagicBlocks.java +++ b/src/main/java/wayoftime/bloodmagic/common/block/BloodMagicBlocks.java @@ -18,6 +18,7 @@ import net.minecraftforge.registries.ForgeRegistries; import wayoftime.bloodmagic.BloodMagic; import wayoftime.bloodmagic.block.enums.BloodRuneType; import wayoftime.bloodmagic.common.item.BloodMagicItems; +import wayoftime.bloodmagic.ritual.EnumRuneType; import wayoftime.bloodmagic.tile.contailer.ContainerSoulForge; public class BloodMagicBlocks @@ -48,6 +49,16 @@ public class BloodMagicBlocks public static final RegistryObject BLOOD_ALTAR = BLOCKS.register("altar", () -> new BlockAltar()); public static final RegistryObject BLOOD_LIGHT = BLOCKS.register("bloodlight", () -> new BlockBloodLight()); + public static final RegistryObject BLANK_RITUAL_STONE = BLOCKS.register("ritualstone", () -> new BlockRitualStone(EnumRuneType.BLANK)); + public static final RegistryObject AIR_RITUAL_STONE = BLOCKS.register("airritualstone", () -> new BlockRitualStone(EnumRuneType.AIR)); + public static final RegistryObject WATER_RITUAL_STONE = BLOCKS.register("waterritualstone", () -> new BlockRitualStone(EnumRuneType.WATER)); + public static final RegistryObject FIRE_RITUAL_STONE = BLOCKS.register("fireritualstone", () -> new BlockRitualStone(EnumRuneType.FIRE)); + public static final RegistryObject EARTH_RITUAL_STONE = BLOCKS.register("earthritualstone", () -> new BlockRitualStone(EnumRuneType.EARTH)); + public static final RegistryObject DUSK_RITUAL_STONE = BLOCKS.register("duskritualstone", () -> new BlockRitualStone(EnumRuneType.DUSK)); + public static final RegistryObject DAWN_RITUAL_STONE = BLOCKS.register("lightritualstone", () -> new BlockRitualStone(EnumRuneType.DAWN)); + + public static final RegistryObject MASTER_RITUAL_STONE = BASICBLOCKS.register("masterritualstone", () -> new BlockMasterRitualStone(false)); + private static ForgeFlowingFluid.Properties makeProperties() { return new ForgeFlowingFluid.Properties(LIFE_ESSENCE_FLUID, LIFE_ESSENCE_FLUID_FLOWING, FluidAttributes.builder(FLUID_STILL, FLUID_FLOWING)).bucket(LIFE_ESSENCE_BUCKET).block(LIFE_ESSENCE_BLOCK); diff --git a/src/main/java/wayoftime/bloodmagic/common/data/GeneratorBlockStates.java b/src/main/java/wayoftime/bloodmagic/common/data/GeneratorBlockStates.java index cbb374ea..04b013f1 100644 --- a/src/main/java/wayoftime/bloodmagic/common/data/GeneratorBlockStates.java +++ b/src/main/java/wayoftime/bloodmagic/common/data/GeneratorBlockStates.java @@ -28,6 +28,13 @@ public class GeneratorBlockStates extends BlockStateProvider } buildCubeAll(BloodMagicBlocks.BLOOD_LIGHT.get()); + buildCubeAll(BloodMagicBlocks.BLANK_RITUAL_STONE.get()); + buildCubeAll(BloodMagicBlocks.AIR_RITUAL_STONE.get()); + buildCubeAll(BloodMagicBlocks.WATER_RITUAL_STONE.get()); + buildCubeAll(BloodMagicBlocks.FIRE_RITUAL_STONE.get()); + buildCubeAll(BloodMagicBlocks.EARTH_RITUAL_STONE.get()); + buildCubeAll(BloodMagicBlocks.DUSK_RITUAL_STONE.get()); + buildCubeAll(BloodMagicBlocks.DAWN_RITUAL_STONE.get()); } private void buildCubeAll(Block block) diff --git a/src/main/java/wayoftime/bloodmagic/common/data/GeneratorItemModels.java b/src/main/java/wayoftime/bloodmagic/common/data/GeneratorItemModels.java index 06c2f49c..77739743 100644 --- a/src/main/java/wayoftime/bloodmagic/common/data/GeneratorItemModels.java +++ b/src/main/java/wayoftime/bloodmagic/common/data/GeneratorItemModels.java @@ -36,6 +36,14 @@ public class GeneratorItemModels extends ItemModelProvider registerBlockModel(block.get()); } + registerBlockModel(BloodMagicBlocks.BLANK_RITUAL_STONE.get()); + registerBlockModel(BloodMagicBlocks.AIR_RITUAL_STONE.get()); + registerBlockModel(BloodMagicBlocks.WATER_RITUAL_STONE.get()); + registerBlockModel(BloodMagicBlocks.FIRE_RITUAL_STONE.get()); + registerBlockModel(BloodMagicBlocks.EARTH_RITUAL_STONE.get()); + registerBlockModel(BloodMagicBlocks.DUSK_RITUAL_STONE.get()); + registerBlockModel(BloodMagicBlocks.DAWN_RITUAL_STONE.get()); + registerToggleableItem(BloodMagicItems.GREEN_GROVE_SIGIL.get()); registerToggleableItem(BloodMagicItems.FAST_MINER_SIGIL.get()); registerToggleableItem(BloodMagicItems.MAGNETISM_SIGIL.get()); diff --git a/src/main/java/wayoftime/bloodmagic/common/data/GeneratorLootTable.java b/src/main/java/wayoftime/bloodmagic/common/data/GeneratorLootTable.java index 5c4092c7..4115ea9a 100644 --- a/src/main/java/wayoftime/bloodmagic/common/data/GeneratorLootTable.java +++ b/src/main/java/wayoftime/bloodmagic/common/data/GeneratorLootTable.java @@ -49,33 +49,17 @@ public class GeneratorLootTable extends LootTableProvider this.registerDropSelfLootTable(block.get()); } - this.registerDropSelfLootTable(BloodMagicBlocks.BLOOD_ALTAR.get()); + registerDropSelfLootTable(BloodMagicBlocks.BLOOD_ALTAR.get()); registerNoDropLootTable(BloodMagicBlocks.ALCHEMY_ARRAY.get()); registerNoDropLootTable(BloodMagicBlocks.BLOOD_LIGHT.get()); - this.registerDropSelfLootTable(BloodMagicBlocks.SOUL_FORGE.get()); - -// LootPool.Builder builder = LootPool.builder().name(ModBlocks.GOO_BLOCK.get().getRegistryName().toString()).rolls(ConstantRange.of(1)).acceptCondition(SurvivesExplosion.builder()).addEntry(ItemLootEntry.builder(ModItems.GOO_RESIDUE.get())); -// this.registerLootTable(ModBlocks.GOO_BLOCK.get(), LootTable.builder().addLootPool(builder)); -// -// LootPool.Builder builder2 = LootPool.builder().name(ModBlocks.GOO_BLOCK_TERRAIN.get().getRegistryName().toString()).rolls(ConstantRange.of(1)).acceptCondition(SurvivesExplosion.builder()).addEntry(ItemLootEntry.builder(ModItems.GOO_RESIDUE.get())); -// this.registerLootTable(ModBlocks.GOO_BLOCK_TERRAIN.get(), LootTable.builder().addLootPool(builder2)); -// -// this.registerDropSelfLootTable(ModBlocks.GOO_BLOCK_POISON.get()); -// this.registerDropSelfLootTable(ModBlocks.GNT_BLOCK_T1.get()); -// this.registerDropSelfLootTable(ModBlocks.GNT_BLOCK_T2.get()); -// this.registerDropSelfLootTable(ModBlocks.GNT_BLOCK_T3.get()); -// this.registerDropSelfLootTable(ModBlocks.GNT_BLOCK_T4.get()); -// this.registerDropSelfLootTable(ModBlocks.TURRET_BLOCK.get()); -// this.registerDropSelfLootTable(ModBlocks.ZAPPER_TURRET_BLOCK.get()); -// this.registerDropSelfLootTable(ModBlocks.ANTI_GOO_BEACON.get()); -// this.registerDropSelfLootTable(ModBlocks.ANTI_GOO_FIELD_GEN.get()); -// this.registerDropSelfLootTable(ModBlocks.GOOLIMINATIONFIELDGEN.get()); -// this.registerDropSelfLootTable(ModBlocks.GOO_DETECTOR.get()); -// this.registerDropping(ModBlocks.GOO_RENDER.get(), ItemStack.EMPTY.getItem()); -// // this.registerDropping(ModBlocks.GOO_RENDER_BURST.get(), -// // ItemStack.EMPTY.getItem()); -// this.registerDropping(ModBlocks.GOO_RENDER_TERRAIN.get(), ItemStack.EMPTY.getItem()); - + registerDropSelfLootTable(BloodMagicBlocks.SOUL_FORGE.get()); + registerDropSelfLootTable(BloodMagicBlocks.BLANK_RITUAL_STONE.get()); + registerDropping(BloodMagicBlocks.AIR_RITUAL_STONE.get(), BloodMagicBlocks.BLANK_RITUAL_STONE.get()); + registerDropping(BloodMagicBlocks.WATER_RITUAL_STONE.get(), BloodMagicBlocks.BLANK_RITUAL_STONE.get()); + registerDropping(BloodMagicBlocks.FIRE_RITUAL_STONE.get(), BloodMagicBlocks.BLANK_RITUAL_STONE.get()); + registerDropping(BloodMagicBlocks.EARTH_RITUAL_STONE.get(), BloodMagicBlocks.BLANK_RITUAL_STONE.get()); + registerDropping(BloodMagicBlocks.DUSK_RITUAL_STONE.get(), BloodMagicBlocks.BLANK_RITUAL_STONE.get()); + registerDropping(BloodMagicBlocks.DAWN_RITUAL_STONE.get(), BloodMagicBlocks.BLANK_RITUAL_STONE.get()); } private void registerNoDropLootTable(Block block) diff --git a/src/main/java/wayoftime/bloodmagic/common/item/BloodMagicItems.java b/src/main/java/wayoftime/bloodmagic/common/item/BloodMagicItems.java index 69855511..f79ae7b2 100644 --- a/src/main/java/wayoftime/bloodmagic/common/item/BloodMagicItems.java +++ b/src/main/java/wayoftime/bloodmagic/common/item/BloodMagicItems.java @@ -54,6 +54,13 @@ public class BloodMagicItems public static final RegistryObject ORB_RUNE_ITEM = ITEMS.register("orbcapacityrune", () -> new BlockItem(BloodMagicBlocks.ORB_RUNE.get(), new Item.Properties().group(BloodMagic.TAB))); public static final RegistryObject ACCELERATION_RUNE_ITEM = ITEMS.register("accelerationrune", () -> new BlockItem(BloodMagicBlocks.ACCELERATION_RUNE.get(), new Item.Properties().group(BloodMagic.TAB))); public static final RegistryObject CHARGING_RUNE_ITEM = ITEMS.register("chargingrune", () -> new BlockItem(BloodMagicBlocks.CHARGING_RUNE.get(), new Item.Properties().group(BloodMagic.TAB))); + public static final RegistryObject BLANK_RITUAL_STONE_ITEM = ITEMS.register("ritualstone", () -> new BlockItem(BloodMagicBlocks.BLANK_RITUAL_STONE.get(), new Item.Properties().group(BloodMagic.TAB))); + public static final RegistryObject AIR_RITUAL_STONE_ITEM = ITEMS.register("airritualstone", () -> new BlockItem(BloodMagicBlocks.AIR_RITUAL_STONE.get(), new Item.Properties().group(BloodMagic.TAB))); + public static final RegistryObject WATER_RITUAL_STONE_ITEM = ITEMS.register("waterritualstone", () -> new BlockItem(BloodMagicBlocks.WATER_RITUAL_STONE.get(), new Item.Properties().group(BloodMagic.TAB))); + public static final RegistryObject FIRE_RITUAL_STONE_ITEM = ITEMS.register("fireritualstone", () -> new BlockItem(BloodMagicBlocks.FIRE_RITUAL_STONE.get(), new Item.Properties().group(BloodMagic.TAB))); + public static final RegistryObject EARTH_RITUAL_STONE_ITEM = ITEMS.register("earthritualstone", () -> new BlockItem(BloodMagicBlocks.EARTH_RITUAL_STONE.get(), new Item.Properties().group(BloodMagic.TAB))); + public static final RegistryObject DUSK_RITUAL_STONE_ITEM = ITEMS.register("duskritualstone", () -> new BlockItem(BloodMagicBlocks.DUSK_RITUAL_STONE.get(), new Item.Properties().group(BloodMagic.TAB))); + public static final RegistryObject DAWN_RITUAL_STONE_ITEM = ITEMS.register("lightritualstone", () -> new BlockItem(BloodMagicBlocks.DAWN_RITUAL_STONE.get(), new Item.Properties().group(BloodMagic.TAB))); public static final RegistryObject BLOOD_ALTAR_ITEM = ITEMS.register("altar", () -> new BlockItem(BloodMagicBlocks.BLOOD_ALTAR.get(), new Item.Properties().group(BloodMagic.TAB))); @@ -87,6 +94,10 @@ public class BloodMagicItems public static final RegistryObject ARCANE_ASHES = BASICITEMS.register("arcaneashes", () -> new ItemArcaneAshes()); public static final RegistryObject DAGGER_OF_SACRIFICE = BASICITEMS.register("daggerofsacrifice", () -> new ItemDaggerOfSacrifice()); + 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)); + public static final RegistryObject CREATIVE_ACTIVATION_CRYSTAL = BASICITEMS.register("activationcrystalcreative", () -> new ItemActivationCrystal(ItemActivationCrystal.CrystalType.CREATIVE)); + // Reagents used to make the Sigils public static final RegistryObject REAGENT_WATER = BASICITEMS.register("reagentwater", () -> new ItemBase()); public static final RegistryObject REAGENT_LAVA = BASICITEMS.register("reagentlava", () -> new ItemBase()); diff --git a/src/main/java/wayoftime/bloodmagic/common/item/ItemActivationCrystal.java b/src/main/java/wayoftime/bloodmagic/common/item/ItemActivationCrystal.java new file mode 100644 index 00000000..83d97492 --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/common/item/ItemActivationCrystal.java @@ -0,0 +1,72 @@ +package wayoftime.bloodmagic.common.item; + +import java.util.List; + +import javax.annotation.Nonnull; + +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.util.text.TranslationTextComponent; +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.data.Binding; +import wayoftime.bloodmagic.iface.IBindable; + +public class ItemActivationCrystal extends Item implements IBindable +{ + final CrystalType type; + + public ItemActivationCrystal(CrystalType type) + { + super(new Item.Properties().maxStackSize(1).group(BloodMagic.TAB)); + this.type = type; + } + + @Override + @OnlyIn(Dist.CLIENT) + public void addInformation(ItemStack stack, World world, List tooltip, ITooltipFlag flag) + { + tooltip.add(new TranslationTextComponent("tooltip.bloodmagic.activation_crystal." + type.name().toLowerCase())); + + if (!stack.hasTag()) + return; + + Binding binding = getBinding(stack); + if (binding != null) + tooltip.add(new TranslationTextComponent("tooltip.bloodmagic.currentOwner", binding.getOwnerName())); + + super.addInformation(stack, world, tooltip, flag); + } + + public int getCrystalLevel(ItemStack stack) + { + return this.type.equals(CrystalType.CREATIVE) ? Integer.MAX_VALUE : type.ordinal() + 1; + } + + public enum CrystalType + { + WEAK, AWAKENED, CREATIVE,; + + @Nonnull + public static ItemStack getStack(int level) + { + if (level < 0) + { + level = 0; + } + switch (level) + { + case 0: + return new ItemStack(BloodMagicItems.WEAK_ACTIVATION_CRYSTAL.get()); + case 1: + return new ItemStack(BloodMagicItems.AWAKENED_ACTIVATION_CRYSTAL.get()); + default: + return new ItemStack(BloodMagicItems.CREATIVE_ACTIVATION_CRYSTAL.get()); + } + } + } +} \ No newline at end of file diff --git a/src/main/java/wayoftime/bloodmagic/demonaura/PosXY.java b/src/main/java/wayoftime/bloodmagic/demonaura/PosXY.java new file mode 100644 index 00000000..2e2fd6da --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/demonaura/PosXY.java @@ -0,0 +1,76 @@ +package wayoftime.bloodmagic.demonaura; + +import org.apache.commons.lang3.builder.ToStringBuilder; + +public class PosXY implements Comparable +{ + public int x; + public int y; + + public PosXY() + { + } + + public PosXY(int x, int y) + { + this.x = x; + this.y = y; + } + + @Override + public int compareTo(PosXY c) + { + return this.y == c.y ? this.x - c.x : this.y - c.y; + } + + public float getDistanceSquared(int x, int z) + { + float f = this.x - x; + float f2 = this.y - z; + return f * f + f2 * f2; + } + + public float getDistanceSquaredToChunkCoordinates(PosXY c) + { + return getDistanceSquared(c.x, c.y); + } + + public void setX(int x) + { + this.x = x; + } + + public void setY(int y) + { + this.y = y; + } + + @Override + public String toString() + { + return new ToStringBuilder(this).append("x", x).append("y", y).toString(); + } + + @Override + public boolean equals(Object o) + { + if (this == o) + return true; + if (!(o instanceof PosXY)) + return false; + + PosXY posXY = (PosXY) o; + + if (x != posXY.x) + return false; + return y == posXY.y; + } + + @Override + public int hashCode() + { + int result = x; + result = 31 * result + y; + return result; + } +} \ No newline at end of file diff --git a/src/main/java/wayoftime/bloodmagic/demonaura/WillChunk.java b/src/main/java/wayoftime/bloodmagic/demonaura/WillChunk.java new file mode 100644 index 00000000..f93cfb8f --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/demonaura/WillChunk.java @@ -0,0 +1,72 @@ +package wayoftime.bloodmagic.demonaura; + +import java.lang.ref.WeakReference; + +import net.minecraft.world.chunk.Chunk; +import wayoftime.bloodmagic.will.DemonWillHolder; + +public class WillChunk +{ + PosXY loc; + private short base; + private DemonWillHolder currentWill = new DemonWillHolder(); + private WeakReference chunkRef; + + public WillChunk(PosXY loc) + { + this.loc = loc; + } + + public WillChunk(Chunk chunk, short base, DemonWillHolder currentWill) + { + this.loc = new PosXY(chunk.getPos().x, chunk.getPos().z); + this.chunkRef = new WeakReference(chunk); + this.base = base; + this.currentWill = currentWill; + } + + public boolean isModified() + { + return (this.chunkRef != null) && (this.chunkRef.get() != null) && this.chunkRef.get().isModified(); + } + + public PosXY getLoc() + { + return loc; + } + + public void setLoc(PosXY loc) + { + this.loc = loc; + } + + public short getBase() + { + return base; + } + + public void setBase(short base) + { + this.base = base; + } + + public DemonWillHolder getCurrentWill() + { + return currentWill; + } + + public void setCurrentWill(DemonWillHolder currentWill) + { + this.currentWill = currentWill; + } + + public WeakReference getChunkRef() + { + return chunkRef; + } + + public void setChunkRef(WeakReference chunkRef) + { + this.chunkRef = chunkRef; + } +} \ No newline at end of file diff --git a/src/main/java/wayoftime/bloodmagic/demonaura/WillWorld.java b/src/main/java/wayoftime/bloodmagic/demonaura/WillWorld.java new file mode 100644 index 00000000..b1f92d9a --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/demonaura/WillWorld.java @@ -0,0 +1,49 @@ +package wayoftime.bloodmagic.demonaura; + +import java.util.concurrent.ConcurrentHashMap; + +import net.minecraft.util.ResourceLocation; + +public class WillWorld +{ + // TODO: It was noted I may need to use RegistryKey instead. + ResourceLocation dim; + ConcurrentHashMap willChunks = new ConcurrentHashMap<>(); + +// private static ConcurrentHashMap nodeTickets = new ConcurrentHashMap(); + + public WillWorld(ResourceLocation resourceLocation) + { + this.dim = resourceLocation; + } + + public WillChunk getWillChunkAt(int x, int y) + { + return getWillChunkAt(new PosXY(x, y)); + } + + public WillChunk getWillChunkAt(PosXY loc) + { + return this.willChunks.get(loc); + } + + public ConcurrentHashMap getWillChunks() + { + return willChunks; + } + + public void setWillChunks(ConcurrentHashMap willChunks) + { + this.willChunks = willChunks; + } + +// public static ConcurrentHashMap getNodeTickets() +// { +// return nodeTickets; +// } +// +// public static void setNodeTickets(ConcurrentHashMap nodeTickets) +// { +// nodeTickets = nodeTickets; +// } +} \ No newline at end of file diff --git a/src/main/java/wayoftime/bloodmagic/demonaura/WorldDemonWillHandler.java b/src/main/java/wayoftime/bloodmagic/demonaura/WorldDemonWillHandler.java new file mode 100644 index 00000000..c26cf624 --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/demonaura/WorldDemonWillHandler.java @@ -0,0 +1,218 @@ +package wayoftime.bloodmagic.demonaura; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; + +import javax.annotation.Nullable; + +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraft.world.chunk.Chunk; +import wayoftime.bloodmagic.util.BMLog; +import wayoftime.bloodmagic.will.DemonWillHolder; +import wayoftime.bloodmagic.will.EnumDemonWillType; + +public class WorldDemonWillHandler +{ + public static ConcurrentHashMap> dirtyChunks = new ConcurrentHashMap<>(); + static ConcurrentHashMap containedWills = new ConcurrentHashMap<>(); + + @Nullable + public static DemonWillHolder getWillHolder(ResourceLocation resourceLocation, int x, int y) + { + WillChunk chunk = getWillChunk(resourceLocation, x, y); + if (chunk != null) + { + return chunk.getCurrentWill(); + } + + return null; + } + + public static DemonWillHolder getWillHolder(World world, BlockPos pos) + { + return getWillHolder(getDimensionResourceLocation(world), pos.getX() >> 4, pos.getZ() >> 4); + } + + public static WillWorld getWillWorld(int dim) + { + return containedWills.get(dim); + } + + @Nullable + public static WillChunk getWillChunk(ResourceLocation resourceLocation, int x, int y) + { + if (!containedWills.containsKey(resourceLocation)) + { + addWillWorld(resourceLocation); + } + + return (containedWills.get(resourceLocation)).getWillChunkAt(x, y); + } + + public static void addWillWorld(ResourceLocation resourceLocation) + { + if (!containedWills.containsKey(resourceLocation)) + { + containedWills.put(resourceLocation, new WillWorld(resourceLocation)); + BMLog.DEBUG.info("Creating demon will cache for world {}", resourceLocation); + } + } + + public static void removeWillWorld(int dim) + { + containedWills.remove(dim); + BMLog.DEBUG.info("Removing demon will cache for world {}", dim); + } + + public static void addWillChunk(ResourceLocation resourceLocation, Chunk chunk, short base, DemonWillHolder currentWill) + { + WillWorld aw = containedWills.get(resourceLocation); + if (aw == null) + { + aw = new WillWorld(resourceLocation); + } + aw.getWillChunks().put(new PosXY(chunk.getPos().x, chunk.getPos().z), new WillChunk(chunk, base, currentWill)); + + containedWills.put(resourceLocation, aw); + } + + public static void removeWillChunk(ResourceLocation resourceLocation, int x, int y) + { + WillWorld aw = containedWills.get(resourceLocation); + if (aw != null) + { + WillChunk chunk = aw.getWillChunks().remove(new PosXY(x, y)); + if (chunk != null) + { + markChunkAsDirty(chunk, resourceLocation); + } + } + } + + public static EnumDemonWillType getHighestDemonWillType(World world, BlockPos pos) + { + double currentMax = 0; + EnumDemonWillType currentHighest = EnumDemonWillType.DEFAULT; + + WillChunk willChunk = getWillChunk(world, pos); + + DemonWillHolder currentWill = willChunk.getCurrentWill(); + for (EnumDemonWillType type : EnumDemonWillType.values()) + { + if (currentWill.getWill(type) > currentMax) + { + currentMax = currentWill.getWill(type); + currentHighest = type; + } + } + + return currentHighest; + } + + public static double drainWill(World world, BlockPos pos, EnumDemonWillType type, double amount, boolean doDrain) + { + WillChunk willChunk = getWillChunk(world, pos); + + DemonWillHolder currentWill = willChunk.getCurrentWill(); + double drain = Math.min(currentWill.getWill(type), amount); + if (!doDrain) + { + return drain; + } + + drain = currentWill.drainWill(type, drain); + markChunkAsDirty(willChunk, getDimensionResourceLocation(world)); + + return drain; + } + + public static double fillWillToMaximum(World world, BlockPos pos, EnumDemonWillType type, double amount, double max, boolean doFill) + { + WillChunk willChunk = getWillChunk(world, pos); + + DemonWillHolder currentWill = willChunk.getCurrentWill(); + double fill = Math.min(amount, max - currentWill.getWill(type)); + if (!doFill || fill <= 0) + { + return fill > 0 ? fill : 0; + } + + fill = currentWill.addWill(type, amount, max); + markChunkAsDirty(willChunk, getDimensionResourceLocation(world)); + + return fill; + } + + public static double fillWill(World world, BlockPos pos, EnumDemonWillType type, double amount, boolean doFill) + { + WillChunk willChunk = getWillChunk(world, pos); + + DemonWillHolder currentWill = willChunk.getCurrentWill(); + if (!doFill) + { + return amount; + } + + currentWill.addWill(type, amount); + markChunkAsDirty(willChunk, getDimensionResourceLocation(world)); + + return amount; + } + + public static WillChunk getWillChunk(World world, BlockPos pos) + { + WillChunk willChunk = getWillChunk(getDimensionResourceLocation(world), pos.getX() >> 4, pos.getZ() >> 4); + if (willChunk == null) + { + Chunk chunk = world.getChunk(pos.getX() >> 4, pos.getZ() >> 4); + generateWill(chunk); + + willChunk = getWillChunk(getDimensionResourceLocation(world), pos.getX() >> 4, pos.getZ() >> 4); + } + + return willChunk; + } + + public static double getCurrentWill(World world, BlockPos pos, EnumDemonWillType type) + { + WillChunk willChunk = getWillChunk(world, pos); + + if (willChunk == null) + { + return 0; + } + + DemonWillHolder currentWill = willChunk.getCurrentWill(); + return currentWill.getWill(type); + } + + private static void markChunkAsDirty(WillChunk chunk, ResourceLocation resourceLocation) + { + if (chunk.isModified()) + { + return; + } + PosXY pos = new PosXY(chunk.loc.x, chunk.loc.y); + if (!dirtyChunks.containsKey(resourceLocation)) + { + dirtyChunks.put(resourceLocation, new CopyOnWriteArrayList<>()); + } + CopyOnWriteArrayList dc = dirtyChunks.get(resourceLocation); + if (!dc.contains(pos)) + { + dc.add(pos); + } + } + + public static void generateWill(Chunk chunk) + { + addWillChunk(chunk.getWorld().getDimensionKey().getLocation(), chunk, (short) 1, new DemonWillHolder()); + } + + private static ResourceLocation getDimensionResourceLocation(World world) + { + return world.getDimensionKey().getLocation(); + } +} \ No newline at end of file diff --git a/src/main/java/wayoftime/bloodmagic/event/RitualEvent.java b/src/main/java/wayoftime/bloodmagic/event/RitualEvent.java new file mode 100644 index 00000000..f5356ec8 --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/event/RitualEvent.java @@ -0,0 +1,151 @@ +package wayoftime.bloodmagic.event; + +import java.util.UUID; + +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; +import net.minecraftforge.eventbus.api.Cancelable; +import net.minecraftforge.eventbus.api.Event; +import wayoftime.bloodmagic.ritual.IMasterRitualStone; +import wayoftime.bloodmagic.ritual.Ritual; +import wayoftime.bloodmagic.ritual.imperfect.IImperfectRitualStone; +import wayoftime.bloodmagic.ritual.imperfect.ImperfectRitual; + +public class RitualEvent extends Event +{ + private final IMasterRitualStone mrs; + private final UUID ownerId; + private final Ritual ritual; + + private RitualEvent(IMasterRitualStone mrs, UUID ownerId, Ritual ritual) + { + this.mrs = mrs; + this.ownerId = ownerId; + this.ritual = ritual; + } + + public IMasterRitualStone getRitualStone() + { + return mrs; + } + + public UUID getOwnerId() + { + return ownerId; + } + + public Ritual getRitual() + { + return ritual; + } + + /** + * This event is called when a ritual is activated. If cancelled, it will not + * activate. + *

+ * {@link WayofTime.bloodmagic.tile.TileMasterRitualStone#activateRitual(ItemStack, PlayerEntity, Ritual)} + */ + @Cancelable + public static class RitualActivatedEvent extends RitualEvent + { + + private final PlayerEntity player; + private final ItemStack crystalStack; + private final int crystalTier; + + public RitualActivatedEvent(IMasterRitualStone mrs, UUID ownerId, Ritual ritual, PlayerEntity player, ItemStack activationCrystal, int crystalTier) + { + super(mrs, ownerId, ritual); + + this.player = player; + this.crystalStack = activationCrystal; + this.crystalTier = crystalTier; + } + + public PlayerEntity getPlayer() + { + return player; + } + + public ItemStack getCrystalStack() + { + return crystalStack; + } + + public int getCrystalTier() + { + return crystalTier; + } + } + + /** + * This event is called when a Ritual effect is performed. If cancelled, the + * effect will not happen. + *

+ * {@link WayofTime.bloodmagic.tile.TileMasterRitualStone#performRitual(World, net.minecraft.util.math.BlockPos)} + */ + @Cancelable + public static class RitualRunEvent extends RitualEvent + { + + public RitualRunEvent(IMasterRitualStone mrs, UUID ownerId, Ritual ritual) + { + super(mrs, ownerId, ritual); + } + } + + /** + * This event is called when a Ritual is stopped by a {@link Ritual.BreakType}. + *

+ * {@link WayofTime.bloodmagic.tile.TileMasterRitualStone#stopRitual(Ritual.BreakType)} + */ + public static class RitualStopEvent extends RitualEvent + { + + private final Ritual.BreakType method; + + public RitualStopEvent(IMasterRitualStone mrs, UUID ownerId, Ritual ritual, Ritual.BreakType method) + { + super(mrs, ownerId, ritual); + + this.method = method; + } + + public Ritual.BreakType getMethod() + { + return method; + } + } + + @Cancelable + public static class ImperfectRitualActivatedEvent extends Event + { + + private final IImperfectRitualStone ims; + private final PlayerEntity activator; + private final ImperfectRitual imperfectRitual; + + public ImperfectRitualActivatedEvent(IImperfectRitualStone ims, PlayerEntity activator, ImperfectRitual imperfectRitual) + { + this.ims = ims; + this.activator = activator; + this.imperfectRitual = imperfectRitual; + } + + public IImperfectRitualStone getRitualStone() + { + return ims; + } + + public PlayerEntity getActivator() + { + return activator; + } + + public ImperfectRitual getImperfectRitual() + { + return imperfectRitual; + } + } +} \ No newline at end of file diff --git a/src/main/java/wayoftime/bloodmagic/ritual/AreaDescriptor.java b/src/main/java/wayoftime/bloodmagic/ritual/AreaDescriptor.java new file mode 100644 index 00000000..b37eeb80 --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/ritual/AreaDescriptor.java @@ -0,0 +1,654 @@ +package wayoftime.bloodmagic.ritual; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.gen.feature.template.PlacementSettings; +import net.minecraft.world.gen.feature.template.Template; +import wayoftime.bloodmagic.util.Constants; + +public abstract class AreaDescriptor implements Iterator +{ + public List getContainedPositions(BlockPos pos) + { + return new ArrayList<>(); + } + + public AxisAlignedBB getAABB(BlockPos pos) + { + return null; + } + + public abstract void resetCache(); + + public abstract boolean isWithinArea(BlockPos pos); + + public abstract void resetIterator(); + + public void readFromNBT(CompoundNBT tag) + { + + } + + public void writeToNBT(CompoundNBT tag) + { + + } + + public abstract AreaDescriptor copy(); + + public abstract int getVolumeForOffsets(BlockPos offset1, BlockPos offset2); + + public abstract boolean isWithinRange(BlockPos offset1, BlockPos offset2, int verticalLimit, int horizontalLimit); + + public abstract int getVolume(); + + public abstract int getHeight(); + + public abstract boolean isWithinRange(int verticalLimit, int horizontalLimit); + + /** + * This method changes the area descriptor so that its range matches the two + * blocks that are selected. When implementing this method, assume that these + * positions are the blocks that are clicked by the player. + * + * @param pos1 + * @param pos2 + */ + public abstract void modifyAreaByBlockPositions(BlockPos pos1, BlockPos pos2); + + public abstract boolean intersects(AreaDescriptor descriptor); + + public abstract AreaDescriptor offset(BlockPos offset); + + public abstract AreaDescriptor rotateDescriptor(PlacementSettings settings); + + public static class Rectangle extends AreaDescriptor + { + protected BlockPos minimumOffset; + protected BlockPos maximumOffset; // Non-inclusive maximum offset. + private BlockPos currentPosition; + + private ArrayList blockPosCache; + private BlockPos cachedPosition; + + private boolean cache = true; + + /** + * This constructor takes in the minimum and maximum BlockPos. The maximum + * offset is non-inclusive, meaning if you pass in (0,0,0) and (1,1,1), calling + * getContainedPositions() will only give (0,0,0). + * + * @param minimumOffset - + * @param maximumOffset - + */ + public Rectangle(BlockPos minimumOffset, BlockPos maximumOffset) + { + setOffsets(minimumOffset, maximumOffset); + } + + public Rectangle(BlockPos minimumOffset, int sizeX, int sizeY, int sizeZ) + { + this(minimumOffset, minimumOffset.add(sizeX, sizeY, sizeZ)); + } + + public Rectangle(BlockPos minimumOffset, int size) + { + this(minimumOffset, size, size, size); + } + + public Rectangle(AreaDescriptor.Rectangle rectangle) + { + this(rectangle.minimumOffset, rectangle.maximumOffset); + } + + public AreaDescriptor.Rectangle copy() + { + return new AreaDescriptor.Rectangle(this); + } + + @Override + public List getContainedPositions(BlockPos pos) + { + if (!cache || !pos.equals(cachedPosition) || blockPosCache.isEmpty()) + { + ArrayList posList = new ArrayList<>(); + + for (int j = minimumOffset.getY(); j < maximumOffset.getY(); j++) + { + for (int i = minimumOffset.getX(); i < maximumOffset.getX(); i++) + { + for (int k = minimumOffset.getZ(); k < maximumOffset.getZ(); k++) + { + posList.add(pos.add(i, j, k)); + } + } + } + + blockPosCache = posList; + cachedPosition = pos; + } + + return Collections.unmodifiableList(blockPosCache); + } + + @Override + public AxisAlignedBB getAABB(BlockPos pos) + { + AxisAlignedBB tempAABB = new AxisAlignedBB(minimumOffset, maximumOffset); + return tempAABB.offset(pos.getX(), pos.getY(), pos.getZ()); + } + + @Override + public int getHeight() + { + return this.maximumOffset.getY() - this.minimumOffset.getY(); + } + + public BlockPos getMinimumOffset() + { + return minimumOffset; + } + + public BlockPos getMaximumOffset() + { + return maximumOffset; + } + + /** + * Sets the offsets of the AreaDescriptor in a safe way that will make + * minimumOffset the lowest corner + * + * @param offset1 - + * @param offset2 - + */ + public void setOffsets(BlockPos offset1, BlockPos offset2) + { + this.minimumOffset = new BlockPos(Math.min(offset1.getX(), offset2.getX()), Math.min(offset1.getY(), offset2.getY()), Math.min(offset1.getZ(), offset2.getZ())); + this.maximumOffset = new BlockPos(Math.max(offset1.getX(), offset2.getX()), Math.max(offset1.getY(), offset2.getY()), Math.max(offset1.getZ(), offset2.getZ())); + blockPosCache = new ArrayList<>(); + } + + @Override + public void resetCache() + { + this.blockPosCache = new ArrayList<>(); + } + + @Override + public boolean isWithinArea(BlockPos pos) + { + int x = pos.getX(); + int y = pos.getY(); + int z = pos.getZ(); + + return x >= minimumOffset.getX() && x < maximumOffset.getX() && y >= minimumOffset.getY() + && y < maximumOffset.getY() && z >= minimumOffset.getZ() && z < maximumOffset.getZ(); + } + + @Override + public boolean hasNext() + { + return currentPosition == null || !(currentPosition.getX() + 1 == maximumOffset.getX() + && currentPosition.getY() + 1 == maximumOffset.getY() + && currentPosition.getZ() + 1 == maximumOffset.getZ()); + } + + @Override + public BlockPos next() + { + if (currentPosition != null) + { + int nextX = currentPosition.getX() + 1 >= maximumOffset.getX() ? minimumOffset.getX() + : currentPosition.getX() + 1; + int nextZ = nextX != minimumOffset.getX() ? currentPosition.getZ() + : (currentPosition.getZ() + 1 >= maximumOffset.getZ() ? minimumOffset.getZ() + : currentPosition.getZ() + 1); + int nextY = (nextZ != minimumOffset.getZ() || nextX != minimumOffset.getX()) ? currentPosition.getY() + : (currentPosition.getY() + 1); + currentPosition = new BlockPos(nextX, nextY, nextZ); + } else + { + currentPosition = minimumOffset; + } + + return currentPosition; + } + + @Override + public void remove() + { + + } + + @Override + public void resetIterator() + { + currentPosition = null; + } + + @Override + public void modifyAreaByBlockPositions(BlockPos pos1, BlockPos pos2) + { + setOffsets(pos1, pos2); + maximumOffset = maximumOffset.add(1, 1, 1); + resetIterator(); + resetCache(); + } + + @Override + public void readFromNBT(CompoundNBT tag) + { + minimumOffset = new BlockPos(tag.getInt(Constants.NBT.X_COORD + "min"), tag.getInt(Constants.NBT.Y_COORD + "min"), tag.getInt(Constants.NBT.Z_COORD + "min")); + maximumOffset = new BlockPos(tag.getInt(Constants.NBT.X_COORD + "max"), tag.getInt(Constants.NBT.Y_COORD + "max"), tag.getInt(Constants.NBT.Z_COORD + "max")); + } + + @Override + public void writeToNBT(CompoundNBT tag) + { + tag.putInt(Constants.NBT.X_COORD + "min", minimumOffset.getX()); + tag.putInt(Constants.NBT.Y_COORD + "min", minimumOffset.getY()); + tag.putInt(Constants.NBT.Z_COORD + "min", minimumOffset.getZ()); + tag.putInt(Constants.NBT.X_COORD + "max", maximumOffset.getX()); + tag.putInt(Constants.NBT.Y_COORD + "max", maximumOffset.getY()); + tag.putInt(Constants.NBT.Z_COORD + "max", maximumOffset.getZ()); + } + + @Override + public int getVolumeForOffsets(BlockPos offset1, BlockPos offset2) + { + BlockPos minPos = new BlockPos(Math.min(offset1.getX(), offset2.getX()), Math.min(offset1.getY(), offset2.getY()), Math.min(offset1.getZ(), offset2.getZ())); + BlockPos maxPos = new BlockPos(Math.max(offset1.getX(), offset2.getX()), Math.max(offset1.getY(), offset2.getY()), Math.max(offset1.getZ(), offset2.getZ())); + + maxPos = maxPos.add(1, 1, 1); + + return (maxPos.getX() - minPos.getX()) * (maxPos.getY() - minPos.getY()) * (maxPos.getZ() - minPos.getZ()); + } + + @Override + public boolean isWithinRange(BlockPos offset1, BlockPos offset2, int verticalLimit, int horizontalLimit) + { + BlockPos minPos = new BlockPos(Math.min(offset1.getX(), offset2.getX()), Math.min(offset1.getY(), offset2.getY()), Math.min(offset1.getZ(), offset2.getZ())); + BlockPos maxPos = new BlockPos(Math.max(offset1.getX(), offset2.getX()), Math.max(offset1.getY(), offset2.getY()), Math.max(offset1.getZ(), offset2.getZ())); + + return minPos.getY() >= -verticalLimit && maxPos.getY() <= verticalLimit + && minPos.getX() >= -horizontalLimit && maxPos.getX() <= horizontalLimit + && minPos.getZ() >= -horizontalLimit && maxPos.getZ() <= horizontalLimit; + } + + @Override + public int getVolume() + { + return (maximumOffset.getX() - minimumOffset.getX()) * (maximumOffset.getY() - minimumOffset.getY()) + * (maximumOffset.getZ() - minimumOffset.getZ()); + } + + @Override + public boolean isWithinRange(int verticalLimit, int horizontalLimit) + { + return minimumOffset.getY() >= -verticalLimit && maximumOffset.getY() <= verticalLimit + 1 + && minimumOffset.getX() >= -horizontalLimit && maximumOffset.getX() <= horizontalLimit + 1 + && minimumOffset.getZ() >= -horizontalLimit && maximumOffset.getZ() <= horizontalLimit + 1; + } + + @Override + public boolean intersects(AreaDescriptor descriptor) + { + if (descriptor instanceof AreaDescriptor.Rectangle) + { + AreaDescriptor.Rectangle rectangle = (AreaDescriptor.Rectangle) descriptor; + + return !(minimumOffset.getX() >= rectangle.maximumOffset.getX() + || minimumOffset.getY() >= rectangle.maximumOffset.getY() + || minimumOffset.getZ() >= rectangle.maximumOffset.getZ() + || rectangle.minimumOffset.getX() >= maximumOffset.getX() + || rectangle.minimumOffset.getY() >= maximumOffset.getY() + || rectangle.minimumOffset.getZ() >= maximumOffset.getZ()); + } + + return false; + } + + @Override + public AreaDescriptor offset(BlockPos offset) + { + return new AreaDescriptor.Rectangle(this.minimumOffset.add(offset), this.maximumOffset.add(offset)); + } + + @Override + public AreaDescriptor rotateDescriptor(PlacementSettings settings) + { + BlockPos rotatePos1 = Template.transformedBlockPos(settings, minimumOffset); + BlockPos rotatePos2 = Template.transformedBlockPos(settings, maximumOffset.add(-1, -1, -1)); // It works, + // shut up! + + AreaDescriptor.Rectangle rectangle = new AreaDescriptor.Rectangle(this.minimumOffset, 1); + rectangle.modifyAreaByBlockPositions(rotatePos1, rotatePos2); + + return rectangle; + } + } + + public static class HemiSphere extends AreaDescriptor + { + private BlockPos minimumOffset; + private int radius; + + private ArrayList blockPosCache; + private BlockPos cachedPosition; + + private boolean cache = true; + + public HemiSphere(BlockPos minimumOffset, int radius) + { + setRadius(minimumOffset, radius); + } + + public HemiSphere(AreaDescriptor.HemiSphere hemiSphere) + { + this(hemiSphere.minimumOffset, hemiSphere.radius); + } + + public AreaDescriptor.HemiSphere copy() + { + return new AreaDescriptor.HemiSphere(this); + } + + public void setRadius(BlockPos minimumOffset, int radius) + { + this.minimumOffset = new BlockPos(Math.min(minimumOffset.getX(), minimumOffset.getX()), Math.min(minimumOffset.getY(), minimumOffset.getY()), Math.min(minimumOffset.getZ(), minimumOffset.getZ())); + this.radius = radius; + blockPosCache = new ArrayList<>(); + } + + @Override + public int getHeight() + { + return this.radius * 2; + } + + @Override + public List getContainedPositions(BlockPos pos) + { + if (!cache || !pos.equals(cachedPosition) || blockPosCache.isEmpty()) + { + ArrayList posList = new ArrayList<>(); + + int i = -radius; + int j = minimumOffset.getY(); + int k = -radius; + + // TODO For some reason the bottom of the hemisphere is not going up with the + // minOffset + + while (i <= radius) + { + while (j <= radius) + { + while (k <= radius) + { + if (i * i + j * j + k * k >= (radius + 0.5F) * (radius + 0.5F)) + { + k++; + continue; + } + + posList.add(pos.add(i, j, k)); + k++; + } + + k = -radius; + j++; + } + + j = minimumOffset.getY(); + i++; + } + + blockPosCache = posList; + cachedPosition = pos; + } + + return Collections.unmodifiableList(blockPosCache); + } + + /** + * Since you can't make a box using a sphere, this returns null + */ + @Override + public AxisAlignedBB getAABB(BlockPos pos) + { + return null; + } + + @Override + public void resetCache() + { + this.blockPosCache = new ArrayList<>(); + } + + @Override + public boolean isWithinArea(BlockPos pos) + { + return blockPosCache.contains(pos); + } + + @Override + public boolean hasNext() + { + return false; + } + + @Override + public BlockPos next() + { + return null; + } + + @Override + public void remove() + { + + } + + @Override + public void resetIterator() + { + + } + + @Override + public void modifyAreaByBlockPositions(BlockPos pos1, BlockPos pos2) + { + + } + + @Override + public int getVolumeForOffsets(BlockPos pos1, BlockPos pos2) + { + return 0; + } + + @Override + public boolean isWithinRange(BlockPos offset1, BlockPos offset2, int verticalLimit, int horizontalLimit) + { + return false; + } + + @Override + public int getVolume() + { + return 0; + } + + @Override + public boolean isWithinRange(int verticalLimit, int horizontalLimit) + { + return false; + } + + @Override + public boolean intersects(AreaDescriptor descriptor) + { + return false; + } + + @Override + public AreaDescriptor offset(BlockPos offset) + { + return new AreaDescriptor.HemiSphere(minimumOffset.add(offset), radius); + } + + @Override + public AreaDescriptor rotateDescriptor(PlacementSettings settings) + { + return this; + } + } + + public static class Cross extends AreaDescriptor + { + + private ArrayList blockPosCache; + private BlockPos cachedPosition; + + private BlockPos centerPos; + private int size; + + private boolean cache = true; + + public Cross(BlockPos center, int size) + { + this.centerPos = center; + this.size = size; + this.blockPosCache = new ArrayList<>(); + } + + public Cross(AreaDescriptor.Cross cross) + { + this(cross.centerPos, cross.size); + } + + public AreaDescriptor.Cross copy() + { + return new AreaDescriptor.Cross(this); + } + + @Override + public int getHeight() + { + return this.size * 2 + 1; + } + + @Override + public List getContainedPositions(BlockPos pos) + { + if (!cache || !pos.equals(cachedPosition) || blockPosCache.isEmpty()) + { + resetCache(); + + blockPosCache.add(centerPos.add(pos)); + for (int i = 1; i <= size; i++) + { + blockPosCache.add(centerPos.add(pos).add(i, 0, 0)); + blockPosCache.add(centerPos.add(pos).add(0, 0, i)); + blockPosCache.add(centerPos.add(pos).add(-i, 0, 0)); + blockPosCache.add(centerPos.add(pos).add(0, 0, -i)); + } + } + + cachedPosition = pos; + + return Collections.unmodifiableList(blockPosCache); + } + + @Override + public void resetCache() + { + blockPosCache = new ArrayList<>(); + } + + @Override + public boolean isWithinArea(BlockPos pos) + { + return blockPosCache.contains(pos); + } + + @Override + public boolean hasNext() + { + return false; + } + + @Override + public BlockPos next() + { + return null; + } + + @Override + public void remove() + { + + } + + @Override + public void resetIterator() + { + + } + + @Override + public void modifyAreaByBlockPositions(BlockPos pos1, BlockPos pos2) + { + + } + + @Override + public int getVolumeForOffsets(BlockPos pos1, BlockPos pos2) + { + return 0; + } + + @Override + public boolean isWithinRange(BlockPos offset1, BlockPos offset2, int verticalLimit, int horizontalLimit) + { + return false; + } + + @Override + public int getVolume() + { + return 0; + } + + @Override + public boolean isWithinRange(int verticalLimit, int horizontalLimit) + { + return false; + } + + @Override + public boolean intersects(AreaDescriptor descriptor) + { + return false; + } + + @Override + public AreaDescriptor offset(BlockPos offset) + { + return new AreaDescriptor.Cross(centerPos.add(offset), size); + } + + @Override + public AreaDescriptor rotateDescriptor(PlacementSettings settings) + { + return this; + } + } +} \ No newline at end of file diff --git a/src/main/java/wayoftime/bloodmagic/ritual/CapabilityRuneType.java b/src/main/java/wayoftime/bloodmagic/ritual/CapabilityRuneType.java new file mode 100644 index 00000000..258867c4 --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/ritual/CapabilityRuneType.java @@ -0,0 +1,58 @@ +package wayoftime.bloodmagic.ritual; + +import java.util.concurrent.Callable; + +import net.minecraft.nbt.ByteNBT; +import net.minecraft.nbt.INBT; +import net.minecraft.util.Direction; +import net.minecraftforge.common.capabilities.Capability; + +public final class CapabilityRuneType +{ + public static class RuneTypeStorage implements Capability.IStorage + { + @Override + public INBT writeNBT(Capability capability, IRitualStone.Tile instance, Direction side) + { + return ByteNBT.valueOf((byte) instance.getRuneType().ordinal()); + } + + @Override + public void readNBT(Capability capability, IRitualStone.Tile instance, Direction side, INBT nbt) + { + instance.setRuneType(EnumRuneType.byMetadata(((ByteNBT) nbt).getByte())); + } + } + + public static class RuneTypeWrapper implements IRitualStone.Tile + { + private EnumRuneType type = EnumRuneType.BLANK; + + @Override + public boolean isRuneType(EnumRuneType runeType) + { + return type == runeType; + } + + @Override + public EnumRuneType getRuneType() + { + return type; + } + + public void setRuneType(EnumRuneType runeType) + { + type = runeType; + } + } + + public static class Factory implements Callable + { + @Override + public IRitualStone.Tile call() + throws Exception + { + return new RuneTypeWrapper(); + } + } +} \ No newline at end of file diff --git a/src/main/java/wayoftime/bloodmagic/ritual/EnumReaderBoundaries.java b/src/main/java/wayoftime/bloodmagic/ritual/EnumReaderBoundaries.java new file mode 100644 index 00000000..3e664671 --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/ritual/EnumReaderBoundaries.java @@ -0,0 +1,22 @@ +package wayoftime.bloodmagic.ritual; + +import java.util.Locale; + +import net.minecraft.util.IStringSerializable; + +public enum EnumReaderBoundaries implements IStringSerializable +{ + SUCCESS, VOLUME_TOO_LARGE, NOT_WITHIN_BOUNDARIES; + + @Override + public String toString() + { + return name().toLowerCase(Locale.ROOT); + } + + @Override + public String getString() + { + return toString(); + } +} \ No newline at end of file diff --git a/src/main/java/wayoftime/bloodmagic/ritual/EnumRuneType.java b/src/main/java/wayoftime/bloodmagic/ritual/EnumRuneType.java new file mode 100644 index 00000000..959e771d --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/ritual/EnumRuneType.java @@ -0,0 +1,54 @@ +package wayoftime.bloodmagic.ritual; + +import java.util.Locale; + +import net.minecraft.util.IStringSerializable; +import net.minecraft.util.text.TextFormatting; + +public enum EnumRuneType implements IStringSerializable +{ + BLANK(TextFormatting.GRAY), + WATER(TextFormatting.AQUA), + FIRE(TextFormatting.RED), + EARTH(TextFormatting.GREEN), + AIR(TextFormatting.WHITE), + DUSK(TextFormatting.DARK_GRAY), + DAWN(TextFormatting.GOLD); + + public final TextFormatting colorCode; + + EnumRuneType(TextFormatting colorCode) + { + this.colorCode = colorCode; + } + + @Override + public String toString() + { + return name().toLowerCase(Locale.ENGLISH); + } + + @Override + public String getString() + { + return this.toString(); + } + +// @Nonnull +// public ItemStack getStack(int count) +// { +// ItemStack ret = new ItemStack(RegistrarBloodMagicItems.INSCRIPTION_TOOL, count, ordinal()); +// CompoundNBT tag = new CompoundNBT(); +// tag.putInt(Constants.NBT.USES, 10); +// ret.setTag(tag); +// return ret; +// } + + public static EnumRuneType byMetadata(int meta) + { + if (meta < 0 || meta >= values().length) + meta = 0; + + return values()[meta]; + } +} \ No newline at end of file diff --git a/src/main/java/wayoftime/bloodmagic/ritual/IMasterRitualStone.java b/src/main/java/wayoftime/bloodmagic/ritual/IMasterRitualStone.java new file mode 100644 index 00000000..e82e2deb --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/ritual/IMasterRitualStone.java @@ -0,0 +1,81 @@ +package wayoftime.bloodmagic.ritual; + +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.util.Direction; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import wayoftime.bloodmagic.core.data.SoulNetwork; +import wayoftime.bloodmagic.core.data.SoulTicket; +import wayoftime.bloodmagic.will.EnumDemonWillType; + +/** + * This interface is for internal implementation only. + *

+ * It is provided via the API for easy obtaining of basic data. + */ +public interface IMasterRitualStone +{ + UUID getOwner(); + + SoulNetwork getOwnerNetwork(); + + boolean activateRitual(ItemStack activationCrystal, PlayerEntity activator, Ritual ritual); + + void performRitual(World world, BlockPos pos); + + void stopRitual(Ritual.BreakType breakType); + + int getCooldown(); + + void setCooldown(int cooldown); + + boolean isActive(); + + void setActive(boolean active); + + Direction getDirection(); + + boolean areTanksEmpty(); + + int getRunningTime(); + + World getWorldObj(); + + BlockPos getBlockPos(); + + String getNextBlockRange(String range); + + void provideInformationOfRitualToPlayer(PlayerEntity player); + + void provideInformationOfRangeToPlayer(PlayerEntity player, String range); + + void provideInformationOfWillConfigToPlayer(PlayerEntity player, List typeList); + + void setActiveWillConfig(PlayerEntity player, List typeList); + + EnumReaderBoundaries setBlockRangeByBounds(PlayerEntity player, String range, BlockPos offset1, BlockPos offset2); + + List getActiveWillConfig(); + + default SoulTicket ticket(int amount) + { + return SoulTicket.block(getWorldObj(), getBlockPos(), amount); + } + + AreaDescriptor getBlockRange(String range); + + void addBlockRanges(Map blockRanges); + + void addBlockRange(String range, AreaDescriptor defaultRange); + + void setBlockRanges(Map blockRanges); + + void setBlockRange(String range, AreaDescriptor defaultRange); + + Ritual getCurrentRitual(); +} diff --git a/src/main/java/wayoftime/bloodmagic/ritual/IRitualStone.java b/src/main/java/wayoftime/bloodmagic/ritual/IRitualStone.java new file mode 100644 index 00000000..a4409fe9 --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/ritual/IRitualStone.java @@ -0,0 +1,20 @@ +package wayoftime.bloodmagic.ritual; + +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +public interface IRitualStone +{ + boolean isRuneType(World world, BlockPos pos, EnumRuneType runeType); + + void setRuneType(World world, BlockPos pos, EnumRuneType runeType); + + interface Tile + { + boolean isRuneType(EnumRuneType runeType); + + EnumRuneType getRuneType(); + + void setRuneType(EnumRuneType runeType); + } +} diff --git a/src/main/java/wayoftime/bloodmagic/ritual/Ritual.java b/src/main/java/wayoftime/bloodmagic/ritual/Ritual.java new file mode 100644 index 00000000..0ecd8c43 --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/ritual/Ritual.java @@ -0,0 +1,427 @@ +package wayoftime.bloodmagic.ritual; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.UUID; +import java.util.function.Consumer; + +import org.apache.commons.lang3.builder.ToStringBuilder; + +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.nbt.ListNBT; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.text.ITextComponent; +import net.minecraft.util.text.TranslationTextComponent; +import net.minecraft.world.World; +import wayoftime.bloodmagic.demonaura.WorldDemonWillHandler; +import wayoftime.bloodmagic.will.DemonWillHolder; +import wayoftime.bloodmagic.will.EnumDemonWillType; + +/** + * Abstract class for creating new rituals. Register your ritual by annotating + * it with {@link RitualRegister} + */ +public abstract class Ritual +{ + + protected final Map modableRangeMap = new HashMap<>(); + protected final Map volumeRangeMap = new HashMap<>(); + protected final Map horizontalRangeMap = new HashMap<>(); + protected final Map verticalRangeMap = new HashMap<>(); + private final String name; + private final int crystalLevel; + private final int activationCost; + private final RitualRenderer renderer; + private final String unlocalizedName; + + public Ritual(String name, int crystalLevel, int activationCost, RitualRenderer renderer, String unlocalizedName) + { + this.name = name; + this.crystalLevel = crystalLevel; + this.activationCost = activationCost; + this.renderer = renderer; + this.unlocalizedName = unlocalizedName; + } + + /** + * @param name - The name of the ritual + * @param crystalLevel - Required Activation Crystal tier + * @param activationCost - Base LP cost for activating the ritual + */ + public Ritual(String name, int crystalLevel, int activationCost, String unlocalizedName) + { + this(name, crystalLevel, activationCost, null, unlocalizedName); + } + + public void readFromNBT(CompoundNBT tag) + { + ListNBT tags = tag.getList("areas", 10); + if (tags.isEmpty()) + { + return; + } + + for (int i = 0; i < tags.size(); i++) + { + CompoundNBT newTag = tags.getCompound(i); + String rangeKey = newTag.getString("key"); + + CompoundNBT storedTag = newTag.getCompound("area"); + AreaDescriptor desc = this.getBlockRange(rangeKey); + if (desc != null) + { + desc.readFromNBT(storedTag); + } + } + } + + public void writeToNBT(CompoundNBT tag) + { + ListNBT tags = new ListNBT(); + + for (Entry entry : modableRangeMap.entrySet()) + { + CompoundNBT newTag = new CompoundNBT(); + newTag.putString("key", entry.getKey()); + CompoundNBT storedTag = new CompoundNBT(); + + entry.getValue().writeToNBT(storedTag); + + newTag.put("area", storedTag); + + tags.add(newTag); + } + + tag.put("areas", tags); + } + + /** + * Called when the player attempts to activate the ritual. + *

+ * {@link WayofTime.bloodmagic.tile.TileMasterRitualStone#activateRitual(ItemStack, PlayerEntity, Ritual)} + * + * @param masterRitualStone - The {@link IMasterRitualStone} that the ritual is + * bound to + * @param player - The activating player + * @param owner - Owner of the crystal activating this ritual, or + * the current owner of the ritual if being + * reactivated. + * @return - Whether activation was successful + */ + public boolean activateRitual(IMasterRitualStone masterRitualStone, PlayerEntity player, UUID owner) + { + return true; + } + + /** + * Called every {@link #getRefreshTime()} ticks while active. + *

+ * {@link WayofTime.bloodmagic.tile.TileMasterRitualStone#performRitual(World, BlockPos)} + * + * @param masterRitualStone - The {@link IMasterRitualStone} that the ritual is + * bound to + */ + public abstract void performRitual(IMasterRitualStone masterRitualStone); + + /** + * Called when the ritual is stopped for a given {@link Ritual.BreakType}. + *

+ * {@link WayofTime.bloodmagic.tile.TileMasterRitualStone#stopRitual(Ritual.BreakType)} + * + * @param masterRitualStone - The {@link IMasterRitualStone} that the ritual is + * bound to + * @param breakType - The type of break that caused the stoppage. + */ + public void stopRitual(IMasterRitualStone masterRitualStone, BreakType breakType) + { + + } + + /** + * Used to set the amount of LP drained every {@link #getRefreshTime()} ticks. + * + * @return - The amount of LP drained per refresh + */ + public abstract int getRefreshCost(); + + /** + * Used to set the refresh rate of the ritual. (How often + * {@link #performRitual(IMasterRitualStone)} is called. + * + * @return - How often to perform the effect in ticks. + */ + public int getRefreshTime() + { + return 20; + } + + public void addBlockRange(String range, AreaDescriptor defaultRange) + { + modableRangeMap.put(range, defaultRange); + } + + /** + * Used to grab the range of a ritual for a given effect. + * + * @param range - Range that needs to be pulled. + * @return - + */ + public AreaDescriptor getBlockRange(String range) + { + if (modableRangeMap.containsKey(range)) + { + return modableRangeMap.get(range); + } + + return null; + } + + public List getListOfRanges() + { + return new ArrayList<>(modableRangeMap.keySet()); + } + + public String getNextBlockRange(String range) + { + List rangeList = getListOfRanges(); + + if (rangeList.isEmpty()) + { + return ""; + } + + if (!rangeList.contains(range)) + { + return rangeList.get(0); + } + + boolean hasMatch = false; + + for (String rangeCheck : rangeList) + { + if (hasMatch) + { + return rangeCheck; + } else if (rangeCheck.equals(range)) + { + hasMatch = true; + } + } + + return rangeList.get(0); + } + + public EnumReaderBoundaries canBlockRangeBeModified(String range, AreaDescriptor descriptor, IMasterRitualStone master, BlockPos offset1, BlockPos offset2, DemonWillHolder holder) + { + List willConfig = master.getActiveWillConfig(); + int maxVolume = getMaxVolumeForRange(range, willConfig, holder); + int maxVertical = getMaxVerticalRadiusForRange(range, willConfig, holder); + int maxHorizontal = getMaxHorizontalRadiusForRange(range, willConfig, holder); + + return (maxVolume <= 0 || descriptor.getVolumeForOffsets(offset1, offset2) <= maxVolume) + ? descriptor.isWithinRange(offset1, offset2, maxVertical, maxHorizontal) ? EnumReaderBoundaries.SUCCESS + : EnumReaderBoundaries.NOT_WITHIN_BOUNDARIES + : EnumReaderBoundaries.VOLUME_TOO_LARGE; + } + + protected void setMaximumVolumeAndDistanceOfRange(String range, int volume, int horizontalRadius, int verticalRadius) + { + volumeRangeMap.put(range, volume); + horizontalRangeMap.put(range, horizontalRadius); + verticalRangeMap.put(range, verticalRadius); + } + + protected boolean checkDescriptorIsWithinRange(AreaDescriptor descriptor, int maxVolume, int maxHorizontal, int maxVertical) + { + return descriptor.getVolume() <= maxVolume && descriptor.isWithinRange(maxVertical, maxHorizontal); + } + + public int getMaxVolumeForRange(String range, List activeTypes, DemonWillHolder holder) + { + return volumeRangeMap.get(range); + } + + public int getMaxVerticalRadiusForRange(String range, List activeTypes, DemonWillHolder holder) + { + return verticalRangeMap.get(range); + } + + public int getMaxHorizontalRadiusForRange(String range, List activeTypes, DemonWillHolder holder) + { + return horizontalRangeMap.get(range); + } + + public ITextComponent getErrorForBlockRangeOnFail(PlayerEntity player, String range, IMasterRitualStone master, BlockPos offset1, BlockPos offset2) + { + AreaDescriptor descriptor = this.getBlockRange(range); + if (descriptor == null) + { + return new TranslationTextComponent("ritual.bloodmagic.blockRange.tooBig", "?"); + } + + List willConfig = master.getActiveWillConfig(); + DemonWillHolder holder = WorldDemonWillHandler.getWillHolder(master.getWorldObj(), master.getBlockPos()); + + int maxVolume = this.getMaxVolumeForRange(range, willConfig, holder); + int maxVertical = this.getMaxVerticalRadiusForRange(range, willConfig, holder); + int maxHorizontal = this.getMaxHorizontalRadiusForRange(range, willConfig, holder); + + if (maxVolume > 0 && descriptor.getVolumeForOffsets(offset1, offset2) > maxVolume) + { + return new TranslationTextComponent("ritual.bloodmagic.blockRange.tooBig", maxVolume); + } else + { + return new TranslationTextComponent("ritual.bloodmagic.blockRange.tooFar", maxVertical, maxHorizontal); + } + } + + public ITextComponent[] provideInformationOfRitualToPlayer(PlayerEntity player) + { + return new ITextComponent[] + { new TranslationTextComponent(this.getTranslationKey() + ".info") }; + } + + public ITextComponent provideInformationOfRangeToPlayer(PlayerEntity player, String range) + { + if (getListOfRanges().contains(range)) + { + return new TranslationTextComponent(this.getTranslationKey() + "." + range + ".info"); + } else + { + return new TranslationTextComponent("ritual.bloodmagic.blockRange.noRange"); + } + } + + public abstract void gatherComponents(Consumer components); + + protected final void addRune(Consumer components, int offset1, int y, int offset2, EnumRuneType rune) + { + components.accept(new RitualComponent(new BlockPos(offset1, y, offset2), rune)); + } + + protected final void addOffsetRunes(Consumer components, int offset1, int offset2, int y, EnumRuneType rune) + { + addRune(components, offset1, y, offset2, rune); + addRune(components, offset2, y, offset1, rune); + addRune(components, offset1, y, -offset2, rune); + addRune(components, -offset2, y, offset1, rune); + addRune(components, -offset1, y, offset2, rune); + addRune(components, offset2, y, -offset1, rune); + addRune(components, -offset1, y, -offset2, rune); + addRune(components, -offset2, y, -offset1, rune); + } + + protected final void addCornerRunes(Consumer components, int offset, int y, EnumRuneType rune) + { + addRune(components, offset, y, offset, rune); + addRune(components, offset, y, -offset, rune); + addRune(components, -offset, y, -offset, rune); + addRune(components, -offset, y, offset, rune); + } + + protected final void addParallelRunes(Consumer components, int offset, int y, EnumRuneType rune) + { + addRune(components, offset, y, 0, rune); + addRune(components, -offset, y, 0, rune); + addRune(components, 0, y, -offset, rune); + addRune(components, 0, y, offset, rune); + } + + public double getWillRespectingConfig(World world, BlockPos pos, EnumDemonWillType type, List willConfig) + { + return willConfig.contains(type) ? WorldDemonWillHandler.getCurrentWill(world, pos, type) : 0; + } + + public abstract Ritual getNewCopy(); + + public String getName() + { + return name; + } + + public int getCrystalLevel() + { + return crystalLevel; + } + + public int getActivationCost() + { + return activationCost; + } + + public RitualRenderer getRenderer() + { + return renderer; + } + + public String getTranslationKey() + { + return unlocalizedName; + } + + public Map getModableRangeMap() + { + return modableRangeMap; + } + + public Map getVolumeRangeMap() + { + return volumeRangeMap; + } + + public Map getHorizontalRangeMap() + { + return horizontalRangeMap; + } + + public Map getVerticalRangeMap() + { + return verticalRangeMap; + } + + @Override + public String toString() + { + return new ToStringBuilder(this).append("name", name).append("crystalLevel", crystalLevel).append("activationCost", activationCost).append("renderer", renderer).append("unlocalizedName", unlocalizedName).append("modableRangeMap", modableRangeMap).append("volumeRangeMap", volumeRangeMap).append("horizontalRangeMap", horizontalRangeMap).append("verticalRangeMap", verticalRangeMap).append("refreshTime", getRefreshTime()).append("listOfRanges", getListOfRanges()).toString(); + } + + @Override + public boolean equals(Object o) + { + if (this == o) + return true; + if (!(o instanceof Ritual)) + return false; + + Ritual ritual = (Ritual) o; + + if (crystalLevel != ritual.crystalLevel) + return false; + if (activationCost != ritual.activationCost) + return false; + if (name != null ? !name.equals(ritual.name) : ritual.name != null) + return false; + return unlocalizedName != null ? unlocalizedName.equals(ritual.unlocalizedName) + : ritual.unlocalizedName == null; + } + + @Override + public int hashCode() + { + int result = name != null ? name.hashCode() : 0; + result = 31 * result + crystalLevel; + result = 31 * result + activationCost; + result = 31 * result + (unlocalizedName != null ? unlocalizedName.hashCode() : 0); + return result; + } + + public enum BreakType + { + REDSTONE, BREAK_MRS, BREAK_STONE, ACTIVATE, DEACTIVATE, EXPLOSION, + } +} \ No newline at end of file diff --git a/src/main/java/wayoftime/bloodmagic/ritual/RitualComponent.java b/src/main/java/wayoftime/bloodmagic/ritual/RitualComponent.java new file mode 100644 index 00000000..0f34813f --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/ritual/RitualComponent.java @@ -0,0 +1,70 @@ +package wayoftime.bloodmagic.ritual; + +import net.minecraft.util.Direction; +import net.minecraft.util.math.BlockPos; + +/** + * Used to set a {@link EnumRuneType} type to a given {@link BlockPos} for usage + * in Ritual creation. + */ +public class RitualComponent +{ + private final BlockPos offset; + private final EnumRuneType runeType; + + public RitualComponent(BlockPos offset, EnumRuneType runeType) + { + this.offset = offset; + this.runeType = runeType; + } + + public int getX(Direction direction) + { + switch (direction) + { + case EAST: + return -this.getOffset().getZ(); + case SOUTH: + return -this.getOffset().getX(); + case WEST: + return this.getOffset().getZ(); + default: + return this.getOffset().getX(); + } + } + + public int getY() + { + return this.getOffset().getY(); + } + + public int getZ(Direction direction) + { + switch (direction) + { + case EAST: + return this.getOffset().getX(); + case SOUTH: + return -this.getOffset().getZ(); + case WEST: + return -this.getOffset().getX(); + default: + return this.getOffset().getZ(); + } + } + + public BlockPos getOffset(Direction direction) + { + return new BlockPos(getX(direction), offset.getY(), getZ(direction)); + } + + public BlockPos getOffset() + { + return offset; + } + + public EnumRuneType getRuneType() + { + return runeType; + } +} \ No newline at end of file diff --git a/src/main/java/wayoftime/bloodmagic/ritual/RitualManager.java b/src/main/java/wayoftime/bloodmagic/ritual/RitualManager.java new file mode 100644 index 00000000..92b29583 --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/ritual/RitualManager.java @@ -0,0 +1,177 @@ +package wayoftime.bloodmagic.ritual; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; + +import net.minecraft.block.BlockState; +import net.minecraft.util.DamageSource; +import net.minecraftforge.fml.ModList; +import wayoftime.bloodmagic.ritual.imperfect.ImperfectRitual; +import wayoftime.bloodmagic.util.BMLog; + +public class RitualManager +{ + public static final DamageSource RITUAL_DAMAGE = new DamageSource("ritual_damage").setDamageBypassesArmor(); + + private final Map rituals; + private final Map ritualsReverse; + private final List sortedRituals; + private final Map imperfectRituals; + private final Map imperfectRitualsReverse; +// private final Configuration config; + + public RitualManager() + { + this.rituals = Maps.newTreeMap(); + this.ritualsReverse = Maps.newHashMap(); + this.sortedRituals = Lists.newArrayList(); + this.imperfectRituals = Maps.newTreeMap(); + this.imperfectRitualsReverse = Maps.newHashMap(); +// this.config = config; + } + +// public void discover(ASMDataTable dataTable) + public void discover() + { + ModList.get().getAllScanData().forEach(scan -> { + scan.getAnnotations().forEach(a -> { + if (a.getAnnotationType().getClassName().equals(RitualRegister.class.getName())) + { + try + { + + Class clazz = Class.forName(a.getClassType().getClassName()); + RitualRegister ritualRegister = clazz.getAnnotation(RitualRegister.class); + String id = ritualRegister.value(); + if (Ritual.class.isAssignableFrom(clazz)) + { + Ritual ritual = (Ritual) clazz.newInstance(); + rituals.put(id, ritual); + ritualsReverse.put(ritual, id); + BMLog.DEBUG.info("Registered ritual {}", id); + } else + { + BMLog.DEFAULT.error("Error creating ritual instance for {}.", id); + } + } catch (Exception e) + { + e.printStackTrace(); + } + } + }); + }); + + ModList.get().getAllScanData().forEach(scan -> { + scan.getAnnotations().forEach(a -> { + if (a.getAnnotationType().getClassName().equals(RitualRegister.Imperfect.class.getName())) + { + try + { + + Class clazz = Class.forName(a.getClassType().getClassName()); + RitualRegister.Imperfect ritualRegister = clazz.getAnnotation(RitualRegister.Imperfect.class); + String id = ritualRegister.value(); + if (ImperfectRitual.class.isAssignableFrom(clazz)) + { + ImperfectRitual ritual = (ImperfectRitual) clazz.newInstance(); + imperfectRituals.put(id, ritual); + imperfectRitualsReverse.put(ritual, id); + BMLog.DEBUG.info("Registered imperfect ritual {}", id); + } else + { + BMLog.DEFAULT.error("Error creating imperfect ritual instance for {}.", id); + } + } catch (Exception e) + { + e.printStackTrace(); + } + } + }); + }); + +// syncConfig(); + + // Sort rituals + sortedRituals.addAll(rituals.values()); + // Oh dear this is probably so slow + sortedRituals.sort((o1, o2) -> { + Set components = Sets.newHashSet(); + o1.gatherComponents(components::add); + int initialSize = components.size(); + components.clear(); + o2.gatherComponents(components::add); + return Integer.compare(initialSize, components.size()); + }); + } + + public Ritual getRitual(String id) + { + return rituals.get(id); + } + + public String getId(Ritual ritual) + { + return ritualsReverse.get(ritual); + } + + public ImperfectRitual getImperfectRitual(BlockState state) + { + for (ImperfectRitual ritual : imperfectRituals.values()) if (ritual.getBlockRequirement().test(state)) + return ritual; + + return null; + } + + public String getId(ImperfectRitual ritual) + { + return imperfectRitualsReverse.get(ritual); + } + + public Collection getRituals() + { + return rituals.values(); + } + + public Collection getImperfectRituals() + { + return imperfectRituals.values(); + } + + public List getSortedRituals() + { + return sortedRituals; + } + +// public void syncConfig() +// { +// config.addCustomCategoryComment("rituals", "Toggles for all rituals"); +// rituals.forEach((k, v) -> config.getBoolean(k, "rituals", true, "Enable the " + k + " ritual.")); +// imperfectRituals.forEach((k, v) -> config.getBoolean(k, "rituals.imperfect", true, "Enable the " + k + " imperfect ritual.")); +// config.save(); +// } +// + public boolean enabled(String id, boolean imperfect) + { + return id != null; +// return id != null && config.getBoolean(id, "rituals" + (imperfect ? ".imperfect" : ""), true, ""); + } +// +// public Configuration getConfig() +// { +// return config; +// } + + public static class BadRitualException extends RuntimeException + { + public BadRitualException(String message) + { + super(message); + } + } +} \ No newline at end of file diff --git a/src/main/java/wayoftime/bloodmagic/ritual/RitualRegister.java b/src/main/java/wayoftime/bloodmagic/ritual/RitualRegister.java new file mode 100644 index 00000000..56527fa6 --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/ritual/RitualRegister.java @@ -0,0 +1,58 @@ +package wayoftime.bloodmagic.ritual; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.util.function.Function; + +import wayoftime.bloodmagic.ritual.imperfect.ImperfectRitual; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface RitualRegister +{ + String value(); + + Class, Ritual>> factory() default DefaultRitualFactory.class; + + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.TYPE) + @interface Imperfect + { + + String value(); + + Class, ImperfectRitual>> factory() default DefaultImperfectRitualFactory.class; + } + + class DefaultRitualFactory implements Function, Ritual> + { + @Override + public Ritual apply(Class aClass) + { + try + { + return aClass.newInstance(); + } catch (Exception e) + { + return null; + } + } + } + + class DefaultImperfectRitualFactory implements Function, ImperfectRitual> + { + @Override + public ImperfectRitual apply(Class aClass) + { + try + { + return aClass.newInstance(); + } catch (Exception e) + { + return null; + } + } + } +} diff --git a/src/main/java/wayoftime/bloodmagic/ritual/RitualRenderer.java b/src/main/java/wayoftime/bloodmagic/ritual/RitualRenderer.java new file mode 100644 index 00000000..a2172c45 --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/ritual/RitualRenderer.java @@ -0,0 +1,14 @@ +package wayoftime.bloodmagic.ritual; + +import net.minecraft.client.Minecraft; +import net.minecraft.util.ResourceLocation; + +public abstract class RitualRenderer +{ + public abstract void renderAt(IMasterRitualStone masterRitualStone, double x, double y, double z); + + protected void bindTexture(ResourceLocation resourceLocation) + { + Minecraft.getInstance().getTextureManager().bindTexture(resourceLocation); + } +} diff --git a/src/main/java/wayoftime/bloodmagic/ritual/imperfect/IImperfectRitualStone.java b/src/main/java/wayoftime/bloodmagic/ritual/imperfect/IImperfectRitualStone.java new file mode 100644 index 00000000..856f5c60 --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/ritual/imperfect/IImperfectRitualStone.java @@ -0,0 +1,20 @@ +package wayoftime.bloodmagic.ritual.imperfect; + +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +/** + * This interface is for internal implementation only. + *

+ * It is provided via the API for easy obtaining of basic data. + */ +public interface IImperfectRitualStone +{ + + boolean performRitual(World world, BlockPos pos, ImperfectRitual imperfectRitual, PlayerEntity player); + + World getRitualWorld(); + + BlockPos getRitualPos(); +} diff --git a/src/main/java/wayoftime/bloodmagic/ritual/imperfect/ImperfectRitual.java b/src/main/java/wayoftime/bloodmagic/ritual/imperfect/ImperfectRitual.java new file mode 100644 index 00000000..6fe28e1f --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/ritual/imperfect/ImperfectRitual.java @@ -0,0 +1,108 @@ +package wayoftime.bloodmagic.ritual.imperfect; + +import java.util.function.Predicate; + +import net.minecraft.block.BlockState; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.world.World; + +/** + * Abstract class for creating new imperfect rituals. To register, annotate your + * class with {@link WayofTime.bloodmagic.ritual.RitualRegister.Imperfect} + */ +public abstract class ImperfectRitual +{ + + private final String name; + private final Predicate blockRequirement; + private final int activationCost; + private final boolean lightShow; + private final String unlocalizedName; + + public ImperfectRitual(String name, Predicate blockRequirement, int activationCost, boolean lightShow, String unlocalizedName) + { + this.name = name; + this.blockRequirement = blockRequirement; + this.activationCost = activationCost; + this.lightShow = lightShow; + this.unlocalizedName = unlocalizedName; + } + + /** + * @param name The name of the ritual + * @param blockRequirement The block required above the ImperfectRitualStone + * @param activationCost Base LP cost for activating the ritual + */ + public ImperfectRitual(String name, Predicate blockRequirement, int activationCost, String unlocalizedName) + { + this(name, blockRequirement, activationCost, false, unlocalizedName); + } + + /** + * Called when the player activates the ritual + * {@link WayofTime.bloodmagic.tile.TileImperfectRitualStone#performRitual(World, net.minecraft.util.math.BlockPos, ImperfectRitual, PlayerEntity)} + * + * @param imperfectRitualStone - The {@link IImperfectRitualStone} that the + * ritual is bound to + * @param player - The player activating the ritual + * @return - Whether activation was successful + */ + public abstract boolean onActivate(IImperfectRitualStone imperfectRitualStone, PlayerEntity player); + + public String getName() + { + return name; + } + + public Predicate getBlockRequirement() + { + return blockRequirement; + } + + public int getActivationCost() + { + return activationCost; + } + + public boolean isLightShow() + { + return lightShow; + } + + public String getTranslationKey() + { + return unlocalizedName; + } + + @Override + public String toString() + { + return getName() + "@" + getActivationCost(); + } + + @Override + public boolean equals(Object o) + { + if (this == o) + return true; + if (!(o instanceof ImperfectRitual)) + return false; + + ImperfectRitual that = (ImperfectRitual) o; + + if (activationCost != that.activationCost) + return false; + if (name != null ? !name.equals(that.name) : that.name != null) + return false; + return unlocalizedName != null ? unlocalizedName.equals(that.unlocalizedName) : that.unlocalizedName == null; + } + + @Override + public int hashCode() + { + int result = name != null ? name.hashCode() : 0; + result = 31 * result + activationCost; + result = 31 * result + (unlocalizedName != null ? unlocalizedName.hashCode() : 0); + return result; + } +} \ No newline at end of file diff --git a/src/main/java/wayoftime/bloodmagic/ritual/types/RitualWater.java b/src/main/java/wayoftime/bloodmagic/ritual/types/RitualWater.java new file mode 100644 index 00000000..aa7d230f --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/ritual/types/RitualWater.java @@ -0,0 +1,85 @@ +package wayoftime.bloodmagic.ritual.types; + +import java.util.function.Consumer; + +import net.minecraft.block.Blocks; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import wayoftime.bloodmagic.BloodMagic; +import wayoftime.bloodmagic.ritual.AreaDescriptor; +import wayoftime.bloodmagic.ritual.EnumRuneType; +import wayoftime.bloodmagic.ritual.IMasterRitualStone; +import wayoftime.bloodmagic.ritual.Ritual; +import wayoftime.bloodmagic.ritual.RitualComponent; +import wayoftime.bloodmagic.ritual.RitualRegister; + +@RitualRegister("water") +public class RitualWater extends Ritual +{ + public static final String WATER_RANGE = "waterRange"; + + public RitualWater() + { + super("ritualWater", 0, 500, "ritual." + BloodMagic.MODID + ".waterRitual"); + addBlockRange(WATER_RANGE, new AreaDescriptor.Rectangle(new BlockPos(0, 1, 0), 1)); + setMaximumVolumeAndDistanceOfRange(WATER_RANGE, 9, 3, 3); + } + + @Override + public void performRitual(IMasterRitualStone masterRitualStone) + { + World world = masterRitualStone.getWorldObj(); + int currentEssence = masterRitualStone.getOwnerNetwork().getCurrentEssence(); + + if (currentEssence < getRefreshCost()) + { + masterRitualStone.getOwnerNetwork().causeNausea(); + return; + } + + int maxEffects = currentEssence / getRefreshCost(); + int totalEffects = 0; + + AreaDescriptor waterRange = masterRitualStone.getBlockRange(WATER_RANGE); + + for (BlockPos newPos : waterRange.getContainedPositions(masterRitualStone.getBlockPos())) + { + if (world.isAirBlock(newPos)) + { + world.setBlockState(newPos, Blocks.WATER.getDefaultState()); + totalEffects++; + } + + if (totalEffects >= maxEffects) + { + break; + } + } + + masterRitualStone.getOwnerNetwork().syphon(masterRitualStone.ticket(getRefreshCost() * totalEffects)); + } + + @Override + public int getRefreshTime() + { + return 1; + } + + @Override + public int getRefreshCost() + { + return 25; + } + + @Override + public void gatherComponents(Consumer components) + { + addCornerRunes(components, 1, 0, EnumRuneType.WATER); + } + + @Override + public Ritual getNewCopy() + { + return new RitualWater(); + } +} diff --git a/src/main/java/wayoftime/bloodmagic/tile/TileMasterRitualStone.java b/src/main/java/wayoftime/bloodmagic/tile/TileMasterRitualStone.java new file mode 100644 index 00000000..5e6083b7 --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/tile/TileMasterRitualStone.java @@ -0,0 +1,566 @@ +package wayoftime.bloodmagic.tile; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import javax.annotation.Nullable; + +import com.google.common.base.Strings; + +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.tileentity.TileEntityType; +import net.minecraft.util.Direction; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.text.TranslationTextComponent; +import net.minecraft.world.World; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.registries.ObjectHolder; +import wayoftime.bloodmagic.BloodMagic; +import wayoftime.bloodmagic.common.item.ItemActivationCrystal; +import wayoftime.bloodmagic.core.data.Binding; +import wayoftime.bloodmagic.core.data.SoulNetwork; +import wayoftime.bloodmagic.demonaura.WorldDemonWillHandler; +import wayoftime.bloodmagic.event.RitualEvent; +import wayoftime.bloodmagic.iface.IBindable; +import wayoftime.bloodmagic.ritual.AreaDescriptor; +import wayoftime.bloodmagic.ritual.EnumReaderBoundaries; +import wayoftime.bloodmagic.ritual.IMasterRitualStone; +import wayoftime.bloodmagic.ritual.Ritual; +import wayoftime.bloodmagic.tile.base.TileTicking; +import wayoftime.bloodmagic.util.ChatUtil; +import wayoftime.bloodmagic.util.Constants; +import wayoftime.bloodmagic.util.helper.BindableHelper; +import wayoftime.bloodmagic.util.helper.NBTHelper; +import wayoftime.bloodmagic.util.helper.NetworkHelper; +import wayoftime.bloodmagic.util.helper.PlayerHelper; +import wayoftime.bloodmagic.util.helper.RitualHelper; +import wayoftime.bloodmagic.will.DemonWillHolder; +import wayoftime.bloodmagic.will.EnumDemonWillType; + +public class TileMasterRitualStone extends TileTicking implements IMasterRitualStone +{ + @ObjectHolder("bloodmagic:masterritualstone") + public static TileEntityType TYPE; + protected final Map modableRangeMap = new HashMap<>(); + private UUID owner; + private SoulNetwork cachedNetwork; + private boolean active; + private boolean redstoned; + private int activeTime; + private int cooldown; + private Ritual currentRitual; + private Direction direction = Direction.NORTH; + private boolean inverted; + private List currentActiveWillConfig = new ArrayList<>(); + + public TileMasterRitualStone(TileEntityType type) + { + super(type); + } + + public TileMasterRitualStone() + { + this(TYPE); + } + + @Override + public void onUpdate() + { + if (getWorld().isRemote) + return; + + if (isPowered() && isActive()) + { + active = false; + redstoned = true; + stopRitual(Ritual.BreakType.REDSTONE); + return; + } + + if (!isActive() && !isPowered() && isRedstoned() && getCurrentRitual() != null) + { + active = true; + ItemStack crystalStack = NBTHelper.checkNBT(ItemActivationCrystal.CrystalType.getStack(getCurrentRitual().getCrystalLevel())); + BindableHelper.applyBinding(crystalStack, new Binding(owner, PlayerHelper.getUsernameFromUUID(owner))); + activateRitual(crystalStack, null, getCurrentRitual()); + redstoned = false; + } + + if (getCurrentRitual() != null && isActive()) + { + if (activeTime % getCurrentRitual().getRefreshTime() == 0) + performRitual(getWorld(), getPos()); + + activeTime++; + } + } + + @Override + public void deserialize(CompoundNBT tag) + { + owner = tag.hasUniqueId("owner") ? tag.getUniqueId("owner") : null; + if (owner != null) + cachedNetwork = NetworkHelper.getSoulNetwork(owner); + currentRitual = BloodMagic.RITUAL_MANAGER.getRitual(tag.getString(Constants.NBT.CURRENT_RITUAL)); + if (currentRitual != null) + { + CompoundNBT ritualTag = tag.getCompound(Constants.NBT.CURRENT_RITUAL_TAG); + if (!ritualTag.isEmpty()) + { + currentRitual.readFromNBT(ritualTag); + } + } + active = tag.getBoolean(Constants.NBT.IS_RUNNING); + activeTime = tag.getInt(Constants.NBT.RUNTIME); + direction = Direction.values()[tag.getInt(Constants.NBT.DIRECTION)]; + redstoned = tag.getBoolean(Constants.NBT.IS_REDSTONED); + + for (EnumDemonWillType type : EnumDemonWillType.values()) + { + if (tag.getBoolean("EnumWill" + type)) + { + currentActiveWillConfig.add(type); + } + } + } + + @Override + public CompoundNBT serialize(CompoundNBT tag) + { + String ritualId = BloodMagic.RITUAL_MANAGER.getId(getCurrentRitual()); + if (owner != null) + tag.putUniqueId("owner", owner); + tag.putString(Constants.NBT.CURRENT_RITUAL, Strings.isNullOrEmpty(ritualId) ? "" : ritualId); + if (currentRitual != null) + { + CompoundNBT ritualTag = new CompoundNBT(); + currentRitual.writeToNBT(ritualTag); + tag.put(Constants.NBT.CURRENT_RITUAL_TAG, ritualTag); + } + tag.putBoolean(Constants.NBT.IS_RUNNING, isActive()); + tag.putInt(Constants.NBT.RUNTIME, getActiveTime()); + tag.putInt(Constants.NBT.DIRECTION, direction.getIndex()); + tag.putBoolean(Constants.NBT.IS_REDSTONED, redstoned); + + for (EnumDemonWillType type : currentActiveWillConfig) + { + tag.putBoolean("EnumWill" + type, true); + } + + return tag; + } + + @Override + public boolean activateRitual(ItemStack activationCrystal, @Nullable PlayerEntity activator, Ritual ritual) + { + if (PlayerHelper.isFakePlayer(activator)) + return false; + + Binding binding = ((IBindable) activationCrystal.getItem()).getBinding(activationCrystal); + if (binding != null && ritual != null) + { + if (activationCrystal.getItem() instanceof ItemActivationCrystal) + { + int crystalLevel = ((ItemActivationCrystal) activationCrystal.getItem()).getCrystalLevel(activationCrystal); + if (RitualHelper.canCrystalActivate(ritual, crystalLevel)) + { + if (!getWorld().isRemote) + { + SoulNetwork network = NetworkHelper.getSoulNetwork(binding); + + if (!isRedstoned() && network.getCurrentEssence() < ritual.getActivationCost() + && (activator != null && !activator.isCreative())) + { + activator.sendStatusMessage(new TranslationTextComponent("chat.bloodmagic.ritual.weak"), true); + return false; + } + + if (currentRitual != null) + currentRitual.stopRitual(this, Ritual.BreakType.ACTIVATE); + + RitualEvent.RitualActivatedEvent event = new RitualEvent.RitualActivatedEvent(this, binding.getOwnerId(), ritual, activator, activationCrystal, crystalLevel); + + if (MinecraftForge.EVENT_BUS.post(event)) + { + if (activator != null) + activator.sendStatusMessage(new TranslationTextComponent("chat.bloodmagic.ritual.prevent"), true); + return false; + } + + if (ritual.activateRitual(this, activator, binding.getOwnerId())) + { + if (!isRedstoned() && (activator != null && !activator.isCreative())) + network.syphon(ticket(ritual.getActivationCost())); + + if (activator != null) + activator.sendStatusMessage(new TranslationTextComponent("chat.bloodmagic.ritual.activate"), true); + + this.active = true; + this.owner = binding.getOwnerId(); + this.cachedNetwork = network; + this.currentRitual = ritual; + + if (!checkBlockRanges(ritual.getModableRangeMap())) + addBlockRanges(ritual.getModableRangeMap()); + + notifyUpdate(); + return true; + } + } + + notifyUpdate(); + return true; + } + } + } else + { + if (activator != null) + activator.sendStatusMessage(new TranslationTextComponent("chat.bloodmagic.ritual.notValid"), true); + } + + return false; + } + + @Override + public void performRitual(World world, BlockPos pos) + { + if (!world.isRemote && getCurrentRitual() != null + && BloodMagic.RITUAL_MANAGER.enabled(BloodMagic.RITUAL_MANAGER.getId(currentRitual), false)) + { + if (RitualHelper.checkValidRitual(getWorld(), getPos(), currentRitual, getDirection())) + { + Ritual ritual = getCurrentRitual(); + RitualEvent.RitualRunEvent event = new RitualEvent.RitualRunEvent(this, getOwner(), ritual); + + if (MinecraftForge.EVENT_BUS.post(event)) + return; + + if (!checkBlockRanges(getCurrentRitual().getModableRangeMap())) + addBlockRanges(getCurrentRitual().getModableRangeMap()); + + getCurrentRitual().performRitual(this); + } else + { + stopRitual(Ritual.BreakType.BREAK_STONE); + } + } + } + + @Override + public void stopRitual(Ritual.BreakType breakType) + { + if (!getWorld().isRemote && getCurrentRitual() != null) + { + RitualEvent.RitualStopEvent event = new RitualEvent.RitualStopEvent(this, getOwner(), getCurrentRitual(), breakType); + + if (MinecraftForge.EVENT_BUS.post(event)) + return; + + getCurrentRitual().stopRitual(this, breakType); + if (breakType != Ritual.BreakType.REDSTONE) + { + this.currentRitual = null; + this.active = false; + this.activeTime = 0; + } + notifyUpdate(); + } + } + + @Override + public int getCooldown() + { + return cooldown; + } + + @Override + public void setCooldown(int cooldown) + { + this.cooldown = cooldown; + } + + @Override + public Direction getDirection() + { + return direction; + } + + public void setDirection(Direction direction) + { + this.direction = direction; + } + + @Override + public boolean areTanksEmpty() + { + return false; + } + + @Override + public int getRunningTime() + { + return activeTime; + } + + @Override + public UUID getOwner() + { + return owner; + } + + public void setOwner(UUID owner) + { + this.owner = owner; + } + + @Override + public SoulNetwork getOwnerNetwork() + { + return cachedNetwork; + } + + @Override + public World getWorld() + { + return super.getWorld(); + } + + @Override + public BlockPos getPos() + { + return super.getPos(); + } + + @Override + public World getWorldObj() + { + return getWorld(); + } + + @Override + public BlockPos getBlockPos() + { + return getPos(); + } + + @Override + public String getNextBlockRange(String range) + { + if (this.currentRitual != null) + { + return this.currentRitual.getNextBlockRange(range); + } + + return ""; + } + + @Override + public void provideInformationOfRitualToPlayer(PlayerEntity player) + { + if (this.currentRitual != null) + { + ChatUtil.sendNoSpam(player, this.currentRitual.provideInformationOfRitualToPlayer(player)); + } + } + + @Override + public void provideInformationOfRangeToPlayer(PlayerEntity player, String range) + { + if (this.currentRitual != null && this.currentRitual.getListOfRanges().contains(range)) + { + ChatUtil.sendNoSpam(player, this.currentRitual.provideInformationOfRangeToPlayer(player, range)); + } + } + + @Override + public void setActiveWillConfig(PlayerEntity player, List typeList) + { + this.currentActiveWillConfig = typeList; + } + + @Override + public EnumReaderBoundaries setBlockRangeByBounds(PlayerEntity player, String range, BlockPos offset1, BlockPos offset2) + { + AreaDescriptor descriptor = this.getBlockRange(range); + DemonWillHolder holder = WorldDemonWillHandler.getWillHolder(world, getBlockPos()); + + EnumReaderBoundaries modificationType = currentRitual.canBlockRangeBeModified(range, descriptor, this, offset1, offset2, holder); + if (modificationType == EnumReaderBoundaries.SUCCESS) + descriptor.modifyAreaByBlockPositions(offset1, offset2); + + return modificationType; + } + + @Override + public List getActiveWillConfig() + { + return new ArrayList<>(currentActiveWillConfig); + } + + @Override + public void provideInformationOfWillConfigToPlayer(PlayerEntity player, List typeList) + { + // There is probably an easier way to make expanded chat messages + if (typeList.size() >= 1) + { + Object[] translations = new TranslationTextComponent[typeList.size()]; + StringBuilder constructedString = new StringBuilder("%s"); + + for (int i = 1; i < typeList.size(); i++) + { + constructedString.append(", %s"); + } + + for (int i = 0; i < typeList.size(); i++) + { + translations[i] = new TranslationTextComponent("tooltip.bloodmagic.currentBaseType." + typeList.get(i).name.toLowerCase()); + } + + ChatUtil.sendNoSpam(player, new TranslationTextComponent("ritual.bloodmagic.willConfig.set", new TranslationTextComponent(constructedString.toString(), translations))); + } else + { + ChatUtil.sendNoSpam(player, new TranslationTextComponent("ritual.bloodmagic.willConfig.void")); + } + } + + public boolean isPowered() + { + if (inverted) + return !getWorld().isBlockPowered(getPos()); + + return getWorld().isBlockPowered(getPos()); + } + + public SoulNetwork getCachedNetwork() + { + return cachedNetwork; + } + + public void setCachedNetwork(SoulNetwork cachedNetwork) + { + this.cachedNetwork = cachedNetwork; + } + + public boolean isActive() + { + return active; + } + + @Override + public void setActive(boolean active) + { + this.active = active; + } + + public boolean isRedstoned() + { + return redstoned; + } + + public void setRedstoned(boolean redstoned) + { + this.redstoned = redstoned; + } + + public int getActiveTime() + { + return activeTime; + } + + public void setActiveTime(int activeTime) + { + this.activeTime = activeTime; + } + + public Ritual getCurrentRitual() + { + return currentRitual; + } + + public void setCurrentRitual(Ritual currentRitual) + { + this.currentRitual = currentRitual; + } + + public boolean isInverted() + { + return inverted; + } + + public void setInverted(boolean inverted) + { + this.inverted = inverted; + } + + public List getCurrentActiveWillConfig() + { + return currentActiveWillConfig; + } + + public void setCurrentActiveWillConfig(List currentActiveWillConfig) + { + this.currentActiveWillConfig = currentActiveWillConfig; + } + + /** + * Used to grab the range of a ritual for a given effect. + * + * @param range - Range that needs to be pulled. + * @return - + */ + public AreaDescriptor getBlockRange(String range) + { + if (modableRangeMap.containsKey(range)) + { + return modableRangeMap.get(range); + } + + return null; + } + + @Override + public void addBlockRange(String range, AreaDescriptor defaultRange) + { + modableRangeMap.putIfAbsent(range, defaultRange.copy()); + } + + @Override + public void addBlockRanges(Map blockRanges) + { + for (Map.Entry entry : blockRanges.entrySet()) + { + modableRangeMap.putIfAbsent(entry.getKey(), entry.getValue().copy()); + } + } + + @Override + public void setBlockRange(String range, AreaDescriptor defaultRange) + { + modableRangeMap.put(range, defaultRange.copy()); + } + + @Override + public void setBlockRanges(Map blockRanges) + { + for (Map.Entry entry : blockRanges.entrySet()) + { + modableRangeMap.put(entry.getKey(), entry.getValue().copy()); + } + } + + public boolean checkBlockRanges(Map blockRanges) + { + for (Map.Entry entry : blockRanges.entrySet()) + { + if (modableRangeMap.get(entry.getKey()) == null) + return false; + } + return true; + } + +} diff --git a/src/main/java/wayoftime/bloodmagic/tile/base/TileTicking.java b/src/main/java/wayoftime/bloodmagic/tile/base/TileTicking.java new file mode 100644 index 00000000..545dec20 --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/tile/base/TileTicking.java @@ -0,0 +1,71 @@ +package wayoftime.bloodmagic.tile.base; + +import net.minecraft.client.renderer.texture.ITickable; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.tileentity.TileEntityType; + +/** + * Base class for tiles that tick. Allows disabling the ticking + * programmatically. + */ +// TODO - Move implementations that depend on existed ticks to new methods from here. +public abstract class TileTicking extends TileBase implements ITickable +{ + private int ticksExisted; + private boolean shouldTick = true; + + public TileTicking(TileEntityType type) + { + super(type); + } + + @Override + public final void tick() + { + if (shouldTick()) + { + ticksExisted++; + onUpdate(); + } + } + + @Override + void deserializeBase(CompoundNBT tagCompound) + { + this.ticksExisted = tagCompound.getInt("ticksExisted"); + this.shouldTick = tagCompound.getBoolean("shouldTick"); + } + + @Override + CompoundNBT serializeBase(CompoundNBT tagCompound) + { + tagCompound.putInt("ticksExisted", getTicksExisted()); + tagCompound.putBoolean("shouldTick", shouldTick()); + return tagCompound; + } + + /** + * Called every tick that {@link #shouldTick()} is true. + */ + public abstract void onUpdate(); + + public int getTicksExisted() + { + return ticksExisted; + } + + public void resetLifetime() + { + ticksExisted = 0; + } + + public boolean shouldTick() + { + return shouldTick; + } + + public void setShouldTick(boolean shouldTick) + { + this.shouldTick = shouldTick; + } +} \ No newline at end of file diff --git a/src/main/java/wayoftime/bloodmagic/util/helper/RitualHelper.java b/src/main/java/wayoftime/bloodmagic/util/helper/RitualHelper.java new file mode 100644 index 00000000..3862d73a --- /dev/null +++ b/src/main/java/wayoftime/bloodmagic/util/helper/RitualHelper.java @@ -0,0 +1,253 @@ +package wayoftime.bloodmagic.util.helper; + +import java.util.List; + +import org.apache.commons.lang3.tuple.Pair; + +import com.google.common.collect.Lists; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.Direction; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraftforge.common.capabilities.Capability; +import net.minecraftforge.common.capabilities.CapabilityInject; +import net.minecraftforge.common.util.LazyOptional; +import wayoftime.bloodmagic.BloodMagic; +import wayoftime.bloodmagic.common.block.BlockRitualStone; +import wayoftime.bloodmagic.common.block.BloodMagicBlocks; +import wayoftime.bloodmagic.ritual.EnumRuneType; +import wayoftime.bloodmagic.ritual.IRitualStone; +import wayoftime.bloodmagic.ritual.IRitualStone.Tile; +import wayoftime.bloodmagic.ritual.Ritual; +import wayoftime.bloodmagic.ritual.RitualComponent; +import wayoftime.bloodmagic.tile.TileMasterRitualStone; + +public class RitualHelper +{ + @CapabilityInject(IRitualStone.Tile.class) + static Capability RUNE_CAPABILITY = null; + + public static boolean canCrystalActivate(Ritual ritual, int crystalLevel) + { + return ritual.getCrystalLevel() <= crystalLevel + && BloodMagic.RITUAL_MANAGER.enabled(BloodMagic.RITUAL_MANAGER.getId(ritual), false); + } + + /** + * Checks the RitualRegistry to see if the configuration of the ritual stones in + * the world is valid for the given Direction. + * + * @param world - The world + * @param pos - Location of the MasterRitualStone + * @return The ID of the valid ritual + */ + public static String getValidRitual(World world, BlockPos pos) + { + for (Ritual ritual : BloodMagic.RITUAL_MANAGER.getRituals()) + { + for (int i = 0; i < 4; i++) + { + Direction direction = Direction.byHorizontalIndex(i); + + if (checkValidRitual(world, pos, ritual, direction)) + return BloodMagic.RITUAL_MANAGER.getId(ritual); + } + } + + return ""; + } + + public static Direction getDirectionOfRitual(World world, BlockPos pos, Ritual ritual) + { + for (int i = 0; i < 4; i++) + { + Direction direction = Direction.byHorizontalIndex(i); + if (checkValidRitual(world, pos, ritual, direction)) + return direction; + } + + return null; + } + + public static boolean checkValidRitual(World world, BlockPos pos, Ritual ritual, Direction direction) + { + if (ritual == null) + { + return false; + } + + List components = Lists.newArrayList(); + ritual.gatherComponents(components::add); + + for (RitualComponent component : components) + { + BlockPos newPos = pos.add(component.getOffset(direction)); + if (!isRuneType(world, newPos, component.getRuneType())) + return false; + } + + return true; + } + + public static boolean isRuneType(World world, BlockPos pos, EnumRuneType type) + { + if (world == null) + return false; + Block block = world.getBlockState(pos).getBlock(); + TileEntity tile = world.getTileEntity(pos); + + if (block instanceof IRitualStone) + return ((IRitualStone) block).isRuneType(world, pos, type); + else if (tile instanceof IRitualStone.Tile) + return ((IRitualStone.Tile) tile).isRuneType(type); + else if (tile != null && tile.getCapability(RUNE_CAPABILITY, null).isPresent()) + return tile.getCapability(RUNE_CAPABILITY, null).resolve().get().isRuneType(type); + + return false; + } + + public static boolean isRune(World world, BlockPos pos) + { + if (world == null) + return false; + Block block = world.getBlockState(pos).getBlock(); + TileEntity tile = world.getTileEntity(pos); + + if (block instanceof IRitualStone) + return true; + else if (tile instanceof IRitualStone.Tile) + return true; + else + return tile != null && tile.getCapability(RUNE_CAPABILITY, null).isPresent(); + + } + + public static void setRuneType(World world, BlockPos pos, EnumRuneType type) + { + if (world == null) + return; + BlockState state = world.getBlockState(pos); + TileEntity tile = world.getTileEntity(pos); + + if (state.getBlock() instanceof IRitualStone) + ((IRitualStone) state.getBlock()).setRuneType(world, pos, type); + else if (tile instanceof IRitualStone.Tile) + ((IRitualStone.Tile) tile).setRuneType(type); + else + { + LazyOptional cap = tile.getCapability(RUNE_CAPABILITY, null); + if (cap.isPresent()) + { + cap.resolve().get().setRuneType(type); + world.notifyBlockUpdate(pos, state, state, 3); + } + + } + } + + public static boolean createRitual(World world, BlockPos pos, Direction direction, Ritual ritual, boolean safe) + { + + List components = Lists.newArrayList(); + ritual.gatherComponents(components::add); + + if (abortConstruction(world, pos, direction, safe, components)) + return false; + + BlockState mrs = BloodMagicBlocks.MASTER_RITUAL_STONE.get().getDefaultState(); + world.setBlockState(pos, mrs); + + setRitualStones(direction, world, pos, components); + return true; + } + + public static boolean abortConstruction(World world, BlockPos pos, Direction direction, boolean safe, List components) + { + // TODO: can be optimized to check only for the first and last component if + // every ritual has those at the highest and lowest y-level respectivly. + for (RitualComponent component : components) + { + BlockPos offset = component.getOffset(direction); + BlockPos newPos = pos.add(offset); + if (world.isOutsideBuildHeight(newPos) || (safe && !world.isAirBlock(newPos))) + return true; + } + return false; + } + + public static boolean repairRitualFromRuins(TileMasterRitualStone tile, boolean safe) + { + Ritual ritual = tile.getCurrentRitual(); + Direction direction; + Pair pair; + if (ritual == null) + { + pair = getRitualFromRuins(tile); + ritual = pair.getKey(); + direction = pair.getValue(); + } else + direction = tile.getDirection(); + + World world = tile.getWorld(); + BlockPos pos = tile.getPos(); + + List components = Lists.newArrayList(); + ritual.gatherComponents(components::add); + + if (abortConstruction(world, pos, direction, safe, components)) + return false; + + setRitualStones(direction, world, pos, components); + return true; + } + + public static void setRitualStones(Direction direction, World world, BlockPos pos, List gatheredComponents) + { + for (RitualComponent component : gatheredComponents) + { + BlockPos offset = component.getOffset(direction); + BlockPos newPos = pos.add(offset); + ((BlockRitualStone) BloodMagicBlocks.BLANK_RITUAL_STONE.get()).setRuneType(world, newPos, component.getRuneType()); + } + } + + public static Pair getRitualFromRuins(TileMasterRitualStone tile) + { + BlockPos pos = tile.getPos(); + World world = tile.getWorld(); + Ritual possibleRitual = tile.getCurrentRitual(); + Direction possibleDirection = tile.getDirection(); + int highestCount = 0; + + if (possibleRitual == null || possibleDirection == null) + for (Ritual ritual : BloodMagic.RITUAL_MANAGER.getRituals()) + { + for (int i = 0; i < 4; i++) + { + Direction direction = Direction.byHorizontalIndex(i); + List components = Lists.newArrayList(); + ritual.gatherComponents(components::add); + int currentCount = 0; + + for (RitualComponent component : components) + { + BlockPos newPos = pos.add(component.getOffset(direction)); + if (isRuneType(world, newPos, component.getRuneType())) + currentCount += 1; + } + if (currentCount > highestCount) + { + highestCount = currentCount; + possibleRitual = ritual; + possibleDirection = direction; + } + + } + + } + return Pair.of(possibleRitual, possibleDirection); + } +}