add first patch

This commit is contained in:
2026-07-31 10:34:32 +09:00
parent 03aac2e45e
commit b1cbc6c78d
6390 changed files with 547430 additions and 0 deletions
@@ -0,0 +1,914 @@
console.info("[SOCIETY] animalBase.js loaded");
const debug = false;
const debugData = (player, level, data, hearts) => {
player.tell(`:heart: ${data.getInt("affection")}-${hearts} hearts`);
player.tell(
`Day: ${Number(
(Math.floor(Number(level.dayTime() / 24000)) + 1).toFixed()
)}`
);
player.tell(`Mood: ${data.getInt("lastMood")}`);
player.tell(`Day Mood last set: ${data.getInt("ageLastSetMood")}`);
player.tell(`Pet: ${data.getInt("ageLastPet")}`);
player.tell(`Fed: ${data.getInt("ageLastFed")}`);
player.tell(`Boosted feed: ${data.getInt("ageLastBoosted")}`);
player.tell(`Dropped Special: ${data.getInt("ageLastDroppedSpecial")}`);
player.tell(`Milked: ${data.getInt("ageLastMilked")}`);
player.tell(`Magic Harvested: ${data.getInt("ageLastMagicHarvested")}`);
};
const initializeFarmAnimal = (day, target, level) => {
const data = target.persistentData;
if (!data.getInt("affection")) {
data.affection = 1;
level.spawnParticles(
"minecraft:heart",
true,
target.x,
target.y + 1.5,
target.z,
0,
0.1,
0,
1,
0.01
);
}
const newBaseDay = day - 1;
if (!data.getInt("ageLastPet")) data.ageLastPet = newBaseDay;
if (!data.getInt("ageLastFed")) data.ageLastFed = newBaseDay;
if (!data.getInt("ageLastDroppedSpecial")) data.ageLastDroppedSpecial = newBaseDay;
if (!data.getInt("ageLastMagicHarvested")) data.ageLastMagicHarvested = newBaseDay;
if (!data.getInt("ageLastMoodSet")) data.ageLastMoodSet = newBaseDay;
if (!data.getInt("ageLastBred")) data.ageLastBred = newBaseDay;
if (!data.getInt("ageLastMilked") && global.checkEntityTag(target, "society:milkable_animal"))
data.ageLastMilked = newBaseDay;
};
// Anti-frustration feature to be forgiving when re-logging
const handleFarmAnimalBackwardsCompat = (target, day) => {
const data = target.persistentData;
if (
day < data.getInt("ageLastPet") ||
data.getInt("ageLastPet") - day > 5000
) {
let newDay = day - 1;
data.ageLastPet = newDay;
data.ageLastMagicHarvested = newDay;
data.ageLastMilked = newDay;
data.ageLastDroppedSpecial = newDay;
data.ageLastBred = newDay;
data.ageLastFed = newDay;
data.ageLastMoodSet = newDay;
}
};
const checkAnimal = (
player,
level,
server,
data,
name,
mood,
hearts,
color
) => {
const nameColor = color || "#55FF55";
const heartsToDisplay = 10;
let icons = [];
if (mood < 64) icons.push("☹");
if (mood > 160) icons.push("☺");
if (data.animalCracker) icons.push("🡅");
if (data.clockwork) icons.push("⚙");
if (data.bff) icons.push("❤");
if (data.bribed) icons.push("💰");
let iconString = "";
icons.forEach((icon, index) => {
iconString += icon;
if (index < icons.length - 1) iconString += " ";
});
global.renderUiText(
player,
server,
{
animalNameIcons: {
type: "text",
x: 0,
y: -88,
text: iconString,
color: nameColor,
alignX: "center",
alignY: "bottom",
},
animalName: {
type: "text",
x: 0,
y: -78,
text: `${name.noColor().toJson()}`,
color: nameColor,
alignX: "center",
alignY: "bottom",
},
animalNameShadow: {
type: "text",
x: 1,
z: -1,
y: -77,
text: `${name.noColor().toJson()}`,
color: "#000000",
alignX: "center",
alignY: "bottom",
},
affection: {
type: "text",
x: 0,
y: -66,
text: `§c${hearts > 0 ? ``.repeat(Math.min(hearts, heartsToDisplay)) : ""
}§0${hearts < heartsToDisplay ? ``.repeat(heartsToDisplay - hearts) : ""
}`,
color: "#FFAA00",
alignX: "center",
alignY: "bottom",
},
affectionShadow: {
type: "text",
x: 1,
z: -1,
y: -65,
text: ``.repeat(heartsToDisplay),
color: "#000000",
alignX: "center",
alignY: "bottom",
},
},
global.mainUiElementIds
);
debug && debugData(player, level, data, hearts);
};
const handlePet = (name, data, mood, day, peckish, hungry, e) => {
const { player, item, target, level, server } = e;
const ageLastPet = data.getInt("ageLastPet");
const affection = data.getInt("affection");
let hearts = Math.floor(affection / 100);
if (hearts > 10) hearts = 10;
else if (hearts < 0) hearts = 0;
let affectionIncreaseMult =
player.stages.has("animal_whisperer") || data.bribed ? 2 : 1;
if (player.stages.has("animal_fancy")) affectionIncreaseMult += 1;
let affectionIncrease = 10 * affectionIncreaseMult;
if (target.isBaby()) {
affectionIncrease =
affectionIncrease * (player.stages.has("fostering") ? 10 : 2);
}
let errorText = "";
if (day > ageLastPet) {
let livableArea = global.getAnimalIsNotCramped(target, 1.1);
if (!player.isFake()) {
debug &&
player.tell(
`Increased Affection by: ${affectionIncrease} from petting`
);
data.affection = affection + affectionIncrease;
}
if (hungry || (!data.clockwork && player.isFake()) || !livableArea) {
data.affection = affection - (hungry ? 15 : 25);
}
data.ageLastPet = day;
level.spawnParticles(
(!data.clockwork && player.isFake()) || hungry
? "minecraft:angry_villager"
: "minecraft:heart",
true,
target.x,
target.y + 1.5,
target.z,
0,
0.1,
0,
1,
0.01
);
global.giveExperience(server, player, "husbandry", Math.max(10, 20 * hearts));
if (!livableArea && !data.clockwork) {
errorText = Text.translatable(
"society.husbandry.crowded",
name
).toJson();
}
if (
!hungry &&
peckish &&
!player.isFake() &&
!item.hasTag("society:animal_feed")
) {
server.runCommandSilent(
global.getEmbersTextAPICommand(
player.username,
`{anchor:"BOTTOM_CENTER",background:1,wrap:220,align:"BOTTOM_CENTER",color:"#FFAA00",offsetY:20}`,
40,
Text.translatable("society.husbandry.peckish", name).toJson()
)
);
}
if (hungry) {
errorText = Text.translatable(
"society.husbandry.starved",
name
).toJson();
}
if (errorText && !player.isFake()) {
server.runCommandSilent(
global.getEmbersTextAPICommand(
player.username,
global.animalMessageSettings,
40,
errorText
)
);
}
} else if (item === "minecraft:air" || item === 'society:mood_scanner') {
let nameColor;
if (peckish) {
nameColor = "#FFAA00";
}
if (hungry) {
nameColor = "#FF5555";
}
checkAnimal(player, level, server, data, name, mood, hearts, nameColor);
}
// Raise Max health
const affectionHealth = hearts * 4;
if (target.maxHealth < affectionHealth) {
target.setMaxHealth(affectionHealth);
target.setHealth(affectionHealth);
}
};
const handleMilk = (name, data, day, hungry, e) => {
const { player, item, target, level, server } = e;
if (player.cooldowns.isOnCooldown(item)) return;
if (player.isFake() && data.getInt("affection") < 100) return;
let errorText;
let milkItem = global.getMilk(level, target, data, player, day, true, undefined, player.stages);
if (milkItem !== -1) {
let milk = level.createEntity("minecraft:item");
milk.x = player.x;
milk.y = player.y;
milk.z = player.z;
milk.item = milkItem;
milk.spawn();
server.runCommandSilent(
`playsound minecraft:entity.cow.milk block @a ${player.x} ${player.y} ${player.z}`
);
global.giveExperience(server, player, "husbandry", 30);
level.spawnParticles(
"minecraft:note",
true,
target.x,
target.y + 1.5,
target.z,
0.1 * rnd(1, 4),
0.1 * rnd(1, 4),
0.1 * rnd(1, 4),
3,
0.01
);
} else if (target.isBaby()) {
errorText = Text.translatable(
"society.husbandry.action.young",
name
).toJson();
} else if (hungry) {
errorText = Text.translatable(
"society.husbandry.action.hungry",
name
).toJson();
} else {
errorText = Text.translatable(
"society.husbandry.action.cooldown_1",
name
).toJson();
}
if (errorText && !player.isFake()) {
server.runCommandSilent(
global.getEmbersTextAPICommand(
player.username,
global.animalMessageSettings,
20,
errorText
)
);
}
};
const handleFeed = (data, day, e) => {
const { player, item, target, level, server } = e;
if (player.cooldowns.isOnCooldown(item)) return;
const ageLastFed = data.getInt("ageLastFed");
const affection = data.getInt("affection");
const affectionIncrease = {
"society:animal_feed": 10,
"society:candied_animal_feed": 100,
"society:mana_feed": 30,
}[item.id];
let affectionIncreaseMult =
player.stages.has("animal_whisperer") || data.bribed ? 2 : 1;
if (player.stages.has("animal_fancy")) affectionIncreaseMult += 0.5;
// Cap affection increase at 100
const totalNewAffection = Math.min(
affectionIncrease * affectionIncreaseMult,
100
);
if (day > ageLastFed) {
server.runCommandSilent(
`playsound minecraft:entity.generic.eat block @a ${player.x} ${player.y} ${player.z}`
);
target.heal(4);
global.giveExperience(server, player, "husbandry", 20);
data.affection = affection + totalNewAffection;
debug &&
player.tell(`Increased Affection by: ${totalNewAffection} from feeding`);
data.ageLastFed = day;
level.spawnParticles(
"legendarycreatures:wisp_particle",
true,
target.x,
target.y + 1.5,
target.z,
0.1 * rnd(1, 4),
0.1 * rnd(1, 4),
0.1 * rnd(1, 4),
5,
0.01
);
item.count--;
global.addItemCooldown(player, item, 10);
}
};
const handleSheepMagicShears = (e) => {
const { target, level, server } = e;
if (target.readyForShearing()) {
target.setSheared(true);
let woolItem = Item.of(target.getColor().getName() + "_wool");
let i = Math.ceil(Math.random() * 4);
for (let j = 0; j < i; j++) {
let wool = level.createEntity("minecraft:item");
wool.x = target.x + rnd(0, 0.5);
wool.y = target.y + 0.5;
wool.z = target.z + rnd(0, 0.5);
wool.item = Item.of(woolItem);
wool.spawn();
wool.setDeltaMovement(
wool
.getDeltaMovement()
.add(
(Math.random() - Math.random()) * 0.1,
Math.random() * 0.05,
(Math.random() - Math.random()) * 0.1
)
);
}
server.runCommandSilent(
`playsound minecraft:entity.sheep.shear block @a ${target.x} ${target.y} ${target.z}`
);
}
};
const handleMagicHarvest = (name, data, e) => {
const { player, level, target, item, server } = e;
if (player.cooldowns.isOnCooldown(item)) return;
if (["minecraft:sheep", "wildernature:minisheep"].includes(target.type)) handleSheepMagicShears(e);
const affection = data.getInt("affection");
let hearts = Math.floor((affection > 1000 ? 1000 : affection) / 100);
let errorText = "";
const droppedLoot = global.getMagicShearsOutput(level, target, player, undefined, player.stages);
if (droppedLoot !== -1) {
server.runCommandSilent(
`playsound minecraft:entity.sheep.shear block @a ${player.x} ${player.y} ${player.z}`
);
global.giveExperience(server, player, "husbandry", 15);
for (let i = 0; i < droppedLoot.length; i++) {
let specialItem = level.createEntity("minecraft:item");
let dropItem = droppedLoot[i];
specialItem.x = player.x;
specialItem.y = player.y;
specialItem.z = player.z;
specialItem.item = dropItem;
specialItem.spawn();
}
global.addItemCooldown(player, item, 1);
} else {
errorText = Text.translatable(
"society.husbandry.action.cooldown_2",
name
).toJson();
if (hearts < 5) {
errorText = Text.translatable(
"society.husbandry.action.need_hearts",
name
).toJson();
}
if (!player.isFake())
server.runCommandSilent(
global.getEmbersTextAPICommand(
player.username,
global.animalMessageSettings,
40,
errorText
)
);
global.addItemCooldown(player, item, 10);
}
};
const handleSpecialItem = (
data,
day,
chance,
hungry,
minHearts,
mult,
item,
hasQuality,
plushieModifiers,
e
) => {
const { player, target, level, server } = e;
let affection;
let mood;
let resolvedItem = item;
let resolvedChance = chance;
let resolvedHasQuality = hasQuality
let dropAmount = mult * (plushieModifiers && plushieModifiers.doubleDrops ? 2 : 1);
if (plushieModifiers) {
affection = 1000;
mood = 256;
resolvedChance = chance + plushieModifiers.probabilityIncrease;
if (plushieModifiers.processItems) {
let processOutput = global.getProcessedItem(item, dropAmount);
resolvedItem = processOutput.item.id;
dropAmount = Math.round(dropAmount / processOutput.divisor) * processOutput.item.count;
resolvedHasQuality = processOutput.preserveQuality
}
} else {
affection = data.getInt("affection") || 0;
mood = global.getOrFetchMood(level, target, day, player);
}
let hearts = Math.floor(affection / 100);
let quality = 0;
if (
(!hungry || plushieModifiers) &&
hearts >= minHearts &&
Math.random() <= resolvedChance
) {
if (item.includes("large")) {
if (Math.random() > (mood + hearts * 10) / 256) {
return;
}
}
if (plushieModifiers) {
data.affection =
affection + (player.stages.has("animal_whisperer") ? 20 : 10);
}
let specialItem = level.createEntity("minecraft:item");
if (resolvedHasQuality && mood >= 160) {
quality = global.getHusbandryQuality(hearts, mood);
}
specialItem.x = player.x;
specialItem.y = player.y;
specialItem.z = player.z;
specialItem.item = Item.of(`${dropAmount}x ${resolvedItem}`,
quality > 0 ? `{quality_food:{effects:[],quality:${quality}}}` : null
);
specialItem.spawn();
server.runCommandSilent(
`playsound stardew_fishing:dwop block @a ${player.x} ${player.y} ${player.z}`
);
global.giveExperience(server, player, "husbandry", 60);
if (target.x) {
level.spawnParticles(
"farmersdelight:star",
true,
target.x,
target.y + 1,
target.z,
0.2 * rnd(1, 4),
0.2 * rnd(1, 4),
0.2 * rnd(1, 4),
3,
0.01
);
}
}
};
const upgradeAnimal = (level, server, item, target, sound, particle) => {
item.count--;
server.runCommandSilent(
`playsound ${sound} block @a ${target.x} ${target.y} ${target.z}`
);
level.spawnParticles(
particle,
true,
target.x,
target.y + 1.5,
target.z,
0.2 * rnd(0, 2),
0.2 * rnd(0, 2),
0.2 * rnd(0, 2),
3,
0.01
);
};
global.handleHusbandryBase = (hand, player, item, target, level, server) => {
const pet = global.checkEntityTag(target, "society:pet_animal");
const eventData = {
player: player,
item: item,
target: target,
level: level,
server: server,
};
if (hand == "OFF_HAND") return;
if (!global.checkEntityTag(target, "society:husbandry_animal") && !pet)
return;
if (item.id === "society:sunlit_crystal") return;
server.scheduleInTicks(1, () => {
if (hand == "MAIN_HAND") {
const day = global.getDay(level);
handleFarmAnimalBackwardsCompat(target, day);
initializeFarmAnimal(day, target, level);
const data = target.persistentData;
let name = target.customName ? target.customName : global.getTranslatedEntityName(String(target.type));
const ageLastFed = data.getInt("ageLastFed");
const peckish = !pet && day - ageLastFed == 1;
const hungry = !pet && day - ageLastFed > 1;
const affection = data.getInt("affection");
const lostProduce = mood < 64 && Math.random() < mood / 64;
let hearts = Math.floor((affection > 1000 ? 1000 : affection) / 100);
player.swing();
const mood = global.getOrFetchMood(level, target, day, player, false, true);
handlePet(name, data, mood, day, peckish, hungry, eventData);
if (pet) return;
if (item.hasTag("society:animal_feed") && !pet)
handleFeed(data, day, eventData);
if (!lostProduce) {
if (
item === "society:milk_pail" &&
global.checkEntityTag(target, "society:milkable_animal")
) {
handleMilk(name, data, day, hungry, eventData);
}
global.handleSpecialHarvest(
level,
target,
player,
server,
undefined,
undefined,
undefined,
handleSpecialItem,
player.stages,
);
}
if (
player.stages.has("biomancer") &&
[
"bakery:bread_knife",
"farmersdelight:iron_knife",
"farmersdelight:diamond_knife",
"farmersdelight:netherite_knife",
"farmersdelight:golden_knife",
"aquaculture:wooden_fillet_knife",
"aquaculture:stone_fillet_knife",
"aquaculture:iron_fillet_knife",
"aquaculture:gold_fillet_knife",
"farmersdelight:flint_knife",
"aquaculture:neptunium_fillet_knife",
"aquaculture:diamond_fillet_knife",
"refurbished_furniture:knife",
].includes(item.id)
) {
if (player.cooldowns.isOnCooldown(item)) return;
if (hearts < 5) {
server.runCommandSilent(
global.getEmbersTextAPICommand(
player.username,
global.animalMessageSettings,
40,
Text.translatable(
"society.husbandry.action.need_hearts",
name
).toJson()
)
);
} else {
let heart = level.createEntity("minecraft:item");
heart.x = player.x;
heart.y = player.y;
heart.z = player.z;
heart.item = Item.of("quark:diamond_heart");
heart.spawn();
server.runCommandSilent(
`playsound minecraft:entity.sheep.shear block @a ${player.x} ${player.y} ${player.z}`
);
server.runCommandSilent(
`playsound legendarycreatures:mojo_hurt block @a ${player.x} ${player.y} ${player.z} 0.1`
);
level.spawnParticles(
"minecraft:angry_villager",
true,
target.x,
target.y + 1.5,
target.z,
0.2 * rnd(1, 4),
0.2 * rnd(1, 4),
0.2 * rnd(1, 4),
5,
0.01
);
data.affection = affection - 100;
global.addItemCooldown(player, item, 5);
}
}
if (
player.stages.has("bribery") &&
item === "numismatics:crown" &&
!data.bribed
) {
if (player.cooldowns.isOnCooldown(item)) return;
data.bribed = true;
data.affection = affection + 100;
item.count--;
server.runCommandSilent(
`playsound stardew_fishing:complete block @a ${player.x} ${player.y} ${player.z}`
);
level.spawnParticles(
"legendarycreatures:desert_mojo_particle",
true,
target.x,
target.y + 1.5,
target.z,
0.2 * rnd(0, 1),
0.2 * rnd(0, 1),
0.2 * rnd(0, 1),
5,
0.01
);
global.addItemCooldown(player, item, 1);
}
if (
player.stages.has("clockwork") &&
item === "create:precision_mechanism" &&
!data.clockwork
) {
data.clockwork = true;
upgradeAnimal(
level,
server,
item,
target,
"trials:vault_activate",
"supplementaries:bomb_explosion"
);
if (data.bff) {
data.bff = false;
server.runCommandSilent(
global.getEmbersTextAPICommand(
player.username,
global.animalMessageSettings,
80,
Text.translatable("society.husbandry.mechanization").toJson()
)
);
}
}
if (
player.stages.has("husbandry_mastery") &&
item === "society:animal_cracker" &&
!data.animalCracker
) {
data.animalCracker = true;
server.runCommandSilent(
`playsound minecraft:entity.generic.eat block @a ${player.x} ${player.y} ${player.z}`
);
upgradeAnimal(
level,
server,
item,
target,
"stardew_fishing:chest_get",
"farmersdelight:star"
);
}
if (
player.stages.has("bff") &&
item === "society:friendship_necklace" &&
!data.bff
) {
data.bff = true;
upgradeAnimal(
level,
server,
item,
target,
"legendarycreatures:wisp_idle",
"buzzier_bees:buttercup_bloom"
);
if (data.clockwork) {
data.clockwork = false;
server.runCommandSilent(
global.getEmbersTextAPICommand(
player.username,
`{anchor:"BOTTOM_CENTER",background:1,wrap:220,align:"BOTTOM_CENTER",color:"#55FF55",offsetY:20}`,
80,
Text.translatable("society.husbandry.emancipation").toJson()
)
);
}
}
if (
player.stages.has("transplanting") &&
item === "quark:diamond_heart" &&
hearts < 10
) {
if (player.cooldowns.isOnCooldown(item)) return;
data.affection = affection + 100;
if (!player.isCreative()) item.count--;
server.runCommandSilent(
`playsound aquaculture:fish_flop block @a ${player.x} ${player.y} ${player.z}`
);
level.spawnParticles(
"minecraft:heart",
true,
target.x,
target.y + 1.5,
target.z,
0.2 * rnd(0, 2),
0.2 * rnd(0, 2),
0.2 * rnd(0, 2),
5,
0.01
);
global.addItemCooldown(player, item, 1);
}
if (!lostProduce && item === "society:magic_shears") {
handleMagicHarvest(name, data, eventData);
}
if (affection > 1075) {
// Cap affection at 1075
data.affection = 1075;
}
if (affection < 0) data.affection = 0;
}
});
};
ItemEvents.entityInteracted((e) => {
const { hand, player, item, target, level, server } = e;
if (item === 'moblassos:diamond_lasso') return;
global.handleHusbandryBase(hand, player, item, target, level, server);
});
BlockEvents.rightClicked(global.plushies, (e) => {
const { level, hand, player, item, server, block } = e;
if (hand == "OFF_HAND") return;
let nbt = block.getEntityData();
if (!nbt) return;
const { animal } = nbt.data;
if (!animal) return;
let animalName = animal.name ? Text.of(animal.name) : global.getTranslatedEntityName(String(animal.type));
if (item === "minecraft:air") {
checkAnimal(
player,
level,
server,
animal,
animalName,
256,
10
);
}
global.executePlushieHusbandry(
level,
server,
player,
item,
block,
handleSpecialItem
);
if (
player.stages.has("clockwork") &&
item === "create:precision_mechanism" &&
!animal.clockwork
) {
nbt.merge({
data: {
animal: {
clockwork: true,
},
},
});
upgradeAnimal(
level,
server,
item,
block,
"trials:vault_activate",
"supplementaries:bomb_explosion"
);
if (animal.bff) {
nbt.merge({
data: {
animal: {
bff: false,
},
},
});
server.runCommandSilent(
global.getEmbersTextAPICommand(
player.username,
global.animalMessageSettings,
80,
Text.translatable("society.husbandry.mechanization").toJson()
)
);
}
}
if (
player.stages.has("husbandry_mastery") &&
item === "society:animal_cracker" &&
!animal.animalCracker
) {
nbt.merge({
data: {
animal: {
animalCracker: true,
},
},
});
server.runCommandSilent(
`playsound minecraft:entity.generic.eat block @a ${player.x} ${player.y} ${player.z}`
);
upgradeAnimal(
level,
server,
item,
block,
"stardew_fishing:chest_get",
"farmersdelight:star"
);
}
if (
player.stages.has("bff") &&
item === "society:friendship_necklace" &&
!animal.bff
) {
nbt.merge({
data: {
animal: {
bff: true,
},
},
});
upgradeAnimal(
level,
server,
item,
block,
"legendarycreatures:wisp_idle",
"buzzier_bees:buttercup_bloom"
);
if (animal.clockwork) {
nbt.merge({
data: {
animal: {
clockwork: false,
},
},
});
server.runCommandSilent(
global.getEmbersTextAPICommand(
player.username,
`{anchor:"BOTTOM_CENTER",background:1,wrap:220,align:"BOTTOM_CENTER",color:"#55FF55",offsetY:20}`,
80,
Text.translatable("society.husbandry.emancipation").toJson()
)
);
}
}
global.setBlockEntityData(block, nbt)
});