console.info("[SOCIETY] villagerMechanics.js loaded"); const npcMap = new Map([ ["carpenter", "humanoid/carpenter"], ["market", "humanoid/market"], ["blacksmith", "humanoid/blacksmith"], ["shepherd", "humanoid_slim/shepherd"], ["fisher", "humanoid_slim/fisher"], ["banker", "humanoid_slim/banker"], ["librarian", "humanoid_slim/librarian"], ["witch", "humanoid_slim/witch"], ["trader", "humanoid/trader"] ]); const getBoundNpc = (level, block, boundNpc) => { let nearbyNPCs = level.getLevel() .getServer() .getEntities() .filter((entityType) => entityType.type === "easy_npc:humanoid" || entityType.type === "easy_npc:humanoid_slim"); let foundNpc = -1; nearbyNPCs.forEach((e) => { if (e.getUuid().toString() === boundNpc) { foundNpc = e; } }); return foundNpc; }; BlockEvents.placed("society:villager_home", (e) => { const { player, block, level, server } = e; if (player.isFake()) e.cancel(); const homeNbt = player.getHeldItem("main_hand").getNbt(); let nbt = block.getEntityData(); const { x, y, z } = block; if (homeNbt) { let villagerType = homeNbt.getString("type"); let day = global.getDay(level); if (!player.persistentData.npcData) player.persistentData.npcData = {} let npcData = player.persistentData.npcData[villagerType]; if (!npcData) { player.persistentData.npcData[villagerType] = { friendship: -1, dayLastChatted: -1, dayLastGifted: -4, dayLastPlaced: -10, maxGifted: false, } npcData = player.persistentData.npcData[villagerType]; } if (!npcData.dayLastPlaced) npcData.dayLastPlaced = -10 if (day > Number(npcData.dayLastPlaced) + 10 || Number(npcData.dayLastPlaced) - day > 1) { let nearbyNPCs = level .getEntitiesWithin(AABB.ofBlock(block).inflate(4)) .filter((entityType) => entityType.type === "easy_npc:humanoid" || entityType.type === "easy_npc:humanoid_slim"); if (player && nearbyNPCs.length == 0) { server.runCommandSilent( `execute in ${level.dimension} run easy_npc preset import_new custom easy_npc:preset/${npcMap.get( String(villagerType) )}.npc.nbt ${x} ${y + 0.25} ${z}` ); nearbyNPCs = level .getEntitiesWithin(AABB.ofBlock(block).inflate(2)) .filter((entityType) => entityType.type === "easy_npc:humanoid" || entityType.type === "easy_npc:humanoid_slim"); level.spawnParticles( "ribbits:spell", true, nearbyNPCs[0].x, nearbyNPCs[0].y + 1.5, nearbyNPCs[0].z, 0.2 * rnd(1, 2), 0.2 * rnd(1, 2), 0.2 * rnd(1, 2), 20, 0.05 ); server.runCommandSilent( `playsound botania:starcaller block @a ${player.x} ${player.y} ${player.z}` ); server.runCommandSilent(`easy_npc navigation set home ${nearbyNPCs[0].getUuid()} ${x} ${y + 0.25} ${z}`) nbt.merge({ data: { type: villagerType, boundNpc: nearbyNPCs[0].getUuid().toString(), placer: player.getUuid().toString(), }, }); global.setBlockEntityData(block, nbt) player.tell( Text.translatable( "society.villager_home.moved_in", Text.translatable(`dialog.npc.${villagerType}.name`).gold() ) ); npcData.dayLastPlaced = day } else { player.tell(Text.translatable("society.villager_home.too_close").red()); player.inventoryMenu.broadcastFullState(); e.cancel(); } } else { player.tell(Text.translatable("society.villager_home.recently_moved_in").red()); player.inventoryMenu.broadcastFullState(); e.cancel(); } } else { player.tell(Text.translatable("society.villager_home.error").red()); player.inventoryMenu.broadcastFullState(); e.cancel(); } }); BlockEvents.broken("society:villager_home", (e) => { const { block, player, level, server } = e; let nbt = block.getEntityData(); const { type, placer, boundNpc } = nbt.data; if (player.getUuid().toString() !== placer && placer != -1 && !player.isCreative()) { player.tell( Text.translatable( "society.villager_home.not_invited_by_you", Text.translatable(`dialog.npc.${type}.name`).gold() ).red() ); e.cancel(); } let foundNpc = getBoundNpc(level, block, boundNpc); if (foundNpc != -1) { foundNpc.setRemoved("unloaded_to_chunk"); level.spawnParticles( "windswept:feather_cloak", true, foundNpc.x, foundNpc.y + 1.5, foundNpc.z, 0.2 * rnd(1, 2), 0.2 * rnd(1, 2), 0.2 * rnd(1, 2), 20, 0.05 ); server.runCommandSilent( `playsound windswept:block.pinecone.note block @a ${player.x} ${player.y} ${player.z}` ); player.tell( Text.translatable( "society.villager_home.moved_out", Text.translatable(`dialog.npc.${type}.name`).gold() ) ); block.popItem(Item.of(block.id, `{type:${type}}`)); player.persistentData.npcData[type].dayLastPlaced = -10 } else { if (!(type == undefined || placer == undefined || boundNpc == undefined)) { if (!player.isCreative()) { e.cancel(); } else { player.tell("Unbound villager to home! If the villager still exists, run /easy_npc delete @e") } } } });