├── LICENSE ├── src └── main │ ├── resources │ ├── data │ │ ├── extraorigins │ │ │ ├── powers │ │ │ │ ├── radioactive.json │ │ │ │ ├── decomposition.json │ │ │ │ ├── jockey.json │ │ │ │ ├── small_appetite.json │ │ │ │ ├── piglin_neutrality.json │ │ │ │ ├── flabby.json │ │ │ │ ├── flammable.json │ │ │ │ ├── crossbow_master.json │ │ │ │ ├── soul_spooked.json │ │ │ │ ├── nectarivore.json │ │ │ │ ├── absorbing.json │ │ │ │ ├── green_thumb.json │ │ │ │ ├── golden_gluttony.json │ │ │ │ ├── nimble.json │ │ │ │ ├── infestation.json │ │ │ │ ├── mobility_spores.json │ │ │ │ ├── offense_spores.json │ │ │ │ ├── defense_spores.json │ │ │ │ ├── bite_sized.json │ │ │ │ ├── photosynthesis.json │ │ │ │ ├── magic_spores.json │ │ │ │ ├── rooted.json │ │ │ │ ├── homesick.json │ │ │ │ └── all_that_glitters.json │ │ │ ├── origins │ │ │ │ ├── nucleon.json │ │ │ │ ├── truffle.json │ │ │ │ ├── inchling.json │ │ │ │ ├── floran.json │ │ │ │ └── piglin.json │ │ │ └── tags │ │ │ │ └── items │ │ │ │ ├── golden_equipment.json │ │ │ │ ├── golden_food.json │ │ │ │ ├── golden_armor.json │ │ │ │ └── golden_tools.json │ │ └── origins │ │ │ └── origin_layers │ │ │ └── origin.json │ ├── assets │ │ └── extraorigins │ │ │ ├── particles │ │ │ ├── defense_spore.json │ │ │ ├── mobility_spore.json │ │ │ └── offense_spore.json │ │ │ ├── icon.png │ │ │ ├── textures │ │ │ ├── gui │ │ │ │ ├── icons.png │ │ │ │ ├── resource_bar.png │ │ │ │ └── sprites │ │ │ │ │ └── choose_origin │ │ │ │ │ └── impact │ │ │ │ │ └── very_high.png │ │ │ └── particle │ │ │ │ ├── defense_spore.png │ │ │ │ ├── mobility_spore.png │ │ │ │ └── offense_spore.png │ │ │ ├── sounds.json │ │ │ └── lang │ │ │ ├── zh_cn.json │ │ │ ├── es_es.json │ │ │ ├── pl_pl.json │ │ │ ├── ko_kr.json │ │ │ ├── ru_ru.json │ │ │ ├── pt_br.json │ │ │ ├── tr_tr.json │ │ │ └── en_us.json │ ├── extraorigins.mixins.json │ └── fabric.mod.json │ └── java │ └── moriyashiine │ └── extraorigins │ ├── common │ ├── util │ │ └── RadialMenuDirection.java │ ├── power │ │ ├── CanStandOnPowderSnowPower.java │ │ ├── PreventBlockSlownessPower.java │ │ ├── ModifyAirStrafingSpeedPower.java │ │ ├── DelayedHitboxPower.java │ │ ├── MobNeutralityPower.java │ │ ├── FoodEffectImmunityPower.java │ │ ├── InnateUnbreakingPower.java │ │ ├── RandomPowerGranterPower.java │ │ ├── MountPower.java │ │ ├── ModifySizePower.java │ │ ├── ModifyItemAttributePower.java │ │ └── RadialMenuPower.java │ ├── event │ │ ├── RandomPowerGranterEvent.java │ │ └── DismountEvent.java │ ├── init │ │ ├── ModSoundEvents.java │ │ ├── ModScaleTypes.java │ │ ├── ModParticleTypes.java │ │ ├── ModEntityComponents.java │ │ ├── ModActions.java │ │ ├── ModConditions.java │ │ └── ModPowers.java │ ├── ExtraOrigins.java │ ├── packet │ │ ├── MountC2SPacket.java │ │ └── ChangeRadialDirectionPacket.java │ └── component │ │ └── entity │ │ └── RandomPowerGranterComponent.java │ ├── mixin │ ├── mount │ │ └── client │ │ │ └── ProjectileUtilMixin.java │ ├── preventblockslowness │ │ └── EntityMixin.java │ ├── canstandonpowdersnow │ │ └── PowderSnowBlockMixin.java │ ├── modifyairstrafingspeed │ │ └── LivingEntityMixin.java │ ├── mobneutrality │ │ ├── HoglinBrainMixin.java │ │ ├── ZoglinEntityMixin.java │ │ ├── EndermanEntityMixin.java │ │ ├── PiglinBruteBrainMixin.java │ │ ├── PiglinSpecificSensorMixin.java │ │ ├── ActiveTargetGoalMixin.java │ │ ├── FleeEntityGoalMixin.java │ │ └── PiglinBrainMixin.java │ ├── delayedhitbox │ │ └── client │ │ │ └── MinecraftClientMixin.java │ ├── util │ │ └── impact4 │ │ │ └── ImpactMixin.java │ ├── innateunbreaking │ │ └── ItemStackMixin.java │ ├── foodeffectimmunity │ │ ├── LivingEntityMixin.java │ │ └── SuspiciousStewItemMixin.java │ ├── modifyitemattribute │ │ └── client │ │ │ └── ItemStackMixin.java │ └── randompowergranter │ │ └── client │ │ └── OriginDisplayScreenMixin.java │ └── client │ ├── event │ ├── DelayedHitboxEvent.java │ ├── RandomPowerGranterClientEvent.java │ └── RadialMenuEvents.java │ ├── packet │ ├── MarkRadialDirectionChangedPacket.java │ ├── MountS2CPacket.java │ └── NotifyRandomPowerChangePacket.java │ ├── particle │ └── SporeParticle.java │ └── ExtraOriginsClient.java ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── .github ├── ISSUE_TEMPLATE │ ├── config.yml │ └── issue.yml └── workflows │ └── build.yml ├── settings.gradle ├── .gitignore ├── gradle.properties ├── README.md ├── gradlew.bat └── gradlew /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) MoriyaShiine. All Rights Reserved. -------------------------------------------------------------------------------- /src/main/resources/data/extraorigins/powers/radioactive.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "extraorigins:random_power_granter" 3 | } -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoriyaShiine/extra-origins/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /src/main/resources/assets/extraorigins/particles/defense_spore.json: -------------------------------------------------------------------------------- 1 | { 2 | "textures": [ 3 | "extraorigins:defense_spore" 4 | ] 5 | } -------------------------------------------------------------------------------- /src/main/resources/assets/extraorigins/particles/mobility_spore.json: -------------------------------------------------------------------------------- 1 | { 2 | "textures": [ 3 | "extraorigins:mobility_spore" 4 | ] 5 | } -------------------------------------------------------------------------------- /src/main/resources/assets/extraorigins/particles/offense_spore.json: -------------------------------------------------------------------------------- 1 | { 2 | "textures": [ 3 | "extraorigins:offense_spore" 4 | ] 5 | } -------------------------------------------------------------------------------- /src/main/resources/data/extraorigins/powers/decomposition.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "extraorigins:food_effect_immunity", 3 | "inverted": true 4 | } -------------------------------------------------------------------------------- /src/main/resources/assets/extraorigins/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoriyaShiine/extra-origins/HEAD/src/main/resources/assets/extraorigins/icon.png -------------------------------------------------------------------------------- /src/main/resources/data/extraorigins/powers/jockey.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "extraorigins:start_riding", 3 | "key": { 4 | "key": "key.origins.secondary_active" 5 | } 6 | } -------------------------------------------------------------------------------- /src/main/resources/assets/extraorigins/textures/gui/icons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoriyaShiine/extra-origins/HEAD/src/main/resources/assets/extraorigins/textures/gui/icons.png -------------------------------------------------------------------------------- /src/main/resources/assets/extraorigins/textures/gui/resource_bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoriyaShiine/extra-origins/HEAD/src/main/resources/assets/extraorigins/textures/gui/resource_bar.png -------------------------------------------------------------------------------- /src/main/resources/data/extraorigins/origins/nucleon.json: -------------------------------------------------------------------------------- 1 | { 2 | "powers": [ 3 | "extraorigins:radioactive" 4 | ], 5 | "icon": "origins:orb_of_origin", 6 | "order": 1, 7 | "impact": 4 8 | } -------------------------------------------------------------------------------- /src/main/resources/data/extraorigins/tags/items/golden_equipment.json: -------------------------------------------------------------------------------- 1 | { 2 | "replace": false, 3 | "values": [ 4 | "#extraorigins:golden_armor", 5 | "#extraorigins:golden_tools" 6 | ] 7 | } -------------------------------------------------------------------------------- /src/main/resources/assets/extraorigins/textures/particle/defense_spore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoriyaShiine/extra-origins/HEAD/src/main/resources/assets/extraorigins/textures/particle/defense_spore.png -------------------------------------------------------------------------------- /src/main/resources/assets/extraorigins/textures/particle/mobility_spore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoriyaShiine/extra-origins/HEAD/src/main/resources/assets/extraorigins/textures/particle/mobility_spore.png -------------------------------------------------------------------------------- /src/main/resources/assets/extraorigins/textures/particle/offense_spore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoriyaShiine/extra-origins/HEAD/src/main/resources/assets/extraorigins/textures/particle/offense_spore.png -------------------------------------------------------------------------------- /src/main/resources/data/extraorigins/powers/small_appetite.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "origins:modify_exhaustion", 3 | "modifier": { 4 | "name": "Origin modifier", 5 | "operation": "multiply_base", 6 | "value": -0.75 7 | } 8 | } -------------------------------------------------------------------------------- /src/main/resources/data/extraorigins/tags/items/golden_food.json: -------------------------------------------------------------------------------- 1 | { 2 | "replace": false, 3 | "values": [ 4 | "minecraft:golden_carrot", 5 | "minecraft:golden_apple", 6 | "minecraft:enchanted_golden_apple" 7 | ] 8 | } -------------------------------------------------------------------------------- /src/main/resources/data/extraorigins/powers/piglin_neutrality.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "extraorigins:mob_neutrality", 3 | "entity_condition": { 4 | "type": "origins:entity_type", 5 | "entity_type": "minecraft:piglin" 6 | } 7 | } -------------------------------------------------------------------------------- /src/main/resources/assets/extraorigins/textures/gui/sprites/choose_origin/impact/very_high.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoriyaShiine/extra-origins/HEAD/src/main/resources/assets/extraorigins/textures/gui/sprites/choose_origin/impact/very_high.png -------------------------------------------------------------------------------- /src/main/resources/data/extraorigins/powers/flabby.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "origins:attribute", 3 | "modifier": { 4 | "name": "Origin modifier", 5 | "attribute": "minecraft:generic.max_health", 6 | "operation": "addition", 7 | "value": -4 8 | } 9 | } -------------------------------------------------------------------------------- /src/main/resources/data/extraorigins/tags/items/golden_armor.json: -------------------------------------------------------------------------------- 1 | { 2 | "replace": false, 3 | "values": [ 4 | "minecraft:golden_helmet", 5 | "minecraft:golden_chestplate", 6 | "minecraft:golden_leggings", 7 | "minecraft:golden_boots" 8 | ] 9 | } -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Moriya's Mods Discord 4 | url: https://discord.gg/Am6M8VQ 5 | about: Join my Discord for suggestions. Please do not submit a GitHub issue for suggestions. 6 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | maven { 4 | name = 'Fabric' 5 | url = 'https://maven.fabricmc.net/' 6 | } 7 | mavenCentral() 8 | gradlePluginPortal() 9 | } 10 | } -------------------------------------------------------------------------------- /src/main/resources/data/origins/origin_layers/origin.json: -------------------------------------------------------------------------------- 1 | { 2 | "replace": false, 3 | "origins": [ 4 | "extraorigins:floran", 5 | "extraorigins:truffle", 6 | "extraorigins:inchling", 7 | "extraorigins:piglin", 8 | "extraorigins:nucleon" 9 | ] 10 | } -------------------------------------------------------------------------------- /src/main/resources/data/extraorigins/tags/items/golden_tools.json: -------------------------------------------------------------------------------- 1 | { 2 | "replace": false, 3 | "values": [ 4 | "minecraft:golden_sword", 5 | "minecraft:golden_pickaxe", 6 | "minecraft:golden_axe", 7 | "minecraft:golden_shovel", 8 | "minecraft:golden_hoe" 9 | ] 10 | } -------------------------------------------------------------------------------- /src/main/resources/data/extraorigins/powers/flammable.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "origins:modify_damage_taken", 3 | "damage_condition": { 4 | "type": "origins:fire" 5 | }, 6 | "modifier": { 7 | "name": "Origin modifier", 8 | "operation": "multiply_base", 9 | "value": 1 10 | } 11 | } -------------------------------------------------------------------------------- /src/main/java/moriyashiine/extraorigins/common/util/RadialMenuDirection.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) MoriyaShiine. All Rights Reserved. 3 | */ 4 | package moriyashiine.extraorigins.common.util; 5 | 6 | public enum RadialMenuDirection { 7 | UP, 8 | DOWN, 9 | LEFT, 10 | RIGHT 11 | } 12 | -------------------------------------------------------------------------------- /src/main/resources/data/extraorigins/origins/truffle.json: -------------------------------------------------------------------------------- 1 | { 2 | "powers": [ 3 | "extraorigins:magic_spores", 4 | "extraorigins:infestation", 5 | "extraorigins:rooted", 6 | "extraorigins:decomposition" 7 | ], 8 | "icon": "minecraft:red_mushroom", 9 | "order": 1, 10 | "impact": 2 11 | } -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /src/main/resources/data/extraorigins/origins/inchling.json: -------------------------------------------------------------------------------- 1 | { 2 | "powers": [ 3 | "extraorigins:bite_sized", 4 | "extraorigins:nimble", 5 | "extraorigins:small_appetite", 6 | "origins:climbing", 7 | "extraorigins:jockey" 8 | ], 9 | "icon": "minecraft:anvil", 10 | "order": 1, 11 | "impact": 3 12 | } -------------------------------------------------------------------------------- /src/main/resources/data/extraorigins/powers/crossbow_master.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "origins:modify_projectile_damage", 3 | "damage_condition": { 4 | "type": "extraorigins:shot_from_crossbow" 5 | }, 6 | "modifier": { 7 | "name": "Origin modifier", 8 | "operation": "multiply_base", 9 | "value": 0.75 10 | } 11 | } -------------------------------------------------------------------------------- /src/main/resources/data/extraorigins/origins/floran.json: -------------------------------------------------------------------------------- 1 | { 2 | "powers": [ 3 | "extraorigins:green_thumb", 4 | "extraorigins:photosynthesis", 5 | "extraorigins:absorbing", 6 | "extraorigins:flammable", 7 | "extraorigins:nectarivore" 8 | ], 9 | "icon": "minecraft:oak_sapling", 10 | "order": 1, 11 | "impact": 2 12 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # gradle 2 | 3 | .gradle/ 4 | build/ 5 | out/ 6 | classes/ 7 | 8 | # eclipse 9 | 10 | *.launch 11 | 12 | # idea 13 | 14 | .idea/ 15 | *.iml 16 | *.ipr 17 | *.iws 18 | 19 | # vscode 20 | 21 | .settings/ 22 | .vscode/ 23 | bin/ 24 | .classpath 25 | .project 26 | 27 | # macos 28 | 29 | *.DS_Store 30 | 31 | # fabric 32 | 33 | run/ 34 | 35 | # java 36 | 37 | hs_err_*.log 38 | replay_*.log 39 | *.hprof 40 | *.jfr 41 | -------------------------------------------------------------------------------- /src/main/resources/data/extraorigins/origins/piglin.json: -------------------------------------------------------------------------------- 1 | { 2 | "powers": [ 3 | "extraorigins:all_that_glitters", 4 | "extraorigins:crossbow_master", 5 | "extraorigins:piglin_neutrality", 6 | "origins:nether_spawn", 7 | "extraorigins:homesick", 8 | "extraorigins:golden_gluttony", 9 | "extraorigins:flabby", 10 | "extraorigins:soul_spooked" 11 | ], 12 | "icon": "minecraft:golden_sword", 13 | "order": 1, 14 | "impact": 3 15 | } -------------------------------------------------------------------------------- /src/main/resources/data/extraorigins/powers/soul_spooked.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "origins:stacking_status_effect", 3 | "condition": { 4 | "type": "origins:block_in_radius", 5 | "radius": 8, 6 | "block_condition": { 7 | "type": "origins:in_tag", 8 | "tag": "minecraft:piglin_repellents" 9 | } 10 | }, 11 | "min_stacks": 0, 12 | "max_stacks": 1, 13 | "duration_per_stack": 30, 14 | "effect": { 15 | "effect": "minecraft:weakness", 16 | "is_ambient": true, 17 | "show_particles": false, 18 | "show_icon": true 19 | } 20 | } -------------------------------------------------------------------------------- /src/main/java/moriyashiine/extraorigins/common/power/CanStandOnPowderSnowPower.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) MoriyaShiine. All Rights Reserved. 3 | */ 4 | package moriyashiine.extraorigins.common.power; 5 | 6 | import io.github.apace100.apoli.power.Power; 7 | import io.github.apace100.apoli.power.PowerType; 8 | import net.minecraft.entity.LivingEntity; 9 | 10 | public class CanStandOnPowderSnowPower extends Power { 11 | public CanStandOnPowderSnowPower(PowerType type, LivingEntity entity) { 12 | super(type, entity); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/moriyashiine/extraorigins/common/power/PreventBlockSlownessPower.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) MoriyaShiine. All Rights Reserved. 3 | */ 4 | package moriyashiine.extraorigins.common.power; 5 | 6 | import io.github.apace100.apoli.power.Power; 7 | import io.github.apace100.apoli.power.PowerType; 8 | import net.minecraft.entity.LivingEntity; 9 | 10 | public class PreventBlockSlownessPower extends Power { 11 | public PreventBlockSlownessPower(PowerType type, LivingEntity entity) { 12 | super(type, entity); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/resources/data/extraorigins/powers/nectarivore.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "origins:prevent_item_use", 3 | "item_condition": { 4 | "type": "origins:and", 5 | "conditions": [ 6 | { 7 | "type": "origins:food" 8 | }, 9 | { 10 | "type": "origins:ingredient", 11 | "ingredient": { 12 | "item": "minecraft:honey_bottle" 13 | }, 14 | "inverted": true 15 | }, 16 | { 17 | "type": "origins:ingredient", 18 | "ingredient": { 19 | "tag": "origins:ignore_diet" 20 | }, 21 | "inverted": true 22 | } 23 | ] 24 | } 25 | } -------------------------------------------------------------------------------- /src/main/java/moriyashiine/extraorigins/common/power/ModifyAirStrafingSpeedPower.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) MoriyaShiine. All Rights Reserved. 3 | */ 4 | package moriyashiine.extraorigins.common.power; 5 | 6 | import io.github.apace100.apoli.power.PowerType; 7 | import io.github.apace100.apoli.power.ValueModifyingPower; 8 | import net.minecraft.entity.LivingEntity; 9 | 10 | public class ModifyAirStrafingSpeedPower extends ValueModifyingPower { 11 | public ModifyAirStrafingSpeedPower(PowerType type, LivingEntity entity) { 12 | super(type, entity); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/resources/data/extraorigins/powers/absorbing.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "origins:stacking_status_effect", 3 | "condition": { 4 | "type": "origins:or", 5 | "conditions": [ 6 | { 7 | "type": "origins:fluid_height", 8 | "fluid": "minecraft:water", 9 | "comparison": ">", 10 | "compare_to": 0.0 11 | }, 12 | { 13 | "type": "origins:in_rain" 14 | } 15 | ] 16 | }, 17 | "min_stacks": 0, 18 | "max_stacks": 1, 19 | "duration_per_stack": 30, 20 | "effect": { 21 | "effect": "minecraft:strength", 22 | "is_ambient": true, 23 | "show_particles": false, 24 | "show_icon": true 25 | } 26 | } -------------------------------------------------------------------------------- /src/main/resources/assets/extraorigins/sounds.json: -------------------------------------------------------------------------------- 1 | { 2 | "block.mycelium.grow": { 3 | "sounds": [ 4 | "minecraft:item/hoe/till1", 5 | "minecraft:item/hoe/till2", 6 | "minecraft:item/hoe/till3", 7 | "minecraft:item/hoe/till4" 8 | ], 9 | "subtitle": "extraorigins.subtitles.block.mycelium.grow" 10 | }, 11 | "entity.generic.spore_shift": { 12 | "sounds": [ 13 | "minecraft:block/chorus_flower/grow1", 14 | "minecraft:block/chorus_flower/grow2", 15 | "minecraft:block/chorus_flower/grow3", 16 | "minecraft:block/chorus_flower/grow4" 17 | ], 18 | "subtitle": "extraorigins.subtitles.entity.generic.spore_shift" 19 | } 20 | } -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Done to increase the memory available to gradle. 2 | org.gradle.jvmargs = -Xmx1G 3 | org.gradle.parallel = true 4 | # Fabric Properties 5 | minecraft_version = 1.20.2 6 | yarn_mappings = 1.20.2+build.4 7 | loader_version = 0.15.11 8 | # Mod Properties 9 | mod_version = 1.20-13 10 | maven_group = moriyashiine 11 | archives_base_name = extraorigins 12 | # Dependencies 13 | fabric_version = 0.91.6+1.20.2 14 | origins_version = v1.12.10 15 | pehkui_version = 3.8.2 16 | # Chenille 17 | modrinth_id = XWEESDPe 18 | curseforge_id = 398419 19 | curseforge_versions = 1.20.2 20 | cf_requirements = fabric-api; origins; pehkui 21 | release_type = release -------------------------------------------------------------------------------- /src/main/java/moriyashiine/extraorigins/common/power/DelayedHitboxPower.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) MoriyaShiine. All Rights Reserved. 3 | */ 4 | package moriyashiine.extraorigins.common.power; 5 | 6 | import io.github.apace100.apoli.power.Power; 7 | import io.github.apace100.apoli.power.PowerType; 8 | import net.minecraft.entity.LivingEntity; 9 | 10 | public class DelayedHitboxPower extends Power { 11 | private final int ticks; 12 | 13 | public DelayedHitboxPower(PowerType type, LivingEntity entity, int ticks) { 14 | super(type, entity); 15 | this.ticks = ticks; 16 | } 17 | 18 | public int getTicks() { 19 | return ticks; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/moriyashiine/extraorigins/common/event/RandomPowerGranterEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) MoriyaShiine. All Rights Reserved. 3 | */ 4 | package moriyashiine.extraorigins.common.event; 5 | 6 | import moriyashiine.extraorigins.common.power.RandomPowerGranterPower; 7 | import net.fabricmc.fabric.api.entity.event.v1.ServerPlayerEvents; 8 | import net.minecraft.server.network.ServerPlayerEntity; 9 | 10 | public class RandomPowerGranterEvent implements ServerPlayerEvents.AfterRespawn { 11 | @Override 12 | public void afterRespawn(ServerPlayerEntity oldPlayer, ServerPlayerEntity newPlayer, boolean alive) { 13 | if (!alive) { 14 | RandomPowerGranterPower.init(newPlayer, true); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/resources/data/extraorigins/powers/green_thumb.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "origins:active_self", 3 | "condition": { 4 | "type": "origins:food_level", 5 | "comparison": ">", 6 | "compare_to": 0 7 | }, 8 | "entity_action": { 9 | "type": "extraorigins:block_action_looking_at", 10 | "block_condition": { 11 | "type": "extraorigins:fertilizable" 12 | }, 13 | "block_action": { 14 | "type": "origins:bonemeal", 15 | "effects": true 16 | }, 17 | "entity_actions": [ 18 | { 19 | "type": "origins:exhaust", 20 | "amount": 20 21 | }, 22 | { 23 | "type": "origins:swing_hand" 24 | } 25 | ] 26 | }, 27 | "key": { 28 | "key": "key.origins.primary_active", 29 | "continuous": true 30 | }, 31 | "cooldown": 5 32 | } -------------------------------------------------------------------------------- /src/main/resources/data/extraorigins/powers/golden_gluttony.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "origins:prevent_item_use", 3 | "item_condition": { 4 | "type": "origins:and", 5 | "conditions": [ 6 | { 7 | "type": "origins:food" 8 | }, 9 | { 10 | "type": "origins:or", 11 | "conditions": [ 12 | { 13 | "type": "origins:ingredient", 14 | "ingredient": { 15 | "tag": "origins:meat" 16 | } 17 | }, 18 | { 19 | "type": "origins:meat" 20 | } 21 | ], 22 | "inverted": true 23 | }, 24 | { 25 | "type": "origins:ingredient", 26 | "ingredient": { 27 | "tag": "extraorigins:golden_food" 28 | }, 29 | "inverted": true 30 | }, 31 | { 32 | "type": "origins:ingredient", 33 | "ingredient": { 34 | "tag": "origins:ignore_diet" 35 | }, 36 | "inverted": true 37 | } 38 | ] 39 | } 40 | } -------------------------------------------------------------------------------- /src/main/resources/data/extraorigins/powers/nimble.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "origins:multiple", 3 | "damage_immunity": { 4 | "type": "origins:invulnerability", 5 | "damage_condition": { 6 | "type": "origins:or", 7 | "conditions": [ 8 | { 9 | "type": "origins:name", 10 | "name": "fall" 11 | }, 12 | { 13 | "type": "origins:name", 14 | "name": "flyIntoWall" 15 | }, 16 | { 17 | "type": "origins:name", 18 | "name": "cactus" 19 | }, 20 | { 21 | "type": "origins:name", 22 | "name": "sweetBerryBush" 23 | }, 24 | { 25 | "type": "origins:name", 26 | "name": "thorns" 27 | } 28 | ] 29 | } 30 | }, 31 | "prevent_block_slowness": { 32 | "type": "extraorigins:prevent_block_slowness" 33 | }, 34 | "can_walk_on_powder_snow": { 35 | "type": "extraorigins:can_walk_on_powder_snow" 36 | } 37 | } -------------------------------------------------------------------------------- /src/main/java/moriyashiine/extraorigins/common/power/MobNeutralityPower.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) MoriyaShiine. All Rights Reserved. 3 | */ 4 | package moriyashiine.extraorigins.common.power; 5 | 6 | import io.github.apace100.apoli.power.Power; 7 | import io.github.apace100.apoli.power.PowerType; 8 | import net.minecraft.entity.Entity; 9 | import net.minecraft.entity.LivingEntity; 10 | 11 | import java.util.function.Predicate; 12 | 13 | public class MobNeutralityPower extends Power { 14 | private final Predicate entityCondition; 15 | 16 | public MobNeutralityPower(PowerType type, LivingEntity entity, Predicate entityCondition) { 17 | super(type, entity); 18 | this.entityCondition = entityCondition; 19 | } 20 | 21 | public boolean shouldBeNeutral(Entity entity) { 22 | return entityCondition.test(entity); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/moriyashiine/extraorigins/common/init/ModSoundEvents.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) MoriyaShiine. All Rights Reserved. 3 | */ 4 | package moriyashiine.extraorigins.common.init; 5 | 6 | import moriyashiine.extraorigins.common.ExtraOrigins; 7 | import net.minecraft.registry.Registries; 8 | import net.minecraft.registry.Registry; 9 | import net.minecraft.sound.SoundEvent; 10 | 11 | public class ModSoundEvents { 12 | public static final SoundEvent BLOCK_MYCELIUM_GROW = SoundEvent.of(ExtraOrigins.id("block.mycelium.grow")); 13 | public static final SoundEvent ENTITY_GENERIC_SPORE_SHIFT = SoundEvent.of(ExtraOrigins.id("entity.generic.spore_shift")); 14 | 15 | public static void init() { 16 | Registry.register(Registries.SOUND_EVENT, BLOCK_MYCELIUM_GROW.getId(), BLOCK_MYCELIUM_GROW); 17 | Registry.register(Registries.SOUND_EVENT, ENTITY_GENERIC_SPORE_SHIFT.getId(), ENTITY_GENERIC_SPORE_SHIFT); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/moriyashiine/extraorigins/common/event/DismountEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) MoriyaShiine. All Rights Reserved. 3 | */ 4 | package moriyashiine.extraorigins.common.event; 5 | 6 | import io.github.apace100.apoli.component.PowerHolderComponent; 7 | import moriyashiine.extraorigins.common.power.MountPower; 8 | import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents; 9 | import net.minecraft.entity.player.PlayerEntity; 10 | import net.minecraft.server.MinecraftServer; 11 | import net.minecraft.server.network.ServerPlayNetworkHandler; 12 | 13 | public class DismountEvent implements ServerPlayConnectionEvents.Disconnect { 14 | @Override 15 | public void onPlayDisconnect(ServerPlayNetworkHandler handler, MinecraftServer server) { 16 | if (PowerHolderComponent.hasPower(handler.player, MountPower.class) && handler.player.getVehicle() instanceof PlayerEntity) { 17 | handler.player.dismountVehicle(); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/issue.yml: -------------------------------------------------------------------------------- 1 | name: Issue 2 | description: File a bug report 3 | body: 4 | - type: checkboxes 5 | attributes: 6 | label: Confirmations 7 | options: 8 | - label: I can verify that I am running the mod on the latest possible Minecraft version. 9 | required: true 10 | - label: I can verify that the issue I am reporting exists on the latest possible Mod version. 11 | required: true 12 | - type: input 13 | attributes: 14 | label: Mod version (NOT Minecraft version) 15 | description: Please do not put "latest,", "newest," or some other vague indiciator. 16 | validations: 17 | required: true 18 | - type: textarea 19 | attributes: 20 | label: A description of the issue 21 | validations: 22 | required: true 23 | - type: input 24 | attributes: 25 | label: Log or crash report 26 | description: Please use [gist](https://gist.github.com/). 27 | validations: 28 | required: true 29 | -------------------------------------------------------------------------------- /src/main/java/moriyashiine/extraorigins/common/power/FoodEffectImmunityPower.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) MoriyaShiine. All Rights Reserved. 3 | */ 4 | package moriyashiine.extraorigins.common.power; 5 | 6 | import io.github.apace100.apoli.power.Power; 7 | import io.github.apace100.apoli.power.PowerType; 8 | import net.minecraft.entity.LivingEntity; 9 | import net.minecraft.entity.effect.StatusEffect; 10 | 11 | import java.util.HashSet; 12 | import java.util.List; 13 | import java.util.Set; 14 | 15 | public class FoodEffectImmunityPower extends Power { 16 | private final Set effects = new HashSet<>(); 17 | private final boolean inverted; 18 | 19 | public FoodEffectImmunityPower(PowerType type, LivingEntity entity, List effects, boolean inverted) { 20 | super(type, entity); 21 | this.effects.addAll(effects); 22 | this.inverted = inverted; 23 | } 24 | 25 | public boolean shouldRemove(StatusEffect effect) { 26 | if (inverted) { 27 | return !effects.contains(effect); 28 | } 29 | return effects.contains(effect); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/resources/data/extraorigins/powers/infestation.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "origins:active_self", 3 | "condition": { 4 | "type": "origins:food_level", 5 | "comparison": ">", 6 | "compare_to": 0 7 | }, 8 | "entity_action": { 9 | "type": "extraorigins:block_action_looking_at", 10 | "block_condition": { 11 | "type": "origins:and", 12 | "conditions": [ 13 | { 14 | "type": "origins:in_tag", 15 | "tag": "minecraft:dirt" 16 | }, 17 | { 18 | "type": "origins:block", 19 | "block": "minecraft:mycelium", 20 | "inverted": true 21 | } 22 | ] 23 | }, 24 | "block_action": { 25 | "type": "origins:set_block", 26 | "block": "minecraft:mycelium" 27 | }, 28 | "entity_actions": [ 29 | { 30 | "type": "origins:play_sound", 31 | "sound": "extraorigins:block.mycelium.grow" 32 | }, 33 | { 34 | "type": "origins:exhaust", 35 | "amount": 10 36 | }, 37 | { 38 | "type": "origins:swing_hand" 39 | } 40 | ] 41 | }, 42 | "key": { 43 | "key": "key.origins.secondary_active", 44 | "continuous": true 45 | }, 46 | "cooldown": 5 47 | } -------------------------------------------------------------------------------- /src/main/resources/data/extraorigins/powers/mobility_spores.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "origins:multiple", 3 | "hidden": true, 4 | "attribute_modifiers": { 5 | "type": "origins:attribute", 6 | "modifiers": [ 7 | { 8 | "name": "Origin modifier", 9 | "attribute": "minecraft:generic.attack_damage", 10 | "value": -0.25, 11 | "operation": "multiply_total" 12 | }, 13 | { 14 | "name": "Origin modifier", 15 | "attribute": "minecraft:generic.movement_speed", 16 | "value": 0.5, 17 | "operation": "multiply_total" 18 | } 19 | ] 20 | }, 21 | "damage_taken_modifier": { 22 | "type": "origins:modify_damage_taken", 23 | "modifier": { 24 | "name": "Origin modifier", 25 | "operation": "multiply_total", 26 | "value": 0.25 27 | } 28 | }, 29 | "air_strafing_speed_modifier": { 30 | "type": "extraorigins:modify_air_strafing_speed", 31 | "modifier": { 32 | "name": "Origin modifier", 33 | "operation": "multiply_total", 34 | "value": 0.5 35 | } 36 | }, 37 | "particles": { 38 | "type": "origins:particle", 39 | "particle": "extraorigins:mobility_spore", 40 | "frequency": 2 41 | } 42 | } -------------------------------------------------------------------------------- /src/main/resources/data/extraorigins/powers/offense_spores.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "origins:multiple", 3 | "hidden": true, 4 | "attribute_modifiers": { 5 | "type": "origins:attribute", 6 | "modifiers": [ 7 | { 8 | "name": "Origin modifier", 9 | "attribute": "minecraft:generic.attack_damage", 10 | "value": 0.5, 11 | "operation": "multiply_total" 12 | }, 13 | { 14 | "name": "Origin modifier", 15 | "attribute": "minecraft:generic.movement_speed", 16 | "value": -0.125, 17 | "operation": "multiply_total" 18 | } 19 | ] 20 | }, 21 | "damage_taken_modifier": { 22 | "type": "origins:modify_damage_taken", 23 | "modifier": { 24 | "name": "Origin modifier", 25 | "operation": "multiply_total", 26 | "value": 0.5 27 | } 28 | }, 29 | "air_strafing_speed_modifier": { 30 | "type": "extraorigins:modify_air_strafing_speed", 31 | "modifier": { 32 | "name": "Origin modifier", 33 | "operation": "multiply_total", 34 | "value": -0.125 35 | } 36 | }, 37 | "particles": { 38 | "type": "origins:particle", 39 | "particle": "extraorigins:offense_spore", 40 | "frequency": 2 41 | } 42 | } -------------------------------------------------------------------------------- /src/main/java/moriyashiine/extraorigins/mixin/mount/client/ProjectileUtilMixin.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) MoriyaShiine. All Rights Reserved. 3 | */ 4 | package moriyashiine.extraorigins.mixin.mount.client; 5 | 6 | import io.github.apace100.apoli.component.PowerHolderComponent; 7 | import moriyashiine.extraorigins.common.power.MountPower; 8 | import net.minecraft.client.MinecraftClient; 9 | import net.minecraft.entity.Entity; 10 | import net.minecraft.entity.projectile.ProjectileUtil; 11 | import org.spongepowered.asm.mixin.Mixin; 12 | import org.spongepowered.asm.mixin.injection.At; 13 | import org.spongepowered.asm.mixin.injection.ModifyVariable; 14 | 15 | import java.util.function.Predicate; 16 | 17 | @Mixin(ProjectileUtil.class) 18 | public class ProjectileUtilMixin { 19 | @ModifyVariable(method = "raycast", at = @At("HEAD"), argsOnly = true) 20 | private static Predicate extraorigins$preventHittingPlayerMount(Predicate value) { 21 | return value.and(entity -> entity.getRootVehicle() != MinecraftClient.getInstance().player || !PowerHolderComponent.hasPower(entity, MountPower.class)); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/resources/data/extraorigins/powers/defense_spores.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "origins:multiple", 3 | "hidden": true, 4 | "attribute_modifiers": { 5 | "type": "origins:attribute", 6 | "modifiers": [ 7 | { 8 | "name": "Origin modifier", 9 | "attribute": "minecraft:generic.attack_damage", 10 | "value": -0.125, 11 | "operation": "multiply_total" 12 | }, 13 | { 14 | "name": "Origin modifier", 15 | "attribute": "minecraft:generic.movement_speed", 16 | "value": -0.25, 17 | "operation": "multiply_total" 18 | } 19 | ] 20 | }, 21 | "damage_taken_modifier": { 22 | "type": "origins:modify_damage_taken", 23 | "modifier": { 24 | "name": "Origin modifier", 25 | "operation": "multiply_total", 26 | "value": -0.25 27 | } 28 | }, 29 | "air_strafing_speed_modifier": { 30 | "type": "extraorigins:modify_air_strafing_speed", 31 | "modifier": { 32 | "name": "Origin modifier", 33 | "operation": "multiply_total", 34 | "value": -0.25 35 | } 36 | }, 37 | "particles": { 38 | "type": "origins:particle", 39 | "particle": "extraorigins:defense_spore", 40 | "frequency": 2 41 | } 42 | } -------------------------------------------------------------------------------- /src/main/resources/extraorigins.mixins.json: -------------------------------------------------------------------------------- 1 | { 2 | "required": true, 3 | "package": "moriyashiine.extraorigins.mixin", 4 | "compatibilityLevel": "JAVA_17", 5 | "mixins": [ 6 | "canstandonpowdersnow.PowderSnowBlockMixin", 7 | "foodeffectimmunity.LivingEntityMixin", 8 | "foodeffectimmunity.SuspiciousStewItemMixin", 9 | "innateunbreaking.ItemStackMixin", 10 | "mobneutrality.ActiveTargetGoalMixin", 11 | "mobneutrality.EndermanEntityMixin", 12 | "mobneutrality.FleeEntityGoalMixin", 13 | "mobneutrality.HoglinBrainMixin", 14 | "mobneutrality.PiglinBrainMixin", 15 | "mobneutrality.PiglinBruteBrainMixin", 16 | "mobneutrality.PiglinSpecificSensorMixin", 17 | "mobneutrality.ZoglinEntityMixin", 18 | "modifyairstrafingspeed.LivingEntityMixin", 19 | "preventblockslowness.EntityMixin", 20 | "util.impact4.ImpactMixin" 21 | ], 22 | "client": [ 23 | "delayedhitbox.client.MinecraftClientMixin", 24 | "modifyitemattribute.client.ItemStackMixin", 25 | "mount.client.ProjectileUtilMixin", 26 | "randompowergranter.client.OriginDisplayScreenMixin" 27 | ], 28 | "injectors": { 29 | "defaultRequire": 1 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/moriyashiine/extraorigins/common/power/InnateUnbreakingPower.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) MoriyaShiine. All Rights Reserved. 3 | */ 4 | package moriyashiine.extraorigins.common.power; 5 | 6 | import io.github.apace100.apoli.power.Power; 7 | import io.github.apace100.apoli.power.PowerType; 8 | import net.minecraft.entity.LivingEntity; 9 | import net.minecraft.item.ItemStack; 10 | import net.minecraft.util.Pair; 11 | import net.minecraft.world.World; 12 | 13 | import java.util.function.Predicate; 14 | 15 | public class InnateUnbreakingPower extends Power { 16 | private final Predicate> itemCondition; 17 | private final int level; 18 | 19 | public InnateUnbreakingPower(PowerType type, LivingEntity entity, Predicate> itemCondition, int level) { 20 | super(type, entity); 21 | this.itemCondition = itemCondition; 22 | this.level = level; 23 | } 24 | 25 | public boolean doesApply(ItemStack stack) { 26 | return itemCondition == null || itemCondition.test(new Pair<>(entity.getWorld(), stack)); 27 | } 28 | 29 | public int getLevel() { 30 | return level; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/moriyashiine/extraorigins/common/init/ModScaleTypes.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) MoriyaShiine. All Rights Reserved. 3 | */ 4 | package moriyashiine.extraorigins.common.init; 5 | 6 | import moriyashiine.extraorigins.common.ExtraOrigins; 7 | import virtuoel.pehkui.api.*; 8 | 9 | public class ModScaleTypes { 10 | public static ScaleType MODIFY_SIZE_TYPE; 11 | public static ScaleModifier MODIFY_SIZE_MODIFIER; 12 | 13 | public static void init() { 14 | MODIFY_SIZE_MODIFIER = ScaleRegistries.register(ScaleRegistries.SCALE_MODIFIERS, ExtraOrigins.id("modify_size"), new TypedScaleModifier(() -> MODIFY_SIZE_TYPE)); 15 | ScaleTypes.WIDTH.getDefaultBaseValueModifiers().add(MODIFY_SIZE_MODIFIER); 16 | ScaleTypes.HEIGHT.getDefaultBaseValueModifiers().add(MODIFY_SIZE_MODIFIER); 17 | ScaleTypes.DROPS.getDefaultBaseValueModifiers().add(MODIFY_SIZE_MODIFIER); 18 | ScaleTypes.VISIBILITY.getDefaultBaseValueModifiers().add(MODIFY_SIZE_MODIFIER); 19 | MODIFY_SIZE_TYPE = ScaleRegistries.register(ScaleRegistries.SCALE_TYPES, ExtraOrigins.id("modify_size"), ScaleType.Builder.create().affectsDimensions().addDependentModifier(MODIFY_SIZE_MODIFIER).build()); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/moriyashiine/extraorigins/mixin/preventblockslowness/EntityMixin.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) MoriyaShiine. All Rights Reserved. 3 | */ 4 | package moriyashiine.extraorigins.mixin.preventblockslowness; 5 | 6 | import io.github.apace100.apoli.component.PowerHolderComponent; 7 | import moriyashiine.extraorigins.common.power.PreventBlockSlownessPower; 8 | import net.minecraft.block.BlockState; 9 | import net.minecraft.entity.Entity; 10 | import net.minecraft.util.math.Vec3d; 11 | import org.spongepowered.asm.mixin.Mixin; 12 | import org.spongepowered.asm.mixin.injection.At; 13 | import org.spongepowered.asm.mixin.injection.Inject; 14 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 15 | 16 | @Mixin(Entity.class) 17 | public class EntityMixin { 18 | @Inject(method = "slowMovement", at = @At("HEAD"), cancellable = true) 19 | private void extraorigins$preventBlockSlowness(BlockState state, Vec3d multiplier, CallbackInfo ci) { 20 | for (PreventBlockSlownessPower power : PowerHolderComponent.getPowers((Entity) (Object) this, PreventBlockSlownessPower.class)) { 21 | if (power.isActive()) { 22 | ci.cancel(); 23 | return; 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/moriyashiine/extraorigins/common/init/ModParticleTypes.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) MoriyaShiine. All Rights Reserved. 3 | */ 4 | package moriyashiine.extraorigins.common.init; 5 | 6 | import moriyashiine.extraorigins.common.ExtraOrigins; 7 | import net.fabricmc.fabric.api.particle.v1.FabricParticleTypes; 8 | import net.minecraft.particle.DefaultParticleType; 9 | import net.minecraft.particle.ParticleType; 10 | import net.minecraft.registry.Registries; 11 | import net.minecraft.registry.Registry; 12 | 13 | public class ModParticleTypes { 14 | public static final ParticleType OFFENSE_SPORE = FabricParticleTypes.simple(); 15 | public static final ParticleType DEFENSE_SPORE = FabricParticleTypes.simple(); 16 | public static final ParticleType MOBILITY_SPORE = FabricParticleTypes.simple(); 17 | 18 | public static void init() { 19 | Registry.register(Registries.PARTICLE_TYPE, ExtraOrigins.id("offense_spore"), OFFENSE_SPORE); 20 | Registry.register(Registries.PARTICLE_TYPE, ExtraOrigins.id("defense_spore"), DEFENSE_SPORE); 21 | Registry.register(Registries.PARTICLE_TYPE, ExtraOrigins.id("mobility_spore"), MOBILITY_SPORE); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/moriyashiine/extraorigins/mixin/canstandonpowdersnow/PowderSnowBlockMixin.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) MoriyaShiine. All Rights Reserved. 3 | */ 4 | package moriyashiine.extraorigins.mixin.canstandonpowdersnow; 5 | 6 | import io.github.apace100.apoli.component.PowerHolderComponent; 7 | import moriyashiine.extraorigins.common.power.CanStandOnPowderSnowPower; 8 | import net.minecraft.block.PowderSnowBlock; 9 | import net.minecraft.entity.Entity; 10 | import org.spongepowered.asm.mixin.Mixin; 11 | import org.spongepowered.asm.mixin.injection.At; 12 | import org.spongepowered.asm.mixin.injection.Inject; 13 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 14 | 15 | @Mixin(PowderSnowBlock.class) 16 | public class PowderSnowBlockMixin { 17 | @Inject(method = "canWalkOnPowderSnow", at = @At("HEAD"), cancellable = true) 18 | private static void extraorigins$canStandOnPowderSnow(Entity entity, CallbackInfoReturnable cir) { 19 | for (CanStandOnPowderSnowPower canStandOnPowderSnowPower : PowerHolderComponent.getPowers(entity, CanStandOnPowderSnowPower.class)) { 20 | if (canStandOnPowderSnowPower.isActive()) { 21 | cir.setReturnValue(true); 22 | return; 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/moriyashiine/extraorigins/common/init/ModEntityComponents.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) MoriyaShiine. All Rights Reserved. 3 | */ 4 | package moriyashiine.extraorigins.common.init; 5 | 6 | import dev.onyxstudios.cca.api.v3.component.ComponentKey; 7 | import dev.onyxstudios.cca.api.v3.component.ComponentRegistry; 8 | import dev.onyxstudios.cca.api.v3.entity.EntityComponentFactoryRegistry; 9 | import dev.onyxstudios.cca.api.v3.entity.EntityComponentInitializer; 10 | import dev.onyxstudios.cca.api.v3.entity.RespawnCopyStrategy; 11 | import moriyashiine.extraorigins.common.component.entity.RandomPowerGranterComponent; 12 | import net.minecraft.entity.LivingEntity; 13 | 14 | public class ModEntityComponents implements EntityComponentInitializer { 15 | public static final ComponentKey RANDOM_POWER_GRANTER = ComponentRegistry.getOrCreate(RandomPowerGranterComponent.RANDOM_POWER_GRANTER, RandomPowerGranterComponent.class); 16 | 17 | @Override 18 | public void registerEntityComponentFactories(EntityComponentFactoryRegistry registry) { 19 | registry.beginRegistration(LivingEntity.class, RANDOM_POWER_GRANTER).respawnStrategy(RespawnCopyStrategy.ALWAYS_COPY).end(RandomPowerGranterComponent::new); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/moriyashiine/extraorigins/client/event/DelayedHitboxEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) MoriyaShiine. All Rights Reserved. 3 | */ 4 | package moriyashiine.extraorigins.client.event; 5 | 6 | import io.github.apace100.apoli.component.PowerHolderComponent; 7 | import moriyashiine.extraorigins.common.power.DelayedHitboxPower; 8 | import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; 9 | import net.minecraft.client.MinecraftClient; 10 | import net.minecraft.client.world.ClientWorld; 11 | import net.minecraft.entity.Entity; 12 | 13 | public class DelayedHitboxEvent implements ClientTickEvents.EndWorldTick { 14 | public static Entity target = null; 15 | public static int ticks = 0; 16 | 17 | @Override 18 | public void onEndTick(ClientWorld world) { 19 | Entity entity = MinecraftClient.getInstance().targetedEntity; 20 | if (entity != null) { 21 | for (DelayedHitboxPower power : PowerHolderComponent.getPowers(entity, DelayedHitboxPower.class)) { 22 | target = entity; 23 | ticks = Math.max(ticks, power.getTicks()); 24 | } 25 | } 26 | if (ticks > 0) { 27 | ticks--; 28 | } 29 | if (ticks == 0 || target == null || target.isRemoved() || !target.isAlive()) { 30 | target = null; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/moriyashiine/extraorigins/mixin/modifyairstrafingspeed/LivingEntityMixin.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) MoriyaShiine. All Rights Reserved. 3 | */ 4 | package moriyashiine.extraorigins.mixin.modifyairstrafingspeed; 5 | 6 | import io.github.apace100.apoli.component.PowerHolderComponent; 7 | import moriyashiine.extraorigins.common.power.ModifyAirStrafingSpeedPower; 8 | import net.minecraft.entity.Entity; 9 | import net.minecraft.entity.EntityType; 10 | import net.minecraft.entity.LivingEntity; 11 | import net.minecraft.world.World; 12 | import org.spongepowered.asm.mixin.Mixin; 13 | import org.spongepowered.asm.mixin.injection.At; 14 | import org.spongepowered.asm.mixin.injection.ModifyArg; 15 | 16 | @Mixin(LivingEntity.class) 17 | public abstract class LivingEntityMixin extends Entity { 18 | public LivingEntityMixin(EntityType type, World world) { 19 | super(type, world); 20 | } 21 | 22 | @ModifyArg(method = "applyMovementInput", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/LivingEntity;updateVelocity(FLnet/minecraft/util/math/Vec3d;)V")) 23 | private float extraorigins$modifyAirStrafingSpeed(float value) { 24 | if (!isOnGround()) { 25 | return PowerHolderComponent.modify(this, ModifyAirStrafingSpeedPower.class, value); 26 | } 27 | return value; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/resources/fabric.mod.json: -------------------------------------------------------------------------------- 1 | { 2 | "schemaVersion": 1, 3 | "id": "extraorigins", 4 | "version": "${version}", 5 | "name": "Extra Origins", 6 | "description": "Adds more origins to the Origins mod", 7 | "authors": [ 8 | "MoriyaShiine" 9 | ], 10 | "contributors": [ 11 | "cybercat5555" 12 | ], 13 | "contact": { 14 | "homepage": "https://modrinth.com/mod/extra-origins", 15 | "sources": "https://github.com/MoriyaShiine/extra-origins", 16 | "issues": "https://github.com/MoriyaShiine/extra-origins/issues" 17 | }, 18 | "license": "All Rights Reserved", 19 | "icon": "assets/extraorigins/icon.png", 20 | "environment": "*", 21 | "entrypoints": { 22 | "main": [ 23 | "moriyashiine.extraorigins.common.ExtraOrigins" 24 | ], 25 | "client": [ 26 | "moriyashiine.extraorigins.client.ExtraOriginsClient" 27 | ], 28 | "cardinal-components-entity": [ 29 | "moriyashiine.extraorigins.common.init.ModEntityComponents" 30 | ] 31 | }, 32 | "mixins": [ 33 | "extraorigins.mixins.json" 34 | ], 35 | "depends": { 36 | "fabricloader": "*", 37 | "minecraft": "~1.20.2", 38 | "java": ">=17", 39 | "fabric-api": "*", 40 | "origins": "*", 41 | "pehkui": "*" 42 | }, 43 | "custom": { 44 | "cardinal-components": [ 45 | "extraorigins:random_power_granter" 46 | ] 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/moriyashiine/extraorigins/mixin/mobneutrality/HoglinBrainMixin.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) MoriyaShiine. All Rights Reserved. 3 | */ 4 | package moriyashiine.extraorigins.mixin.mobneutrality; 5 | 6 | import com.llamalad7.mixinextras.injector.ModifyReturnValue; 7 | import io.github.apace100.apoli.component.PowerHolderComponent; 8 | import moriyashiine.extraorigins.common.power.MobNeutralityPower; 9 | import net.minecraft.entity.LivingEntity; 10 | import net.minecraft.entity.mob.HoglinBrain; 11 | import net.minecraft.entity.mob.HoglinEntity; 12 | import org.spongepowered.asm.mixin.Mixin; 13 | import org.spongepowered.asm.mixin.injection.At; 14 | 15 | import java.util.Optional; 16 | 17 | @Mixin(HoglinBrain.class) 18 | public class HoglinBrainMixin { 19 | @ModifyReturnValue(method = "getNearestVisibleTargetablePlayer", at = @At("RETURN")) 20 | private static Optional extraorigins$mobNeutrality(Optional original, HoglinEntity hoglin) { 21 | if (original.isPresent()) { 22 | LivingEntity entity = original.get(); 23 | for (MobNeutralityPower power : PowerHolderComponent.getPowers(entity, MobNeutralityPower.class)) { 24 | if (power.shouldBeNeutral(hoglin) && power.isActive()) { 25 | return Optional.empty(); 26 | } 27 | } 28 | } 29 | return original; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/moriyashiine/extraorigins/mixin/mobneutrality/ZoglinEntityMixin.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) MoriyaShiine. All Rights Reserved. 3 | */ 4 | package moriyashiine.extraorigins.mixin.mobneutrality; 5 | 6 | import com.llamalad7.mixinextras.injector.ModifyReturnValue; 7 | import io.github.apace100.apoli.component.PowerHolderComponent; 8 | import moriyashiine.extraorigins.common.power.MobNeutralityPower; 9 | import net.minecraft.entity.EntityType; 10 | import net.minecraft.entity.LivingEntity; 11 | import net.minecraft.entity.mob.ZoglinEntity; 12 | import net.minecraft.world.World; 13 | import org.spongepowered.asm.mixin.Mixin; 14 | import org.spongepowered.asm.mixin.injection.At; 15 | 16 | @Mixin(ZoglinEntity.class) 17 | public abstract class ZoglinEntityMixin extends LivingEntity { 18 | protected ZoglinEntityMixin(EntityType entityType, World world) { 19 | super(entityType, world); 20 | } 21 | 22 | @ModifyReturnValue(method = "shouldAttack", at = @At("RETURN")) 23 | private boolean extraorigins$mobNeutrality(boolean original, LivingEntity entity) { 24 | if (original) { 25 | for (MobNeutralityPower power : PowerHolderComponent.getPowers(entity, MobNeutralityPower.class)) { 26 | if (power.shouldBeNeutral(this) && power.isActive()) { 27 | return false; 28 | } 29 | } 30 | } 31 | return original; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | # Automatically build the project and run any configured tests for every push 2 | # and submitted pull request. This can help catch issues that only occur on 3 | # certain platforms or Java versions, and provides a first line of defence 4 | # against bad commits. 5 | 6 | name: build 7 | on: [ pull_request, push ] 8 | 9 | jobs: 10 | build: 11 | strategy: 12 | matrix: 13 | # Use these Java versions 14 | java: [ 15 | 17, # Current Java LTS & minimum supported by Minecraft 16 | 21, # Current Java LTS 17 | ] 18 | runs-on: ubuntu-22.04 19 | steps: 20 | - name: checkout repository 21 | uses: actions/checkout@v4 22 | - name: validate gradle wrapper 23 | uses: gradle/wrapper-validation-action@v2 24 | - name: setup jdk ${{ matrix.java }} 25 | uses: actions/setup-java@v4 26 | with: 27 | java-version: ${{ matrix.java }} 28 | distribution: 'microsoft' 29 | - name: make gradle wrapper executable 30 | run: chmod +x ./gradlew 31 | - name: build 32 | run: ./gradlew build 33 | - name: capture build artifacts 34 | if: ${{ matrix.java == '21' }} # Only upload artifacts built from latest java 35 | uses: actions/upload-artifact@v4 36 | with: 37 | name: Artifacts 38 | path: build/libs/ -------------------------------------------------------------------------------- /src/main/java/moriyashiine/extraorigins/common/power/RandomPowerGranterPower.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) MoriyaShiine. All Rights Reserved. 3 | */ 4 | package moriyashiine.extraorigins.common.power; 5 | 6 | import io.github.apace100.apoli.power.Power; 7 | import io.github.apace100.apoli.power.PowerType; 8 | import moriyashiine.extraorigins.common.component.entity.RandomPowerGranterComponent; 9 | import moriyashiine.extraorigins.common.init.ModEntityComponents; 10 | import net.minecraft.entity.LivingEntity; 11 | 12 | public class RandomPowerGranterPower extends Power { 13 | public RandomPowerGranterPower(PowerType type, LivingEntity entity) { 14 | super(type, entity); 15 | } 16 | 17 | @Override 18 | public void onGained() { 19 | init(entity, false); 20 | } 21 | 22 | @Override 23 | public void onLost() { 24 | RandomPowerGranterComponent randomPowerGranterComponent = ModEntityComponents.RANDOM_POWER_GRANTER.get(entity); 25 | randomPowerGranterComponent.removePowers(); 26 | randomPowerGranterComponent.sync(); 27 | } 28 | 29 | public static void init(LivingEntity entity, boolean checkEnabled) { 30 | RandomPowerGranterComponent randomPowerGranterComponent = ModEntityComponents.RANDOM_POWER_GRANTER.get(entity); 31 | if (checkEnabled && !randomPowerGranterComponent.isEnabled()) { 32 | return; 33 | } 34 | randomPowerGranterComponent.initializePowers(); 35 | randomPowerGranterComponent.sync(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/moriyashiine/extraorigins/mixin/mobneutrality/EndermanEntityMixin.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) MoriyaShiine. All Rights Reserved. 3 | */ 4 | package moriyashiine.extraorigins.mixin.mobneutrality; 5 | 6 | import com.llamalad7.mixinextras.injector.ModifyReturnValue; 7 | import io.github.apace100.apoli.component.PowerHolderComponent; 8 | import moriyashiine.extraorigins.common.power.MobNeutralityPower; 9 | import net.minecraft.entity.EntityType; 10 | import net.minecraft.entity.LivingEntity; 11 | import net.minecraft.entity.mob.EndermanEntity; 12 | import net.minecraft.entity.player.PlayerEntity; 13 | import net.minecraft.world.World; 14 | import org.spongepowered.asm.mixin.Mixin; 15 | import org.spongepowered.asm.mixin.injection.At; 16 | 17 | @Mixin(EndermanEntity.class) 18 | public abstract class EndermanEntityMixin extends LivingEntity { 19 | protected EndermanEntityMixin(EntityType entityType, World world) { 20 | super(entityType, world); 21 | } 22 | 23 | @ModifyReturnValue(method = "isPlayerStaring", at = @At("RETURN")) 24 | private boolean extraorigins$mobNeutrality(boolean original, PlayerEntity player) { 25 | if (original) { 26 | for (MobNeutralityPower power : PowerHolderComponent.getPowers(player, MobNeutralityPower.class)) { 27 | if (power.shouldBeNeutral(this) && power.isActive()) { 28 | return false; 29 | } 30 | } 31 | } 32 | return original; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/resources/data/extraorigins/powers/bite_sized.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "origins:multiple", 3 | "modify_size": { 4 | "type": "extraorigins:modify_size", 5 | "scale_types": [ 6 | "extraorigins:modify_size" 7 | ], 8 | "scale": 0.25 9 | }, 10 | "modify_hitbox_width": { 11 | "type": "extraorigins:modify_size", 12 | "scale_types": [ 13 | "pehkui:hitbox_width" 14 | ], 15 | "scale": 2 16 | }, 17 | "attribute_modifiers": { 18 | "type": "origins:attribute", 19 | "modifiers": [ 20 | { 21 | "name": "Origin modifier", 22 | "attribute": "minecraft:generic.max_health", 23 | "operation": "multiply_total", 24 | "value": -0.5 25 | }, 26 | { 27 | "name": "Origin modifier", 28 | "attribute": "minecraft:generic.movement_speed", 29 | "operation": "addition", 30 | "value": -0.015 31 | }, 32 | { 33 | "name": "Origin modifier", 34 | "attribute": "reach-entity-attributes:attack_range", 35 | "operation": "addition", 36 | "value": -0.25 37 | }, 38 | { 39 | "name": "Origin modifier", 40 | "attribute": "reach-entity-attributes:reach", 41 | "operation": "addition", 42 | "value": -1.5 43 | } 44 | ] 45 | }, 46 | "jump_modifier": { 47 | "type": "origins:modify_jump", 48 | "modifier": { 49 | "name": "Origin modifier", 50 | "operation": "multiply_total", 51 | "value": -0.3333 52 | } 53 | }, 54 | "delayed_hitbox": { 55 | "type": "extraorigins:delayed_hitbox", 56 | "ticks": 5 57 | } 58 | } -------------------------------------------------------------------------------- /src/main/java/moriyashiine/extraorigins/mixin/mobneutrality/PiglinBruteBrainMixin.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) MoriyaShiine. All Rights Reserved. 3 | */ 4 | package moriyashiine.extraorigins.mixin.mobneutrality; 5 | 6 | import com.llamalad7.mixinextras.injector.wrapoperation.Operation; 7 | import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; 8 | import io.github.apace100.apoli.component.PowerHolderComponent; 9 | import moriyashiine.extraorigins.common.power.MobNeutralityPower; 10 | import net.minecraft.entity.Entity; 11 | import net.minecraft.entity.LivingEntity; 12 | import net.minecraft.entity.mob.PiglinBruteBrain; 13 | import org.spongepowered.asm.mixin.Mixin; 14 | import org.spongepowered.asm.mixin.injection.At; 15 | 16 | @Mixin(PiglinBruteBrain.class) 17 | public class PiglinBruteBrainMixin { 18 | @WrapOperation(method = "method_30255", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/LivingEntity;isInRange(Lnet/minecraft/entity/Entity;D)Z")) 19 | private static boolean extraorigins$mobNeutrality(LivingEntity instance, Entity entity, double radius, Operation original) { 20 | boolean inRange = original.call(instance, entity, radius); 21 | if (inRange) { 22 | for (MobNeutralityPower power : PowerHolderComponent.getPowers(instance, MobNeutralityPower.class)) { 23 | if (power.shouldBeNeutral(entity) && power.isActive()) { 24 | return false; 25 | } 26 | } 27 | } 28 | return inRange; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/moriyashiine/extraorigins/mixin/delayedhitbox/client/MinecraftClientMixin.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) MoriyaShiine. All Rights Reserved. 3 | */ 4 | package moriyashiine.extraorigins.mixin.delayedhitbox.client; 5 | 6 | import moriyashiine.extraorigins.client.event.DelayedHitboxEvent; 7 | import net.minecraft.client.MinecraftClient; 8 | import net.minecraft.client.network.ClientPlayerEntity; 9 | import net.minecraft.client.network.ClientPlayerInteractionManager; 10 | import net.minecraft.util.Hand; 11 | import org.jetbrains.annotations.Nullable; 12 | import org.spongepowered.asm.mixin.Mixin; 13 | import org.spongepowered.asm.mixin.Shadow; 14 | import org.spongepowered.asm.mixin.injection.At; 15 | import org.spongepowered.asm.mixin.injection.Inject; 16 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 17 | 18 | @Mixin(MinecraftClient.class) 19 | public class MinecraftClientMixin { 20 | @Shadow 21 | @Nullable 22 | public ClientPlayerInteractionManager interactionManager; 23 | 24 | @Shadow 25 | @Nullable 26 | public ClientPlayerEntity player; 27 | 28 | @Inject(method = "doAttack", at = @At("HEAD"), cancellable = true) 29 | private void enchancement$coyoteBite(CallbackInfoReturnable cir) { 30 | if (DelayedHitboxEvent.target != null) { 31 | interactionManager.attackEntity(player, DelayedHitboxEvent.target); 32 | player.swingHand(Hand.MAIN_HAND); 33 | cir.setReturnValue(true); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/moriyashiine/extraorigins/client/packet/MarkRadialDirectionChangedPacket.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) MoriyaShiine. All Rights Reserved. 3 | */ 4 | package moriyashiine.extraorigins.client.packet; 5 | 6 | import io.netty.buffer.Unpooled; 7 | import moriyashiine.extraorigins.client.event.RadialMenuEvents; 8 | import moriyashiine.extraorigins.common.ExtraOrigins; 9 | import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; 10 | import net.fabricmc.fabric.api.networking.v1.PacketSender; 11 | import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; 12 | import net.minecraft.client.MinecraftClient; 13 | import net.minecraft.client.network.ClientPlayNetworkHandler; 14 | import net.minecraft.network.PacketByteBuf; 15 | import net.minecraft.server.network.ServerPlayerEntity; 16 | import net.minecraft.util.Identifier; 17 | 18 | public class MarkRadialDirectionChangedPacket { 19 | public static final Identifier ID = ExtraOrigins.id("mark_radial_direction_changed"); 20 | 21 | public static void send(ServerPlayerEntity player) { 22 | ServerPlayNetworking.send(player, ID, new PacketByteBuf(Unpooled.buffer())); 23 | } 24 | 25 | public static class Receiver implements ClientPlayNetworking.PlayChannelHandler { 26 | @Override 27 | public void receive(MinecraftClient client, ClientPlayNetworkHandler handler, PacketByteBuf buf, PacketSender responseSender) { 28 | client.execute(() -> RadialMenuEvents.directionChanged = false); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/moriyashiine/extraorigins/mixin/mobneutrality/PiglinSpecificSensorMixin.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) MoriyaShiine. All Rights Reserved. 3 | */ 4 | package moriyashiine.extraorigins.mixin.mobneutrality; 5 | 6 | import com.llamalad7.mixinextras.injector.wrapoperation.Operation; 7 | import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; 8 | import io.github.apace100.apoli.component.PowerHolderComponent; 9 | import moriyashiine.extraorigins.common.power.MobNeutralityPower; 10 | import net.minecraft.entity.LivingEntity; 11 | import net.minecraft.entity.ai.brain.sensor.PiglinSpecificSensor; 12 | import net.minecraft.server.world.ServerWorld; 13 | import org.spongepowered.asm.mixin.Mixin; 14 | import org.spongepowered.asm.mixin.injection.At; 15 | 16 | @Mixin(PiglinSpecificSensor.class) 17 | public class PiglinSpecificSensorMixin { 18 | @WrapOperation(method = "sense", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/mob/PiglinBrain;wearsGoldArmor(Lnet/minecraft/entity/LivingEntity;)Z")) 19 | private boolean extraorigins$mobNeutrality(LivingEntity player, Operation original, ServerWorld world, LivingEntity entity) { 20 | boolean wearsGold = original.call(player); 21 | if (!wearsGold) { 22 | for (MobNeutralityPower power : PowerHolderComponent.getPowers(player, MobNeutralityPower.class)) { 23 | if (power.shouldBeNeutral(entity) && power.isActive()) { 24 | return true; 25 | } 26 | } 27 | } 28 | return wearsGold; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/moriyashiine/extraorigins/mixin/mobneutrality/ActiveTargetGoalMixin.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) MoriyaShiine. All Rights Reserved. 3 | */ 4 | package moriyashiine.extraorigins.mixin.mobneutrality; 5 | 6 | import io.github.apace100.apoli.component.PowerHolderComponent; 7 | import moriyashiine.extraorigins.common.power.MobNeutralityPower; 8 | import net.minecraft.entity.LivingEntity; 9 | import net.minecraft.entity.ai.goal.ActiveTargetGoal; 10 | import net.minecraft.entity.mob.MobEntity; 11 | import org.spongepowered.asm.mixin.Mixin; 12 | import org.spongepowered.asm.mixin.injection.At; 13 | import org.spongepowered.asm.mixin.injection.ModifyVariable; 14 | 15 | import java.util.function.Predicate; 16 | 17 | @Mixin(ActiveTargetGoal.class) 18 | public class ActiveTargetGoalMixin { 19 | @ModifyVariable(method = "(Lnet/minecraft/entity/mob/MobEntity;Ljava/lang/Class;IZZLjava/util/function/Predicate;)V", at = @At("HEAD"), argsOnly = true) 20 | private static Predicate extraorigins$mobNeutrality(Predicate value, MobEntity mob) { 21 | Predicate neutralityPredicate = target -> { 22 | for (MobNeutralityPower power : PowerHolderComponent.getPowers(target, MobNeutralityPower.class)) { 23 | if (power.shouldBeNeutral(mob) && power.isActive()) { 24 | return false; 25 | } 26 | } 27 | return true; 28 | }; 29 | if (value == null) { 30 | return neutralityPredicate; 31 | } 32 | return value.and(neutralityPredicate); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/moriyashiine/extraorigins/common/power/MountPower.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) MoriyaShiine. All Rights Reserved. 3 | */ 4 | package moriyashiine.extraorigins.common.power; 5 | 6 | import io.github.apace100.apoli.power.Active; 7 | import io.github.apace100.apoli.power.Power; 8 | import io.github.apace100.apoli.power.PowerType; 9 | import moriyashiine.extraorigins.common.packet.MountC2SPacket; 10 | import net.minecraft.client.MinecraftClient; 11 | import net.minecraft.client.network.ClientPlayerEntity; 12 | import net.minecraft.entity.LivingEntity; 13 | import net.minecraft.entity.player.PlayerEntity; 14 | import net.minecraft.util.hit.EntityHitResult; 15 | import net.minecraft.util.hit.HitResult; 16 | 17 | public class MountPower extends Power implements Active { 18 | private Key key; 19 | 20 | public MountPower(PowerType type, LivingEntity entity) { 21 | super(type, entity); 22 | } 23 | 24 | @Override 25 | public void onUse() { 26 | if (entity.getWorld().isClient && entity instanceof ClientPlayerEntity) { 27 | MinecraftClient client = MinecraftClient.getInstance(); 28 | if (client.crosshairTarget != null && client.crosshairTarget.getType() == HitResult.Type.ENTITY && ((EntityHitResult) client.crosshairTarget).getEntity() instanceof PlayerEntity player) { 29 | MountC2SPacket.send(player); 30 | } 31 | } 32 | } 33 | 34 | @Override 35 | public Key getKey() { 36 | return key; 37 | } 38 | 39 | @Override 40 | public void setKey(Key key) { 41 | this.key = key; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/moriyashiine/extraorigins/common/power/ModifySizePower.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) MoriyaShiine. All Rights Reserved. 3 | */ 4 | package moriyashiine.extraorigins.common.power; 5 | 6 | import io.github.apace100.apoli.power.Power; 7 | import io.github.apace100.apoli.power.PowerType; 8 | import net.minecraft.entity.LivingEntity; 9 | import net.minecraft.util.Identifier; 10 | import virtuoel.pehkui.api.ScaleData; 11 | import virtuoel.pehkui.api.ScaleRegistries; 12 | import virtuoel.pehkui.api.ScaleType; 13 | 14 | import java.util.HashSet; 15 | import java.util.List; 16 | import java.util.Set; 17 | 18 | public class ModifySizePower extends Power { 19 | private final Set scaleTypes = new HashSet<>(); 20 | private final float scale; 21 | 22 | public ModifySizePower(PowerType type, LivingEntity entity, List identifiers, float scale) { 23 | super(type, entity); 24 | identifiers.forEach(identifier -> scaleTypes.add(ScaleRegistries.SCALE_TYPES.get(identifier))); 25 | this.scale = scale; 26 | setTicking(true); 27 | } 28 | 29 | @Override 30 | public void tick() { 31 | scaleTypes.forEach(scaleType -> { 32 | ScaleData data = scaleType.getScaleData(entity); 33 | if (isActive() && data.getScale() != scale) { 34 | data.setScale(scale); 35 | } else if (!isActive() && data.getScale() != 1) { 36 | data.setScale(1); 37 | } 38 | }); 39 | } 40 | 41 | @Override 42 | public void onLost() { 43 | scaleTypes.forEach(scaleType -> scaleType.getScaleData(entity).setScale(1)); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/moriyashiine/extraorigins/mixin/util/impact4/ImpactMixin.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) MoriyaShiine. All Rights Reserved. 3 | */ 4 | package moriyashiine.extraorigins.mixin.util.impact4; 5 | 6 | import io.github.apace100.origins.origin.Impact; 7 | import moriyashiine.extraorigins.common.ExtraOrigins; 8 | import net.minecraft.util.Formatting; 9 | import net.minecraft.util.Identifier; 10 | import org.spongepowered.asm.mixin.*; 11 | import org.spongepowered.asm.mixin.gen.Invoker; 12 | 13 | import java.util.ArrayList; 14 | import java.util.Arrays; 15 | import java.util.List; 16 | 17 | @Mixin(Impact.class) 18 | public class ImpactMixin { 19 | @Unique 20 | private static final Impact VERY_HIGH = extraorigins$addImpact4(ExtraOrigins.id("choose_origin/impact/very_high")); 21 | 22 | @Shadow 23 | @Final 24 | @Mutable 25 | private static Impact[] $VALUES; 26 | 27 | @Invoker("") 28 | public static Impact extraorigins$init(String name, int id, int impactValue, String translationKey, Formatting textStyle, Identifier spriteId) { 29 | throw new UnsupportedOperationException(); 30 | } 31 | 32 | @Unique 33 | private static Impact extraorigins$addImpact4(Identifier spriteId) { 34 | List originalList = new ArrayList<>(Arrays.asList(Impact.values())); 35 | Impact impact4 = extraorigins$init("VERY_HIGH", originalList.get(originalList.size() - 1).ordinal() + 1, 4, "very_high", Formatting.LIGHT_PURPLE, spriteId); 36 | originalList.add(impact4); 37 | $VALUES = originalList.toArray(new Impact[0]); 38 | return impact4; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/moriyashiine/extraorigins/mixin/mobneutrality/FleeEntityGoalMixin.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) MoriyaShiine. All Rights Reserved. 3 | */ 4 | package moriyashiine.extraorigins.mixin.mobneutrality; 5 | 6 | import io.github.apace100.apoli.component.PowerHolderComponent; 7 | import moriyashiine.extraorigins.common.power.MobNeutralityPower; 8 | import net.minecraft.entity.LivingEntity; 9 | import net.minecraft.entity.ai.goal.FleeEntityGoal; 10 | import net.minecraft.entity.mob.PathAwareEntity; 11 | import org.spongepowered.asm.mixin.Mixin; 12 | import org.spongepowered.asm.mixin.injection.At; 13 | import org.spongepowered.asm.mixin.injection.ModifyVariable; 14 | 15 | import java.util.function.Predicate; 16 | 17 | @Mixin(FleeEntityGoal.class) 18 | public class FleeEntityGoalMixin { 19 | @ModifyVariable(method = "(Lnet/minecraft/entity/mob/PathAwareEntity;Ljava/lang/Class;Ljava/util/function/Predicate;FDDLjava/util/function/Predicate;)V", at = @At("HEAD"), ordinal = 1, argsOnly = true) 20 | private static Predicate extraorigins$mobNeutrality(Predicate value, PathAwareEntity mob) { 21 | Predicate neutralityPredicate = target -> { 22 | for (MobNeutralityPower power : PowerHolderComponent.getPowers(target, MobNeutralityPower.class)) { 23 | if (power.shouldBeNeutral(mob) && power.isActive()) { 24 | return false; 25 | } 26 | } 27 | return true; 28 | }; 29 | if (value == null) { 30 | return neutralityPredicate; 31 | } 32 | return value.and(neutralityPredicate); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/moriyashiine/extraorigins/client/packet/MountS2CPacket.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) MoriyaShiine. All Rights Reserved. 3 | */ 4 | package moriyashiine.extraorigins.client.packet; 5 | 6 | import io.netty.buffer.Unpooled; 7 | import moriyashiine.extraorigins.common.ExtraOrigins; 8 | import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; 9 | import net.fabricmc.fabric.api.networking.v1.PacketSender; 10 | import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; 11 | import net.minecraft.client.MinecraftClient; 12 | import net.minecraft.client.network.ClientPlayNetworkHandler; 13 | import net.minecraft.entity.Entity; 14 | import net.minecraft.network.PacketByteBuf; 15 | import net.minecraft.server.network.ServerPlayerEntity; 16 | import net.minecraft.util.Identifier; 17 | 18 | public class MountS2CPacket { 19 | public static final Identifier ID = ExtraOrigins.id("mount_s2c"); 20 | 21 | public static void send(ServerPlayerEntity player, Entity entity) { 22 | PacketByteBuf buf = new PacketByteBuf(Unpooled.buffer()); 23 | buf.writeInt(entity.getId()); 24 | ServerPlayNetworking.send(player, ID, buf); 25 | } 26 | 27 | public static class Receiver implements ClientPlayNetworking.PlayChannelHandler { 28 | @Override 29 | public void receive(MinecraftClient client, ClientPlayNetworkHandler handler, PacketByteBuf buf, PacketSender responseSender) { 30 | int id = buf.readInt(); 31 | client.execute(() -> { 32 | Entity entity = client.world.getEntityById(id); 33 | if (entity != null) { 34 | entity.startRiding(client.player, true); 35 | } 36 | }); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/moriyashiine/extraorigins/mixin/mobneutrality/PiglinBrainMixin.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) MoriyaShiine. All Rights Reserved. 3 | */ 4 | package moriyashiine.extraorigins.mixin.mobneutrality; 5 | 6 | import com.llamalad7.mixinextras.injector.wrapoperation.Operation; 7 | import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; 8 | import io.github.apace100.apoli.component.PowerHolderComponent; 9 | import moriyashiine.extraorigins.common.power.MobNeutralityPower; 10 | import net.minecraft.entity.Entity; 11 | import net.minecraft.entity.mob.PiglinBrain; 12 | import net.minecraft.entity.player.PlayerEntity; 13 | import net.minecraft.util.math.Box; 14 | import net.minecraft.world.World; 15 | import org.spongepowered.asm.mixin.Mixin; 16 | import org.spongepowered.asm.mixin.injection.At; 17 | 18 | import java.util.List; 19 | 20 | @Mixin(PiglinBrain.class) 21 | public class PiglinBrainMixin { 22 | @WrapOperation(method = "onGuardedBlockInteracted", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/World;getNonSpectatingEntities(Ljava/lang/Class;Lnet/minecraft/util/math/Box;)Ljava/util/List;")) 23 | private static List extraorigins$mobNeutrality(World instance, Class aClass, Box box, Operation> original, PlayerEntity player) { 24 | List list = original.call(instance, aClass, box); 25 | for (int i = list.size() - 1; i >= 0; i--) { 26 | for (MobNeutralityPower power : PowerHolderComponent.getPowers(player, MobNeutralityPower.class)) { 27 | if (power.shouldBeNeutral(list.get(i)) && power.isActive()) { 28 | list.remove(i); 29 | break; 30 | } 31 | } 32 | } 33 | return list; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/moriyashiine/extraorigins/mixin/innateunbreaking/ItemStackMixin.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) MoriyaShiine. All Rights Reserved. 3 | */ 4 | package moriyashiine.extraorigins.mixin.innateunbreaking; 5 | 6 | import com.llamalad7.mixinextras.injector.wrapoperation.Operation; 7 | import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; 8 | import io.github.apace100.apoli.component.PowerHolderComponent; 9 | import moriyashiine.extraorigins.common.power.InnateUnbreakingPower; 10 | import net.minecraft.enchantment.Enchantment; 11 | import net.minecraft.item.ItemStack; 12 | import net.minecraft.server.network.ServerPlayerEntity; 13 | import net.minecraft.util.math.random.Random; 14 | import org.jetbrains.annotations.Nullable; 15 | import org.spongepowered.asm.mixin.Mixin; 16 | import org.spongepowered.asm.mixin.injection.At; 17 | 18 | @Mixin(ItemStack.class) 19 | public class ItemStackMixin { 20 | @WrapOperation(method = "damage(ILnet/minecraft/util/math/random/Random;Lnet/minecraft/server/network/ServerPlayerEntity;)Z", at = @At(value = "INVOKE", target = "Lnet/minecraft/enchantment/EnchantmentHelper;getLevel(Lnet/minecraft/enchantment/Enchantment;Lnet/minecraft/item/ItemStack;)I")) 21 | private int extraorigins$innateUnbreaking(Enchantment enchantment, ItemStack stack, Operation original, int amount, Random random, @Nullable ServerPlayerEntity player) { 22 | int level = original.call(enchantment, stack); 23 | if (player != null) { 24 | for (InnateUnbreakingPower power : PowerHolderComponent.getPowers(player, InnateUnbreakingPower.class)) { 25 | if (power.doesApply((ItemStack) (Object) this) && power.isActive()) { 26 | level += power.getLevel(); 27 | } 28 | } 29 | } 30 | return level; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/moriyashiine/extraorigins/common/ExtraOrigins.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) MoriyaShiine. All Rights Reserved. 3 | */ 4 | package moriyashiine.extraorigins.common; 5 | 6 | import moriyashiine.extraorigins.common.event.DismountEvent; 7 | import moriyashiine.extraorigins.common.event.RandomPowerGranterEvent; 8 | import moriyashiine.extraorigins.common.init.*; 9 | import moriyashiine.extraorigins.common.packet.ChangeRadialDirectionPacket; 10 | import moriyashiine.extraorigins.common.packet.MountC2SPacket; 11 | import net.fabricmc.api.ModInitializer; 12 | import net.fabricmc.fabric.api.entity.event.v1.ServerPlayerEvents; 13 | import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents; 14 | import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; 15 | import net.minecraft.util.Identifier; 16 | 17 | public class ExtraOrigins implements ModInitializer { 18 | public static final String MOD_ID = "extraorigins"; 19 | 20 | @Override 21 | public void onInitialize() { 22 | ModParticleTypes.init(); 23 | ModSoundEvents.init(); 24 | ModPowers.init(); 25 | ModConditions.init(); 26 | ModActions.init(); 27 | ModScaleTypes.init(); 28 | initPackets(); 29 | initEvents(); 30 | } 31 | 32 | public static Identifier id(String value) { 33 | return new Identifier(MOD_ID, value); 34 | } 35 | 36 | private void initPackets() { 37 | ServerPlayNetworking.registerGlobalReceiver(ChangeRadialDirectionPacket.ID, new ChangeRadialDirectionPacket.Receiver()); 38 | ServerPlayNetworking.registerGlobalReceiver(MountC2SPacket.ID, new MountC2SPacket.Receiver()); 39 | } 40 | 41 | private void initEvents() { 42 | ServerPlayConnectionEvents.DISCONNECT.register(new DismountEvent()); 43 | ServerPlayerEvents.AFTER_RESPAWN.register(new RandomPowerGranterEvent()); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/resources/data/extraorigins/powers/photosynthesis.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "origins:multiple", 3 | "regenerate_food": { 4 | "type": "origins:action_over_time", 5 | "condition": { 6 | "type": "origins:and", 7 | "conditions": [ 8 | { 9 | "type": "origins:daytime" 10 | }, 11 | { 12 | "type": "origins:exposed_to_sky" 13 | }, 14 | { 15 | "type": "origins:or", 16 | "conditions": [ 17 | { 18 | "type": "origins:food_level", 19 | "comparison": "<", 20 | "compare_to": 20 21 | }, 22 | { 23 | "type": "origins:saturation_level", 24 | "comparison": "<", 25 | "compare_to": 20 26 | } 27 | ] 28 | } 29 | ] 30 | }, 31 | "interval": 20, 32 | "entity_action": { 33 | "type": "origins:feed", 34 | "food": 1, 35 | "saturation": 1 36 | } 37 | }, 38 | "prevent_healing": { 39 | "type": "origins:disable_regen" 40 | }, 41 | "natural_regeneration": { 42 | "type": "origins:action_over_time", 43 | "condition": { 44 | "type": "origins:and", 45 | "conditions": [ 46 | { 47 | "type": "origins:relative_health", 48 | "comparison": "<", 49 | "compare_to": 1 50 | }, 51 | { 52 | "type": "origins:food_level", 53 | "comparison": ">", 54 | "compare_to": 0 55 | } 56 | ] 57 | }, 58 | "interval": 40, 59 | "entity_action": { 60 | "type": "origins:heal", 61 | "amount": 1 62 | } 63 | }, 64 | "natural_regeneration_exhaustion": { 65 | "type": "origins:action_over_time", 66 | "condition": { 67 | "type": "origins:and", 68 | "conditions": [ 69 | { 70 | "type": "origins:relative_health", 71 | "comparison": "<", 72 | "compare_to": 1 73 | }, 74 | { 75 | "type": "origins:food_level", 76 | "comparison": ">", 77 | "compare_to": 0 78 | } 79 | ] 80 | }, 81 | "interval": 40, 82 | "entity_action": { 83 | "type": "origins:exhaust", 84 | "amount": 2 85 | } 86 | } 87 | } -------------------------------------------------------------------------------- /src/main/java/moriyashiine/extraorigins/client/packet/NotifyRandomPowerChangePacket.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) MoriyaShiine. All Rights Reserved. 3 | */ 4 | package moriyashiine.extraorigins.client.packet; 5 | 6 | import io.netty.buffer.Unpooled; 7 | import moriyashiine.extraorigins.client.event.RandomPowerGranterClientEvent; 8 | import moriyashiine.extraorigins.common.ExtraOrigins; 9 | import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; 10 | import net.fabricmc.fabric.api.networking.v1.PacketSender; 11 | import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; 12 | import net.minecraft.client.MinecraftClient; 13 | import net.minecraft.client.network.ClientPlayNetworkHandler; 14 | import net.minecraft.network.PacketByteBuf; 15 | import net.minecraft.server.network.ServerPlayerEntity; 16 | import net.minecraft.util.Identifier; 17 | 18 | public class NotifyRandomPowerChangePacket { 19 | public static final Identifier ID = ExtraOrigins.id("notify_random_power_change"); 20 | 21 | public static void send(ServerPlayerEntity player, int index, Identifier oldPower, Identifier newPower) { 22 | PacketByteBuf buf = new PacketByteBuf(Unpooled.buffer()); 23 | buf.writeInt(index); 24 | buf.writeIdentifier(oldPower); 25 | buf.writeIdentifier(newPower); 26 | ServerPlayNetworking.send(player, ID, buf); 27 | } 28 | 29 | public static class Receiver implements ClientPlayNetworking.PlayChannelHandler { 30 | @Override 31 | public void receive(MinecraftClient client, ClientPlayNetworkHandler handler, PacketByteBuf buf, PacketSender responseSender) { 32 | int index = buf.readInt(); 33 | Identifier oldPower = buf.readIdentifier(); 34 | Identifier newPower = buf.readIdentifier(); 35 | client.execute(() -> { 36 | RandomPowerGranterClientEvent.DISPLAY_INSTANCES[index] = new RandomPowerGranterClientEvent.DisplayInstance(oldPower, newPower, 120); 37 | }); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/moriyashiine/extraorigins/common/packet/MountC2SPacket.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) MoriyaShiine. All Rights Reserved. 3 | */ 4 | package moriyashiine.extraorigins.common.packet; 5 | 6 | import io.netty.buffer.Unpooled; 7 | import moriyashiine.extraorigins.client.packet.MountS2CPacket; 8 | import moriyashiine.extraorigins.common.ExtraOrigins; 9 | import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; 10 | import net.fabricmc.fabric.api.networking.v1.PacketSender; 11 | import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; 12 | import net.minecraft.entity.Entity; 13 | import net.minecraft.network.PacketByteBuf; 14 | import net.minecraft.server.MinecraftServer; 15 | import net.minecraft.server.network.ServerPlayNetworkHandler; 16 | import net.minecraft.server.network.ServerPlayerEntity; 17 | import net.minecraft.util.Identifier; 18 | 19 | public class MountC2SPacket { 20 | public static final Identifier ID = ExtraOrigins.id("mount_c2s"); 21 | 22 | public static void send(Entity entity) { 23 | PacketByteBuf buf = new PacketByteBuf(Unpooled.buffer()); 24 | buf.writeInt(entity.getId()); 25 | ClientPlayNetworking.send(ID, buf); 26 | } 27 | 28 | public static class Receiver implements ServerPlayNetworking.PlayChannelHandler { 29 | @Override 30 | public void receive(MinecraftServer server, ServerPlayerEntity player, ServerPlayNetworkHandler handler, PacketByteBuf buf, PacketSender responseSender) { 31 | int id = buf.readInt(); 32 | server.execute(() -> { 33 | Entity entity = player.getWorld().getEntityById(id); 34 | if (entity != null) { 35 | if (player.getUuid().equals(entity.getUuid())) { 36 | return; 37 | } 38 | player.startRiding(entity, true); 39 | if (entity instanceof ServerPlayerEntity playerBeingRidden) { 40 | MountS2CPacket.send(playerBeingRidden, player); 41 | } 42 | } 43 | }); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/moriyashiine/extraorigins/mixin/foodeffectimmunity/LivingEntityMixin.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) MoriyaShiine. All Rights Reserved. 3 | */ 4 | package moriyashiine.extraorigins.mixin.foodeffectimmunity; 5 | 6 | import com.llamalad7.mixinextras.injector.wrapoperation.Operation; 7 | import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; 8 | import com.mojang.datafixers.util.Pair; 9 | import io.github.apace100.apoli.component.PowerHolderComponent; 10 | import moriyashiine.extraorigins.common.power.FoodEffectImmunityPower; 11 | import net.minecraft.entity.LivingEntity; 12 | import net.minecraft.entity.effect.StatusEffectInstance; 13 | import net.minecraft.item.FoodComponent; 14 | import org.spongepowered.asm.mixin.Mixin; 15 | import org.spongepowered.asm.mixin.injection.At; 16 | 17 | import java.util.ArrayList; 18 | import java.util.List; 19 | 20 | @Mixin(LivingEntity.class) 21 | public class LivingEntityMixin { 22 | @WrapOperation(method = "applyFoodEffects", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/FoodComponent;getStatusEffects()Ljava/util/List;")) 23 | private List> extraorigins$foodEffectImmunity(FoodComponent instance, Operation>> original) { 24 | List> effects = original.call(instance); 25 | if (!effects.isEmpty()) { 26 | List powers = PowerHolderComponent.getPowers((LivingEntity) (Object) this, FoodEffectImmunityPower.class); 27 | if (!powers.isEmpty()) { 28 | effects = new ArrayList<>(effects); 29 | for (FoodEffectImmunityPower foodEffectImmunityPower : powers) { 30 | for (int i = effects.size() - 1; i >= 0; i--) { 31 | if (foodEffectImmunityPower.shouldRemove(effects.get(i).getFirst().getEffectType())) { 32 | effects.remove(i); 33 | } 34 | } 35 | } 36 | } 37 | } 38 | return effects; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/moriyashiine/extraorigins/client/particle/SporeParticle.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) MoriyaShiine. All Rights Reserved. 3 | */ 4 | package moriyashiine.extraorigins.client.particle; 5 | 6 | import net.minecraft.client.particle.*; 7 | import net.minecraft.client.world.ClientWorld; 8 | import net.minecraft.particle.DefaultParticleType; 9 | 10 | public class SporeParticle extends SpriteBillboardParticle { 11 | protected SporeParticle(ClientWorld clientWorld, double posX, double posY, double posZ, double velocityX, double velocityY, double velocityZ) { 12 | super(clientWorld, posX, posY, posZ, velocityX, velocityY, velocityZ); 13 | setBoundingBoxSpacing(0.02F, 0.02F); 14 | scale *= 0.1F; 15 | this.velocityX *= 0.02F; 16 | this.velocityY *= 0.02F; 17 | this.velocityZ *= 0.02F; 18 | maxAge = (int) (20 / (Math.random() * 0.8 + 0.2)); 19 | } 20 | 21 | @Override 22 | public ParticleTextureSheet getType() { 23 | return ParticleTextureSheet.PARTICLE_SHEET_OPAQUE; 24 | } 25 | 26 | @Override 27 | public void tick() { 28 | prevPosX = x; 29 | prevPosY = y; 30 | prevPosZ = z; 31 | if (maxAge-- <= 0) { 32 | markDead(); 33 | return; 34 | } 35 | move(velocityX, velocityY, velocityZ); 36 | velocityX *= 0.99; 37 | velocityY *= 0.99; 38 | velocityZ *= 0.99; 39 | } 40 | 41 | @Override 42 | public void move(double dx, double dy, double dz) { 43 | setBoundingBox(getBoundingBox().offset(dx, dy, dz)); 44 | repositionFromBoundingBox(); 45 | } 46 | 47 | public static class Factory implements ParticleFactory { 48 | private final SpriteProvider spriteProvider; 49 | 50 | public Factory(SpriteProvider spriteProvider) { 51 | this.spriteProvider = spriteProvider; 52 | } 53 | 54 | @Override 55 | public Particle createParticle(DefaultParticleType defaultParticleType, ClientWorld clientWorld, double posX, double posY, double posZ, double velocityX, double velocityY, double velocityZ) { 56 | SporeParticle particle = new SporeParticle(clientWorld, posX, posY, posZ, velocityX, velocityY, velocityZ); 57 | particle.setSprite(spriteProvider); 58 | return particle; 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/moriyashiine/extraorigins/mixin/foodeffectimmunity/SuspiciousStewItemMixin.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) MoriyaShiine. All Rights Reserved. 3 | */ 4 | package moriyashiine.extraorigins.mixin.foodeffectimmunity; 5 | 6 | import com.google.common.collect.ImmutableList; 7 | import io.github.apace100.apoli.component.PowerHolderComponent; 8 | import moriyashiine.extraorigins.common.power.FoodEffectImmunityPower; 9 | import net.minecraft.block.SuspiciousStewIngredient; 10 | import net.minecraft.entity.LivingEntity; 11 | import net.minecraft.item.ItemStack; 12 | import net.minecraft.item.SuspiciousStewItem; 13 | import net.minecraft.world.World; 14 | import org.spongepowered.asm.mixin.Mixin; 15 | import org.spongepowered.asm.mixin.Unique; 16 | import org.spongepowered.asm.mixin.injection.At; 17 | import org.spongepowered.asm.mixin.injection.Inject; 18 | import org.spongepowered.asm.mixin.injection.ModifyVariable; 19 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; 20 | 21 | import java.util.List; 22 | 23 | @Mixin(SuspiciousStewItem.class) 24 | public class SuspiciousStewItemMixin { 25 | @Unique 26 | private static LivingEntity cachedEntity = null; 27 | 28 | @Inject(method = "finishUsing", at = @At("HEAD")) 29 | private void extraorigins$cacheLivingBefore(ItemStack stack, World world, LivingEntity user, CallbackInfoReturnable cir) { 30 | cachedEntity = user; 31 | } 32 | 33 | @ModifyVariable(method = "method_53207", at = @At("HEAD"), argsOnly = true) 34 | private static List extraorigins$foodEffectImmunity(List list) { 35 | if (PowerHolderComponent.hasPower(cachedEntity, FoodEffectImmunityPower.class)) { 36 | ImmutableList.Builder newList = ImmutableList.builder(); 37 | for (SuspiciousStewIngredient.StewEffect stewEffect : list) { 38 | if (PowerHolderComponent.getPowers(cachedEntity, FoodEffectImmunityPower.class).stream().noneMatch(foodEffectImmunityPower -> foodEffectImmunityPower.shouldRemove(stewEffect.effect()))) { 39 | newList.add(stewEffect); 40 | } 41 | } 42 | cachedEntity = null; 43 | return newList.build(); 44 | } 45 | return list; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/moriyashiine/extraorigins/mixin/modifyitemattribute/client/ItemStackMixin.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) MoriyaShiine. All Rights Reserved. 3 | */ 4 | package moriyashiine.extraorigins.mixin.modifyitemattribute.client; 5 | 6 | import com.google.common.collect.LinkedHashMultimap; 7 | import com.google.common.collect.Multimap; 8 | import com.llamalad7.mixinextras.injector.wrapoperation.Operation; 9 | import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; 10 | import io.github.apace100.apoli.component.PowerHolderComponent; 11 | import io.github.apace100.apoli.util.AttributedEntityAttributeModifier; 12 | import moriyashiine.extraorigins.common.power.ModifyItemAttributePower; 13 | import net.minecraft.entity.EquipmentSlot; 14 | import net.minecraft.entity.attribute.EntityAttribute; 15 | import net.minecraft.entity.attribute.EntityAttributeModifier; 16 | import net.minecraft.entity.player.PlayerEntity; 17 | import net.minecraft.item.ItemStack; 18 | import org.jetbrains.annotations.Nullable; 19 | import org.spongepowered.asm.mixin.Mixin; 20 | import org.spongepowered.asm.mixin.injection.At; 21 | 22 | import java.util.List; 23 | 24 | @Mixin(ItemStack.class) 25 | public class ItemStackMixin { 26 | @WrapOperation(method = "getTooltip", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;getAttributeModifiers(Lnet/minecraft/entity/EquipmentSlot;)Lcom/google/common/collect/Multimap;")) 27 | private Multimap extraorigins$addToolBonusTooltips(ItemStack instance, EquipmentSlot slot, Operation> original, @Nullable PlayerEntity player) { 28 | Multimap value = original.call(instance, slot); 29 | if (player != null && !value.isEmpty()) { 30 | List powers = PowerHolderComponent.getPowers(player, ModifyItemAttributePower.class); 31 | if (!powers.isEmpty()) { 32 | value = LinkedHashMultimap.create(value); 33 | for (ModifyItemAttributePower power : powers) { 34 | if (slot == power.getSlot() && power.doesApply(instance)) { 35 | for (AttributedEntityAttributeModifier modifier : power.getModifiers()) { 36 | value.put(modifier.getAttribute(), modifier.getModifier()); 37 | } 38 | } 39 | } 40 | } 41 | } 42 | return value; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/moriyashiine/extraorigins/client/ExtraOriginsClient.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) MoriyaShiine. All Rights Reserved. 3 | */ 4 | package moriyashiine.extraorigins.client; 5 | 6 | import moriyashiine.extraorigins.client.event.DelayedHitboxEvent; 7 | import moriyashiine.extraorigins.client.event.RadialMenuEvents; 8 | import moriyashiine.extraorigins.client.event.RandomPowerGranterClientEvent; 9 | import moriyashiine.extraorigins.client.packet.MarkRadialDirectionChangedPacket; 10 | import moriyashiine.extraorigins.client.packet.MountS2CPacket; 11 | import moriyashiine.extraorigins.client.packet.NotifyRandomPowerChangePacket; 12 | import moriyashiine.extraorigins.client.particle.SporeParticle; 13 | import moriyashiine.extraorigins.common.init.ModParticleTypes; 14 | import net.fabricmc.api.ClientModInitializer; 15 | import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; 16 | import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; 17 | import net.fabricmc.fabric.api.client.particle.v1.ParticleFactoryRegistry; 18 | import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback; 19 | 20 | public class ExtraOriginsClient implements ClientModInitializer { 21 | @Override 22 | public void onInitializeClient() { 23 | initPackets(); 24 | initParticles(); 25 | RadialMenuEvents.init(); 26 | ClientTickEvents.END_WORLD_TICK.register(new DelayedHitboxEvent()); 27 | ClientTickEvents.END_WORLD_TICK.register(new RandomPowerGranterClientEvent.ClientTick()); 28 | HudRenderCallback.EVENT.register(new RandomPowerGranterClientEvent.Hud()); 29 | } 30 | 31 | private void initPackets() { 32 | ClientPlayNetworking.registerGlobalReceiver(MountS2CPacket.ID, new MountS2CPacket.Receiver()); 33 | ClientPlayNetworking.registerGlobalReceiver(MarkRadialDirectionChangedPacket.ID, new MarkRadialDirectionChangedPacket.Receiver()); 34 | ClientPlayNetworking.registerGlobalReceiver(NotifyRandomPowerChangePacket.ID, new NotifyRandomPowerChangePacket.Receiver()); 35 | } 36 | 37 | private void initParticles() { 38 | ParticleFactoryRegistry.getInstance().register(ModParticleTypes.OFFENSE_SPORE, SporeParticle.Factory::new); 39 | ParticleFactoryRegistry.getInstance().register(ModParticleTypes.DEFENSE_SPORE, SporeParticle.Factory::new); 40 | ParticleFactoryRegistry.getInstance().register(ModParticleTypes.MOBILITY_SPORE, SporeParticle.Factory::new); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/moriyashiine/extraorigins/common/packet/ChangeRadialDirectionPacket.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) MoriyaShiine. All Rights Reserved. 3 | */ 4 | package moriyashiine.extraorigins.common.packet; 5 | 6 | import io.github.apace100.apoli.component.PowerHolderComponent; 7 | import io.github.apace100.apoli.data.ApoliDataTypes; 8 | import io.github.apace100.apoli.power.PowerType; 9 | import io.github.apace100.apoli.power.PowerTypeReference; 10 | import io.netty.buffer.Unpooled; 11 | import moriyashiine.extraorigins.client.packet.MarkRadialDirectionChangedPacket; 12 | import moriyashiine.extraorigins.common.ExtraOrigins; 13 | import moriyashiine.extraorigins.common.power.RadialMenuPower; 14 | import moriyashiine.extraorigins.common.util.RadialMenuDirection; 15 | import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; 16 | import net.fabricmc.fabric.api.networking.v1.PacketSender; 17 | import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; 18 | import net.minecraft.network.PacketByteBuf; 19 | import net.minecraft.server.MinecraftServer; 20 | import net.minecraft.server.network.ServerPlayNetworkHandler; 21 | import net.minecraft.server.network.ServerPlayerEntity; 22 | import net.minecraft.util.Identifier; 23 | 24 | import java.util.Locale; 25 | 26 | public class ChangeRadialDirectionPacket { 27 | public static final Identifier ID = ExtraOrigins.id("change_radial_direction"); 28 | 29 | public static void send(RadialMenuDirection direction, PowerType powerType) { 30 | PacketByteBuf buf = new PacketByteBuf(Unpooled.buffer()); 31 | buf.writeString(direction.toString().toUpperCase(Locale.ROOT)); 32 | ApoliDataTypes.POWER_TYPE.send(buf, new PowerTypeReference<>(powerType.getIdentifier())); 33 | ClientPlayNetworking.send(ID, buf); 34 | } 35 | 36 | public static class Receiver implements ServerPlayNetworking.PlayChannelHandler { 37 | @Override 38 | public void receive(MinecraftServer server, ServerPlayerEntity player, ServerPlayNetworkHandler handler, PacketByteBuf buf, PacketSender responseSender) { 39 | String direction = buf.readString(); 40 | PowerTypeReference power = ApoliDataTypes.POWER_TYPE.receive(buf); 41 | server.execute(() -> { 42 | if (power.get(player) instanceof RadialMenuPower radialMenuPower) { 43 | radialMenuPower.setDirection(RadialMenuDirection.valueOf(direction)); 44 | PowerHolderComponent.syncPower(player, radialMenuPower.getType()); 45 | MarkRadialDirectionChangedPacket.send(player); 46 | } 47 | }); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Extra Origins 2 | 3 | Adds more origins to the [Origins](https://modrinth.com/mod/origins) mod, requires [Pehkui](https://modrinth.com/mod/pehkui) 4 | 5 | ``` 6 | 🌲 Floran 🌲 7 | + You can grow plants at the cost of hunger. 8 | + You are satiated by being exposed to sunlight. 9 | + You gain strength when exposed to water. 10 | - You take twice as much damage from fire. 11 | - You can only consume honey bottles. 12 | 13 | 🍄 Truffle 🍄 14 | +- You can switch between different Magic Spores. Red Cap boosts offense, Green Cap boosts defense, and Blue Cap boosts mobility. Changing Spores will decrease the abilities of the other two Caps. 15 | + You can turn soil blocks into mycelium at the cost of hunger. 16 | + You gain bonuses based on the Spore you have active when standing on mycelium. Red Cap increases attack speed, Green Cap grants knockback immunity, and Blue Cap amplifies jump height while sprinting.. 17 | +- Food is decomposed before it's consumed, nullifying any status effects you would otherwise gain. 18 | 19 | 🔨 Inchling 🔨 20 | +- You are significantly smaller than a human and have half as much health. 21 | + You are immune to thorns and velocity based damage. You are not slowed by blocks such as sweet berry bushes or cobwebs. You can walk on powder snow. 22 | + You exhaust much slower than others, requiring you to eat less. 23 | + You are able to climb up any kind of wall, not just ladders. 24 | + You can ride other players. 25 | 26 | 🪙 Piglin 🪙 27 | + Golden tools deal extra damage and golden armor has additional protection. Golden equipment lasts much longer. 28 | + You deal 75% more damage with crossbows. 29 | + Piglins do not attack you unless provoked. Brutes will still attack on sight. 30 | - Your natural spawn will be in the Nether. 31 | +- When outside of the Nether, you zombify, becoming undead and immune to fire, but weaker. Eating golden food negates this effect for a while. 32 | - Your diet is restricted to meat, you can't eat vegetables. Golden food is still edible. 33 | - You have 2 less hearts of health than humans. 34 | - You are afraid of soul fire, becoming weak when near it. 35 | 36 | ⚛️ Nucleon ⚛️ 37 | +- You have 3 random powers, each of which will decay into a new power after a certain amount of time. 38 | ``` 39 | 40 | ## External Links 41 | Support me on Ko-fi! I release new versions of my mods early here <3 42 | 43 | [![Ko-fi](https://i.imgur.com/6pkJV6h.png)](https://ko-fi.com/moriyashiine) 44 | 45 | Join my Discord! 46 | 47 | [![Discord](https://i.imgur.com/72QzxP1.png)](https://discord.gg/Am6M8VQ) -------------------------------------------------------------------------------- /src/main/resources/data/extraorigins/powers/magic_spores.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "extraorigins:radial_menu", 3 | "key": { 4 | "key": "key.origins.primary_active" 5 | }, 6 | "sprite_location": "extraorigins:textures/gui/icons.png", 7 | "up_action": { 8 | "type": "origins:and", 9 | "actions": [ 10 | { 11 | "type": "origins:grant_power", 12 | "power": "extraorigins:mobility_spores", 13 | "source": "extraorigins:magic_spores" 14 | }, 15 | { 16 | "type": "origins:revoke_power", 17 | "power": "extraorigins:defense_spores", 18 | "source": "extraorigins:magic_spores" 19 | }, 20 | { 21 | "type": "origins:revoke_power", 22 | "power": "extraorigins:offense_spores", 23 | "source": "extraorigins:magic_spores" 24 | }, 25 | { 26 | "type": "origins:play_sound", 27 | "sound": "extraorigins:entity.generic.spore_shift" 28 | } 29 | ] 30 | }, 31 | "left_action": { 32 | "type": "origins:and", 33 | "actions": [ 34 | { 35 | "type": "origins:grant_power", 36 | "power": "extraorigins:offense_spores", 37 | "source": "extraorigins:magic_spores" 38 | }, 39 | { 40 | "type": "origins:revoke_power", 41 | "power": "extraorigins:defense_spores", 42 | "source": "extraorigins:magic_spores" 43 | }, 44 | { 45 | "type": "origins:revoke_power", 46 | "power": "extraorigins:mobility_spores", 47 | "source": "extraorigins:magic_spores" 48 | }, 49 | { 50 | "type": "origins:play_sound", 51 | "sound": "extraorigins:entity.generic.spore_shift" 52 | } 53 | ] 54 | }, 55 | "right_action": { 56 | "type": "origins:and", 57 | "actions": [ 58 | { 59 | "type": "origins:grant_power", 60 | "power": "extraorigins:defense_spores", 61 | "source": "extraorigins:magic_spores" 62 | }, 63 | { 64 | "type": "origins:revoke_power", 65 | "power": "extraorigins:offense_spores", 66 | "source": "extraorigins:magic_spores" 67 | }, 68 | { 69 | "type": "origins:revoke_power", 70 | "power": "extraorigins:mobility_spores", 71 | "source": "extraorigins:magic_spores" 72 | }, 73 | { 74 | "type": "origins:play_sound", 75 | "sound": "extraorigins:entity.generic.spore_shift" 76 | } 77 | ] 78 | }, 79 | "lost_action": { 80 | "type": "origins:and", 81 | "actions": [ 82 | { 83 | "type": "origins:revoke_power", 84 | "power": "extraorigins:offense_spores", 85 | "source": "extraorigins:magic_spores" 86 | }, 87 | { 88 | "type": "origins:revoke_power", 89 | "power": "extraorigins:defense_spores", 90 | "source": "extraorigins:magic_spores" 91 | }, 92 | { 93 | "type": "origins:revoke_power", 94 | "power": "extraorigins:mobility_spores", 95 | "source": "extraorigins:magic_spores" 96 | } 97 | ] 98 | } 99 | } -------------------------------------------------------------------------------- /src/main/resources/data/extraorigins/powers/rooted.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "origins:multiple", 3 | "mobility": { 4 | "type": "origins:modify_jump", 5 | "condition": { 6 | "type": "origins:and", 7 | "conditions": [ 8 | { 9 | "type": "extraorigins:radial_menu_direction", 10 | "direction": "up", 11 | "power": "extraorigins:magic_spores" 12 | }, 13 | { 14 | "type": "origins:sprinting" 15 | }, 16 | { 17 | "type": "origins:on_block", 18 | "block_condition": { 19 | "type": "origins:block", 20 | "block": "minecraft:mycelium" 21 | } 22 | } 23 | ] 24 | }, 25 | "modifier": { 26 | "name": "Origins modifier", 27 | "operation": "addition", 28 | "value": 0.4 29 | } 30 | }, 31 | "mobility_fall_immunity": { 32 | "type": "origins:invulnerability", 33 | "condition": { 34 | "type": "origins:and", 35 | "conditions": [ 36 | { 37 | "type": "extraorigins:radial_menu_direction", 38 | "direction": "up", 39 | "power": "extraorigins:magic_spores" 40 | }, 41 | { 42 | "type": "origins:block_in_radius", 43 | "block_condition": { 44 | "type": "origins:block", 45 | "block": "minecraft:mycelium" 46 | }, 47 | "radius": 1 48 | } 49 | ] 50 | }, 51 | "damage_condition": { 52 | "type": "origins:name", 53 | "name": "fall" 54 | } 55 | }, 56 | "offense": { 57 | "type": "origins:conditioned_attribute", 58 | "condition": { 59 | "type": "origins:and", 60 | "conditions": [ 61 | { 62 | "type": "extraorigins:radial_menu_direction", 63 | "direction": "left", 64 | "power": "extraorigins:magic_spores" 65 | }, 66 | { 67 | "type": "origins:on_block", 68 | "block_condition": { 69 | "type": "origins:block", 70 | "block": "minecraft:mycelium" 71 | } 72 | } 73 | ] 74 | }, 75 | "modifier": { 76 | "name": "Origins modifier", 77 | "attribute": "minecraft:generic.attack_speed", 78 | "operation": "addition", 79 | "value": 0.4 80 | } 81 | }, 82 | "defense": { 83 | "type": "origins:conditioned_attribute", 84 | "condition": { 85 | "type": "origins:and", 86 | "conditions": [ 87 | { 88 | "type": "extraorigins:radial_menu_direction", 89 | "direction": "right", 90 | "power": "extraorigins:magic_spores" 91 | }, 92 | { 93 | "type": "origins:on_block", 94 | "block_condition": { 95 | "type": "origins:block", 96 | "block": "minecraft:mycelium" 97 | } 98 | } 99 | ] 100 | }, 101 | "modifier": { 102 | "name": "Origins modifier", 103 | "attribute": "minecraft:generic.knockback_resistance", 104 | "operation": "addition", 105 | "value": 10 106 | } 107 | } 108 | } -------------------------------------------------------------------------------- /src/main/resources/data/extraorigins/powers/homesick.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "origins:multiple", 3 | "change_group": { 4 | "type": "origins:entity_group", 5 | "condition": { 6 | "type": "origins:and", 7 | "conditions": [ 8 | { 9 | "type": "extraorigins:piglin_safe", 10 | "inverted": true 11 | }, 12 | { 13 | "type": "origins:resource", 14 | "resource": "extraorigins:homesick_timer", 15 | "comparison": "==", 16 | "compare_to": 0 17 | } 18 | ] 19 | }, 20 | "group": "undead" 21 | }, 22 | "fire_immunity": { 23 | "type": "origins:fire_immunity", 24 | "condition": { 25 | "type": "origins:and", 26 | "conditions": [ 27 | { 28 | "type": "extraorigins:piglin_safe", 29 | "inverted": true 30 | }, 31 | { 32 | "type": "origins:resource", 33 | "resource": "extraorigins:homesick_timer", 34 | "comparison": "==", 35 | "compare_to": 0 36 | } 37 | ] 38 | } 39 | }, 40 | "weakness": { 41 | "type": "origins:stacking_status_effect", 42 | "condition": { 43 | "type": "origins:and", 44 | "conditions": [ 45 | { 46 | "type": "extraorigins:piglin_safe", 47 | "inverted": true 48 | }, 49 | { 50 | "type": "origins:resource", 51 | "resource": "extraorigins:homesick_timer", 52 | "comparison": "==", 53 | "compare_to": 0 54 | } 55 | ] 56 | }, 57 | "min_stacks": 0, 58 | "max_stacks": 1, 59 | "duration_per_stack": 30, 60 | "effect": { 61 | "effect": "minecraft:weakness", 62 | "is_ambient": true, 63 | "show_particles": false, 64 | "show_icon": true 65 | } 66 | }, 67 | "shaking": { 68 | "type": "origins:shaking", 69 | "condition": { 70 | "type": "origins:and", 71 | "conditions": [ 72 | { 73 | "type": "extraorigins:piglin_safe", 74 | "inverted": true 75 | }, 76 | { 77 | "type": "origins:resource", 78 | "resource": "extraorigins:homesick_timer", 79 | "comparison": "==", 80 | "compare_to": 0 81 | } 82 | ] 83 | } 84 | }, 85 | "timer": { 86 | "type": "origins:cooldown", 87 | "cooldown": 3600, 88 | "hud_render": { 89 | "sprite_location": "extraorigins:textures/gui/resource_bar.png", 90 | "condition": { 91 | "type": "origins:resource", 92 | "resource": "extraorigins:homesick_timer", 93 | "comparison": ">", 94 | "compare_to": 0 95 | }, 96 | "inverted": true 97 | } 98 | }, 99 | "set_timer": { 100 | "type": "origins:action_on_item_use", 101 | "entity_action": { 102 | "type": "origins:trigger_cooldown", 103 | "power": "extraorigins:homesick_timer" 104 | }, 105 | "item_condition": { 106 | "type": "origins:ingredient", 107 | "ingredient": { 108 | "tag": "extraorigins:golden_food" 109 | } 110 | } 111 | } 112 | } -------------------------------------------------------------------------------- /src/main/resources/data/extraorigins/powers/all_that_glitters.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "origins:multiple", 3 | "golden_head_boost": { 4 | "type": "extraorigins:modify_item_attribute", 5 | "equipment_slot": "head", 6 | "item_condition": { 7 | "type": "origins:ingredient", 8 | "ingredient": { 9 | "tag": "extraorigins:golden_armor" 10 | } 11 | }, 12 | "modifier": { 13 | "name": "Origin modifier", 14 | "attribute": "minecraft:generic.armor", 15 | "operation": "addition", 16 | "value": 1 17 | } 18 | }, 19 | "golden_chest_boost": { 20 | "type": "extraorigins:modify_item_attribute", 21 | "equipment_slot": "chest", 22 | "item_condition": { 23 | "type": "origins:ingredient", 24 | "ingredient": { 25 | "tag": "extraorigins:golden_armor" 26 | } 27 | }, 28 | "modifier": { 29 | "name": "Origin modifier", 30 | "attribute": "minecraft:generic.armor", 31 | "operation": "addition", 32 | "value": 2 33 | } 34 | }, 35 | "golden_legs_boost": { 36 | "type": "extraorigins:modify_item_attribute", 37 | "equipment_slot": "legs", 38 | "item_condition": { 39 | "type": "origins:ingredient", 40 | "ingredient": { 41 | "tag": "extraorigins:golden_armor" 42 | } 43 | }, 44 | "modifier": { 45 | "name": "Origin modifier", 46 | "attribute": "minecraft:generic.armor", 47 | "operation": "addition", 48 | "value": 2 49 | } 50 | }, 51 | "golden_feet_boost": { 52 | "type": "extraorigins:modify_item_attribute", 53 | "equipment_slot": "feet", 54 | "item_condition": { 55 | "type": "origins:ingredient", 56 | "ingredient": { 57 | "tag": "extraorigins:golden_armor" 58 | } 59 | }, 60 | "modifier": { 61 | "name": "Origin modifier", 62 | "attribute": "minecraft:generic.armor", 63 | "operation": "addition", 64 | "value": 1 65 | } 66 | }, 67 | "golden_mainhand_boost": { 68 | "type": "extraorigins:modify_item_attribute", 69 | "equipment_slot": "mainhand", 70 | "item_condition": { 71 | "type": "origins:ingredient", 72 | "ingredient": { 73 | "tag": "extraorigins:golden_tools" 74 | } 75 | }, 76 | "modifier": { 77 | "name": "Origin modifier", 78 | "attribute": "minecraft:generic.attack_damage", 79 | "operation": "addition", 80 | "value": 2.5 81 | } 82 | }, 83 | "golden_armor_durability_multiplier": { 84 | "type": "extraorigins:innate_unbreaking", 85 | "item_condition": { 86 | "type": "origins:ingredient", 87 | "ingredient": { 88 | "tag": "extraorigins:golden_armor" 89 | } 90 | }, 91 | "level": 3 92 | }, 93 | "golden_tool_durability_multiplier": { 94 | "type": "extraorigins:innate_unbreaking", 95 | "item_condition": { 96 | "type": "origins:ingredient", 97 | "ingredient": { 98 | "tag": "extraorigins:golden_tools" 99 | } 100 | }, 101 | "level": 15 102 | } 103 | } -------------------------------------------------------------------------------- /src/main/java/moriyashiine/extraorigins/common/init/ModActions.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) MoriyaShiine. All Rights Reserved. 3 | */ 4 | package moriyashiine.extraorigins.common.init; 5 | 6 | import com.jamieswhiteshirt.reachentityattributes.ReachEntityAttributes; 7 | import io.github.apace100.apoli.data.ApoliDataTypes; 8 | import io.github.apace100.apoli.power.factory.action.ActionFactory; 9 | import io.github.apace100.apoli.registry.ApoliRegistries; 10 | import io.github.apace100.calio.data.SerializableData; 11 | import moriyashiine.extraorigins.common.ExtraOrigins; 12 | import net.minecraft.block.pattern.CachedBlockPosition; 13 | import net.minecraft.entity.Entity; 14 | import net.minecraft.entity.LivingEntity; 15 | import net.minecraft.entity.player.PlayerEntity; 16 | import net.minecraft.registry.Registry; 17 | import net.minecraft.util.hit.BlockHitResult; 18 | import net.minecraft.util.math.BlockPos; 19 | import net.minecraft.util.math.Direction; 20 | import net.minecraft.world.RaycastContext; 21 | import net.minecraft.world.World; 22 | import org.apache.commons.lang3.tuple.Triple; 23 | 24 | import java.util.List; 25 | import java.util.function.Predicate; 26 | 27 | public class ModActions { 28 | public static ActionFactory BLOCK_ACTION_LOOKING_AT = new ActionFactory<>(ExtraOrigins.id("block_action_looking_at"), new SerializableData().add("block_condition", ApoliDataTypes.BLOCK_CONDITION).add("block_action", ApoliDataTypes.BLOCK_ACTION).add("entity_action", ApoliDataTypes.ENTITY_ACTION, null).add("entity_actions", ApoliDataTypes.ENTITY_ACTIONS, null), 29 | (data, entity) -> { 30 | if (entity instanceof LivingEntity living) { 31 | BlockHitResult hitResult = entity.getWorld().raycast(new RaycastContext(entity.getEyePos(), entity.getEyePos().add(entity.getRotationVector().multiply(ReachEntityAttributes.getReachDistance(living, entity instanceof PlayerEntity player && player.isCreative() ? 5 : 4.5))), RaycastContext.ShapeType.OUTLINE, RaycastContext.FluidHandling.NONE, entity)); 32 | Predicate blockCondition = data.get("block_condition"); 33 | if (blockCondition.test(new CachedBlockPosition(entity.getWorld(), hitResult.getBlockPos(), false))) { 34 | //noinspection unchecked 35 | ((ActionFactory>.Instance) data.get("block_action")).accept(Triple.of(entity.getWorld(), hitResult.getBlockPos(), Direction.UP)); 36 | List.Instance> entityActions = data.get("entity_actions"); 37 | if (entityActions != null) { 38 | entityActions.forEach(action -> action.accept(entity)); 39 | } else { 40 | ActionFactory.Instance entityAction = data.get("entity_action"); 41 | if (entityAction != null) { 42 | entityAction.accept(entity); 43 | } 44 | } 45 | } 46 | } 47 | }); 48 | 49 | public static void init() { 50 | Registry.register(ApoliRegistries.ENTITY_ACTION, BLOCK_ACTION_LOOKING_AT.getSerializerId(), BLOCK_ACTION_LOOKING_AT); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/moriyashiine/extraorigins/common/init/ModConditions.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) MoriyaShiine. All Rights Reserved. 3 | */ 4 | package moriyashiine.extraorigins.common.init; 5 | 6 | import io.github.apace100.apoli.data.ApoliDataTypes; 7 | import io.github.apace100.apoli.power.PowerTypeReference; 8 | import io.github.apace100.apoli.power.factory.condition.ConditionFactory; 9 | import io.github.apace100.apoli.registry.ApoliRegistries; 10 | import io.github.apace100.calio.data.SerializableData; 11 | import io.github.apace100.calio.data.SerializableDataType; 12 | import moriyashiine.extraorigins.common.ExtraOrigins; 13 | import moriyashiine.extraorigins.common.power.RadialMenuPower; 14 | import moriyashiine.extraorigins.common.util.RadialMenuDirection; 15 | import net.minecraft.block.Fertilizable; 16 | import net.minecraft.block.pattern.CachedBlockPosition; 17 | import net.minecraft.entity.Entity; 18 | import net.minecraft.entity.damage.DamageSource; 19 | import net.minecraft.entity.projectile.PersistentProjectileEntity; 20 | import net.minecraft.registry.Registry; 21 | import net.minecraft.util.Pair; 22 | 23 | public class ModConditions { 24 | public static final ConditionFactory FERTILIZABLE = new ConditionFactory<>(ExtraOrigins.id("fertilizable"), new SerializableData(), (data, cachedBlockPosition) -> cachedBlockPosition.getBlockState().getBlock() instanceof Fertilizable fertilizable && fertilizable.isFertilizable(cachedBlockPosition.getWorld(), cachedBlockPosition.getBlockPos(), cachedBlockPosition.getBlockState())); 25 | 26 | public static final ConditionFactory> SHOT_FROM_CROSSBOW = new ConditionFactory<>(ExtraOrigins.id("shot_from_crossbow"), new SerializableData(), (data, damageSourceFloatPair) -> damageSourceFloatPair.getLeft().getSource() instanceof PersistentProjectileEntity projectile && projectile.isShotFromCrossbow()); 27 | 28 | public static final ConditionFactory PIGLIN_SAFE = new ConditionFactory<>(ExtraOrigins.id("piglin_safe"), new SerializableData(), (data, entity) -> entity.getWorld().getDimension().piglinSafe()); 29 | public static final ConditionFactory RADIAL_MENU_DIRECTION = new ConditionFactory<>(ExtraOrigins.id("radial_menu_direction"), new SerializableData().add("direction", SerializableDataType.enumValue(RadialMenuDirection.class)).add("power", ApoliDataTypes.POWER_TYPE), (data, entity) -> { 30 | if (((PowerTypeReference) data.get("power")).get(entity) instanceof RadialMenuPower radialMenuPower) { 31 | return radialMenuPower.isActive() && radialMenuPower.getDirection() == data.get("direction"); 32 | } 33 | return false; 34 | }); 35 | 36 | public static void init() { 37 | Registry.register(ApoliRegistries.BLOCK_CONDITION, FERTILIZABLE.getSerializerId(), FERTILIZABLE); 38 | Registry.register(ApoliRegistries.DAMAGE_CONDITION, SHOT_FROM_CROSSBOW.getSerializerId(), SHOT_FROM_CROSSBOW); 39 | Registry.register(ApoliRegistries.ENTITY_CONDITION, PIGLIN_SAFE.getSerializerId(), PIGLIN_SAFE); 40 | Registry.register(ApoliRegistries.ENTITY_CONDITION, RADIAL_MENU_DIRECTION.getSerializerId(), RADIAL_MENU_DIRECTION); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%"=="" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%"=="" set DIRNAME=. 29 | @rem This is normally unused 30 | set APP_BASE_NAME=%~n0 31 | set APP_HOME=%DIRNAME% 32 | 33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 35 | 36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 38 | 39 | @rem Find java.exe 40 | if defined JAVA_HOME goto findJavaFromJavaHome 41 | 42 | set JAVA_EXE=java.exe 43 | %JAVA_EXE% -version >NUL 2>&1 44 | if %ERRORLEVEL% equ 0 goto execute 45 | 46 | echo. 1>&2 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 48 | echo. 1>&2 49 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 50 | echo location of your Java installation. 1>&2 51 | 52 | goto fail 53 | 54 | :findJavaFromJavaHome 55 | set JAVA_HOME=%JAVA_HOME:"=% 56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 57 | 58 | if exist "%JAVA_EXE%" goto execute 59 | 60 | echo. 1>&2 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 62 | echo. 1>&2 63 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 64 | echo location of your Java installation. 1>&2 65 | 66 | goto fail 67 | 68 | :execute 69 | @rem Setup the command line 70 | 71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 72 | 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if %ERRORLEVEL% equ 0 goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | set EXIT_CODE=%ERRORLEVEL% 85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 87 | exit /b %EXIT_CODE% 88 | 89 | :mainEnd 90 | if "%OS%"=="Windows_NT" endlocal 91 | 92 | :omega 93 | -------------------------------------------------------------------------------- /src/main/resources/assets/extraorigins/lang/zh_cn.json: -------------------------------------------------------------------------------- 1 | { 2 | "extraorigins.subtitles.block.mycelium.grow": "菌丝:生长", 3 | "extraorigins.subtitles.entity.generic.spore_shift": "孢子:切换", 4 | "origin.extraorigins.floran.name": "花灵族", 5 | "origin.extraorigins.floran.description": "一个从阳光中汲取营养,从水源中获得力量的种族。", 6 | "origin.extraorigins.truffle.name": "松露族", 7 | "origin.extraorigins.truffle.description": "松露族除了拥有真菌的常规属性之外,还拥有在空中随机应变的独特能力。", 8 | "origin.extraorigins.inchling.name": "尺灵族", 9 | "origin.extraorigins.inchling.description": "一种人类的亚种,体格极小。它们利用矮小的体格来躲避攻击,并在狭小的空间中穿梭。", 10 | "origin.extraorigins.piglin.name": "猪灵族", 11 | "origin.extraorigins.piglin.description": "猪灵族来自下界,它们喜欢黄金,同时也擅长利用黄金。", 12 | "power.extraorigins.absorbing.name": "吸水", 13 | "power.extraorigins.absorbing.description": "在水中你会获得力量效果。", 14 | "power.extraorigins.flammable.name": "易燃", 15 | "power.extraorigins.flammable.description": "你将会受到双倍的火焰伤害。", 16 | "power.extraorigins.green_thumb.name": "园丁", 17 | "power.extraorigins.green_thumb.description": "你可以通过消耗饥饿值来催熟植物", 18 | "power.extraorigins.nectarivore.name": "食蜜动物", 19 | "power.extraorigins.nectarivore.description": "你只能食用蜂蜜瓶。", 20 | "power.extraorigins.photosynthesis.name": "光合作用", 21 | "power.extraorigins.photosynthesis.description": "在阳光下,你会逐渐感觉到饱腹。", 22 | "power.extraorigins.decomposition.name": "分解", 23 | "power.extraorigins.decomposition.description": "食物在消化前就会被你分解,因此食物所提供的状态效果会失效。", 24 | "power.extraorigins.magic_spores.name": "魔法孢子", 25 | "power.extraorigins.magic_spores.description": "你可以切换到不同种类的魔法孢子。红色孢子增加攻击力,绿色孢子增加护甲值,蓝色孢子可以增加速度。切换孢子时会降低其他两个孢子提供的属性加成。", 26 | "power.extraorigins.infestation.name": "侵染", 27 | "power.extraorigins.infestation.description": "你可以通过消耗饥饿值来将固体方块变为菌丝。", 28 | "power.extraorigins.rooted.name": "扎根", 29 | "power.extraorigins.rooted.description": "当你站在菌丝体上时,你可以根据你激活的魔法孢子来获得对应的属性加成。红色孢子增加攻击速度,绿色孢子提供击退免疫,蓝色孢子增加冲刺时的跳跃高度。", 30 | "power.extraorigins.bite_sized.name": "小体格", 31 | "power.extraorigins.bite_sized.description": "你的体型显著地小于正常人类,最大生命值只有正常人类的一半。", 32 | "power.extraorigins.small_appetite.name": "小胃口", 33 | "power.extraorigins.small_appetite.description": "你的饥饿值消耗速度比其他人慢很多,也因此你吃得更少。", 34 | "power.extraorigins.nimble.name": "矫健", 35 | "power.extraorigins.nimble.description": "你免疫荆棘伤害和基于速度造成的伤害。诸如蜘蛛网和浆果丛这类方块不会使你减速。你可以在细雪上行走。", 36 | "power.extraorigins.jockey.name": "骑手", 37 | "power.extraorigins.jockey.description": "你可以骑乘其他玩家。", 38 | "power.extraorigins.all_that_glitters.name": "闪闪发光", 39 | "power.extraorigins.all_that_glitters.description": "使用金质工具造成的伤害提升;金质盔甲提供的盔甲值增加。金质装备的耐久提高。", 40 | "power.extraorigins.piglin_neutrality.name": "猪灵中立", 41 | "power.extraorigins.piglin_neutrality.description": "猪灵不会主动攻击你,除非你激怒他们。猪灵蛮兵仍会在看见你时主动攻击。", 42 | "power.extraorigins.crossbow_master.name": "万弩大师", 43 | "power.extraorigins.crossbow_master.description": "使用弩造成的伤害增加75%。", 44 | "power.extraorigins.flabby.name": "软弱", 45 | "power.extraorigins.flabby.description": "你的最大生命值比正常人类少2颗心。", 46 | "power.extraorigins.golden_gluttony.name": "‘金质’暴食者", 47 | "power.extraorigins.golden_gluttony.description": "你只能吃肉而不能吃蔬菜。金质食物仍然可以食用。", 48 | "power.extraorigins.homesick.name": "思乡病", 49 | "power.extraorigins.homesick.description": "当不在下界时,你将会僵尸化,成为亡灵生物并免疫火焰,但会变虚弱。吃下金质食物可以延缓这一效果一小会。", 50 | "power.extraorigins.soul_spooked.name": "惊魂", 51 | "power.extraorigins.soul_spooked.description": "你害怕灵魂火,靠近时会虚弱。" 52 | } 53 | -------------------------------------------------------------------------------- /src/main/resources/assets/extraorigins/lang/es_es.json: -------------------------------------------------------------------------------- 1 | { 2 | "origin.extraorigins.floran.name": "Florano", 3 | "origin.extraorigins.floran.description": "Una especie de gente planta que obtiene nutrientes por el sol y gana fuerza mojado.", 4 | "origin.extraorigins.inchling.name": "Inchling", 5 | "origin.extraorigins.inchling.description": "Una subespecie humana que es increíblemente pequeña. Utilizan su tamaño a su favor para esconderse de sus enemigos y pasar por sitios pequeños.", 6 | "origin.extraorigins.piglin.name": "Piglin", 7 | "origin.extraorigins.piglin.description": "Provinientes del nether, los Piglins aman el oro y son expertos en su uso.", 8 | "power.extraorigins.green_thumb.name": "Pulgar Verde", 9 | "power.extraorigins.green_thumb.description": "Puedes hacer que las plantas a tu alrededor crezcan a cambio de comida.", 10 | "power.extraorigins.photosynthesis.name": "Fotosíntesis", 11 | "power.extraorigins.photosynthesis.description": "Estar expuesto al sol te sacia.", 12 | "power.extraorigins.absorbing.name": "Absorpción", 13 | "power.extraorigins.absorbing.description": "Haces 2 más de daño cuando estás mojado.", 14 | "power.extraorigins.flammable.name": "Inflamable", 15 | "power.extraorigins.flammable.description": "El fuego te daña el doble.", 16 | "power.extraorigins.nectarivore.name": "Nectarívoro", 17 | "power.extraorigins.nectarivore.description": "Solo puedes consumir frascos con miel.", 18 | "power.extraorigins.bite_sized.name": "Enano", 19 | "power.extraorigins.bite_sized.description": "Eres 4 veces más pequeño que una persona normal. Tienes 5 corazones menos, 0.5 más de velocidad de ataque, 0.25 menos de rango de ataque y 1 bloque menos de alcanze para construir.", 20 | "power.extraorigins.small_appetite.name": "Poco Apetito", 21 | "power.extraorigins.small_appetite.description": "Necesitas comer menos.", 22 | "power.extraorigins.nimble.name": "Ágil", 23 | "power.extraorigins.nimble.description": "Eres inmune a el encantamiento espinas y daño basado en velocidad.", 24 | "power.extraorigins.all_that_glitters.name": "¡Brillante!", 25 | "power.extraorigins.all_that_glitters.description": "Las herramientas doradas inflijen más daño y la armadura dorada tiene protección adicional. Cualquier equipamiento dorado tiene mucha más durabilidad, pero cualquier otro equipo que no sea dorado o de netherita se rompe antes. La armadura de netherita da una pequeña bonificación de velocidad.", 26 | "power.extraorigins.piglin_neutrality.name": "Neutralidad Piglin", 27 | "power.extraorigins.piglin_neutrality.description": "Los piglins no te atacarán a no ser que sean provocados. Los brutos piglin seguirán atacándote en cuanto te vean.", 28 | "power.extraorigins.crossbow_master.name": "Maestro de la Ballesta", 29 | "power.extraorigins.crossbow_master.description": "Haces un 75% más de daño con ballestas.", 30 | "power.extraorigins.homesick.name": "Nostálgico", 31 | "power.extraorigins.homesick.description": "Cuando estés fuera del nether, te zombificarás. Esto te hará inmune al fuego, pero irás más lento.", 32 | "power.extraorigins.flabby.name": "Flojo", 33 | "power.extraorigins.flabby.description": "Tienes 2 corazones menos que los humanos.", 34 | "power.extraorigins.soul_spooked.name": "Miedo a las Almas", 35 | "power.extraorigins.soul_spooked.description": "Le tienes miedo al fuego de almas, por lo tanto, te vuelves débil a su alrededor." 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/moriyashiine/extraorigins/common/power/ModifyItemAttributePower.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) MoriyaShiine. All Rights Reserved. 3 | */ 4 | package moriyashiine.extraorigins.common.power; 5 | 6 | import io.github.apace100.apoli.data.ApoliDataTypes; 7 | import io.github.apace100.apoli.power.AttributePower; 8 | import io.github.apace100.apoli.power.PowerType; 9 | import io.github.apace100.apoli.power.factory.PowerFactory; 10 | import io.github.apace100.apoli.util.AttributedEntityAttributeModifier; 11 | import io.github.apace100.calio.data.SerializableData; 12 | import io.github.apace100.calio.data.SerializableDataTypes; 13 | import net.minecraft.entity.EquipmentSlot; 14 | import net.minecraft.entity.LivingEntity; 15 | import net.minecraft.item.ItemStack; 16 | import net.minecraft.util.Identifier; 17 | import net.minecraft.util.Pair; 18 | import net.minecraft.world.World; 19 | 20 | import java.util.List; 21 | import java.util.function.Predicate; 22 | 23 | public class ModifyItemAttributePower extends AttributePower { 24 | private final Predicate> itemCondition; 25 | private final EquipmentSlot slot; 26 | private final int tickRate; 27 | 28 | public ModifyItemAttributePower(PowerType type, LivingEntity entity, EquipmentSlot slot, Predicate> itemCondition, int tickRate, boolean updateHealth) { 29 | super(type, entity, updateHealth); 30 | this.itemCondition = itemCondition; 31 | this.slot = slot; 32 | this.tickRate = tickRate; 33 | setTicking(true); 34 | } 35 | 36 | @Override 37 | public void tick() { 38 | if (entity.age % tickRate != 0) { 39 | return; 40 | } 41 | for (EquipmentSlot slot : EquipmentSlot.values()) { 42 | if (this.slot == slot) { 43 | if (doesApply(entity.getEquippedStack(slot))) { 44 | applyTempMods(); 45 | } else { 46 | removeTempMods(); 47 | } 48 | } 49 | } 50 | } 51 | 52 | public List getModifiers() { 53 | return modifiers; 54 | } 55 | 56 | public EquipmentSlot getSlot() { 57 | return slot; 58 | } 59 | 60 | public boolean doesApply(ItemStack stack) { 61 | return itemCondition == null || itemCondition.test(new Pair<>(entity.getWorld(), stack)); 62 | } 63 | 64 | public static PowerFactory createFactory(Identifier identifier) { 65 | return new PowerFactory<>(identifier, 66 | new SerializableData() 67 | .add("equipment_slot", SerializableDataTypes.EQUIPMENT_SLOT) 68 | .add("item_condition", ApoliDataTypes.ITEM_CONDITION, null) 69 | .add("tick_rate", SerializableDataTypes.POSITIVE_INT, 20) 70 | .add("update_health", SerializableDataTypes.BOOLEAN, true) 71 | .add("modifier", ApoliDataTypes.ATTRIBUTED_ATTRIBUTE_MODIFIER, null) 72 | .add("modifiers", ApoliDataTypes.ATTRIBUTED_ATTRIBUTE_MODIFIERS, null), 73 | data -> (powerType, livingEntity) -> { 74 | ModifyItemAttributePower conditionedAttributePower = new ModifyItemAttributePower( 75 | powerType, 76 | livingEntity, 77 | data.get("equipment_slot"), 78 | data.get("item_condition"), 79 | data.getInt("tick_rate"), 80 | data.getBoolean("update_health") 81 | ); 82 | data.ifPresent("modifier", conditionedAttributePower::addModifier); 83 | data.>ifPresent("modifiers", mods -> mods.forEach(conditionedAttributePower::addModifier)); 84 | return conditionedAttributePower; 85 | }); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/main/java/moriyashiine/extraorigins/mixin/randompowergranter/client/OriginDisplayScreenMixin.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) MoriyaShiine. All Rights Reserved. 3 | */ 4 | package moriyashiine.extraorigins.mixin.randompowergranter.client; 5 | 6 | import com.llamalad7.mixinextras.injector.wrapoperation.Operation; 7 | import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; 8 | import io.github.apace100.apoli.power.PowerType; 9 | import io.github.apace100.origins.origin.Origin; 10 | import io.github.apace100.origins.screen.OriginDisplayScreen; 11 | import moriyashiine.extraorigins.client.event.RandomPowerGranterClientEvent; 12 | import moriyashiine.extraorigins.common.component.entity.RandomPowerGranterComponent; 13 | import moriyashiine.extraorigins.common.init.ModEntityComponents; 14 | import net.minecraft.client.gui.screen.Screen; 15 | import net.minecraft.text.MutableText; 16 | import net.minecraft.text.Text; 17 | import net.minecraft.util.Formatting; 18 | import org.spongepowered.asm.mixin.Mixin; 19 | import org.spongepowered.asm.mixin.Unique; 20 | import org.spongepowered.asm.mixin.injection.At; 21 | 22 | import java.util.ArrayList; 23 | import java.util.List; 24 | 25 | @Mixin(OriginDisplayScreen.class) 26 | public class OriginDisplayScreenMixin extends Screen { 27 | @Unique 28 | private final List> randomPowers = new ArrayList<>(); 29 | 30 | @Unique 31 | private int index = 0; 32 | 33 | protected OriginDisplayScreenMixin(Text title) { 34 | super(title); 35 | } 36 | 37 | @WrapOperation(method = "renderOriginContent", at = @At(value = "INVOKE", target = "Lio/github/apace100/origins/origin/Origin;getPowerTypes()Ljava/util/List;")) 38 | private List> extraorigins$randomPowerGranter(Origin instance, Operation>> original) { 39 | List> powerTypes = original.call(instance); 40 | randomPowers.clear(); 41 | index = 0; 42 | if (client != null && client.player != null) { 43 | RandomPowerGranterComponent randomPowerGranterComponent = ModEntityComponents.RANDOM_POWER_GRANTER.get(client.player); 44 | if (randomPowerGranterComponent.isEnabled()) { 45 | powerTypes = new ArrayList<>(powerTypes); 46 | for (RandomPowerGranterComponent.TemporaryPowerType temporaryPowerType : randomPowerGranterComponent.getTemporaryPowerTypes()) { 47 | powerTypes.add(temporaryPowerType.getPowerType()); 48 | randomPowers.add(temporaryPowerType.getPowerType()); 49 | } 50 | } 51 | } 52 | return powerTypes; 53 | } 54 | 55 | @WrapOperation(method = "renderOriginContent", at = @At(value = "INVOKE", target = "Lio/github/apace100/apoli/power/PowerType;getName()Lnet/minecraft/text/MutableText;")) 56 | private MutableText extraorigins$randomPowerGranter(PowerType instance, Operation original) { 57 | MutableText name = original.call(instance); 58 | if (randomPowers.contains(instance)) { 59 | name = Text.literal(RandomPowerGranterClientEvent.CHARACTERS[index] + " ").append(name); 60 | index++; 61 | } 62 | return name; 63 | } 64 | 65 | @WrapOperation(method = "renderOriginContent", at = @At(value = "INVOKE", target = "Lnet/minecraft/text/MutableText;formatted(Lnet/minecraft/util/Formatting;)Lnet/minecraft/text/MutableText;")) 66 | private MutableText extraorigins$randomPowerGranter(MutableText instance, Formatting formatting, Operation original) { 67 | MutableText formatted = original.call(instance, formatting); 68 | if (index > 0) { 69 | return formatted.formatted(RandomPowerGranterClientEvent.FORMATTING[index - 1]); 70 | } 71 | return formatted; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/main/resources/assets/extraorigins/lang/pl_pl.json: -------------------------------------------------------------------------------- 1 | { 2 | "origin.extraorigins.floran.name": "Floran", 3 | "origin.extraorigins.floran.description": "Gatunek roślinoludzi, które czerpią składniki odżywcze ze słońca i zyskują siłę z wody.", 4 | "origin.extraorigins.inchling.name": "Calin", 5 | "origin.extraorigins.inchling.description": "Podgatunek niewiarygodnie małych ludzi. Wykorzystują swój rozmiar do ukrywania się przed wrogami i poruszania się po małych przestrzeniach.", 6 | "origin.extraorigins.piglin.name": "Piglin", 7 | "origin.extraorigins.piglin.description": "Pochodzące z Netheru Pigliny bardzo lubią złoto i są ekspertami w jego wykorzystaniu. ", 8 | "power.extraorigins.green_thumb.name": "Zielony kciuk", 9 | "power.extraorigins.green_thumb.description": "Możesz uprawiać rośliny kosztem jedzenia.", 10 | "power.extraorigins.photosynthesis.name": "Fotosynteza", 11 | "power.extraorigins.photosynthesis.description": "Jesteś nasycony przez wystawienie na działanie promieni słonecznych.", 12 | "power.extraorigins.absorbing.name": "Absorbcja", 13 | "power.extraorigins.absorbing.description": "Zadajesz 2 punkty dodatkowe obrażenia, gdy jest mokry. ", 14 | "power.extraorigins.flammable.name": "Łatwopalny", 15 | "power.extraorigins.flammable.description": "Otrzymujesz dwa razy więcej obrażeń od ognia.", 16 | "power.extraorigins.nectarivore.name": "Nektarożerca", 17 | "power.extraorigins.nectarivore.description": "Możesz spożywać tylko butelki miodu.", 18 | "power.extraorigins.bite_sized.name": "Malutki", 19 | "power.extraorigins.bite_sized.description": "Jesteś 4 razy mniejszy od zwykłej osoby. Masz o 5 serc mniej, o 0,5 więcej szybkości ataku, 0,25 mniej zasięgu ataku i 1 mniej zasięgu budowy.", 20 | "power.extraorigins.small_appetite.name": "Mały apetyt", 21 | "power.extraorigins.small_appetite.description": "Potrzebujesz mniej jedzenia do przetrwania", 22 | "power.extraorigins.nimble.name": "Zwinny", 23 | "power.extraorigins.nimble.description": "Jesteś odporny na ciernie i obrażenia zależne od prędkości. W ogóle nie spowalniają Cię bloki takie jak krzaki słodkich jagód czy pajęczyny.", 24 | "power.extraorigins.jockey.name": "Dżokej", 25 | "power.extraorigins.jockey.description": "Możesz ujeżdzać innych graczy.", 26 | "power.extraorigins.all_that_glitters.name": "Wszystko co błyszczy", 27 | "power.extraorigins.all_that_glitters.description": "Złote narzędzia zadają dodatkowe obrażenia, a złota zbroja ma dodatkową ochronę. Wyroby ze złota wytrzymują znacznie dłużej, ale zbroja i narzędzia inne niż złote i netherytowe psują się szybciej. Netherytowa zbroja daje niewielki wzrost prędkości. ", 28 | "power.extraorigins.piglin_neutrality.name": "Neutralność piglinów", 29 | "power.extraorigins.piglin_neutrality.description": "Pigliny nie atakują cię, chyba że zostaną sprowokowane. Okrutnicy nadal będą atakować, gdy tylko zobaczą.", 30 | "power.extraorigins.crossbow_master.name": "Mistrz kuszy", 31 | "power.extraorigins.crossbow_master.description": "Zadajesz o 75% więcej obrażeń za pomocą kuszy.", 32 | "power.extraorigins.homesick.name": "Tęsknota za domem", 33 | "power.extraorigins.homesick.description": "Gdy znajdziesz się poza Netherem, zombifikujesz się, stając się nieumarłym i odpornym na ogień, ale wolniejszym.", 34 | "power.extraorigins.flabby.name": "Wiotki", 35 | "power.extraorigins.flabby.description": "Masz o 2 serca zdrowia mniej niż ludzie.", 36 | "power.extraorigins.soul_spooked.name": "Eteryczny strach", 37 | "power.extraorigins.soul_spooked.description": "Boisz się eterycznego ognia, słabniesz, gdy się do niego zbliżasz." 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/moriyashiine/extraorigins/common/power/RadialMenuPower.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) MoriyaShiine. All Rights Reserved. 3 | */ 4 | package moriyashiine.extraorigins.common.power; 5 | 6 | import io.github.apace100.apoli.power.Active; 7 | import io.github.apace100.apoli.power.Power; 8 | import io.github.apace100.apoli.power.PowerType; 9 | import moriyashiine.extraorigins.common.util.RadialMenuDirection; 10 | import net.minecraft.entity.Entity; 11 | import net.minecraft.entity.LivingEntity; 12 | import net.minecraft.nbt.NbtCompound; 13 | import net.minecraft.nbt.NbtElement; 14 | import net.minecraft.util.Identifier; 15 | 16 | import java.util.function.Consumer; 17 | 18 | public class RadialMenuPower extends Power implements Active { 19 | private Key key; 20 | public final Identifier spriteLocation; 21 | public final Consumer upAction; 22 | public final Consumer downAction; 23 | public final Consumer leftAction; 24 | public final Consumer rightAction; 25 | private final Consumer lostAction; 26 | public final int swapTime; 27 | 28 | private RadialMenuDirection direction; 29 | 30 | private boolean shouldUpdate = false; 31 | 32 | public RadialMenuPower(PowerType type, LivingEntity entity, Identifier spriteLocation, Consumer upAction, Consumer downAction, Consumer leftAction, Consumer rightAction, Consumer lostAction, int swapTime, RadialMenuDirection defaultDirection) { 33 | super(type, entity); 34 | this.spriteLocation = spriteLocation; 35 | this.upAction = upAction; 36 | this.downAction = downAction; 37 | this.leftAction = leftAction; 38 | this.rightAction = rightAction; 39 | this.lostAction = lostAction; 40 | this.swapTime = swapTime; 41 | this.direction = defaultDirection; 42 | setTicking(true); 43 | } 44 | 45 | @Override 46 | public void onUse() { 47 | } 48 | 49 | @Override 50 | public void tick() { 51 | if (shouldUpdate) { 52 | update(); 53 | shouldUpdate = false; 54 | } 55 | } 56 | 57 | @Override 58 | public void onAdded() { 59 | shouldUpdate = true; 60 | } 61 | 62 | @Override 63 | public void onLost() { 64 | if (lostAction != null) { 65 | lostAction.accept(entity); 66 | } 67 | } 68 | 69 | @Override 70 | public Key getKey() { 71 | return key; 72 | } 73 | 74 | @Override 75 | public void setKey(Key key) { 76 | this.key = key; 77 | } 78 | 79 | public RadialMenuDirection getDirection() { 80 | return this.direction; 81 | } 82 | 83 | public void setDirection(RadialMenuDirection direction) { 84 | this.direction = direction; 85 | shouldUpdate = true; 86 | } 87 | 88 | @Override 89 | public void fromTag(NbtElement tag) { 90 | if (tag instanceof NbtCompound nbt) { 91 | direction = RadialMenuDirection.valueOf(nbt.getString("Direction")); 92 | } 93 | } 94 | 95 | @Override 96 | public NbtElement toTag() { 97 | NbtCompound nbt = new NbtCompound(); 98 | nbt.putString("Direction", direction.toString()); 99 | return nbt; 100 | } 101 | 102 | public Consumer getActionFromDirection(RadialMenuDirection direction) { 103 | return switch (direction) { 104 | case UP -> upAction; 105 | case DOWN -> downAction; 106 | case LEFT -> leftAction; 107 | case RIGHT -> rightAction; 108 | }; 109 | } 110 | 111 | private void update() { 112 | Consumer actionFromDirection = getActionFromDirection(direction); 113 | if (actionFromDirection != null) { 114 | actionFromDirection.accept(entity); 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/main/resources/assets/extraorigins/lang/ko_kr.json: -------------------------------------------------------------------------------- 1 | { 2 | "extraorigins.subtitles.block.mycelium.grow": "자라난 균사체", 3 | "extraorigins.subtitles.entity.generic.spore_shift": "포자 이동", 4 | "origin.extraorigins.floran.name": "플로리안", 5 | "origin.extraorigins.floran.description": "식물 인간인 플로리안은 태양로부터 영양분을 얻고 물에서 힘을 얻습니다.", 6 | "origin.extraorigins.truffle.name": "트러플", 7 | "origin.extraorigins.truffle.description": "트러플은 균류의 성질을 가지고 있고 상황에 적응하는 능력이 뛰어납니다.", 8 | "origin.extraorigins.inchling.name": "난쟁이", 9 | "origin.extraorigins.inchling.description": "난쟁이는 엄청나게 작은 인간의 변종으로 그들의 크기를 이용하여 적들로부터 숨고 작은 공간을 탐색할 수 있습니다.", 10 | "origin.extraorigins.piglin.name": "피글린", 11 | "origin.extraorigins.piglin.description": "네더의 원주민인 피글린은 금을 매우 좋아하며 금을 이용하는데 만큼은 전문적입니다.", 12 | "power.extraorigins.green_thumb.name": "그린 핑거", 13 | "power.extraorigins.green_thumb.description": "웅크린 상태로 빈 손으로 비료 사용이 가능한 블럭에 우클릭하면 배고픔을 약간 소모하고 작물을 자라나게 할 수 있습니다.", 14 | "power.extraorigins.photosynthesis.name": "광합성", 15 | "power.extraorigins.photosynthesis.description": "당신은 햇빛에 노출됨으로써 배고픔을 채울 수 있습니다.", 16 | "power.extraorigins.absorbing.name": "흡수", 17 | "power.extraorigins.absorbing.description": "젖었을 때 2의 데미지를 더 줍니다.", 18 | "power.extraorigins.flammable.name": "가연성", 19 | "power.extraorigins.flammable.description": "당신은 불로부터 2배의 데미지를 받습니다.", 20 | "power.extraorigins.nectarivore.name": "꿀", 21 | "power.extraorigins.nectarivore.description": "당신은 오직 꿀만 섭취 가능합니다.", 22 | "power.extraorigins.magic_spores.name": "마법 포자", 23 | "power.extraorigins.magic_spores.description": "당신은 마법 포자 3개 중에서 서로 전환할 수 있습니다. 빨간 포자는 공격력을 높이고, 초록색 포자는 방어력을 높이며 파란색 포자는 이동 속도를 늘려줍니다. 포자를 바꾸면 나머지 두 능력이 감소합니다.", 24 | "power.extraorigins.infestation.name": "감염", 25 | "power.extraorigins.infestation.description": "웅크린 상태로 빈 손으로 흙을 우클릭하면 배고픔을 약간 소모하고 흙을 균사체로 바꿉니다.", 26 | "power.extraorigins.rooted.name": "뿌리 내림", 27 | "power.extraorigins.rooted.description": "당신은 균사체에 서 있을 때 마법 포자에 따라 버프가 생깁니다. 빨간 포자는 공격 속도를 높이고, 초록 포자는 넉백 면역을 부여하며, 파란색 포자는 점프 높이를 증가시킵니다.", 28 | "power.extraorigins.decomposition.name": "분해", 29 | "power.extraorigins.decomposition.description": "음식이 먹기 전에 분해되어, 음식으로 얻을 수 있는 효과를 얻을 수 없습니다.", 30 | "power.extraorigins.bite_sized.name": "아주 작은 크기", 31 | "power.extraorigins.bite_sized.description": "당신은 인간보다 4배나 더 작습니다. 하트 5칸, 공격 속도 0.5, 공격 범위 0.25, 블록 설치 범위 1이 줄어듭니다.", 32 | "power.extraorigins.small_appetite.name": "적은 식욕", 33 | "power.extraorigins.small_appetite.description": "당신은 다른 사람들보다 훨씬 천천히 지쳐서 덜 먹어도 됩니다.", 34 | "power.extraorigins.nimble.name": "날렵함", 35 | "power.extraorigins.nimble.description": "가시와 속도에 따른 데미지에 면역이 됩니다. 당신은 달콤한 열매 덤불이나 거미줄 같은 블록에 의해 전혀 느려지지 않습니다. 또한 가루 눈 위를 걸을 수 있습니다.", 36 | "power.extraorigins.jockey.name": "기수", 37 | "power.extraorigins.jockey.description": "당신은 다른 플레이어에게 탈 수 있습니다.", 38 | "power.extraorigins.all_that_glitters.name": "모두 반짝거려", 39 | "power.extraorigins.all_that_glitters.description": "금 도구들은 추가적인 피해를 주고 금 갑옷들은 추가적인 방어도를 얻습니다. 금 장비는 오래 지속되지만, 금 장비가 아닌 장비나 네더라이트 장비는 훨씬 빨리 부숴집니다. 네더라이트 갑옷은 약간의 속도 증가를 줍니다.", 40 | "power.extraorigins.piglin_neutrality.name": "피글린 중립적", 41 | "power.extraorigins.piglin_neutrality.description": "피글린은 먼저 공격하지 않는 이상 당신을 공격하지 않습니다. 피글린 야수는 여전히 당신을 공격합니다.", 42 | "power.extraorigins.crossbow_master.name": "석궁 마스터", 43 | "power.extraorigins.crossbow_master.description": "당신의 석궁의 피해가 75% 증가합니다.", 44 | "power.extraorigins.homesick.name": "향수병", 45 | "power.extraorigins.homesick.description": "네더 바깥에서는 좀비화되어 언데드가 되고 불에 면역이 되지만 느려집니다.", 46 | "power.extraorigins.flabby.name": "무기력함", 47 | "power.extraorigins.flabby.description": "당신은 인간보다 하트 2칸이 적습니다.", 48 | "power.extraorigins.soul_spooked.name": "영혼 두려움", 49 | "power.extraorigins.soul_spooked.description": "당신은 영혼 불 가까이 있을 때 겁먹어서, 영혼 불 가까이 있으면 약해집니다." 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/moriyashiine/extraorigins/client/event/RandomPowerGranterClientEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) MoriyaShiine. All Rights Reserved. 3 | */ 4 | package moriyashiine.extraorigins.client.event; 5 | 6 | import io.github.apace100.apoli.power.PowerTypeRegistry; 7 | import io.github.apace100.origins.Origins; 8 | import moriyashiine.extraorigins.common.component.entity.RandomPowerGranterComponent; 9 | import moriyashiine.extraorigins.common.init.ModEntityComponents; 10 | import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; 11 | import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback; 12 | import net.minecraft.client.MinecraftClient; 13 | import net.minecraft.client.gui.DrawContext; 14 | import net.minecraft.client.world.ClientWorld; 15 | import net.minecraft.text.MutableText; 16 | import net.minecraft.text.Text; 17 | import net.minecraft.util.Formatting; 18 | import net.minecraft.util.Identifier; 19 | 20 | public class RandomPowerGranterClientEvent { 21 | public static final DisplayInstance[] DISPLAY_INSTANCES = new DisplayInstance[3]; 22 | public static final String[] CHARACTERS = {"α", "β", "γ"}; 23 | public static final Formatting[] FORMATTING = {Formatting.GREEN, Formatting.LIGHT_PURPLE, Formatting.GOLD}; 24 | 25 | public static class ClientTick implements ClientTickEvents.EndWorldTick { 26 | @Override 27 | public void onEndTick(ClientWorld world) { 28 | for (int i = 0; i < DISPLAY_INSTANCES.length; i++) { 29 | DisplayInstance displayInstance = DISPLAY_INSTANCES[i]; 30 | if (displayInstance != null && --displayInstance.duration == 0) { 31 | DISPLAY_INSTANCES[i] = null; 32 | } 33 | } 34 | } 35 | } 36 | 37 | public static class Hud implements HudRenderCallback { 38 | private static final MinecraftClient client = MinecraftClient.getInstance(); 39 | private static final Identifier TEXTURE = Origins.identifier("textures/gui/community/spiderkolo/resource_bar_01.png"); 40 | 41 | private static final int[] VS = {150, 120, 110}; 42 | 43 | @Override 44 | public void onHudRender(DrawContext drawContext, float tickDelta) { 45 | if (client.player != null) { 46 | RandomPowerGranterComponent randomPowerGranterComponent = ModEntityComponents.RANDOM_POWER_GRANTER.get(client.player); 47 | if (randomPowerGranterComponent.isEnabled()) { 48 | for (int i = 0; i < randomPowerGranterComponent.getTemporaryPowerTypes().length; i++) { 49 | int y = 4 + (i * 10); 50 | drawContext.drawText(client.textRenderer, CHARACTERS[i], 4, y, FORMATTING[i].getColorValue(), true); 51 | drawContext.drawTexture(TEXTURE, 12, y + 2, 0, 0, 71, 5, 256, 256); 52 | drawContext.drawTexture(TEXTURE, 12, y + 2, 0, VS[i], (int) (71 * (randomPowerGranterComponent.getTemporaryPowerTypes()[i].getProgress())), 5, 256, 256); 53 | DisplayInstance displayInstance = DISPLAY_INSTANCES[i]; 54 | if (displayInstance != null) { 55 | Text display = displayInstance.oldPower.append(" -> ").append(displayInstance.newPower); 56 | drawContext.setShaderColor(1, 1, 1, displayInstance.getOpacity()); 57 | drawContext.drawText(client.textRenderer, display, 86, y, FORMATTING[i].getColorValue(), true); 58 | } 59 | drawContext.setShaderColor(1, 1, 1, 1); 60 | } 61 | } 62 | } 63 | } 64 | } 65 | 66 | public static class DisplayInstance { 67 | private final MutableText oldPower, newPower; 68 | private int duration; 69 | private final float maxDuration; 70 | 71 | public DisplayInstance(Identifier oldPower, Identifier newPower, int duration) { 72 | this.oldPower = PowerTypeRegistry.get(oldPower).getName(); 73 | this.newPower = PowerTypeRegistry.get(newPower).getName(); 74 | this.duration = duration; 75 | this.maxDuration = duration; 76 | } 77 | 78 | private float getOpacity() { 79 | if (duration < 10) { 80 | return duration / 10F; 81 | } 82 | if (duration > maxDuration - 10) { 83 | return 1 - (duration - (maxDuration - 10)) / 10F; 84 | } 85 | return 1; 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/main/resources/assets/extraorigins/lang/ru_ru.json: -------------------------------------------------------------------------------- 1 | { 2 | "extraorigins.subtitles.block.mycelium.grow": "Мицелий растёт", 3 | "extraorigins.subtitles.entity.generic.spore_shift": "Споры перемещаются", 4 | "origin.extraorigins.floran.name": "Флоран", 5 | "origin.extraorigins.floran.description": "Вид растений, которые получают питательные вещества от солнца и набирают силу от воды.", 6 | "origin.extraorigins.truffle.name": "Трюфель", 7 | "origin.extraorigins.truffle.description": "Трюфели, наряду с обычными свойствами грибов, обладают уникальной способностью адаптироваться к ситуациям на лету.", 8 | "origin.extraorigins.inchling.name": "Инхлинг", 9 | "origin.extraorigins.inchling.description": "Подвид людей, которые невероятно малы. Они используют свой размер, чтобы прятаться от врагов и перемещаться по маленьким пространствам. Физически они слабы.", 10 | "origin.extraorigins.piglin.name": "Пиглин", 11 | "origin.extraorigins.piglin.description": "Будучи уроженцами Незера, Пиглины очень любят золото и знают толк в его использовании.", 12 | "power.extraorigins.green_thumb.name": "Озеленение", 13 | "power.extraorigins.green_thumb.description": "Вы можете взращивать растения за счёт своей сытости.", 14 | "power.extraorigins.photosynthesis.name": "Фотосинтез", 15 | "power.extraorigins.photosynthesis.description": "Вы насыщаетесь солнечным светом.", 16 | "power.extraorigins.absorbing.name": "Впитывание", 17 | "power.extraorigins.absorbing.description": "Вы наносите 2 доп. урона, будучи мокрым.", 18 | "power.extraorigins.flammable.name": "Легковозгораемый", 19 | "power.extraorigins.flammable.description": "Вы получаете двойной урон от огня.", 20 | "power.extraorigins.nectarivore.name": "Нектароядный", 21 | "power.extraorigins.nectarivore.description": "Вы можете употреблять только бутылки с мёдом.", 22 | "power.extraorigins.magic_spores.name": "Магические споры", 23 | "power.extraorigins.magic_spores.description": "Вы можете переключаться между различными магическими спорами. Красная шляпка усиливает атаку, зеленая шляпка усиливает защиту, а синяя шляпка повышает мобильность. Изменение спор уменьшит способности двух других шляпок.", 24 | "power.extraorigins.infestation.name": "Заражение", 25 | "power.extraorigins.infestation.description": "Нанесение крадучись на почвенный блок пустой рукой превратит его в мицелий, за счет некоторого количества пищи.", 26 | "power.extraorigins.rooted.name": "Укоренённый", 27 | "power.extraorigins.rooted.description": "Вы получаете бонусы в зависимости от того, какая спора у вас активна, когда вы стоите на мицелии. Красная шапочка увеличивает скорость атаки, зеленая шапочка дает иммунитет к отбрасыванию, а синяя шапочка увеличивает высоту прыжка.", 28 | "power.extraorigins.decomposition.name": "Разложение", 29 | "power.extraorigins.decomposition.description": "Пища разлагается перед употреблением, сводя на нет любые статусные эффекты, которые вы могли бы получить в противном случае.", 30 | "power.extraorigins.bite_sized.name": "Чу-уток маленький", 31 | "power.extraorigins.bite_sized.description": "Вы в 4 раза меньше обычного. У вас на 5 сердце меньше, скорость атаки больше на 0.5, дальность атаки меньше на 0.25 и дальность постройки блоков меньше на 1.", 32 | "power.extraorigins.small_appetite.name": "Небольшой аппетит", 33 | "power.extraorigins.small_appetite.description": "Вам требуется меньше еды для насыщения.", 34 | "power.extraorigins.nimble.name": "Шустрый", 35 | "power.extraorigins.nimble.description": "Вы невосприимчивы к урону от шипов и падения.", 36 | "power.extraorigins.jockey.name": "Наездник", 37 | "power.extraorigins.jockey.description": "Вы можете оседлать других игроков.", 38 | "power.extraorigins.all_that_glitters.name": "Бранзулетка!", 39 | "power.extraorigins.all_that_glitters.description": "Золотые инструменты наносят больше урона, а золотая броня имеет большую защиту. Золотое снаряжение намного крепче, но не золотое и не незеритовое снаряжение ломается быстрей. Незеритовые доспехи дают небольшой прирост к скорости.", 40 | "power.extraorigins.piglin_neutrality.name": "Пиглинский нейтралитет", 41 | "power.extraorigins.piglin_neutrality.description": "Пиглины не атакуют вас, пока вы не трогаете их. Брутальные пиглины всё еще будут вас атаковать.", 42 | "power.extraorigins.crossbow_master.name": "Арбалетный мастер", 43 | "power.extraorigins.crossbow_master.description": "Вы наносите на 75% больше урона с помощью арбалета.", 44 | "power.extraorigins.homesick.name": "Привязанность к дому", 45 | "power.extraorigins.homesick.description": "Вне Незера вы зомбифицируетесь, становлясь нежитью и имея иммунитет к огню, но двигаетесь медленней.", 46 | "power.extraorigins.flabby.name": "Дряблый", 47 | "power.extraorigins.flabby.description": "У вас на 2 сердца меньше чем у людей.", 48 | "power.extraorigins.soul_spooked.name": "Напуган до глубины души", 49 | "power.extraorigins.soul_spooked.description": "Вы боитесь огня душ, становясь слабым около него." 50 | } 51 | -------------------------------------------------------------------------------- /src/main/resources/assets/extraorigins/lang/pt_br.json: -------------------------------------------------------------------------------- 1 | { 2 | "extraorigins.subtitles.block.mycelium.grow": "Micélio cresce", 3 | "extraorigins.subtitles.entity.generic.spore_shift": "Troca de esporos", 4 | "origin.extraorigins.floran.name": "Floran", 5 | "origin.extraorigins.floran.description": "Uma espécie de pessoa-planta que obtem seus nutrientes do sol e ganham forças na água.", 6 | "origin.extraorigins.truffle.name": "Trufa", 7 | "origin.extraorigins.truffle.description": "Trufas, além de possuirem propriedades normais de fungos, possuem a habilidade única de serem adaptáveis.", 8 | "origin.extraorigins.inchling.name": "Polegadeanos", 9 | "origin.extraorigins.inchling.description": "Uma subespécie de humanos que são incrivelmente pequenos. Eles utilizam seu tamanho para se esconder de inimigos e navegar em espaços pequenos.", 10 | "origin.extraorigins.piglin.name": "Piglin", 11 | "origin.extraorigins.piglin.description": "Nativos do Nether, Piglins gostam muito de ouro e são especialistas em usá-lo.", 12 | "power.extraorigins.green_thumb.name": "Polegar Verde", 13 | "power.extraorigins.green_thumb.description": "Ao se agachar e interagir com um bloco fertilizável com uma mão vazia faz crescer plantas consumindo um pouco de sua barra de comida.", 14 | "power.extraorigins.photosynthesis.name": "Fotossíntese", 15 | "power.extraorigins.photosynthesis.description": "Você é saciado quando exposto à luz do sol.", 16 | "power.extraorigins.absorbing.name": "Absorvedor", 17 | "power.extraorigins.absorbing.description": "Você dá mais 2 de dano quando molhado.", 18 | "power.extraorigins.flammable.name": "Inflamável", 19 | "power.extraorigins.flammable.description": "Você toma o dobro de dano por fogo.", 20 | "power.extraorigins.nectarivore.name": "Nectarívoro", 21 | "power.extraorigins.nectarivore.description": "Você só pode consumir Garrafas de Mel.", 22 | "power.extraorigins.magic_spores.name": "Esporos Mágicos", 23 | "power.extraorigins.magic_spores.description": "Você pode trocar entre diferentes esporos mágicos. Chapéu Vermelho melhora sua ofensiva; Chapéu Verde, sua defesa; e Chapéu Azul, sua mobilidade. Trocar de esporos irá diminuir as habilidades dos outros dois Chapéus.", 24 | "power.extraorigins.infestation.name": "Infestação", 25 | "power.extraorigins.infestation.description": "Ao se agachar e interagir com um bloco de solo com uma mão vazia irá transformá-lo em micélio consumindo um pouco de sua barra de comida.", 26 | "power.extraorigins.rooted.name": "Enraízado", 27 | "power.extraorigins.rooted.description": "Você ganha um efeito positivo baseado no esporo ativo quando estiver sobre micélio. Chapéu Vermelho aumenta sua velocidade de ataque, Chapéu Verde te dá imunidade a repulsão, e o Chapéu Azul aumenta a altura do seu salto.", 28 | "power.extraorigins.decomposition.name": "Decomposição", 29 | "power.extraorigins.decomposition.description": "Comida é decomposta antes de ser consumida, nulificando qualquer efeito de estado que você receberia.", 30 | "power.extraorigins.bite_sized.name": "Porção pequena", 31 | "power.extraorigins.bite_sized.description": "Você é 4 vezes menor que o normal. Você tem menos 5 corações, 0.5 mais velocidade de ataque, 0.25 menos alcance de ataque, e 1 menos alcance de construção.", 32 | "power.extraorigins.small_appetite.name": "Apetite pequeno", 33 | "power.extraorigins.small_appetite.description": "Você se cansa muito menos do que os outros, precisando de menos comida para viver.", 34 | "power.extraorigins.nimble.name": "Ágil", 35 | "power.extraorigins.nimble.description": "Você é imune à espinhos e dano baseado em velocidade (dano cinético). Você não é retardado de forma alguma por blocos como arbustos de baga doce ou teias de aranha. Você pode andar em neve fofa.", 36 | "power.extraorigins.jockey.name": "Jóquei", 37 | "power.extraorigins.jockey.description": "Você pode montar outros jogadores.", 38 | "power.extraorigins.all_that_glitters.name": "Tudo que brilha", 39 | "power.extraorigins.all_that_glitters.description": "Ferramentas douradas dão dano extra e armadura dourada dá proteção adicional. Equipamento dourado dura muito mais, mas equipamento não-dourado e equipamento não-netherita quebra mais rápido. Armadura de Netherita dá um leve aumento na sua velocidade.", 40 | "power.extraorigins.piglin_neutrality.name": "Neutralidade Piglin", 41 | "power.extraorigins.piglin_neutrality.description": "Piglins não te atacam a menos se provocados. Brutos ainda te atacarão assim que te verem.", 42 | "power.extraorigins.crossbow_master.name": "Mestre das Bestas", 43 | "power.extraorigins.crossbow_master.description": "Você dá 75% mais dano com bestas.", 44 | "power.extraorigins.homesick.name": "Saudade", 45 | "power.extraorigins.homesick.description": "Quando fora do Nether, você zombefica, ficando morto-vivo e imune ao fogo, porém mais lento.", 46 | "power.extraorigins.flabby.name": "Frouxo", 47 | "power.extraorigins.flabby.description": "Você tem 2 corações a menos que humanos.", 48 | "power.extraorigins.soul_spooked.name": "Almassustado", 49 | "power.extraorigins.soul_spooked.description": "Você tem medo de fogo das almas, ficando mais fraco quando perto do mesmo." 50 | } 51 | -------------------------------------------------------------------------------- /src/main/resources/assets/extraorigins/lang/tr_tr.json: -------------------------------------------------------------------------------- 1 | { 2 | "extraorigins.subtitles.block.mycelium.grow": "Miselyum büyür", 3 | "extraorigins.subtitles.entity.generic.spore_shift": "Spor değişir", 4 | "origin.extraorigins.floran.name": "Floran", 5 | "origin.extraorigins.floran.description": "Besinlerini güneşten, güçlerini sudan alan bir bitki-insan türü.", 6 | "origin.extraorigins.truffle.name": "Truffle", 7 | "origin.extraorigins.truffle.description": "Trufflelar, mantarların normal özelliklerine sahip olmakla birlikte, olaylara anında uyum sağlarlar.", 8 | "origin.extraorigins.inchling.name": "Inchling", 9 | "origin.extraorigins.inchling.description": "İnanılmaz derecede küçük olan bir insan türü. Büyüklüklerini düşmanlarından saklanmak ve küçük alanlarda gezmek için kullanırlar.", 10 | "origin.extraorigins.piglin.name": "Piglin", 11 | "origin.extraorigins.piglin.description": "Nether'ın Yerlileri Piglinler, altının hayranı ve ondan faydalanmanın ustalarıdır.", 12 | "origin.extraorigins.nucleon.name": "Nükleon", 13 | "origin.extraorigins.nucleon.description": "Adlarını atomun çekirdeğinden alan Nükleonların envai çeşit tahmin edilemeyen güçleri vardır.", 14 | "power.extraorigins.green_thumb.name": "Doğa Dostu", 15 | "power.extraorigins.green_thumb.description": "Açlık karşılığında bitkileri büyütebilirsin.", 16 | "power.extraorigins.photosynthesis.name": "Fotosentez", 17 | "power.extraorigins.photosynthesis.description": "Güneş ışınlarına maruz kalarak açlığını giderirsin.", 18 | "power.extraorigins.absorbing.name": "Emiş", 19 | "power.extraorigins.absorbing.description": "Suya maruz kaldığında kuvvet kazanırsın.", 20 | "power.extraorigins.flammable.name": "Yanıcı", 21 | "power.extraorigins.flammable.description": "Ateşten iki kat hasar alırsın.", 22 | "power.extraorigins.nectarivore.name": "Balcıl", 23 | "power.extraorigins.nectarivore.description": "Sadece bal tüketebilirsin.", 24 | "power.extraorigins.magic_spores.name": "Sihirli Sporlar", 25 | "power.extraorigins.magic_spores.description": "Farklı Sihirli Sporlar arasında değişebilirsin. Kırmızı başlık saldırı, Yeşil başlık savunma ve Mavi başlık hareket etme kabiliyetini arttırır. Spor değiştirmek diğer başlıkların özelliklerini azaltır.", 26 | "power.extraorigins.infestation.name": "Değişim", 27 | "power.extraorigins.infestation.description": "Açlık karşılığında toprak bloklarını miselyuma dönüştürebilirsin.", 28 | "power.extraorigins.rooted.name": "Kök Salmış", 29 | "power.extraorigins.rooted.description": "Miselyum üzerinde dururken başlık rengine göre özellikler kazanırsın. Kırmızı başlık saldırı hızını arttırır, Yeşil başlık savrulmanı engeller ve Mavi başlık koşarken zıplama yüksekliğini arttırır.", 30 | "power.extraorigins.decomposition.name": "Ayrıştırma", 31 | "power.extraorigins.decomposition.description": "Yemeği tüketmeden önce ayrıştırırsın, bu normalde alıcağın etkileri ortadan kaldırır.", 32 | "power.extraorigins.bite_sized.name": "Cüce", 33 | "power.extraorigins.bite_sized.description": "Bir insana göre oldukça küçüksün ve yarısı kadar canın var", 34 | "power.extraorigins.small_appetite.name": "İştahsız", 35 | "power.extraorigins.small_appetite.description": "Diğerlerine göre daha az yorulursun, yani daha az yemek ihtiyacı duyarsın.", 36 | "power.extraorigins.nimble.name": "Çevik", 37 | "power.extraorigins.nimble.description": "Hız ve diken kaynaklı hasara karşı dirençlisin. Tatlı orman meyvesi çalısı ve örümcek ağı gibi bloklar tarafından hiç yavaşlatılmazsın ve tozlaşmış kar üzerinde yürüyebilirsin.", 38 | "power.extraorigins.jockey.name": "Jokey", 39 | "power.extraorigins.jockey.description": "Diğer oyunculara binebilirsin.", 40 | "power.extraorigins.all_that_glitters.name": "Altın Ustası", 41 | "power.extraorigins.all_that_glitters.description": "Altın aletlerin ek hasar verir ve altın zırhın ek koruma elde eder. Altın ekipman çok daha dayanıklıdır.", 42 | "power.extraorigins.crossbow_master.name": "Arbalet Ustası", 43 | "power.extraorigins.crossbow_master.description": "Arbeletlerle %75 daha fazla hasar verirsin.", 44 | "power.extraorigins.flabby.name": "Yumuşak", 45 | "power.extraorigins.flabby.description": "İnsanlara göre 2 daha az canın var.", 46 | "power.extraorigins.golden_gluttony.name": "Açgöz", 47 | "power.extraorigins.golden_gluttony.description": "Diyetiniz et ile kısıtlı, sebze yiyemezsiniz. Altın yemekler hala yenilebilir.", 48 | "power.extraorigins.homesick.name": "Ev Hastası", 49 | "power.extraorigins.homesick.description": "Nether'ın dışındayken zombileşirsin, ölü ve ateşe dayanıklı ama zayıf olursun. Altın yemek yemek bunu bir süreliğine etkisiz hale getirir", 50 | "power.extraorigins.piglin_neutrality.name": "Piglin Dostluğu", 51 | "power.extraorigins.piglin_neutrality.description": "Piglinler onları rahatsız etmezsen sana saldırmaz. Zalim Piglinler yinede seni gördüklerinde saldırır.", 52 | "power.extraorigins.soul_spooked.name": "Ruh Korkusu", 53 | "power.extraorigins.soul_spooked.description": "Ruh ateşinden korkarsın ve yakınındayken zayıflarsın.", 54 | "power.extraorigins.radioactive.name": "Radyoaktif", 55 | "power.extraorigins.radioactive.description": "3 rastgele gücünüz var, her biri belirli bir zaman içerisinde başka güçlere bozunur.", 56 | "origins.gui.impact.very_high": "Çok Yüksek" 57 | } 58 | -------------------------------------------------------------------------------- /src/main/resources/assets/extraorigins/lang/en_us.json: -------------------------------------------------------------------------------- 1 | { 2 | "extraorigins.subtitles.block.mycelium.grow": "Mycelium grows", 3 | "extraorigins.subtitles.entity.generic.spore_shift": "Spore shifts", 4 | "origin.extraorigins.floran.name": "Floran", 5 | "origin.extraorigins.floran.description": "A species of plant people that obtain their nutrients from the sun and gain strength from water.", 6 | "origin.extraorigins.truffle.name": "Truffle", 7 | "origin.extraorigins.truffle.description": "Truffles, along with having normal properties of fungi, have the unique ability to adapt to situations on the fly.", 8 | "origin.extraorigins.inchling.name": "Inchling", 9 | "origin.extraorigins.inchling.description": "A subspecies of humans that are incredibly small. They utilize their size to hide from enemies and navigate small spaces.", 10 | "origin.extraorigins.piglin.name": "Piglin", 11 | "origin.extraorigins.piglin.description": "Natives of the Nether, Piglins are very fond of gold and are experts at utilizing it.", 12 | "origin.extraorigins.nucleon.name": "Nucleon", 13 | "origin.extraorigins.nucleon.description": "Named after the atomic nucleus, Nucleons are incredibly unpredictable and have a wide array of ever-changing powers.", 14 | "power.extraorigins.absorbing.name": "Absorbing", 15 | "power.extraorigins.absorbing.description": "You gain strength when exposed to water.", 16 | "power.extraorigins.flammable.name": "Flammable", 17 | "power.extraorigins.flammable.description": "You take twice as much damage from fire.", 18 | "power.extraorigins.green_thumb.name": "Green Thumb", 19 | "power.extraorigins.green_thumb.description": "You can grow plants at the cost of hunger.", 20 | "power.extraorigins.nectarivore.name": "Nectarivore", 21 | "power.extraorigins.nectarivore.description": "You can only consume honey bottles.", 22 | "power.extraorigins.photosynthesis.name": "Photosynthesis", 23 | "power.extraorigins.photosynthesis.description": "You are satiated by being exposed to sunlight.", 24 | "power.extraorigins.decomposition.name": "Decomposition", 25 | "power.extraorigins.decomposition.description": "Food is decomposed before it's consumed, nullifying any status effects you would otherwise gain.", 26 | "power.extraorigins.infestation.name": "Infestation", 27 | "power.extraorigins.infestation.description": "You can turn soil blocks into mycelium at the cost of hunger.", 28 | "power.extraorigins.magic_spores.name": "Magic Spores", 29 | "power.extraorigins.magic_spores.description": "You can switch between different Magic Spores. Red Cap boosts offense, Green Cap boosts defense, and Blue Cap boosts mobility. Changing Spores will decrease the abilities of the other two Caps.", 30 | "power.extraorigins.rooted.name": "Rooted", 31 | "power.extraorigins.rooted.description": "You gain bonuses based on the Spore you have active when standing on mycelium. Red Cap increases attack speed, Green Cap grants knockback immunity, and Blue Cap amplifies jump height while sprinting.", 32 | "power.extraorigins.bite_sized.name": "Bite Sized", 33 | "power.extraorigins.bite_sized.description": "You are significantly smaller than a human and have half as much health.", 34 | "power.extraorigins.jockey.name": "Jockey", 35 | "power.extraorigins.jockey.description": "You can ride other players.", 36 | "power.extraorigins.nimble.name": "Nimble", 37 | "power.extraorigins.nimble.description": "You are immune to thorns and velocity based damage. You are not slowed by blocks such as sweet berry bushes or cobwebs. You can walk on powder snow.", 38 | "power.extraorigins.small_appetite.name": "Small Appetite", 39 | "power.extraorigins.small_appetite.description": "You exhaust much slower than others, requiring you to eat less.", 40 | "power.extraorigins.all_that_glitters.name": "All That Glitters", 41 | "power.extraorigins.all_that_glitters.description": "Golden tools deal extra damage and golden armor has additional protection. Golden equipment lasts much longer.", 42 | "power.extraorigins.crossbow_master.name": "Crossbow Master", 43 | "power.extraorigins.crossbow_master.description": "You deal 75% more damage with crossbows.", 44 | "power.extraorigins.flabby.name": "Flabby", 45 | "power.extraorigins.flabby.description": "You have 2 less hearts of health than humans.", 46 | "power.extraorigins.golden_gluttony.name": "Golden Gluttony", 47 | "power.extraorigins.golden_gluttony.description": "Your diet is restricted to meat, you can't eat vegetables. Golden food is still edible.", 48 | "power.extraorigins.homesick.name": "Homesick", 49 | "power.extraorigins.homesick.description": "When outside of the Nether, you zombify, becoming undead and immune to fire, but weaker. Eating golden food negates this effect for a while.", 50 | "power.extraorigins.piglin_neutrality.name": "Piglin Neutrality", 51 | "power.extraorigins.piglin_neutrality.description": "Piglins do not attack you unless provoked. Brutes will still attack on sight.", 52 | "power.extraorigins.soul_spooked.name": "Soul Spooked", 53 | "power.extraorigins.soul_spooked.description": "You are afraid of soul fire, becoming weak when near it.", 54 | "power.extraorigins.radioactive.name": "Radioactive", 55 | "power.extraorigins.radioactive.description": "You have 3 random powers, each of which will decay into a new power after a certain amount of time.", 56 | "origins.gui.impact.very_high": "Very High" 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/moriyashiine/extraorigins/common/init/ModPowers.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) MoriyaShiine. All Rights Reserved. 3 | */ 4 | package moriyashiine.extraorigins.common.init; 5 | 6 | import io.github.apace100.apoli.data.ApoliDataTypes; 7 | import io.github.apace100.apoli.power.Active; 8 | import io.github.apace100.apoli.power.ValueModifyingPower; 9 | import io.github.apace100.apoli.power.factory.PowerFactory; 10 | import io.github.apace100.apoli.registry.ApoliRegistries; 11 | import io.github.apace100.calio.data.SerializableData; 12 | import io.github.apace100.calio.data.SerializableDataType; 13 | import io.github.apace100.calio.data.SerializableDataTypes; 14 | import moriyashiine.extraorigins.common.ExtraOrigins; 15 | import moriyashiine.extraorigins.common.component.entity.RandomPowerGranterComponent; 16 | import moriyashiine.extraorigins.common.power.*; 17 | import moriyashiine.extraorigins.common.util.RadialMenuDirection; 18 | import net.minecraft.registry.Registry; 19 | 20 | import java.util.Collections; 21 | 22 | public class ModPowers { 23 | public static final PowerFactory CAN_WALK_ON_POWDER_SNOW = new PowerFactory<>(ExtraOrigins.id("can_walk_on_powder_snow"), new SerializableData(), data -> (type, entity) -> new CanStandOnPowderSnowPower(type, entity)).allowCondition(); 24 | public static final PowerFactory DELAYED_HITBOX = new PowerFactory<>(ExtraOrigins.id("delayed_hitbox"), new SerializableData().add("ticks", SerializableDataTypes.INT), data -> (type, entity) -> new DelayedHitboxPower(type, entity, data.getInt("ticks"))); 25 | public static final PowerFactory FOOD_EFFECT_IMMUNITY = new PowerFactory<>(ExtraOrigins.id("food_effect_immunity"), new SerializableData().add("effects", SerializableDataTypes.STATUS_EFFECTS, Collections.emptyList()).add("inverted", SerializableDataTypes.BOOLEAN, false), data -> (type, entity) -> new FoodEffectImmunityPower(type, entity, data.get("effects"), data.getBoolean("inverted"))).allowCondition(); 26 | public static final PowerFactory INNATE_UNBREAKING = new PowerFactory<>(ExtraOrigins.id("innate_unbreaking"), new SerializableData().add("item_condition", ApoliDataTypes.ITEM_CONDITION, null).add("level", SerializableDataTypes.INT), data -> (type, entity) -> new InnateUnbreakingPower(type, entity, data.get("item_condition"), data.getInt("level"))); 27 | public static final PowerFactory MOB_NEUTRALITY = new PowerFactory<>(ExtraOrigins.id("mob_neutrality"), new SerializableData().add("entity_condition", ApoliDataTypes.ENTITY_CONDITION), data -> (type, entity) -> new MobNeutralityPower(type, entity, data.get("entity_condition"))).allowCondition(); 28 | public static final PowerFactory MODIFY_AIR_STRAFING_SPEED = ValueModifyingPower.createValueModifyingFactory(ModifyAirStrafingSpeedPower::new, ExtraOrigins.id("modify_air_strafing_speed")); 29 | public static final PowerFactory MODIFY_ITEM_ATTRIBUTE = ModifyItemAttributePower.createFactory(ExtraOrigins.id("modify_item_attribute")); 30 | public static final PowerFactory MODIFY_SIZE = new PowerFactory<>(ExtraOrigins.id("modify_size"), new SerializableData().add("scale_types", SerializableDataTypes.IDENTIFIERS).add("scale", SerializableDataTypes.FLOAT), data -> (type, entity) -> new ModifySizePower(type, entity, data.get("scale_types"), data.getFloat("scale"))).allowCondition(); 31 | public static final PowerFactory PREVENT_BLOCK_SLOWNESS = new PowerFactory<>(ExtraOrigins.id("prevent_block_slowness"), new SerializableData(), data -> (type, entity) -> new PreventBlockSlownessPower(type, entity)).allowCondition(); 32 | public static final PowerFactory RADIAL_MENU = new PowerFactory<>(ExtraOrigins.id("radial_menu"), new SerializableData() 33 | .add("key", ApoliDataTypes.KEY, new Active.Key()) 34 | .add("sprite_location", SerializableDataTypes.IDENTIFIER) 35 | .add("up_action", ApoliDataTypes.ENTITY_ACTION, null) 36 | .add("down_action", ApoliDataTypes.ENTITY_ACTION, null) 37 | .add("left_action", ApoliDataTypes.ENTITY_ACTION, null) 38 | .add("right_action", ApoliDataTypes.ENTITY_ACTION, null) 39 | .add("lost_action", ApoliDataTypes.ENTITY_ACTION, null) 40 | .add("swap_time", SerializableDataTypes.INT, 20) 41 | .add("default_direction", SerializableDataType.enumValue(RadialMenuDirection.class), RadialMenuDirection.UP), data -> (type, entity) -> { 42 | RadialMenuPower power = new RadialMenuPower(type, entity, data.getId("sprite_location"), data.get("up_action"), data.get("down_action"), data.get("left_action"), data.get("right_action"), data.get("lost_action"), data.getInt("swap_time"), data.get("default_direction")); 43 | power.setKey(data.get("key")); 44 | return power; 45 | }).allowCondition(); 46 | public static final PowerFactory RANDOM_POWER_GRANTER = new PowerFactory<>(RandomPowerGranterComponent.RANDOM_POWER_GRANTER, new SerializableData(), data -> (type, entity) -> new RandomPowerGranterPower(type, entity)); 47 | public static final PowerFactory START_RIDING = new PowerFactory<>(ExtraOrigins.id("start_riding"), new SerializableData().add("key", ApoliDataTypes.KEY, new Active.Key()), data -> (type, entity) -> { 48 | MountPower power = new MountPower(type, entity); 49 | power.setKey(data.get("key")); 50 | return power; 51 | }).allowCondition(); 52 | 53 | public static void init() { 54 | Registry.register(ApoliRegistries.POWER_FACTORY, CAN_WALK_ON_POWDER_SNOW.getSerializerId(), CAN_WALK_ON_POWDER_SNOW); 55 | Registry.register(ApoliRegistries.POWER_FACTORY, DELAYED_HITBOX.getSerializerId(), DELAYED_HITBOX); 56 | Registry.register(ApoliRegistries.POWER_FACTORY, FOOD_EFFECT_IMMUNITY.getSerializerId(), FOOD_EFFECT_IMMUNITY); 57 | Registry.register(ApoliRegistries.POWER_FACTORY, INNATE_UNBREAKING.getSerializerId(), INNATE_UNBREAKING); 58 | Registry.register(ApoliRegistries.POWER_FACTORY, MOB_NEUTRALITY.getSerializerId(), MOB_NEUTRALITY); 59 | Registry.register(ApoliRegistries.POWER_FACTORY, MODIFY_AIR_STRAFING_SPEED.getSerializerId(), MODIFY_AIR_STRAFING_SPEED); 60 | Registry.register(ApoliRegistries.POWER_FACTORY, MODIFY_ITEM_ATTRIBUTE.getSerializerId(), MODIFY_ITEM_ATTRIBUTE); 61 | Registry.register(ApoliRegistries.POWER_FACTORY, MODIFY_SIZE.getSerializerId(), MODIFY_SIZE); 62 | Registry.register(ApoliRegistries.POWER_FACTORY, PREVENT_BLOCK_SLOWNESS.getSerializerId(), PREVENT_BLOCK_SLOWNESS); 63 | Registry.register(ApoliRegistries.POWER_FACTORY, RADIAL_MENU.getSerializerId(), RADIAL_MENU); 64 | Registry.register(ApoliRegistries.POWER_FACTORY, RANDOM_POWER_GRANTER.getSerializerId(), RANDOM_POWER_GRANTER); 65 | Registry.register(ApoliRegistries.POWER_FACTORY, START_RIDING.getSerializerId(), START_RIDING); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/moriyashiine/extraorigins/client/event/RadialMenuEvents.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) MoriyaShiine. All Rights Reserved. 3 | */ 4 | package moriyashiine.extraorigins.client.event; 5 | 6 | import io.github.apace100.apoli.ApoliClient; 7 | import io.github.apace100.apoli.component.PowerHolderComponent; 8 | import moriyashiine.extraorigins.common.packet.ChangeRadialDirectionPacket; 9 | import moriyashiine.extraorigins.common.power.RadialMenuPower; 10 | import moriyashiine.extraorigins.common.util.RadialMenuDirection; 11 | import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; 12 | import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents; 13 | import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback; 14 | import net.minecraft.client.MinecraftClient; 15 | import net.minecraft.client.gui.DrawContext; 16 | import net.minecraft.client.util.InputUtil; 17 | import net.minecraft.client.util.Window; 18 | import net.minecraft.util.math.Direction; 19 | 20 | import java.util.List; 21 | 22 | public class RadialMenuEvents { 23 | public static boolean directionChanged = false; 24 | 25 | private static List activePowers; 26 | private static RadialMenuPower lastUsedPower; 27 | private static RadialMenuDirection targetDirection = null; 28 | private static boolean renderModeSwitch = false; 29 | private static int timer = 0; 30 | 31 | public static void init() { 32 | ClientPlayConnectionEvents.DISCONNECT.register((handler, client) -> { 33 | activePowers = null; 34 | lastUsedPower = null; 35 | directionChanged = false; 36 | targetDirection = null; 37 | renderModeSwitch = false; 38 | timer = 0; 39 | }); 40 | ClientTickEvents.END_CLIENT_TICK.register(new ClientTickEvents.EndTick() { 41 | @Override 42 | public void onEndTick(MinecraftClient client) { 43 | if (client.currentScreen != null) { 44 | return; 45 | } 46 | activePowers = PowerHolderComponent.getPowers(client.player, RadialMenuPower.class).stream().filter(power -> ApoliClient.idToKeyBindingMap.containsKey(power.getKey().key) && ApoliClient.idToKeyBindingMap.get(power.getKey().key).isPressed()).toList(); 47 | if (!activePowers.isEmpty()) { 48 | client.mouse.unlockCursor(); 49 | changeTargetMode(client); 50 | handleModeChange(); 51 | renderModeSwitch = true; 52 | } else { 53 | client.mouse.lockCursor(); 54 | lastUsedPower = null; 55 | directionChanged = false; 56 | targetDirection = null; 57 | renderModeSwitch = false; 58 | timer = 0; 59 | } 60 | } 61 | 62 | private void changeTargetMode(MinecraftClient client) { 63 | RadialMenuDirection direction = null; 64 | boolean arrowKey = false; 65 | if (InputUtil.isKeyPressed(client.getWindow().getHandle(), InputUtil.GLFW_KEY_UP)) { 66 | direction = RadialMenuDirection.UP; 67 | arrowKey = true; 68 | } else if (InputUtil.isKeyPressed(client.getWindow().getHandle(), InputUtil.GLFW_KEY_DOWN)) { 69 | direction = RadialMenuDirection.DOWN; 70 | arrowKey = true; 71 | } else if (InputUtil.isKeyPressed(client.getWindow().getHandle(), InputUtil.GLFW_KEY_LEFT)) { 72 | direction = RadialMenuDirection.LEFT; 73 | arrowKey = true; 74 | } else if (InputUtil.isKeyPressed(client.getWindow().getHandle(), InputUtil.GLFW_KEY_RIGHT)) { 75 | direction = RadialMenuDirection.RIGHT; 76 | arrowKey = true; 77 | } 78 | if (!arrowKey) { 79 | double x = client.mouse.getX() - (client.getWindow().getWidth() / 2F); 80 | double y = (client.getWindow().getHeight() / 2F) - client.mouse.getY(); 81 | if (Math.abs(x) > 48 || Math.abs(y) > 48) { 82 | direction = switch (Direction.getFacing(x, y, 0)) { 83 | case UP -> RadialMenuDirection.UP; 84 | case DOWN -> RadialMenuDirection.DOWN; 85 | case WEST -> RadialMenuDirection.LEFT; 86 | case EAST -> RadialMenuDirection.RIGHT; 87 | default -> null; 88 | }; 89 | } 90 | } 91 | if (targetDirection != direction) { 92 | targetDirection = direction; 93 | timer = 0; 94 | } 95 | } 96 | 97 | private void handleModeChange() { 98 | if (activePowers.get(0) != lastUsedPower) { 99 | timer = 0; 100 | lastUsedPower = activePowers.get(0); 101 | } 102 | if (targetDirection != null && lastUsedPower.getDirection() != targetDirection && lastUsedPower.getActionFromDirection(targetDirection) != null) { 103 | if (!directionChanged) { 104 | timer++; 105 | } 106 | if (timer == lastUsedPower.swapTime) { 107 | directionChanged = true; 108 | timer = 0; 109 | ChangeRadialDirectionPacket.send(targetDirection, lastUsedPower.getType()); 110 | } 111 | } 112 | } 113 | }); 114 | HudRenderCallback.EVENT.register(new HudRenderCallback() { 115 | @Override 116 | public void onHudRender(DrawContext drawContext, float tickDelta) { 117 | if (!renderModeSwitch) { 118 | return; 119 | } 120 | Window window = MinecraftClient.getInstance().getWindow(); 121 | drawContext.drawTexture(lastUsedPower.spriteLocation, (window.getScaledWidth() / 2) - 64, (window.getScaledHeight() / 2) - 64, 0, 0, 128, 128, 320, 256); 122 | renderSection(RadialMenuDirection.UP, drawContext, window, -32, -80, 0); 123 | renderSection(RadialMenuDirection.DOWN, drawContext, window, -32, 16, 64); 124 | renderSection(RadialMenuDirection.LEFT, drawContext, window, -80, -32, 128); 125 | renderSection(RadialMenuDirection.RIGHT, drawContext, window, 16, -32, 192); 126 | if (timer > 0) { 127 | drawContext.drawTexture(lastUsedPower.spriteLocation, (window.getScaledWidth() / 2) - 13, (window.getScaledHeight() / 2) - 13, 48, 128, 26, 26, 320, 256); 128 | drawContext.drawTexture(lastUsedPower.spriteLocation, (window.getScaledWidth() / 2) - 12, (window.getScaledHeight() / 2) - 12, 24, 128, 24, 24, 320, 256); 129 | drawContext.drawTexture(lastUsedPower.spriteLocation, (window.getScaledWidth() / 2) - 12, (window.getScaledHeight() / 2) - 12, 0, 128, 24, (int) (24 - 24 * ((timer + 1) / (float) lastUsedPower.swapTime)), 320, 256); 130 | } 131 | } 132 | 133 | private void renderSection(RadialMenuDirection targetMode, DrawContext drawContext, Window window, int posXOffset, int posYOffset, int v) { 134 | if (lastUsedPower.getActionFromDirection(targetMode) == null) { 135 | return; 136 | } 137 | int u = 128; 138 | if (lastUsedPower.getDirection() == targetMode) { 139 | u += 128; 140 | } else if (targetDirection == targetMode) { 141 | u += 64; 142 | } 143 | drawContext.drawTexture(lastUsedPower.spriteLocation, (window.getScaledWidth() / 2) + posXOffset, (window.getScaledHeight() / 2) + posYOffset, u, v, 64, 64, 320, 256); 144 | } 145 | }); 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /src/main/java/moriyashiine/extraorigins/common/component/entity/RandomPowerGranterComponent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) MoriyaShiine. All Rights Reserved. 3 | */ 4 | package moriyashiine.extraorigins.common.component.entity; 5 | 6 | import dev.onyxstudios.cca.api.v3.component.sync.AutoSyncedComponent; 7 | import dev.onyxstudios.cca.api.v3.component.tick.CommonTickingComponent; 8 | import io.github.apace100.apoli.component.PowerHolderComponent; 9 | import io.github.apace100.apoli.power.ModifyPlayerSpawnPower; 10 | import io.github.apace100.apoli.power.PowerType; 11 | import io.github.apace100.apoli.power.PowerTypeRegistry; 12 | import io.github.apace100.origins.Origins; 13 | import moriyashiine.extraorigins.client.packet.NotifyRandomPowerChangePacket; 14 | import moriyashiine.extraorigins.common.ExtraOrigins; 15 | import moriyashiine.extraorigins.common.init.ModEntityComponents; 16 | import net.minecraft.entity.LivingEntity; 17 | import net.minecraft.nbt.NbtCompound; 18 | import net.minecraft.nbt.NbtElement; 19 | import net.minecraft.nbt.NbtList; 20 | import net.minecraft.server.network.ServerPlayerEntity; 21 | import net.minecraft.util.Identifier; 22 | 23 | import java.util.ArrayList; 24 | import java.util.Arrays; 25 | import java.util.List; 26 | 27 | public class RandomPowerGranterComponent implements AutoSyncedComponent, CommonTickingComponent { 28 | public static final Identifier RANDOM_POWER_GRANTER = ExtraOrigins.id("random_power_granter"); 29 | 30 | private static final List DISALLOWED_IDENTIFIERS = List.of(RANDOM_POWER_GRANTER, ExtraOrigins.id("rooted"), Origins.identifier("hunger_over_time"), Origins.identifier("invisibility"), Origins.identifier("phantomize"), Origins.identifier("phasing"), Origins.identifier("webbing")); 31 | 32 | private final LivingEntity obj; 33 | private final TemporaryPowerType[] temporaryPowerTypes = new TemporaryPowerType[3]; 34 | private boolean enabled = false; 35 | 36 | public RandomPowerGranterComponent(LivingEntity obj) { 37 | this.obj = obj; 38 | } 39 | 40 | @Override 41 | public void readFromNbt(NbtCompound tag) { 42 | enabled = tag.getBoolean("Enabled"); 43 | Arrays.fill(temporaryPowerTypes, null); 44 | if (enabled) { 45 | NbtList list = tag.getList("PowerTypes", NbtElement.COMPOUND_TYPE); 46 | for (int i = 0; i < list.size(); i++) { 47 | NbtCompound compound = list.getCompound(i); 48 | temporaryPowerTypes[i] = new TemporaryPowerType(PowerTypeRegistry.get(Identifier.tryParse(compound.getString("Identifier"))), compound.getInt("Duration"), compound.getInt("MaxDuration")); 49 | } 50 | } 51 | } 52 | 53 | @Override 54 | public void writeToNbt(NbtCompound tag) { 55 | tag.putBoolean("Enabled", enabled); 56 | if (enabled) { 57 | NbtList list = new NbtList(); 58 | for (TemporaryPowerType temporaryPowerType : temporaryPowerTypes) { 59 | NbtCompound compound = new NbtCompound(); 60 | compound.putString("Identifier", temporaryPowerType.powerType.getIdentifier().toString()); 61 | compound.putInt("Duration", temporaryPowerType.duration); 62 | compound.putInt("MaxDuration", temporaryPowerType.maxDuration); 63 | list.add(compound); 64 | } 65 | tag.put("PowerTypes", list); 66 | } 67 | } 68 | 69 | @Override 70 | public void tick() { 71 | if (enabled) { 72 | for (TemporaryPowerType temporaryPowerType : temporaryPowerTypes) { 73 | if (temporaryPowerType.duration > 0) { 74 | temporaryPowerType.duration--; 75 | } 76 | } 77 | } 78 | } 79 | 80 | @Override 81 | public void serverTick() { 82 | tick(); 83 | if (enabled) { 84 | for (int i = 0; i < temporaryPowerTypes.length; i++) { 85 | if (temporaryPowerTypes[i].duration == 0) { 86 | randomizePower(i); 87 | sync(); 88 | } 89 | } 90 | } 91 | } 92 | 93 | public void sync() { 94 | ModEntityComponents.RANDOM_POWER_GRANTER.sync(obj); 95 | } 96 | 97 | public boolean isEnabled() { 98 | return enabled; 99 | } 100 | 101 | public TemporaryPowerType[] getTemporaryPowerTypes() { 102 | return temporaryPowerTypes; 103 | } 104 | 105 | public void initializePowers() { 106 | removePowers(); 107 | enabled = true; 108 | givePower(getRandomPower(), 0); 109 | givePower(getRandomPower(), 1); 110 | givePower(getRandomPower(), 2); 111 | } 112 | 113 | public void removePowers() { 114 | enabled = false; 115 | Arrays.fill(temporaryPowerTypes, null); 116 | PowerHolderComponent powerHolderComponent = PowerHolderComponent.KEY.get(obj); 117 | powerHolderComponent.removeAllPowersFromSource(RANDOM_POWER_GRANTER); 118 | powerHolderComponent.sync(); 119 | } 120 | 121 | private PowerType getRandomPower() { 122 | List> allPowers = new ArrayList<>(); 123 | for (PowerType powerType : PowerTypeRegistry.values()) { 124 | if (isPowerAllowed(powerType)) { 125 | allPowers.add(powerType); 126 | } 127 | } 128 | return allPowers.get(obj.getRandom().nextInt(allPowers.size())); 129 | } 130 | 131 | private void givePower(PowerType powerType, int index) { 132 | temporaryPowerTypes[index] = new TemporaryPowerType(powerType, obj.getRandom().nextBetween(6000, 18000)); 133 | PowerHolderComponent powerHolderComponent = PowerHolderComponent.KEY.get(obj); 134 | powerHolderComponent.addPower(powerType, RANDOM_POWER_GRANTER); 135 | powerHolderComponent.sync(); 136 | } 137 | 138 | private void randomizePower(int index) { 139 | PowerHolderComponent powerHolderComponent = PowerHolderComponent.KEY.get(obj); 140 | powerHolderComponent.removePower(temporaryPowerTypes[index].getPowerType(), RANDOM_POWER_GRANTER); 141 | powerHolderComponent.sync(); 142 | Identifier oldId = temporaryPowerTypes[index].getPowerType().getIdentifier(); 143 | givePower(getRandomPower(), index); 144 | if (obj instanceof ServerPlayerEntity player) { 145 | NotifyRandomPowerChangePacket.send(player, index, oldId, temporaryPowerTypes[index].getPowerType().getIdentifier()); 146 | } 147 | } 148 | 149 | private boolean isPowerAllowed(PowerType powerType) { 150 | for (TemporaryPowerType temporaryPowerType : temporaryPowerTypes) { 151 | if (temporaryPowerType != null && temporaryPowerType.powerType == powerType) { 152 | return false; 153 | } 154 | } 155 | if (powerType.isHidden() || powerType.isSubPower()) { 156 | return false; 157 | } 158 | String name = powerType.getName().getString(); 159 | if (name.startsWith("power.") && name.endsWith(".name")) { 160 | return false; 161 | } 162 | if (powerType.create(null) instanceof ModifyPlayerSpawnPower) { 163 | return false; 164 | } 165 | return !DISALLOWED_IDENTIFIERS.contains(powerType.getIdentifier()); 166 | } 167 | 168 | public static class TemporaryPowerType { 169 | private final PowerType powerType; 170 | private int duration; 171 | private final int maxDuration; 172 | 173 | public TemporaryPowerType(PowerType powerType, int duration, int maxDuration) { 174 | this.powerType = powerType; 175 | this.duration = duration; 176 | this.maxDuration = maxDuration; 177 | } 178 | 179 | public TemporaryPowerType(PowerType powerType, int duration) { 180 | this(powerType, duration, duration); 181 | } 182 | 183 | public PowerType getPowerType() { 184 | return powerType; 185 | } 186 | 187 | public float getProgress() { 188 | return (float) duration / maxDuration; 189 | } 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | # 21 | # Gradle start up script for POSIX generated by Gradle. 22 | # 23 | # Important for running: 24 | # 25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 26 | # noncompliant, but you have some other compliant shell such as ksh or 27 | # bash, then to run this script, type that shell name before the whole 28 | # command line, like: 29 | # 30 | # ksh Gradle 31 | # 32 | # Busybox and similar reduced shells will NOT work, because this script 33 | # requires all of these POSIX shell features: 34 | # * functions; 35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 37 | # * compound commands having a testable exit status, especially «case»; 38 | # * various built-in commands including «command», «set», and «ulimit». 39 | # 40 | # Important for patching: 41 | # 42 | # (2) This script targets any POSIX shell, so it avoids extensions provided 43 | # by Bash, Ksh, etc; in particular arrays are avoided. 44 | # 45 | # The "traditional" practice of packing multiple parameters into a 46 | # space-separated string is a well documented source of bugs and security 47 | # problems, so this is (mostly) avoided, by progressively accumulating 48 | # options in "$@", and eventually passing that to Java. 49 | # 50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 52 | # see the in-line comments for details. 53 | # 54 | # There are tweaks for specific operating systems such as AIX, CygWin, 55 | # Darwin, MinGW, and NonStop. 56 | # 57 | # (3) This script is generated from the Groovy template 58 | # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 59 | # within the Gradle project. 60 | # 61 | # You can find Gradle at https://github.com/gradle/gradle/. 62 | # 63 | ############################################################################## 64 | 65 | # Attempt to set APP_HOME 66 | 67 | # Resolve links: $0 may be a link 68 | app_path=$0 69 | 70 | # Need this for daisy-chained symlinks. 71 | while 72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 73 | [ -h "$app_path" ] 74 | do 75 | ls=$( ls -ld "$app_path" ) 76 | link=${ls#*' -> '} 77 | case $link in #( 78 | /*) app_path=$link ;; #( 79 | *) app_path=$APP_HOME$link ;; 80 | esac 81 | done 82 | 83 | # This is normally unused 84 | # shellcheck disable=SC2034 85 | APP_BASE_NAME=${0##*/} 86 | # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) 87 | APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit 88 | 89 | # Use the maximum available, or set MAX_FD != -1 to use that value. 90 | MAX_FD=maximum 91 | 92 | warn () { 93 | echo "$*" 94 | } >&2 95 | 96 | die () { 97 | echo 98 | echo "$*" 99 | echo 100 | exit 1 101 | } >&2 102 | 103 | # OS specific support (must be 'true' or 'false'). 104 | cygwin=false 105 | msys=false 106 | darwin=false 107 | nonstop=false 108 | case "$( uname )" in #( 109 | CYGWIN* ) cygwin=true ;; #( 110 | Darwin* ) darwin=true ;; #( 111 | MSYS* | MINGW* ) msys=true ;; #( 112 | NONSTOP* ) nonstop=true ;; 113 | esac 114 | 115 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 116 | 117 | 118 | # Determine the Java command to use to start the JVM. 119 | if [ -n "$JAVA_HOME" ] ; then 120 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 121 | # IBM's JDK on AIX uses strange locations for the executables 122 | JAVACMD=$JAVA_HOME/jre/sh/java 123 | else 124 | JAVACMD=$JAVA_HOME/bin/java 125 | fi 126 | if [ ! -x "$JAVACMD" ] ; then 127 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 128 | 129 | Please set the JAVA_HOME variable in your environment to match the 130 | location of your Java installation." 131 | fi 132 | else 133 | JAVACMD=java 134 | if ! command -v java >/dev/null 2>&1 135 | then 136 | die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 137 | 138 | Please set the JAVA_HOME variable in your environment to match the 139 | location of your Java installation." 140 | fi 141 | fi 142 | 143 | # Increase the maximum file descriptors if we can. 144 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 145 | case $MAX_FD in #( 146 | max*) 147 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. 148 | # shellcheck disable=SC2039,SC3045 149 | MAX_FD=$( ulimit -H -n ) || 150 | warn "Could not query maximum file descriptor limit" 151 | esac 152 | case $MAX_FD in #( 153 | '' | soft) :;; #( 154 | *) 155 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. 156 | # shellcheck disable=SC2039,SC3045 157 | ulimit -n "$MAX_FD" || 158 | warn "Could not set maximum file descriptor limit to $MAX_FD" 159 | esac 160 | fi 161 | 162 | # Collect all arguments for the java command, stacking in reverse order: 163 | # * args from the command line 164 | # * the main class name 165 | # * -classpath 166 | # * -D...appname settings 167 | # * --module-path (only if needed) 168 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 169 | 170 | # For Cygwin or MSYS, switch paths to Windows format before running java 171 | if "$cygwin" || "$msys" ; then 172 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 173 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 174 | 175 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 176 | 177 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 178 | for arg do 179 | if 180 | case $arg in #( 181 | -*) false ;; # don't mess with options #( 182 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 183 | [ -e "$t" ] ;; #( 184 | *) false ;; 185 | esac 186 | then 187 | arg=$( cygpath --path --ignore --mixed "$arg" ) 188 | fi 189 | # Roll the args list around exactly as many times as the number of 190 | # args, so each arg winds up back in the position where it started, but 191 | # possibly modified. 192 | # 193 | # NB: a `for` loop captures its iteration list before it begins, so 194 | # changing the positional parameters here affects neither the number of 195 | # iterations, nor the values presented in `arg`. 196 | shift # remove old arg 197 | set -- "$@" "$arg" # push replacement arg 198 | done 199 | fi 200 | 201 | 202 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 203 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 204 | 205 | # Collect all arguments for the java command: 206 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, 207 | # and any embedded shellness will be escaped. 208 | # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be 209 | # treated as '${Hostname}' itself on the command line. 210 | 211 | set -- \ 212 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 213 | -classpath "$CLASSPATH" \ 214 | org.gradle.wrapper.GradleWrapperMain \ 215 | "$@" 216 | 217 | # Stop when "xargs" is not available. 218 | if ! command -v xargs >/dev/null 2>&1 219 | then 220 | die "xargs is not available" 221 | fi 222 | 223 | # Use "xargs" to parse quoted args. 224 | # 225 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 226 | # 227 | # In Bash we could simply go: 228 | # 229 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 230 | # set -- "${ARGS[@]}" "$@" 231 | # 232 | # but POSIX shell has neither arrays nor command substitution, so instead we 233 | # post-process each arg (as a line of input to sed) to backslash-escape any 234 | # character that might be a shell metacharacter, then use eval to reverse 235 | # that process (while maintaining the separation between arguments), and wrap 236 | # the whole thing up as a single "set" statement. 237 | # 238 | # This will of course break if any of these variables contains a newline or 239 | # an unmatched quote. 240 | # 241 | 242 | eval "set -- $( 243 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 244 | xargs -n1 | 245 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 246 | tr '\n' ' ' 247 | )" '"$@"' 248 | 249 | exec "$JAVACMD" "$@" 250 | --------------------------------------------------------------------------------