Files
client/kubejs/client_scripts/createrp_ponder.js
T
FulldroperandClaude Opus 5.5 42ee586e63 0.6.2: readable tutorial texts, clearer energy scene
- one short sentence per step like Create (no more paragraphs); literal _underscores_ removed —
  PonderJS shows them as is
- energy scene tells the substation story: state machines need power, meter at the input,
  your generator connects, coins every minute, no power — no pay

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 06:53:48 +03:00

355 lines
19 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Create RP — туторіал у стилі Create (Ponder): наведи на предмет і затисни W.
// Потрібні PonderJS (мод «Ponder for KubeJS») і startup_scripts/createrp_items.js (предмет kubejs:citizen_guide).
// Більшість сцен — на стандартній плиті 5x5 (y=0 — плита, блоки з y=1); продаж і покупки — на схематиці Create з ланцюгами.
// Підписи — як у Create: одне коротке речення на крок.
const PACKAGE = 'create:cardboard_package_10x12'
// Справжні посилки на ланцюгах — тими ж викликами, що й у сценах самого Create (FrogAndConveyorScenes).
// Якщо KubeJS не дасть доступу до класів — сцени все одно покажуть мережу й текст, лише без руху посилок.
let CreateScene = null, Frogport = null, ChainConveyor = null, PackageItem = null, PackageStyles = null
try {
CreateScene = Java.loadClass('com.simibubi.create.foundation.ponder.CreateSceneBuilder')
Frogport = Java.loadClass('com.simibubi.create.content.logistics.packagePort.frogport.FrogportBlockEntity')
ChainConveyor = Java.loadClass('com.simibubi.create.content.kinetics.chainConveyor.ChainConveyorBlockEntity')
PackageItem = Java.loadClass('com.simibubi.create.content.logistics.box.PackageItem')
PackageStyles = Java.loadClass('com.simibubi.create.content.logistics.box.PackageStyles')
} catch (e) {
console.warn('[createrp] Create classes unavailable for Ponder animations: ' + e)
}
// один крок: підпис біля точки й пауза, поки його читають
function say(scene, ticks, text, pos, colour, keyframe) {
const t = scene.text(ticks, text, pos).placeNearTarget()
if (colour) t.colored(colour)
if (keyframe) t.attachKeyFrame()
scene.idle(ticks + 10)
}
function setSpeed(scene, sel, speed) {
if (CreateScene) new CreateScene(scene).world().setKineticSpeed(sel, speed)
}
// ---- мережа ланцюгів (схематика Create «Transporting packages between Frogports», 9x9) --------
const FROG_STRUCTURE = 'create:high_logistics/package_frogport'
const CONV1 = [1, 4, 7], CONV2 = [7, 4, 7]
const FROM_FROG = [5, 2, 2], TO_FROG = [2, 2, 5]
function addressedBox(address) {
const box = PackageStyles.getDefaultBox().copy()
PackageItem.addAddress(box, address)
return box
}
// посилки, що крутяться на одному вузлі ланцюга, їдуть до іншого (Create: boxTransfer)
function chainTransfer(scene, util, to, from) {
scene.world.modifyBlockEntity(util.grid.at(from[0], from[1], from[2]), ChainConveyor, be => {
const it = be.getLoopingPackages().iterator()
while (it.hasNext()) {
const p = it.next()
p.chainPosition = 0
be.addTravellingPackage(p, util.grid.at(to[0] - from[0], to[1] - from[1], to[2] - from[2]))
it.remove()
}
})
}
// посилка з адресою їде ланцюгами від пакужаби (5,2,2) до пакужаби (2,2,5)
function shipOnChains(scene, util, address) {
if (!Frogport) {
scene.overlay.showBigLine(PonderPalette.OUTPUT, [5.5, 3, 2.5], [2.5, 3, 5.5], 140)
scene.idle(150)
return
}
const box = addressedBox(address)
scene.world.modifyBlockEntity(util.grid.at(FROM_FROG[0], FROM_FROG[1], FROM_FROG[2]), Frogport, be => be.startAnimation(box, true))
scene.idle(95)
chainTransfer(scene, util, CONV1, CONV2)
scene.idle(45)
scene.world.modifyBlockEntity(util.grid.at(CONV1[0], CONV1[1], CONV1[2]), ChainConveyor, be => be.getLoopingPackages().clear())
scene.world.modifyBlockEntity(util.grid.at(TO_FROG[0], TO_FROG[1], TO_FROG[2]), Frogport, be => be.startAnimation(box, false))
scene.idle(15)
}
// мережа з'являється так само, як у Create
function showChainNetwork(scene, util) {
scene.configureBasePlate(0, 0, 9)
scene.scaleSceneView(0.75)
scene.setSceneOffsetY(-1)
scene.world.showSection(util.select.layer(0).substract(util.select.position(9, 0, 1)), Direction.UP)
scene.idle(10)
scene.world.showSection(util.select.position(2, 1, 8), Direction.SOUTH)
scene.idle(2)
scene.world.showSection(util.select.fromTo(1, 1, 7, 1, 3, 7), Direction.DOWN)
scene.idle(2)
scene.world.showSection(util.select.fromTo(7, 1, 7, 7, 3, 7), Direction.DOWN)
scene.idle(2)
scene.world.showSection(util.select.fromTo(7, 1, 1, 7, 3, 1), Direction.DOWN)
scene.idle(5)
scene.world.showSection(util.select.position(1, 4, 7), Direction.DOWN)
scene.world.showSection(util.select.position(7, 4, 7), Direction.DOWN)
scene.world.showSection(util.select.position(7, 4, 1), Direction.DOWN)
scene.idle(20)
}
function showRightSide(scene, util) { // пакувальник, сховище й пакужаба праворуч (5..7, z=2)
scene.world.showSection(util.select.fromTo(7, 1, 2, 5, 1, 2), Direction.DOWN)
scene.world.showSection(util.select.position(5, 1, 3), Direction.DOWN)
scene.idle(5)
scene.world.showSection(util.select.position(5, 2, 2), Direction.DOWN)
scene.idle(15)
}
function showLeftSide(scene, util) { // пакужаба з пакувальником ліворуч (2, z=5)
scene.world.showSection(util.select.position(2, 1, 5), Direction.SOUTH)
scene.world.showSection(util.select.fromTo(2, 1, 4, 0, 1, 4), Direction.DOWN)
scene.world.showSection(util.select.position(3, 1, 5), Direction.DOWN)
scene.idle(5)
scene.world.showSection(util.select.position(2, 2, 5), Direction.DOWN)
scene.idle(15)
}
// ---------------------------------------------------------------------------------------------
// 1. Термінал держави
function terminalScene(scene, util) {
scene.showBasePlate()
scene.world.setBlocks([2, 1, 2], 'computercraft:computer_advanced')
scene.world.setBlocks([1, 1, 3, 3, 2, 3], 'computercraft:monitor_advanced')
scene.idle(10)
scene.world.showSection([2, 1, 2], Direction.DOWN)
scene.idle(15)
scene.showControls(60, [2.5, 2, 2.5], 'down').rightClick()
say(scene, 70, 'Будь-який комп\'ютер — термінал держави', [2.5, 1.5, 2.5], null, true)
say(scene, 60, 'Набери rp і натисни Enter', [2.5, 1.5, 2.5])
say(scene, 70, 'Увійди: свій нік і пароль', [2.5, 1.5, 2.5], PonderPalette.BLUE, true)
say(scene, 70, 'Першого разу термінал попросить створити пароль', [2.5, 1.5, 2.5])
say(scene, 60, 'Стій поруч — здалеку не пустить', [2.5, 1.5, 2.5], PonderPalette.RED)
say(scene, 80, 'Тут усе: рахунок, бізнес, ціни, магазин, земля, робота, банк', [2.5, 1.5, 2.5], null, true)
scene.world.showSection([1, 1, 3, 3, 2, 3], Direction.DOWN)
scene.idle(15)
say(scene, 70, 'Додай монітор — і набери prices metal', [2, 2.5, 3], PonderPalette.BLUE, true)
say(scene, 60, 'Вийде табло цін держави', [2, 2.5, 3])
}
// ---------------------------------------------------------------------------------------------
// 2. Продаж державі
function sellScene(scene, util) {
showChainNetwork(scene, util)
say(scene, 70, 'Держава купує все, що ти добуваєш і виробляєш', [4, 4.5, 4], null, true)
say(scene, 70, 'Товар їде до неї посилками по ланцюгах', [4, 4.5, 7])
showRightSide(scene, util)
scene.world.showSection(util.select.position(4, 1, 2), Direction.EAST)
scene.idle(10)
say(scene, 70, 'Твій бізнес: сховище, пакувальник і пакужаба', [5.5, 2.5, 2.5], null, true)
say(scene, 80, 'На пакувальник — табличка з адресою gov-…', [4.5, 1.5, 2.5], PonderPalette.BLUE)
say(scene, 70, 'Адресу дає термінал: Бізнес → Адреса продажу', [4.5, 1.5, 2.5])
showLeftSide(scene, util)
say(scene, 80, 'Це державна пакужаба — вона приймає всі адреси gov-…', [2.5, 2.5, 5.5], PonderPalette.BLUE, true)
scene.text(60, 'Посилка їде ланцюгами…', [6.78, 4.37, 3.5]).placeNearTarget()
shipOnChains(scene, util, 'gov-a1b2c3')
say(scene, 70, '…і гроші приходять на рахунок бізнесу', [2.5, 2.5, 5.5], PonderPalette.GREEN, true)
say(scene, 70, 'Багато однакового товару — ціна падає', [4, 4.5, 4], PonderPalette.RED)
say(scene, 60, 'Дефіцит — ціна росте', [4, 4.5, 4], PonderPalette.GREEN)
say(scene, 60, 'Ціни дивись на табло або в терміналі', [4, 4.5, 4])
}
// ---------------------------------------------------------------------------------------------
// 3. Покупки в держави
function buyScene(scene, util) {
showChainNetwork(scene, util)
showRightSide(scene, util)
say(scene, 70, 'Це державний склад', [5.5, 2.5, 2.5], PonderPalette.BLUE, true)
say(scene, 80, 'Держава продає імпорт: алмази, незерит, елітри, ліцензії', [5.5, 2.5, 2.5])
say(scene, 60, 'Купуй у терміналі: Магазин держави', [4, 4.5, 4])
showLeftSide(scene, util)
say(scene, 70, 'Це твоя пакужаба, напр. «Склад Олі»', [2.5, 2.5, 5.5], null, true)
say(scene, 70, 'Цю назву впиши як адресу доставки', [2.5, 2.5, 5.5], PonderPalette.BLUE)
shipOnChains(scene, util, 'Склад Олі')
say(scene, 70, 'Посилка приїжджає сама', [2.5, 2.5, 5.5], PonderPalette.GREEN, true)
say(scene, 70, 'Пакувальник розпакує її у скриню', [3.5, 1.5, 5.5])
say(scene, 70, 'Не доїхала — гроші повернуться самі', [4, 4.5, 4], PonderPalette.RED)
}
// ---------------------------------------------------------------------------------------------
// 4. Гроші й банк
function moneyScene(scene, util) {
scene.showBasePlate()
scene.world.setBlocks([2, 1, 2], 'computercraft:computer_advanced')
scene.world.showSection([2, 1, 2], Direction.DOWN)
scene.idle(15)
say(scene, 70, 'Твої гроші лежать на рахунку в банку', [2.5, 1.5, 2.5], null, true)
say(scene, 60, 'Баланс і перекази — у терміналі', [2.5, 1.5, 2.5])
const coins = ['numismatics:spur', 'numismatics:bevel', 'numismatics:sprocket', 'numismatics:cog']
for (let i = 0; i < coins.length; i++) {
scene.world.createItemEntity([1 + i, 3, 1], [0, 0.1, 0], coins[i])
scene.idle(5)
}
scene.idle(10)
say(scene, 70, 'Монети — це готівка', [2.5, 2, 1.5], PonderPalette.GREEN, true)
say(scene, 70, 'Зняти: /cash withdraw <сума>', [2.5, 2, 1.5])
say(scene, 70, 'Покласти: монети в руку і /cash deposit', [2.5, 2, 1.5])
say(scene, 70, 'Банк дає кредити бізнесу', [2.5, 1.5, 2.5], PonderPalette.BLUE, true)
say(scene, 60, 'А вклад щодня приносить відсоток', [2.5, 1.5, 2.5])
say(scene, 80, 'Пропустив 3 платежі по кредиту — рахунок заморожено', [2.5, 1.5, 2.5], PonderPalette.RED)
}
// ---------------------------------------------------------------------------------------------
// 5. Земля й надра
function landScene(scene, util) {
scene.showBasePlate()
scene.world.setBlocks([1, 1, 1], 'minecraft:oak_fence')
scene.world.setBlocks([3, 1, 1], 'minecraft:oak_fence')
scene.world.setBlocks([1, 1, 3], 'minecraft:oak_fence')
scene.world.setBlocks([3, 1, 3], 'minecraft:oak_fence')
scene.world.setBlocks([2, 1, 2], 'minecraft:iron_ore')
scene.idle(10)
say(scene, 70, 'Нічия земля належить державі', [2.5, 1, 2.5], null, true)
scene.overlay.showOutline(PonderPalette.GREEN, 'plot', util.select.fromTo(0, 0, 0, 4, 0, 4), 150)
scene.world.showSection([1, 1, 1, 3, 1, 3], Direction.DOWN)
say(scene, 70, 'Будуй на своїй ділянці', [2.5, 1.5, 2.5], PonderPalette.GREEN, true)
say(scene, 70, 'Орендуй або купи її в терміналі: Земля', [2.5, 1.5, 2.5])
say(scene, 70, 'На ділянці над хотбаром видно її назву', [2.5, 1.5, 2.5])
say(scene, 70, 'Чужі тут не ламають, а твої працівники — можуть', [2.5, 1.5, 2.5])
scene.overlay.showOutline(PonderPalette.RED, 'ore', util.select.position(2, 1, 2), 150)
say(scene, 70, 'Руду копають лише з концесією', [2.5, 1.5, 2.5], PonderPalette.RED, true)
say(scene, 70, 'Купи її в терміналі: Земля → Купити концесію', [2.5, 1.5, 2.5])
say(scene, 80, 'За землю платиш щодня. Не платив 3 дні — ділянку забирають', [2.5, 2.5, 2.5])
}
// ---------------------------------------------------------------------------------------------
// 6. Робота: ринок праці й пошта
function jobsScene(scene, util) {
scene.showBasePlate()
scene.idle(10)
scene.world.createEntity('minecraft:villager', [1, 1, 2.5])
scene.idle(10)
say(scene, 70, 'Немає роботи? Стань на ринок праці', [2.5, 2.5, 2.5], null, true)
say(scene, 70, 'Держава щодня платить допомогу, якщо ти грав', [2.5, 2.5, 2.5])
scene.showControls(60, [1, 2.3, 2.5], 'down').rightClick()
say(scene, 70, 'Хочеш більше — працюй поштарем', [1, 2.5, 2.5], PonderPalette.BLUE, true)
scene.world.createItemEntity([1.5, 2, 2.5], [0.05, 0.25, 0], PACKAGE)
scene.world.createItemEntity([1.5, 2, 2.5], [0.03, 0.3, 0.03], 'minecraft:compass')
scene.idle(20)
say(scene, 70, 'NPC пошти дасть посилку й компас', [2, 1.5, 2.5], null, true)
say(scene, 70, 'Компас веде до адресата', [2, 1.5, 2.5])
say(scene, 70, 'ПКМ компасом — мітка на місці', [2, 1.5, 2.5], PonderPalette.BLUE)
scene.world.createEntity('minecraft:villager', [4, 1, 2.5])
scene.overlay.showBigLine(PonderPalette.OUTPUT, [1.5, 1.2, 2.5], [4, 1.2, 2.5], 100)
say(scene, 70, 'Віддай посилку адресату — і отримаєш гроші', [4, 2.5, 2.5], PonderPalette.GREEN, true)
say(scene, 60, 'Що далі везти — то більше платять', [4, 2.5, 2.5])
say(scene, 60, 'На доставку — 2 ігрові дні', [2.5, 2.5, 2.5], PonderPalette.RED)
say(scene, 80, 'Або наймися в бізнес: термінал → Бізнес', [2.5, 2.5, 2.5], null, true)
}
// ---------------------------------------------------------------------------------------------
// 7. Продаж енергії державі: державна підстанція
function energyScene(scene, util) {
const STATE = util.select.fromTo(3, 1, 0, 4, 1, 4)
const BUSINESS = util.select.fromTo(0, 1, 2, 1, 1, 2)
const ALL = util.select.fromTo(0, 1, 0, 4, 1, 4)
scene.showBasePlate()
// генератор бізнесу → вал → лічильник → коробка передач підстанції → три вентилятори держави
scene.world.setBlocks([0, 1, 2], 'create:water_wheel[facing=east]')
scene.world.setBlocks([1, 1, 2], 'create:shaft[axis=x]')
scene.world.setBlocks([2, 1, 2], 'create:stressometer[facing=south,axis_along_first=true]')
scene.world.setBlocks([3, 1, 2], 'create:gearbox')
scene.world.setBlocks([4, 1, 2], 'create:encased_fan[facing=east]')
scene.world.setBlocks([3, 1, 1], 'create:shaft[axis=z]')
scene.world.setBlocks([3, 1, 3], 'create:shaft[axis=z]')
scene.world.setBlocks([3, 1, 0], 'create:encased_fan[facing=north]')
scene.world.setBlocks([3, 1, 4], 'create:encased_fan[facing=south]')
scene.idle(10)
scene.world.showSection(STATE, Direction.DOWN)
scene.idle(15)
scene.overlay.showOutline(PonderPalette.BLUE, 'state', STATE, 90)
say(scene, 80, 'Це державна підстанція: її машинам потрібна сила', [3.5, 2.5, 2.5], PonderPalette.BLUE, true)
scene.world.showSection([2, 1, 2], Direction.DOWN)
scene.idle(10)
say(scene, 70, 'На вході стоїть лічильник — стресометр', [2.5, 1.8, 2.5], null, true)
say(scene, 70, 'Держава закріплює його за твоїм бізнесом', [2.5, 1.8, 2.5])
scene.world.showSection(BUSINESS, Direction.EAST)
scene.idle(15)
scene.overlay.showOutline(PonderPalette.GREEN, 'biz', BUSINESS, 90)
say(scene, 70, 'Підведи вал від свого генератора', [0.5, 1.5, 2.5], PonderPalette.GREEN, true)
setSpeed(scene, ALL, 32)
scene.idle(10)
say(scene, 70, 'Машини держави закрутились', [3.5, 2.5, 2.5])
for (let i = 0; i < 3; i++) {
scene.world.createItemEntity([2.5, 2.2, 2.5], [0, 0.2, 0], 'numismatics:spur')
scene.idle(12)
}
say(scene, 70, 'Щохвилини держава платить твоєму бізнесу', [2.5, 2.5, 2.5], PonderPalette.GREEN, true)
say(scene, 70, 'Платить за силу, яку забирає підстанція', [2.5, 2.5, 2.5])
say(scene, 70, 'Приклад: 2048 SU — приблизно 1 ¤ за хвилину', [2.5, 2.5, 2.5], PonderPalette.BLUE)
setSpeed(scene, ALL, 0)
scene.idle(10)
say(scene, 70, 'Сили не вистачає — машини стоять, грошей немає', [1.5, 1.5, 2.5], PonderPalette.RED, true)
setSpeed(scene, ALL, 32)
say(scene, 80, 'Хочеш продавати енергію — знайди підстанцію й підключись', [2.5, 2.5, 2.5], null, true)
}
// ---------------------------------------------------------------------------------------------
Ponder.tags(event => {
event.createTag('kubejs:createrp', 'kubejs:citizen_guide', 'Держава Create RP',
'Як жити й заробляти в державній економіці',
['kubejs:citizen_guide', 'create:package_frogport', 'computercraft:computer_advanced', 'computercraft:computer_normal', 'computercraft:monitor_advanced', 'create:stressometer'])
})
Ponder.registry(event => {
event.create('kubejs:citizen_guide')
.scene('guide_terminal', 'Термінал держави', terminalScene)
.scene('guide_sell', 'Продаж державі', FROG_STRUCTURE, sellScene)
.scene('guide_buy', 'Покупки в держави', FROG_STRUCTURE, buyScene)
.scene('guide_energy', 'Продаж енергії державі', energyScene)
.scene('guide_money', 'Гроші й банк', moneyScene)
.scene('guide_land', 'Земля й надра', landScene)
.scene('guide_jobs', 'Робота: ринок праці й пошта', jobsScene)
event.create('create:package_frogport')
.scene('frogport_sell', 'Create RP: продаж державі', FROG_STRUCTURE, sellScene)
.scene('frogport_buy', 'Create RP: покупки в держави', FROG_STRUCTURE, buyScene)
event.create('create:stressometer')
.scene('stressometer_energy', 'Create RP: продаж енергії державі', energyScene)
event.create(['computercraft:computer_advanced', 'computercraft:computer_normal'])
.scene('computer_terminal', 'Create RP: термінал держави', terminalScene)
event.create('computercraft:monitor_advanced')
.scene('monitor_terminal', 'Create RP: термінал і табло цін', terminalScene)
})