This commit is contained in:
Chipperfluff 2025-12-19 17:49:13 +01:00
parent 7061142d56
commit f096a93b86
22 changed files with 253 additions and 32 deletions

View File

@ -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());

View File

@ -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;

View File

@ -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); // 1030 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);
}
}

View File

@ -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;

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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(

View File

@ -10,7 +10,7 @@ public enum ChipperToolMaterial implements ToolMaterial {
@Override
public int getDurability() {
return 1561; // diamond-ish but cursed
return 5;
}
@Override

View File

@ -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() {}
}

View File

@ -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<ScheduledTask> 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<ScheduledTask> 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;
}
}
}

View File

@ -19,12 +19,14 @@
"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",
"item.chipi.chipper_leggings": "Chipper Leggings",
@ -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 shouldnt."
"tooltip.chipi.chipper_hoe": "§7Makes things grow.§r §8They shouldnt.",
"tooltip.chipi.mep_milk": "§7Warm.§r §8You probably shouldn't drink this."
}

View File

@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "chipi:item/mep_milk"
}
}

View File

@ -0,0 +1,7 @@
{
"entity.mep.milk": {
"sounds": [
"chipi:mep_milk"
]
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 279 B

After

Width:  |  Height:  |  Size: 278 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 161 B

After

Width:  |  Height:  |  Size: 262 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 181 B

After

Width:  |  Height:  |  Size: 313 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 168 B

After

Width:  |  Height:  |  Size: 267 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 194 B

After

Width:  |  Height:  |  Size: 326 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 336 B

View File

@ -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)),