Files
2026-07-31 10:34:32 +09:00

220 lines
11 KiB
JavaScript

console.info("[SOCIETY] npcInteraction.js loaded");
// These lengths are formed from generateNpcDialog.js
const dialogLengths = {
banker: { chatterLengths: [15.0, 20.0, 13.0, 9.0, 11.0, 18.0], giftResponseLengths: { loved: 9.0, liked: 8.0, neutral: 8.0, disliked: 12.0, hated: 16.0 } },
blacksmith: { chatterLengths: [16.0, 10.0, 13.0, 12.0, 11.0, 14.0], giftResponseLengths: { loved: 8.0, liked: 9.0, neutral: 8.0, disliked: 8.0, hated: 10.0 } },
carpenter: { chatterLengths: [11.0, 10.0, 13.0, 9.0, 9.0, 15.0], giftResponseLengths: { loved: 6.0, liked: 7.0, neutral: 8.0, disliked: 10.0, hated: 10.0 } },
fisher: { chatterLengths: [11.0, 9.0, 10.0, 10.0, 10.0, 11.0], giftResponseLengths: { loved: 7.0, liked: 6.0, neutral: 9.0, disliked: 7.0, hated: 7.0 } },
librarian: { chatterLengths: [5.0, 5.0, 5.0, 5.0, 5.0, 6.0], giftResponseLengths: { loved: 5.0, liked: 5.0, neutral: 5.0, disliked: 5.0, hated: 5.0 } },
market: { chatterLengths: [18.0, 14.0, 9.0, 16.0, 14.0, 14.0], giftResponseLengths: { loved: 10.0, liked: 8.0, neutral: 17.0, disliked: 12.0, hated: 13.0 } },
shepherd: { chatterLengths: [15.0, 14.0, 13.0, 12.0, 14.0, 17.0], giftResponseLengths: { loved: 9.0, liked: 10.0, neutral: 8.0, disliked: 8.0, hated: 11.0 } },
trader: { chatterLengths: [7.0, 5.0, 5.0, 7.0, 7.0, 6.0], giftResponseLengths: { loved: 5.0, liked: 5.0, neutral: 5.0, disliked: 5.0, hated: 5.0 } },
wise_oak: { chatterLengths: [7.0, 5.0, 5.0, 5.0, 5.0, 8.0], giftResponseLengths: { loved: 0.0, liked: 0.0, neutral: 0.0, disliked: 0.0, hated: 0.0 } },
witch: { chatterLengths: [7.0, 5.0, 6.0, 8.0, 6.0, 5.0], giftResponseLengths: { loved: 5.0, liked: 5.0, neutral: 5.0, disliked: 5.0, hated: 6.0 } },
}
const maxGifts = {
banker: "society:slouching_towards_artistry",
blacksmith: Item.of('justhammers:iron_hammer', "{Damage:0,RepairCost:0,display:{Name:'{\"text\":\"§6Aiden\\'s Hammer\"}'}}").enchant('minecraft:efficiency', 5).enchant('minecraft:fortune', 3),
carpenter: Item.of('portable_blueprints:worn_blueprint', '{Damage:1,allow_nbt:1,altezza:0,blueprint_name:"blockapedia",buildAnyway:0b,display:{Name:\'{"italic":false,"color":"#FFFF00","text":"Blueprint: Blockapedia"}\'},free_build:1,inventari_blocco_selezionati:"",lunghezzaX:0,lunghezzaZ:0,mirrowX:0b,mirrowY:0b,mirrowZ:0b,nome:"blockapedia",owner:"worn",owner_name:"Ace (Built by Mimsy)",remaining_uses:1,rotateValue:0s,skipObstructionBlock:0b,visualizeBuild:1b,wasHolding:1b,worn_set:1b}'),
fisher: "society:heart_of_neptunium",
market: "society:universal_methods_of_farming",
shepherd: Item.of('2x wildernature:penguin_spawn_egg'),
librarian: 'society:debt_caverns',
trader: "",
witch: "society:auto_petter",
}
const getNpcKey = (customName) => {
const startIndex = customName.indexOf("dialog.npc.");
const endIndex = customName.indexOf(".name");
if (startIndex === -1 || endIndex === -1 || endIndex <= startIndex) {
console.log("[SOCIETY] WARNING: NPC has no custom name!")
return;
}
return customName.substring(startIndex + "dialog.npc.".length, endIndex);
}
const npcIds = ["easy_npc:humanoid", "easy_npc:humanoid_slim"];
const handleNpc = (e, npcId, level, server, target, player, item) => {
let day = global.getDay(level);
if (!player.persistentData.npcData) player.persistentData.npcData = {}
let npcData = player.persistentData.npcData[npcId];
if (!npcData) {
if (!player.stages.has(`invited_${npcId}`)) {
player.stages.add(`invited_${npcId}`)
}
player.persistentData.npcData[npcId] = {
friendship: -1,
dayLastChatted: -1,
dayLastGifted: -4,
maxGifted: false
}
} else if (Number(npcData.friendship) == -1) {
npcData.friendship = 5
server.runCommandSilent(
`dialog ${player.getUuid()} show ${player.username} ${npcId}_intro`
);
} else if (!npcData.maxGifted && Number(npcData.friendship) >= 500) {
if (npcId.equals("banker") && player.stages.has("slouching_towards_artistry")) {
player.give(Item.of("2x waystones:waystone"))
server.runCommandSilent(`dialog ${player.username} show ${player.username} banker_unique__gift_read`);
} else if (npcId.equals("market") && player.stages.has("universal_methods_of_farming")) {
player.give(Item.of("16x society:sparkpod_seed"))
server.runCommandSilent(`dialog ${player.username} show ${player.username} market_unique_five_gift_read`);
} else if (npcId.equals("librarian") && player.stages.has("debt_caverns")) {
player.give(Item.of('botania:diva_charm'))
player.give(Item.of('botania:mana_ring', '{mana:500000}'))
server.runCommandSilent(`dialog ${player.username} show ${player.username} librarian_unique_five_gift_read`);
} else if (npcId.equals("trader")) {
player.stages.add("trader_clothing")
server.runCommandSilent(`dialog ${player.getUuid()} show ${player.username} ${npcId}_unique_five_gift`);
} else {
player.give(maxGifts[npcId])
server.runCommandSilent(`dialog ${player.getUuid()} show ${player.username} ${npcId}_unique_five_gift`);
}
npcData.maxGifted = true
} else {
// Carpenter has two shops so it always needs dialog to choose between the two.
let dialogNumber;
if (player.isCrouching() && item.hasTag("society:villager_gift")) {
if (npcId === "wise_oak") {
server.runCommandSilent(`dialog ${player.getUuid()} show ${player.username} wise_oak_unique_no_gifting`);
server.runCommandSilent(`playsound stardew_fishing:fish_escape block @a ${target.x} ${target.y} ${target.z}`);
server.runCommandSilent(`playsound species:item.wicked_swapper.teleport block @a ${target.x} ${target.y} ${target.z}`);
level.spawnParticles(
"mysticaloaktree:wind",
true,
target.x,
target.y + 1.5,
target.z,
0.2 * rnd(1, 2),
0.2 * rnd(1, 2),
0.2 * rnd(1, 2),
25,
0.001
);
return;
}
if (day > npcData.dayLastGifted + 3 || npcData.dayLastGifted - day > 1) {
let giftValue = global.getVillagerGiftResult(npcId, item.id);
dialogNumber = Math.floor(Math.random() * dialogLengths[npcId].giftResponseLengths[giftValue]);
let friendshipModification = 0;
switch (giftValue) {
case "hated":
friendshipModification = -30;
break;
case "disliked":
friendshipModification = -15;
break;
case "loved":
friendshipModification = 40;
break;
case "liked":
friendshipModification = 25;
break;
case "neutral":
default:
friendshipModification = 10;
break;
}
npcData.friendship = npcData.friendship + friendshipModification;
npcData.dayLastGifted = day
server.runCommandSilent(`playsound stardew_fishing:complete block @a ${target.x} ${target.y} ${target.z}`);
server.runCommandSilent(`playsound species:item.wicked_swapper.teleport block @a ${target.x} ${target.y} ${target.z}`);
level.spawnParticles(
"supplementaries:confetti",
true,
target.x,
target.y + 1.5,
target.z,
0.2 * rnd(1, 2),
0.2 * rnd(1, 2),
0.2 * rnd(1, 2),
25,
0.001
);
let delay = 0;
if (item.isEdible()) delay = 20
if (!player.isCreative()) item.shrink(1);
server.scheduleInTicks(delay, () => {
server.runCommandSilent(
`dialog ${player.getUuid()} show ${player.username} ${npcId}_gift_${giftValue}_${dialogNumber}`
);
});
if (Math.random() < 0.01) {
let newGolem = level.createEntity(Math.random() < 0.5 ? "golemoverhaul:barrel_golem" : "golemoverhaul:hay_golem");
newGolem.setX(target.getX() + 8);
newGolem.setY(target.getY() + 2);
newGolem.setZ(target.getZ() + -8);
newGolem.spawn();
}
} else {
player.tell(Text.translatable("society.npc.gifted_too_soon").gold())
}
} else {
if (global.compareDay(day, npcData.dayLastChatted, 1)) {
let hearts = Math.floor(npcData.friendship / 100);
dialogNumber = Math.floor(Math.random() * (dialogLengths[npcId].chatterLengths[hearts]));
server.runCommandSilent(
`dialog ${player.getUuid()} show ${player.username} ${npcId}_chatter_friendship${hearts}_${dialogNumber}`
);
npcData.dayLastChatted = day
if (npcData.friendship + 5 > 500) {
npcData.friendship = 500
} else {
if (npcId === "wise_oak") npcData.friendship = npcData.friendship + 15
npcData.friendship = npcData.friendship + 5
}
} else {
if (npcId === "carpenter") {
server.runCommandSilent(`dialog ${player.getUuid()} show ${player.username} carpenter_choice_dialog_need_to_buy`);
} else if (npcId === "librarian" && global.isLateSeason(level)) {
server.runCommandSilent(`dialog ${player.getUuid()} show ${player.username} librarian_choice_dialog_book_fair`);
} else if (npcId === "wise_oak") {
if (Number(npcData.friendship) >= 500) {
player.tell("opening shop")
server.runCommandSilent(`openshop ${player.username} wise_oak`)
}
} else {
server.runCommandSilent(`openshop ${player.username} ${npcId}`)
}
}
}
}
if (npcId === "wise_oak") {
if (['society:tapper', 'society:auto_tapper'].includes(item.id)) {
npcData.friendship = 0;
}
} else {
e.cancel()
}
}
ItemEvents.entityInteracted((e) => {
const { hand, player, item, level, target, server } = e;
if (player.isFake()) return;
if (hand == "OFF_HAND") return;
if (item.id == 'easy_npc_config_ui:easy_npc_wand') return;
if (!npcIds.includes(target.type)) return;
if (hand == "MAIN_HAND") {
let npcId = getNpcKey(target.nbt.CustomName.toString())
handleNpc(e, npcId, level, server, target, player, item)
}
});
BlockEvents.rightClicked("mysticaloaktree:wise_oak", (e) => {
const { hand, player, block, level, server, item } = e;
if (player.isFake()) return;
if (hand == "OFF_HAND") return;
if (hand == "MAIN_HAND") {
handleNpc(e, "wise_oak", level, server, block, player, item)
}
});