diff --git a/src/main/java/net/Chipperfluff/chipi/ChipiMod.java b/src/main/java/net/Chipperfluff/chipi/ChipiMod.java index c26b89a..af6d378 100644 --- a/src/main/java/net/Chipperfluff/chipi/ChipiMod.java +++ b/src/main/java/net/Chipperfluff/chipi/ChipiMod.java @@ -8,13 +8,14 @@ import net.Chipperfluff.chipi.effect.ChipiHungerHandler; import net.Chipperfluff.chipi.effect.ModEffects; import net.Chipperfluff.chipi.entity.ModEntities; import net.Chipperfluff.chipi.entity.SpawnLogic; -import net.Chipperfluff.chipi.entity.custom.MepEntity; +import net.Chipperfluff.chipi.entity.MepEntity; import net.Chipperfluff.chipi.item.ModItemGroups; import net.Chipperfluff.chipi.item.ModItems; import net.Chipperfluff.chipi.server.ChipiServerEvents; - +import net.Chipperfluff.chipi.sound.ModSounds; import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.object.builder.v1.entity.FabricDefaultAttributeRegistry; +import net.Chipperfluff.chipi.util.TickScheduler; public class ChipiMod implements ModInitializer { @@ -33,6 +34,9 @@ public class ChipiMod implements ModInitializer { ChipiHungerHandler.register(); SpawnLogic.register(); + ModSounds.register(); + + TickScheduler.init(); CommandHandler.register(); FabricDefaultAttributeRegistry.register(ModEntities.MEP, MepEntity.createMepAttributes()); diff --git a/src/main/java/net/Chipperfluff/chipi/client/entity/MepRenderer.java b/src/main/java/net/Chipperfluff/chipi/client/entity/MepRenderer.java index 989a15b..842ab5b 100644 --- a/src/main/java/net/Chipperfluff/chipi/client/entity/MepRenderer.java +++ b/src/main/java/net/Chipperfluff/chipi/client/entity/MepRenderer.java @@ -1,7 +1,7 @@ package net.Chipperfluff.chipi.client.entity; import net.Chipperfluff.chipi.ChipiMod; -import net.Chipperfluff.chipi.entity.custom.MepEntity; +import net.Chipperfluff.chipi.entity.MepEntity; import net.minecraft.client.render.entity.BipedEntityRenderer; import net.minecraft.client.render.entity.EntityRendererFactory; import net.minecraft.client.render.entity.model.BipedEntityModel; diff --git a/src/main/java/net/Chipperfluff/chipi/entity/custom/MepEntity.java b/src/main/java/net/Chipperfluff/chipi/entity/MepEntity.java similarity index 65% rename from src/main/java/net/Chipperfluff/chipi/entity/custom/MepEntity.java rename to src/main/java/net/Chipperfluff/chipi/entity/MepEntity.java index 07846d1..ea4ac78 100644 --- a/src/main/java/net/Chipperfluff/chipi/entity/custom/MepEntity.java +++ b/src/main/java/net/Chipperfluff/chipi/entity/MepEntity.java @@ -1,4 +1,4 @@ -package net.Chipperfluff.chipi.entity.custom; +package net.Chipperfluff.chipi.entity; import net.minecraft.block.BlockState; import net.minecraft.block.SlabBlock; @@ -16,10 +16,19 @@ import net.minecraft.entity.attribute.EntityAttributes; import net.minecraft.entity.damage.DamageSource; import net.minecraft.entity.mob.PathAwareEntity; import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.sound.SoundCategory; import net.minecraft.state.property.Properties; +import net.minecraft.util.ActionResult; +import net.minecraft.util.Hand; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; +import net.Chipperfluff.chipi.item.ModItems; +import net.Chipperfluff.chipi.sound.ModSounds; +import net.Chipperfluff.chipi.util.TickScheduler; + public class MepEntity extends PathAwareEntity { private static final int FORGET_TARGET_AFTER_TICKS = 100; @@ -31,6 +40,8 @@ public class MepEntity extends PathAwareEntity { super(entityType, world); } + // === AI === + @Override protected void initGoals() { this.goalSelector.add(1, new SwimGoal(this)); @@ -58,6 +69,8 @@ public class MepEntity extends PathAwareEntity { .add(EntityAttributes.GENERIC_FOLLOW_RANGE, 32.0); } + // === Combat memory === + @Override public boolean damage(DamageSource source, float amount) { if (source.getAttacker() instanceof PlayerEntity) { @@ -74,12 +87,11 @@ public class MepEntity extends PathAwareEntity { LivingEntity target = this.getTarget(); if (!(target instanceof PlayerEntity player)) { - ticksSinceLastSeen = 0; angryAtPlayer = false; + ticksSinceLastSeen = 0; return; } - // Protected players instantly cancel targeting if (isPlayerProtected(player)) { clearTarget(); return; @@ -91,8 +103,6 @@ public class MepEntity extends PathAwareEntity { this.getNavigation().startMovingTo(player, 1.2D); } else { ticksSinceLastSeen++; - - // Keep chasing for a while even without LOS if (ticksSinceLastSeen <= FORGET_TARGET_AFTER_TICKS) { this.getNavigation().startMovingTo(player, 1.2D); } else { @@ -131,4 +141,57 @@ public class MepEntity extends PathAwareEntity { public boolean canImmediatelyDespawn(double distanceSquared) { return false; } + + // === MILKING (FEVER DREAM EDITION) === + + @Override + public ActionResult interactMob(PlayerEntity player, Hand hand) { + ItemStack stack = player.getStackInHand(hand); + + if (stack.isOf(Items.BUCKET) && !this.isBaby()) { + if (!player.getWorld().isClient) { + + stack.decrement(1); + player.giveItemStack(new ItemStack(ModItems.MEP_MILK)); + + // ---- base sound ---- + float basePitch = 0.3f + this.random.nextFloat() * 1.9f; + float baseVolume = 0.9f + this.random.nextFloat() * 0.6f; + + this.getWorld().playSound( + null, + this.getBlockPos(), + ModSounds.MEP_MILK, + SoundCategory.NEUTRAL, + baseVolume, + basePitch + ); + + // ---- single delayed echo (10% chance) ---- + if (this.random.nextFloat() < 0.10f) { + + int delay = 10 + this.random.nextInt(21); // 10–30 ticks + + float echoPitch = basePitch * 0.5f; + float echoVolume = baseVolume * 0.5f; + + TickScheduler.schedule(delay, () -> { + if (!this.isAlive()) return; + + this.getWorld().playSound( + null, + this.getBlockPos(), + ModSounds.MEP_MILK, + SoundCategory.NEUTRAL, + echoVolume, + echoPitch + ); + }); + } + } + return ActionResult.SUCCESS; + } + + return super.interactMob(player, hand); + } } diff --git a/src/main/java/net/Chipperfluff/chipi/entity/ModEntities.java b/src/main/java/net/Chipperfluff/chipi/entity/ModEntities.java index 8371741..43c1371 100644 --- a/src/main/java/net/Chipperfluff/chipi/entity/ModEntities.java +++ b/src/main/java/net/Chipperfluff/chipi/entity/ModEntities.java @@ -1,6 +1,6 @@ package net.Chipperfluff.chipi.entity; -import net.Chipperfluff.chipi.entity.custom.MepEntity; +import net.Chipperfluff.chipi.entity.MepEntity; import net.fabricmc.fabric.api.object.builder.v1.entity.FabricEntityTypeBuilder; diff --git a/src/main/java/net/Chipperfluff/chipi/item/MepMilkItem.java b/src/main/java/net/Chipperfluff/chipi/item/MepMilkItem.java new file mode 100644 index 0000000..88598d9 --- /dev/null +++ b/src/main/java/net/Chipperfluff/chipi/item/MepMilkItem.java @@ -0,0 +1,30 @@ +package net.Chipperfluff.chipi.item; + +import net.Chipperfluff.chipi.effect.ModEffects; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.effect.StatusEffectInstance; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.world.World; + +public class MepMilkItem extends Item { + + public MepMilkItem(Settings settings) { + super(settings); + } + + @Override + public ItemStack finishUsing(ItemStack stack, World world, LivingEntity user) { + if (!world.isClient) { + user.addStatusEffect( + new StatusEffectInstance( + ModEffects.CHIPI_BLESSING, + 20 * 20, + 0 + ) + ); + } + return new ItemStack(Items.BUCKET); + } +} diff --git a/src/main/java/net/Chipperfluff/chipi/item/ModItemGroups.java b/src/main/java/net/Chipperfluff/chipi/item/ModItemGroups.java index 6e8fa08..cfd6aff 100644 --- a/src/main/java/net/Chipperfluff/chipi/item/ModItemGroups.java +++ b/src/main/java/net/Chipperfluff/chipi/item/ModItemGroups.java @@ -27,12 +27,15 @@ public class ModItemGroups { entries.add(ModBlocks.CHIPPER_ALLOY_BLOCK); // Items - entries.add(ModItems.NUT); entries.add(ModItems.RAW_CHIPPER_ORE); entries.add(ModItems.CHIPPER_INGOT); entries.add(ModItems.CHIPPER_ALLOY); entries.add(ModItems.MEP_SPAWN_EGG); + // Food + entries.add(ModItems.MEP_MILK); + entries.add(ModItems.NUT); + // Armor entries.add(ModItems.CHIPPER_HELMET); entries.add(ModItems.CHIPPER_CHESTPLATE); diff --git a/src/main/java/net/Chipperfluff/chipi/item/ModItems.java b/src/main/java/net/Chipperfluff/chipi/item/ModItems.java index a701813..66c2f7d 100644 --- a/src/main/java/net/Chipperfluff/chipi/item/ModItems.java +++ b/src/main/java/net/Chipperfluff/chipi/item/ModItems.java @@ -10,6 +10,8 @@ import net.minecraft.registry.Registries; import net.minecraft.registry.Registry; import net.minecraft.util.Identifier; import net.Chipperfluff.chipi.item.tool.ChipperToolMaterial; +import net.Chipperfluff.chipi.item.MepMilkItem; +import net.minecraft.item.Items; public class ModItems { @@ -55,12 +57,6 @@ public class ModItems { // ===== NORMAL ITEMS ===== - public static final Item NUT = Registry.register( - Registries.ITEM, - new Identifier(ChipiMod.MOD_ID, "nut"), - new Item(new FabricItemSettings().food(ModFoodComponents.NUT)) - ); - public static final Item RAW_CHIPPER_ORE = Registry.register( Registries.ITEM, new Identifier(ChipiMod.MOD_ID, "raw_chipper_ore"), @@ -79,6 +75,20 @@ public class ModItems { new Item(new FabricItemSettings()) ); + // ===== FOOD ITEMS ===== + + public static final Item NUT = Registry.register( + Registries.ITEM, + new Identifier(ChipiMod.MOD_ID, "nut"), + new Item(new FabricItemSettings().food(ModFoodComponents.NUT)) + ); + + public static final Item MEP_MILK = Registry.register( + Registries.ITEM, + new Identifier(ChipiMod.MOD_ID, "mep_milk"), + new MepMilkItem(new Item.Settings().maxCount(1).recipeRemainder(Items.BUCKET)) + ); + // ===== ARMOR ===== public static final Item CHIPPER_HELMET = Registry.register( diff --git a/src/main/java/net/Chipperfluff/chipi/item/tool/ChipperToolMaterial.java b/src/main/java/net/Chipperfluff/chipi/item/tool/ChipperToolMaterial.java index c5728f1..f3b9398 100644 --- a/src/main/java/net/Chipperfluff/chipi/item/tool/ChipperToolMaterial.java +++ b/src/main/java/net/Chipperfluff/chipi/item/tool/ChipperToolMaterial.java @@ -10,7 +10,7 @@ public enum ChipperToolMaterial implements ToolMaterial { @Override public int getDurability() { - return 1561; // diamond-ish but cursed + return 5; } @Override diff --git a/src/main/java/net/Chipperfluff/chipi/sound/ModSounds.java b/src/main/java/net/Chipperfluff/chipi/sound/ModSounds.java new file mode 100644 index 0000000..72f4a09 --- /dev/null +++ b/src/main/java/net/Chipperfluff/chipi/sound/ModSounds.java @@ -0,0 +1,23 @@ +package net.Chipperfluff.chipi.sound; + +import net.Chipperfluff.chipi.ChipiMod; +import net.minecraft.registry.Registries; +import net.minecraft.registry.Registry; +import net.minecraft.sound.SoundEvent; +import net.minecraft.util.Identifier; + +public class ModSounds { + + public static final SoundEvent MEP_MILK = register("entity.mep.milk"); + + private static SoundEvent register(String id) { + Identifier identifier = new Identifier(ChipiMod.MOD_ID, id); + return Registry.register( + Registries.SOUND_EVENT, + identifier, + SoundEvent.of(identifier) + ); + } + + public static void register() {} +} diff --git a/src/main/java/net/Chipperfluff/chipi/util/TickScheduler.java b/src/main/java/net/Chipperfluff/chipi/util/TickScheduler.java new file mode 100644 index 0000000..a0c5299 --- /dev/null +++ b/src/main/java/net/Chipperfluff/chipi/util/TickScheduler.java @@ -0,0 +1,52 @@ +package net.Chipperfluff.chipi.util; + +import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents; +import net.minecraft.server.MinecraftServer; + +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + +public class TickScheduler { + + private static final List TASKS = new LinkedList<>(); + private static boolean registered = false; + + public static void init() { + if (registered) return; + registered = true; + + ServerTickEvents.END_SERVER_TICK.register(TickScheduler::tick); + } + + public static void schedule(int delayTicks, Runnable action) { + TASKS.add(new ScheduledTask(delayTicks, action)); + } + + private static void tick(MinecraftServer server) { + Iterator it = TASKS.iterator(); + while (it.hasNext()) { + ScheduledTask task = it.next(); + task.ticks--; + + if (task.ticks <= 0) { + try { + task.action.run(); + } catch (Exception e) { + e.printStackTrace(); + } + it.remove(); + } + } + } + + private static class ScheduledTask { + int ticks; + Runnable action; + + ScheduledTask(int ticks, Runnable action) { + this.ticks = ticks; + this.action = action; + } + } +} diff --git a/src/main/resources/assets/chipi/lang/en_us.json b/src/main/resources/assets/chipi/lang/en_us.json index d4191d7..2ad533e 100644 --- a/src/main/resources/assets/chipi/lang/en_us.json +++ b/src/main/resources/assets/chipi/lang/en_us.json @@ -19,11 +19,13 @@ "item.chipi.chipper_portal": "Chipper Portal", "item.chipi.chipper_ore": "Chipper Ore", "item.chipi.chipper_alloy_block": "Chipper Alloy Block", - "item.chipi.nut": "Nut", "item.chipi.raw_chipper_ore": "Raw Chipper Ore", "item.chipi.chipper_ingot": "Chipper Ingot", "item.chipi.chipper_alloy": "Chipper Alloy", "item.chipi.mep_spawn_egg": "Mep Spawn Egg", + + "item.chipi.nut": "Nut", + "item.chipi.mep_milk": "Mep Milk", "item.chipi.chipper_helmet": "Chipper Helmet", "item.chipi.chipper_chestplate": "Chipper Chestplate", @@ -58,5 +60,8 @@ "tooltip.chipi.chipper_pickaxe": "§7Breaks stone.§r §8Breaks trust.", "tooltip.chipi.chipper_axe": "§7Heavy swing.§r §8Heavier consequence.", "tooltip.chipi.chipper_shovel": "§7Digs fast.§r §8Finds nothing good.", - "tooltip.chipi.chipper_hoe": "§7Makes things grow.§r §8They shouldn’t." + "tooltip.chipi.chipper_hoe": "§7Makes things grow.§r §8They shouldn’t.", + + "tooltip.chipi.mep_milk": "§7Warm.§r §8You probably shouldn't drink this." + } diff --git a/src/main/resources/assets/chipi/models/item/mep_milk.json b/src/main/resources/assets/chipi/models/item/mep_milk.json new file mode 100644 index 0000000..1c4724a --- /dev/null +++ b/src/main/resources/assets/chipi/models/item/mep_milk.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "chipi:item/mep_milk" + } +} diff --git a/src/main/resources/assets/chipi/sounds.json b/src/main/resources/assets/chipi/sounds.json new file mode 100644 index 0000000..5c349f7 --- /dev/null +++ b/src/main/resources/assets/chipi/sounds.json @@ -0,0 +1,7 @@ +{ + "entity.mep.milk": { + "sounds": [ + "chipi:mep_milk" + ] + } +} diff --git a/src/main/resources/assets/chipi/sounds/mep_milk.ogg b/src/main/resources/assets/chipi/sounds/mep_milk.ogg new file mode 100644 index 0000000..793598d Binary files /dev/null and b/src/main/resources/assets/chipi/sounds/mep_milk.ogg differ diff --git a/src/main/resources/assets/chipi/sounds/mep_milk.wav b/src/main/resources/assets/chipi/sounds/mep_milk.wav new file mode 100644 index 0000000..29ae4dc Binary files /dev/null and b/src/main/resources/assets/chipi/sounds/mep_milk.wav differ diff --git a/src/main/resources/assets/chipi/textures/item/chipper_axe.png b/src/main/resources/assets/chipi/textures/item/chipper_axe.png index 6cb38e7..4e0cc1b 100644 Binary files a/src/main/resources/assets/chipi/textures/item/chipper_axe.png and b/src/main/resources/assets/chipi/textures/item/chipper_axe.png differ diff --git a/src/main/resources/assets/chipi/textures/item/chipper_hoe.png b/src/main/resources/assets/chipi/textures/item/chipper_hoe.png index f2d6cce..b6a94e4 100644 Binary files a/src/main/resources/assets/chipi/textures/item/chipper_hoe.png and b/src/main/resources/assets/chipi/textures/item/chipper_hoe.png differ diff --git a/src/main/resources/assets/chipi/textures/item/chipper_pickaxe.png b/src/main/resources/assets/chipi/textures/item/chipper_pickaxe.png index 405a273..0d57dba 100644 Binary files a/src/main/resources/assets/chipi/textures/item/chipper_pickaxe.png and b/src/main/resources/assets/chipi/textures/item/chipper_pickaxe.png differ diff --git a/src/main/resources/assets/chipi/textures/item/chipper_shovel.png b/src/main/resources/assets/chipi/textures/item/chipper_shovel.png index 1a67da1..671d1c7 100644 Binary files a/src/main/resources/assets/chipi/textures/item/chipper_shovel.png and b/src/main/resources/assets/chipi/textures/item/chipper_shovel.png differ diff --git a/src/main/resources/assets/chipi/textures/item/chipper_sword.png b/src/main/resources/assets/chipi/textures/item/chipper_sword.png index 2430c2f..b06929f 100644 Binary files a/src/main/resources/assets/chipi/textures/item/chipper_sword.png and b/src/main/resources/assets/chipi/textures/item/chipper_sword.png differ diff --git a/src/main/resources/assets/chipi/textures/item/mep_milk.png b/src/main/resources/assets/chipi/textures/item/mep_milk.png new file mode 100644 index 0000000..ecb6f19 Binary files /dev/null and b/src/main/resources/assets/chipi/textures/item/mep_milk.png differ diff --git a/tools/recolor/color_maps/chipper_orange.py b/tools/recolor/color_maps/chipper_orange.py index 4da829b..e199661 100644 --- a/tools/recolor/color_maps/chipper_orange.py +++ b/tools/recolor/color_maps/chipper_orange.py @@ -1,19 +1,31 @@ from tools.recolor import Color, ColorMask COLOR_MAP = [ - # ---- item/armor (teal -> orange) ---- - ColorMask(Color( 8, 37, 32), Color(100, 45, 10)), - ColorMask(Color( 14, 62, 53), Color(130, 60, 15)), - ColorMask(Color( 26, 168, 165), Color(160, 80, 20)), - ColorMask(Color( 32, 195, 179), Color(190, 100, 25)), - ColorMask(Color( 73, 234, 214), Color(220, 120, 30)), - ColorMask(Color(159, 248, 229), Color(235, 140, 40)), - ColorMask(Color(252, 252, 252), Color(255, 220, 180)), - # ---- model/armor (old teal -> orange) ---- - ColorMask(Color( 44, 224, 216), Color(130, 60, 15)), - ColorMask(Color( 45, 196, 178), Color(160, 80, 20)), - ColorMask(Color( 48, 208, 190), Color(190, 100, 25)), + # ============================================================ + # item / tool teal → orange (all observed variants) + # ============================================================ + + ColorMask(Color( 8, 37, 32), Color(100, 45, 10)), + ColorMask(Color( 14, 63, 54), Color(130, 60, 15)), + ColorMask(Color( 21, 99, 85), Color(145, 70, 18)), + ColorMask(Color( 30, 138, 119), Color(160, 80, 20)), + ColorMask(Color( 39, 178, 154), Color(190, 100, 25)), + ColorMask(Color( 43, 199, 172), Color(210, 115, 28)), + ColorMask(Color( 51, 235, 203), Color(220, 120, 30)), + ColorMask(Color( 73, 234, 214), Color(235, 140, 40)), + ColorMask(Color(107, 243, 227), Color(245, 160, 60)), + ColorMask(Color(137, 248, 240), Color(255, 180, 100)), + ColorMask(Color(159, 248, 229), Color(255, 200, 140)), + ColorMask(Color(164, 253, 240), Color(255, 220, 180)), + + # ============================================================ + # model / armor teal variants (older & lighter) + # ============================================================ + + ColorMask(Color( 44, 224, 216), Color(160, 80, 20)), + ColorMask(Color( 45, 196, 178), Color(190, 100, 25)), + ColorMask(Color( 48, 208, 190), Color(210, 115, 28)), ColorMask(Color( 74, 237, 217), Color(220, 120, 30)), ColorMask(Color(107, 243, 227), Color(235, 140, 40)), ColorMask(Color(154, 248, 240), Color(245, 160, 60)), @@ -21,11 +33,17 @@ COLOR_MAP = [ ColorMask(Color(180, 253, 238), Color(255, 200, 140)), ColorMask(Color(229, 255, 250), Color(255, 220, 180)), - # ---- already orange (identity, makes it safe to rerun) ---- + # ============================================================ + # already-orange safety (idempotent) + # ============================================================ + ColorMask(Color(100, 45, 10), Color(100, 45, 10)), ColorMask(Color(130, 60, 15), Color(130, 60, 15)), + ColorMask(Color(145, 70, 18), Color(145, 70, 18)), ColorMask(Color(160, 80, 20), Color(160, 80, 20)), + ColorMask(Color(175, 90, 22), Color(175, 90, 22)), ColorMask(Color(190, 100, 25), Color(190, 100, 25)), + ColorMask(Color(210, 115, 28), Color(210, 115, 28)), ColorMask(Color(220, 120, 30), Color(220, 120, 30)), ColorMask(Color(235, 140, 40), Color(235, 140, 40)), ColorMask(Color(245, 160, 60), Color(245, 160, 60)),