diff --git a/gradle.properties b/gradle.properties index c5b7f7f..35727d4 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,7 +6,7 @@ minecraft_version=1.20.1 yarn_mappings=1.20.1+build.10 loader_version=0.18.3 # Mod Properties -mod_version=26.2.12 +mod_version=26.2.13 maven_group=dev.tggamesyt archives_base_name=szar # Dependencies diff --git a/src/client/java/dev/tggamesyt/szar/client/mixin/RadiationHeartMixin.java b/src/client/java/dev/tggamesyt/szar/client/mixin/RadiationHeartMixin.java new file mode 100644 index 0000000..b338f7f --- /dev/null +++ b/src/client/java/dev/tggamesyt/szar/client/mixin/RadiationHeartMixin.java @@ -0,0 +1,25 @@ +package dev.tggamesyt.szar.client.mixin; + +import dev.tggamesyt.szar.Szar; +import net.minecraft.client.gui.hud.InGameHud; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.effect.StatusEffects; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(InGameHud.HeartType.class) +public class RadiationHeartMixin { + + @Inject( + method = "fromPlayerState", + at = @At("HEAD"), + cancellable = true + ) + private static void radiationHeart(PlayerEntity player, CallbackInfoReturnable cir) { + if (player.hasStatusEffect(Szar.RADIATION)) { + cir.setReturnValue(InGameHud.HeartType.POISONED); + } + } +} diff --git a/src/client/resources/szar.client.mixins.json b/src/client/resources/szar.client.mixins.json index cce8fa8..294c188 100644 --- a/src/client/resources/szar.client.mixins.json +++ b/src/client/resources/szar.client.mixins.json @@ -4,7 +4,8 @@ "package": "dev.tggamesyt.szar.client.mixin", "compatibilityLevel": "JAVA_17", "client": [ - "MouseMixin" + "MouseMixin", + "RadiationHeartMixin" ], "injectors": { "defaultRequire": 1 diff --git a/src/main/generated/.cache/0dcec3edc46b99b91b10474633480b6842e700fc b/src/main/generated/.cache/0dcec3edc46b99b91b10474633480b6842e700fc index e2f7c4e..5fced18 100644 --- a/src/main/generated/.cache/0dcec3edc46b99b91b10474633480b6842e700fc +++ b/src/main/generated/.cache/0dcec3edc46b99b91b10474633480b6842e700fc @@ -1,3 +1,3 @@ -// 1.20.1 2026-02-11T16:16:44.8131744 szar/World Gen +// 1.20.1 2026-02-13T13:11:58.9342791 szar/World Gen 1d26b5da3b0a2ea6b23d456d1f0b82455a788ca1 data\szar\worldgen\configured_feature\uranium_ore.json 32864170bdb41310f9ee5d06f5720dfdb3badb6d data\szar\worldgen\placed_feature\uranium_ore_placed.json diff --git a/src/main/generated/.cache/79d6404f7b0803346bb38c848032926817f10037 b/src/main/generated/.cache/79d6404f7b0803346bb38c848032926817f10037 index 7f73d5a..5aff0d6 100644 --- a/src/main/generated/.cache/79d6404f7b0803346bb38c848032926817f10037 +++ b/src/main/generated/.cache/79d6404f7b0803346bb38c848032926817f10037 @@ -1,2 +1,2 @@ -// 1.20.1 2026-02-11T16:16:44.8131744 szar/Tags for minecraft:point_of_interest_type +// 1.20.1 2026-02-13T13:11:58.9352765 szar/Tags for minecraft:point_of_interest_type eba137b51c50a7143a3668876f41adaa1447b1d1 data\minecraft\tags\point_of_interest_type\acquirable_job_site.json diff --git a/src/main/generated/.cache/e8da7d0da6535b734ad1b062d141fd76f701db77 b/src/main/generated/.cache/e8da7d0da6535b734ad1b062d141fd76f701db77 index 4b5a10c..e6b58a5 100644 --- a/src/main/generated/.cache/e8da7d0da6535b734ad1b062d141fd76f701db77 +++ b/src/main/generated/.cache/e8da7d0da6535b734ad1b062d141fd76f701db77 @@ -1,2 +1,2 @@ -// 1.20.1 2026-02-11T16:16:44.81217 szar/Tags for minecraft:item -6995bcff12c66325bf8878f8f536d542b4b8776e data\minecraft\tags\items\music_discs.json +// 1.20.1 2026-02-13T13:11:58.9332826 szar/Tags for minecraft:item +044a7669228ee893e38875357ee12c83cdad7ec6 data\minecraft\tags\items\music_discs.json diff --git a/src/main/generated/data/minecraft/tags/items/music_discs.json b/src/main/generated/data/minecraft/tags/items/music_discs.json index d88fb30..02b0cfa 100644 --- a/src/main/generated/data/minecraft/tags/items/music_discs.json +++ b/src/main/generated/data/minecraft/tags/items/music_discs.json @@ -1,6 +1,7 @@ { "replace": false, "values": [ - "szar:pop_tart" + "szar:pop_tart", + "szar:baiter" ] } \ No newline at end of file diff --git a/src/main/java/dev/tggamesyt/szar/ModItemTagProvider.java b/src/main/java/dev/tggamesyt/szar/ModItemTagProvider.java index 7d68646..157342a 100644 --- a/src/main/java/dev/tggamesyt/szar/ModItemTagProvider.java +++ b/src/main/java/dev/tggamesyt/szar/ModItemTagProvider.java @@ -24,5 +24,6 @@ public class ModItemTagProvider extends FabricTagProvider.ItemTagProvider { @Override protected void configure(RegistryWrapper.WrapperLookup lookup) { getOrCreateTagBuilder(ItemTags.MUSIC_DISCS).add(Szar.POPTART); + getOrCreateTagBuilder(ItemTags.MUSIC_DISCS).add(Szar.BAITER_DISK); } } \ No newline at end of file diff --git a/src/main/java/dev/tggamesyt/szar/RadiatedBlock.java b/src/main/java/dev/tggamesyt/szar/RadiatedBlock.java new file mode 100644 index 0000000..7972049 --- /dev/null +++ b/src/main/java/dev/tggamesyt/szar/RadiatedBlock.java @@ -0,0 +1,81 @@ +package dev.tggamesyt.szar; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.entity.Entity; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.particle.DustParticleEffect; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.random.Random; +import net.minecraft.world.World; +import net.minecraft.entity.effect.StatusEffectInstance; +import org.joml.Vector3f; + +public class RadiatedBlock extends Block { + + private static final DustParticleEffect GREEN_DUST = + new DustParticleEffect(new Vector3f(0.2f, 1.0f, 0.2f), 1.0f); + + public RadiatedBlock(Settings settings) { + super(settings); + } + + // Standing on it + @Override + public void onSteppedOn(World world, BlockPos pos, BlockState state, Entity entity) { + if (!world.isClient && entity instanceof LivingEntity living) { + applyRadiation(living, 60, 0); + } + + spawnParticles(world, pos); + super.onSteppedOn(world, pos, state, entity); + } + + // When mined + @Override + public void onBreak(World world, BlockPos pos, BlockState state, PlayerEntity player) { + if (!world.isClient) { + applyRadiation(player, 200, 1); + } + + spawnParticles(world, pos); + super.onBreak(world, pos, state, player); + } + + // Random tick glow like redstone + @Override + public void randomDisplayTick(BlockState state, World world, BlockPos pos, Random random) { + if (random.nextFloat() < 0.3f) { + spawnParticles(world, pos); + } + } + + private void applyRadiation(LivingEntity entity, int duration, int amplifier) { + entity.addStatusEffect(new StatusEffectInstance( + Szar.RADIATION, + duration, + amplifier, + true, + true, + true + )); + } + + private void spawnParticles(World world, BlockPos pos) { + if (world instanceof ServerWorld serverWorld) { + for (int i = 0; i < 5; i++) { + serverWorld.spawnParticles( + GREEN_DUST, + pos.getX() + world.random.nextDouble(), + pos.getY() + 1.0, + pos.getZ() + world.random.nextDouble(), + 1, + 0, 0, 0, + 0 + ); + } + } + } +} diff --git a/src/main/java/dev/tggamesyt/szar/RadiatedItem.java b/src/main/java/dev/tggamesyt/szar/RadiatedItem.java new file mode 100644 index 0000000..f4fe5a5 --- /dev/null +++ b/src/main/java/dev/tggamesyt/szar/RadiatedItem.java @@ -0,0 +1,65 @@ +package dev.tggamesyt.szar; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.effect.StatusEffectInstance; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +public class RadiatedItem extends Item { + + private final double radiationPerItem; // e.g. 0.1 per item + private final double heldMultiplier; // extra multiplier when selected + + public RadiatedItem(Settings settings, double radiationPerItem, double heldMultiplier) { + super(settings); + this.radiationPerItem = radiationPerItem; + this.heldMultiplier = heldMultiplier; + } + + public double getRadiationPerItem() { + return radiationPerItem; + } + + @Override + public void inventoryTick(ItemStack stack, World world, Entity entity, int slot, boolean selected) { + if (!world.isClient && entity instanceof PlayerEntity player) { + + double totalRadiation = 0.0; + + // Loop entire inventory + for (ItemStack invStack : player.getInventory().main) { + if (invStack.getItem() instanceof RadiatedItem radiatedItem) { + + double perItem = radiatedItem.getRadiationPerItem(); + double stackContribution = invStack.getCount() * perItem; + + // If this stack is selected, increase its contribution + if (player.getInventory().getStack(slot) == invStack && selected) { + stackContribution *= radiatedItem.heldMultiplier; + } + + totalRadiation += stackContribution; + } + } + + // Round final radiation to amplifier level + int amplifier = (int) Math.round(totalRadiation); + + if (amplifier > 0) { + player.addStatusEffect(new StatusEffectInstance( + Szar.RADIATION, + 100, + amplifier - 1, + true, + false, + true + )); + } + } + + super.inventoryTick(stack, world, entity, slot, selected); + } +} diff --git a/src/main/java/dev/tggamesyt/szar/RadiationStatusEffect.java b/src/main/java/dev/tggamesyt/szar/RadiationStatusEffect.java new file mode 100644 index 0000000..f66fc9a --- /dev/null +++ b/src/main/java/dev/tggamesyt/szar/RadiationStatusEffect.java @@ -0,0 +1,69 @@ +package dev.tggamesyt.szar; + +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.damage.DamageSource; +import net.minecraft.entity.effect.StatusEffect; +import net.minecraft.entity.effect.StatusEffectCategory; +import net.minecraft.server.world.ServerWorld; + +public class RadiationStatusEffect extends StatusEffect { + + public RadiationStatusEffect() { + super(StatusEffectCategory.HARMFUL, 0x39FF14); + } + + @Override + public boolean canApplyUpdateEffect(int duration, int amplifier) { + int level = amplifier + 1; + int interval = (int) getInterpolatedInterval(level); + + return duration % Math.max(interval, 1) == 0; + } + + @Override + public void applyUpdateEffect(LivingEntity entity, int amplifier) { + int level = amplifier + 1; + + float damage = (float) getInterpolatedDamage(level); + + entity.damage( + entity.getDamageSources().magic(), + damage + ); + } + + /* ========================= */ + /* INTERPOLATION */ + /* ========================= */ + + private double getInterpolatedDamage(int level) { + if (level <= 1) return 1.0; + + if (level <= 10) + return lerp(level, 1, 10, 1.0, 2.0); + + if (level <= 100) + return lerp(level, 10, 100, 2.0, 4.0); + + return lerp(level, 100, 255, 4.0, 8.0); + } + + private double getInterpolatedInterval(int level) { + if (level <= 1) return 200; + + if (level <= 10) + return lerp(level, 1, 10, 200, 100); + + if (level <= 100) + return lerp(level, 10, 100, 100, 40); + + return lerp(level, 100, 255, 40, 20); + } + + private double lerp(double value, double minLevel, double maxLevel, + double minValue, double maxValue) { + + double t = (value - minLevel) / (maxLevel - minLevel); + return minValue + t * (maxValue - minValue); + } +} diff --git a/src/main/java/dev/tggamesyt/szar/Szar.java b/src/main/java/dev/tggamesyt/szar/Szar.java index d7c0501..be23d0c 100644 --- a/src/main/java/dev/tggamesyt/szar/Szar.java +++ b/src/main/java/dev/tggamesyt/szar/Szar.java @@ -91,7 +91,7 @@ public class Szar implements ModInitializer { public static final Block SZAR_BLOCK = new SzarBlock(); public static final Block URANIUM_BLOCK = - new Block( + new RadiatedBlock( FabricBlockSettings.create() .strength(20.0f, 1200.0f).requiresTool() ); @@ -261,6 +261,7 @@ public class Szar implements ModInitializer { entries.add(Szar.URANIUM_ROD); entries.add(Szar.ATOM_CORE); entries.add(Szar.ATOM); + entries.add(Szar.BAITER_DISK); }) .build() ); @@ -571,6 +572,13 @@ public class Szar implements ModInitializer { new DrogEffect() ); public static final StatusEffect ARRESTED = Registry.register(Registries.STATUS_EFFECT, new Identifier(MOD_ID, "arrested"), new ArrestedEffect()); + public static final StatusEffect RADIATION = Registry.register( + Registries.STATUS_EFFECT, + new Identifier(MOD_ID, "radiation"), + new RadiationStatusEffect() + ); + public static final RegistryKey RADIATION_DAMAGE = + RegistryKey.of(RegistryKeys.DAMAGE_TYPE, new Identifier("yourmod", "radiation")); public static final Item AK_AMMO = Registry.register( Registries.ITEM, new Identifier(MOD_ID, "bullet"), @@ -642,17 +650,17 @@ public class Szar implements ModInitializer { public static final Item URANIUM = Registry.register( Registries.ITEM, new Identifier(MOD_ID, "uranium"), - new Item(new Item.Settings()) + new RadiatedItem(new Item.Settings(), 0.1, 1.1) ); public static final Item URANIUM_ROD = Registry.register( Registries.ITEM, new Identifier(MOD_ID, "uranium_rod"), - new Item(new Item.Settings()) + new RadiatedItem(new Item.Settings(), 0.2, 1.2) ); public static final Item ATOM_CORE = Registry.register( Registries.ITEM, new Identifier(MOD_ID, "nuke_core"), - new Item(new Item.Settings()) + new RadiatedItem(new Item.Settings(), 1, 2) ); public static final Item KEY_ITEM = Registry.register( Registries.ITEM, @@ -796,6 +804,13 @@ public class Szar implements ModInitializer { hunger((Math.random() < 0.5) ? 6 : 7) // SIX OR SEVEN .build()), 217) ); + public static final SoundEvent BAITER = + SoundEvent.of(new Identifier(MOD_ID, "baiter")); + public static final Item BAITER_DISK = Registry.register( + Registries.ITEM, + new Identifier(MOD_ID, "baiter"), + new MusicDiscItem(12, BAITER, new Item.Settings(), 172) + ); public static final Item ATOM_DETONATOR = Registry.register( Registries.ITEM, new Identifier(MOD_ID, "detonator"), diff --git a/src/main/resources/assets/szar/lang/en_us.json b/src/main/resources/assets/szar/lang/en_us.json index 5c0d4e1..0e884dc 100644 --- a/src/main/resources/assets/szar/lang/en_us.json +++ b/src/main/resources/assets/szar/lang/en_us.json @@ -61,5 +61,10 @@ "item.szar.uranium": "Uranium", "item.szar.uranium_rod": "Uranium Rod", "item.szar.nuke_core": "Nuke Core", - "item.szar.atom": "Nuke" + "item.szar.atom": "Nuke", + "effect.szar.radiation": "Radiation", + "item.szar.baiter": "Music Disk", + "item.szar.baiter.desc": "HaVexy - Hyperabaiter Disstrack", + "death.attack.radiation": "%1$s succumbed to radiation sickness", + "death.attack.radiation.player": "%1$s was lethally irradiated by %2$s" } diff --git a/src/main/resources/assets/szar/models/item/baiter.json b/src/main/resources/assets/szar/models/item/baiter.json new file mode 100644 index 0000000..c0680b1 --- /dev/null +++ b/src/main/resources/assets/szar/models/item/baiter.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "szar:item/baiter" + } +} diff --git a/src/main/resources/assets/szar/sounds.json b/src/main/resources/assets/szar/sounds.json index ce67c06..16b3f35 100644 --- a/src/main/resources/assets/szar/sounds.json +++ b/src/main/resources/assets/szar/sounds.json @@ -42,5 +42,13 @@ "stream": true } ] + }, + "baiter": { + "sounds": [ + { + "name": "szar:baiter", + "stream": true + } + ] } } diff --git a/src/main/resources/assets/szar/sounds/baiter.ogg b/src/main/resources/assets/szar/sounds/baiter.ogg new file mode 100644 index 0000000..8b7546d Binary files /dev/null and b/src/main/resources/assets/szar/sounds/baiter.ogg differ diff --git a/src/main/resources/assets/szar/textures/item/baiter.png b/src/main/resources/assets/szar/textures/item/baiter.png new file mode 100644 index 0000000..4d5cc73 Binary files /dev/null and b/src/main/resources/assets/szar/textures/item/baiter.png differ diff --git a/src/main/resources/assets/szar/textures/mob_effect/radiation.png b/src/main/resources/assets/szar/textures/mob_effect/radiation.png new file mode 100644 index 0000000..cbd9e73 Binary files /dev/null and b/src/main/resources/assets/szar/textures/mob_effect/radiation.png differ diff --git a/src/main/resources/data/szar/damage_type/radiation.json b/src/main/resources/data/szar/damage_type/radiation.json new file mode 100644 index 0000000..7ca48b7 --- /dev/null +++ b/src/main/resources/data/szar/damage_type/radiation.json @@ -0,0 +1,5 @@ +{ + "message_id": "radiation", + "exhaustion": 0.1, + "scaling": "never" +} diff --git a/src/main/resources/szar.accesswidener b/src/main/resources/szar.accesswidener index a3a3bf4..56dccd0 100644 --- a/src/main/resources/szar.accesswidener +++ b/src/main/resources/szar.accesswidener @@ -1,4 +1,5 @@ accessWidener v2 named accessible field net/minecraft/client/gui/hud/InGameHud spyglassScale F -accessible field net/minecraft/entity/LivingEntity jumping Z \ No newline at end of file +accessible field net/minecraft/entity/LivingEntity jumping Z +accessible class net/minecraft/client/gui/hud/InGameHud$HeartType \ No newline at end of file