7 Commits
Author SHA1 Message Date
FulldroperandClaude Opus 5.5 3baf5e8493 0.6.1: tutorial on real chain networks, energy scene
- selling and buying scenes use Create's own frogport schematic and move an addressed package along
  the chains with the same calls as Create's scenes (guarded: without the classes they still show the network)
- new scene: selling energy to the state through a metered stressometer (also on create:stressometer)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 06:44:46 +03:00
FulldroperandClaude Opus 5.5 eef8225cfd 0.6.0: in-game tutorial in Create's Ponder style
- Ponder for KubeJS 2.4.0 (client) + client_scripts/createrp_ponder.js: six scenes (terminal, selling,
  buying, money and bank, land and ore, jobs) on «Довідник громадянина», frogport and CC computers,
  plus a «Держава Create RP» tag in the Ponder index
- startup_scripts/createrp_items.js registers kubejs:citizen_guide (identical in the server pack)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 06:32:31 +03:00
FulldroperandClaude Opus 5.5 80693085e1 0.5.0: Cyrillic CC terminal font (CCCyrillic, MIT) via kubejs/assets
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 02:59:49 +03:00
FulldroperandClaude Opus 5.5 7e109471a2 0.4.0: Easy NPC
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 01:13:26 +03:00
Full_droperandClaude Opus 5.5 c1fea71237 Easy NPC
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 00:51:19 +03:00
Full_droperandClaude Opus 5.5 adea640a78 0.3.0: Open Parties and Claims
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 22:57:57 +03:00
Full_droperandClaude Opus 5.5 0db88ac9fe 0.2.0: KubeJS (+Rhino, Better Advanced Tooltips); tools/add-mod.mjs
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 21:06:03 +03:00
16 changed files with 604 additions and 3 deletions
+56
View File
@@ -804,6 +804,22 @@ hash = "d438aea41ca41e93697e059f523686935c0add482f6abe96b532bbf10c6ed80a"
file = "config/yacl.json5" file = "config/yacl.json5"
hash = "121b93764159be6fb7dab523b29a844e2bb78400ce8c48f52135a097e9b0006e" hash = "121b93764159be6fb7dab523b29a844e2bb78400ce8c48f52135a097e9b0006e"
[[files]]
file = "kubejs/assets/computercraft/textures/gui/CREDITS.txt"
hash = "19b844245d03fcdd488a7a791e287447191a74acd0f14995209339d768c5e6ce"
[[files]]
file = "kubejs/assets/computercraft/textures/gui/term_font.png"
hash = "db4c4a8ab49265f6e8e456f495800ea148b133b18a3242aabca30b98ab7f784f"
[[files]]
file = "kubejs/client_scripts/createrp_ponder.js"
hash = "4a6ebdddb0249b1f59fd0d3b67649df682b81c10ff60a65a9739c0fb8c4de6ac"
[[files]]
file = "kubejs/startup_scripts/createrp_items.js"
hash = "58100f02cf749b138c2a91567df37afce4b2ef494738268963e8443a3e603036"
[[files]] [[files]]
file = "mods/3dskinlayers.pw.toml" file = "mods/3dskinlayers.pw.toml"
hash = "82becc6910845ae1a68884e6f7a3dcdc861d79a087ae81b1d7e120e82884372d" hash = "82becc6910845ae1a68884e6f7a3dcdc861d79a087ae81b1d7e120e82884372d"
@@ -849,6 +865,11 @@ file = "mods/balm.pw.toml"
hash = "392901b7f79963442553456af846d06f48b4057a054a928adb8a76eea13c6383" hash = "392901b7f79963442553456af846d06f48b4057a054a928adb8a76eea13c6383"
metafile = true metafile = true
[[files]]
file = "mods/better-advanced-tooltips.pw.toml"
hash = "03084ff4f74cedc1b8ac6c85a98842f75956fb4fa811d285d8ca7caa8d54da5d"
metafile = true
[[files]] [[files]]
file = "mods/better-ping-display.pw.toml" file = "mods/better-ping-display.pw.toml"
hash = "cc2e6dda94a7a6f5487843cafe569d8044bf9482cbf03f062cf4595f1fb05281" hash = "cc2e6dda94a7a6f5487843cafe569d8044bf9482cbf03f062cf4595f1fb05281"
@@ -979,6 +1000,21 @@ file = "mods/dynamic-fps.pw.toml"
hash = "ae6fd52d8bdcbeca5bbe6db840f22f92c1928fe0fda22017b19612b9b00a245a" hash = "ae6fd52d8bdcbeca5bbe6db840f22f92c1928fe0fda22017b19612b9b00a245a"
metafile = true metafile = true
[[files]]
file = "mods/easy-npc-config-ui.pw.toml"
hash = "6f78b2a8761dc39680d58db1f4343204be8223a8b734d16a82fdbbd89f0cea1a"
metafile = true
[[files]]
file = "mods/easy-npc-core.pw.toml"
hash = "240307bd539f88529af38d0365bff3ea2b778e41bb5cbb1ba9d88557a1d4347c"
metafile = true
[[files]]
file = "mods/easy-npc.pw.toml"
hash = "98fbf36b902f51b003016d672cef0538a7846313a30ab6b3da2d2ef30b9b4ad6"
metafile = true
[[files]] [[files]]
file = "mods/elytra-slot.pw.toml" file = "mods/elytra-slot.pw.toml"
hash = "9e2b351f3cabb1252259f5383e6f2fec3e3d90534dbecddef4ed183eba42f35a" hash = "9e2b351f3cabb1252259f5383e6f2fec3e3d90534dbecddef4ed183eba42f35a"
@@ -1114,6 +1150,11 @@ file = "mods/kotlin-for-forge.pw.toml"
hash = "27302b0087cf53570cd7a3b4eb550a208cbb6f6ba07210c604176155f39e0078" hash = "27302b0087cf53570cd7a3b4eb550a208cbb6f6ba07210c604176155f39e0078"
metafile = true metafile = true
[[files]]
file = "mods/kubejs.pw.toml"
hash = "7e0eca275f27b6543f06c36dec433851a956960cbedd2be57d19e159d636bfc1"
metafile = true
[[files]] [[files]]
file = "mods/longer-chat-history.pw.toml" file = "mods/longer-chat-history.pw.toml"
hash = "12e4601519ca5fb940e9658b71f2218f2a06c41847b714978e1568435688858d" hash = "12e4601519ca5fb940e9658b71f2218f2a06c41847b714978e1568435688858d"
@@ -1174,6 +1215,11 @@ file = "mods/oceans-delight.pw.toml"
hash = "7bf7c8369bd28212a1e294c60310ccb72f1eb773630970e6ab106ae666766cd3" hash = "7bf7c8369bd28212a1e294c60310ccb72f1eb773630970e6ab106ae666766cd3"
metafile = true metafile = true
[[files]]
file = "mods/open-parties-and-claims.pw.toml"
hash = "97660396e7f075f4c9ca8447878ec3da58ebea9ed464cdb494d4db1d62989936"
metafile = true
[[files]] [[files]]
file = "mods/particle-rain.pw.toml" file = "mods/particle-rain.pw.toml"
hash = "6f24e7f5ecef862b1bdb61031637e27b093f185c3219023bea94d2d954ec4180" hash = "6f24e7f5ecef862b1bdb61031637e27b093f185c3219023bea94d2d954ec4180"
@@ -1204,6 +1250,11 @@ file = "mods/polytone.pw.toml"
hash = "636f08c84e9a1e1793850aa4f2390e5ece8fc25abee1d5d83679f3813e113802" hash = "636f08c84e9a1e1793850aa4f2390e5ece8fc25abee1d5d83679f3813e113802"
metafile = true metafile = true
[[files]]
file = "mods/ponder.pw.toml"
hash = "5ead8d8bc26cdbe1a17dc055f7f0fe762a08254d0199d6ea8fcc58839ab274f2"
metafile = true
[[files]] [[files]]
file = "mods/puzzles-lib.pw.toml" file = "mods/puzzles-lib.pw.toml"
hash = "6812c3faa178cd48c65c5b8e7aeef50bc0b63d8e3b2117065d6179a43d8d3649" hash = "6812c3faa178cd48c65c5b8e7aeef50bc0b63d8e3b2117065d6179a43d8d3649"
@@ -1214,6 +1265,11 @@ file = "mods/reeses-sodium-options.pw.toml"
hash = "09306b955060349986ccf6a6d2a67f1e019fa172a7dc690dd6007f81c966309a" hash = "09306b955060349986ccf6a6d2a67f1e019fa172a7dc690dd6007f81c966309a"
metafile = true metafile = true
[[files]]
file = "mods/rhino.pw.toml"
hash = "673de9cae75d2ad02796368939384de0d7238cf5c782975d71848a2187f753e7"
metafile = true
[[files]] [[files]]
file = "mods/rrls.pw.toml" file = "mods/rrls.pw.toml"
hash = "b78044fd79ce21750d05dc61b6aede33c4b87cdc16a26f5aff472d4f73ab623c" hash = "b78044fd79ce21750d05dc61b6aede33c4b87cdc16a26f5aff472d4f73ab623c"
@@ -0,0 +1,2 @@
term_font.png — "CCCyrillic" by sashafiesta (MIT), https://modrinth.com/resourcepack/cccyrillic
Windows-1251 Cyrillic glyphs for the CC:Tweaked terminal font. The server's terminal programs write text in 1251.
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

+379
View File
@@ -0,0 +1,379 @@
// 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)
}
// посилка з адресою їде ланцюгами від пакужаби from до пакужаби to (по вузлах CONV2 → CONV1)
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)
frogTakes(scene, util, CONV1, TO_FROG, box)
scene.idle(10)
}
function setSpeed(scene, util, sel, speed) {
if (CreateScene) new CreateScene(scene).world().setKineticSpeed(sel, speed)
}
// схематика Create «Transporting packages between Frogports» (9x9): ланцюги на висоті 4, дві пакужаби
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()
}
})
}
// пакужаба на прийомі: знімає посилки з вузла й «ковтає» їх
function frogTakes(scene, util, conv, frog, box) {
scene.world.modifyBlockEntity(util.grid.at(conv[0], conv[1], conv[2]), ChainConveyor, be => be.getLoopingPackages().clear())
scene.world.modifyBlockEntity(util.grid.at(frog[0], frog[1], frog[2]), Frogport, be => be.startAnimation(box, false))
}
// спільна частина: мережа ланцюгів з'являється так само, як у 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)
}
// ---------------------------------------------------------------------------------------------
// 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.text(80, 'Будь-який _комп\'ютер_ — це термінал держави. Відкрий його й набери _rp_.', [2.5, 1.5, 2.5])
.placeNearTarget().attachKeyFrame()
scene.showControls(60, [2.5, 2, 2.5], 'down').rightClick()
scene.idle(90)
scene.text(90, 'Вхід — твій _нік_ і _пароль_. Першого разу термінал попросить створити пароль. Стій поруч із комп\'ютером — здалеку не пустить.', [2.5, 1.5, 2.5])
.placeNearTarget().attachKeyFrame()
scene.idle(100)
scene.text(90, 'У меню: _рахунок_, _бізнес_, _ціни_, _магазин_, _земля_, _робота_, _тендери_, _банк_. Стрілки й Enter, Backspace — назад.', [2.5, 1.5, 2.5])
.placeNearTarget()
scene.idle(100)
scene.world.showSection([1, 1, 3, 3, 2, 3], Direction.DOWN)
scene.idle(15)
scene.text(90, 'Комп\'ютер з _монітором_ — табло цін держави: програма _prices metal_ (або stone, wood, farm, food, create…).', [2, 2.5, 3])
.colored(PonderPalette.BLUE).placeNearTarget().attachKeyFrame()
scene.idle(100)
}
// ---------------------------------------------------------------------------------------------
// 2. Продаж державі (схематика Create з ланцюгами)
function sellScene(scene, util) {
showChainNetwork(scene, util)
scene.text(90, 'Бізнеси й держава з\'єднані _мережею ланцюгів_. Посилка сама знаходить пакужабу з потрібною адресою.', [4, 4.5, 7])
.placeNearTarget().attachKeyFrame()
scene.idle(100)
// бізнес: сховище, пакувальник з табличкою, пакужаба на ланцюгу
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(4, 1, 2), Direction.EAST)
scene.world.showSection(util.select.position(5, 2, 2), Direction.DOWN)
scene.idle(15)
scene.text(110, 'Твій бізнес: сховище → _пакувальник_ → _пакужаба_ на ланцюгу. Табличка на пакувальнику — адреса продажу _gov-…_ (термінал → Бізнес → Адреса продажу).', [4.5, 1.5, 2.5])
.placeNearTarget().attachKeyFrame()
scene.idle(120)
// держава: пакужаба з фільтром gov-* і приймач під нею
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.idle(5)
scene.world.showSection(util.select.position(2, 2, 5), Direction.DOWN)
scene.idle(15)
scene.text(100, '_Державна пакужаба_ приймає посилки на всі адреси gov-… Під нею — державний приймач.', [2.5, 2.5, 5.5])
.colored(PonderPalette.BLUE).placeNearTarget().attachKeyFrame()
scene.idle(110)
scene.text(70, 'Посилка з адресою gov-… їде ланцюгами…', [6.78, 4.37, 3.5]).placeNearTarget()
shipOnChains(scene, util, 'gov-a1b2c3')
scene.text(110, '…до держави. Гроші — на _рахунок бізнесу_. Товару забагато — ціна падає, дефіцит — росте. Ціни — на табло й у терміналі.', [2.5, 2.5, 5.5])
.colored(PonderPalette.GREEN).placeNearTarget().attachKeyFrame()
scene.idle(120)
scene.text(80, 'Поїзди, ферми, ланцюги — продаж іде сам, поки ти робиш інше.', [4, 4.5, 4])
scene.idle(90)
}
// ---------------------------------------------------------------------------------------------
// 3. Покупка в держави (та сама мережа, напрямок навпаки)
function buyScene(scene, util) {
showChainNetwork(scene, util)
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)
scene.text(100, '_Державний склад_: пакувальник і пакужаба держави на тій самій мережі ланцюгів.', [5.5, 2.5, 2.5])
.colored(PonderPalette.BLUE).placeNearTarget().attachKeyFrame()
scene.idle(110)
scene.text(100, 'Держава продає _імпорт_ (алмази, незерит, елітри…) і _ліцензії_. Купівля — термінал → Магазин держави.', [4, 4.5, 4])
.placeNearTarget().attachKeyFrame()
scene.idle(110)
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)
scene.text(100, 'Твоя пакужаба з адресою, напр. _Склад Олі_. Цю назву вкажи під час покупки — термінал запам\'ятає.', [2.5, 2.5, 5.5])
.placeNearTarget().attachKeyFrame()
scene.idle(110)
shipOnChains(scene, util, 'Склад Олі')
scene.text(100, 'Посилка приходить сама. _Пакувальник_ під твоєю пакужабою розпакує її у скриню.', [3.5, 1.5, 5.5])
.colored(PonderPalette.GREEN).placeNearTarget().attachKeyFrame()
scene.idle(110)
scene.text(80, 'Не дійшла? Гроші _повертаються_ автоматично, а в чаті буде причина.', [4, 4.5, 4])
scene.idle(90)
}
// ---------------------------------------------------------------------------------------------
// 7. Продаж енергії державі
function energyScene(scene, util) {
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:shaft[axis=x]')
scene.world.setBlocks([4, 1, 2], 'create:encased_fan[facing=east]')
scene.idle(10)
scene.world.showSection([0, 1, 2], Direction.DOWN)
scene.world.showSection([1, 1, 2], Direction.DOWN)
scene.idle(10)
setSpeed(scene, util, util.select.fromTo(0, 1, 2, 1, 1, 2), 16)
scene.text(90, 'Енергію теж можна _продавати державі_. Твій генератор — колесо, вітряк, двигун — крутить вал до державної мережі.', [0.5, 1.5, 2.5])
.placeNearTarget().attachKeyFrame()
scene.idle(100)
scene.world.showSection([3, 1, 2, 4, 1, 2], Direction.DOWN)
scene.idle(10)
scene.world.showSection([2, 1, 2], Direction.DOWN)
scene.idle(10)
setSpeed(scene, util, util.select.fromTo(0, 1, 2, 4, 1, 2), 16)
scene.overlay.showOutline(PonderPalette.GREEN, 'biz', util.select.fromTo(0, 1, 2, 1, 1, 2), 100)
scene.overlay.showOutline(PonderPalette.BLUE, 'state', util.select.fromTo(3, 1, 2, 4, 1, 2), 100)
scene.text(100, 'На стику — _державний лічильник_ (стресометр). Його ставить держава і прив\'язує до твого бізнесу.', [2.5, 1.8, 2.5])
.colored(PonderPalette.BLUE).placeNearTarget().attachKeyFrame()
scene.idle(110)
scene.text(110, 'Щохвилини держава платить бізнесу за _силу_ (SU), яку забирають її машини, — до ліміту лічильника.', [3.5, 1.5, 2.5])
.colored(PonderPalette.GREEN).placeNearTarget().attachKeyFrame()
scene.idle(120)
setSpeed(scene, util, util.select.fromTo(0, 1, 2, 4, 1, 2), 0)
scene.text(90, 'Генератор зупинився — оплата зупинилась. Перевантажив мережу — теж нічого не заробиш.', [1.5, 1.5, 2.5])
.colored(PonderPalette.RED).placeNearTarget()
scene.idle(100)
setSpeed(scene, util, util.select.fromTo(0, 1, 2, 4, 1, 2), 16)
scene.text(80, 'Хочеш лічильник? Звернися до держави — вона підключить твою електростанцію.', [2.5, 2.5, 2.5])
scene.idle(90)
}
// ---------------------------------------------------------------------------------------------
// 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)
scene.text(90, 'Твої гроші — на _рахунку_ в державному банку. Баланс і перекази — термінал → Рахунок.', [2.5, 1.5, 2.5])
.placeNearTarget().attachKeyFrame()
scene.idle(100)
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)
scene.text(110, '_Готівка_ — монети: зняти /cash withdraw <сума>, покласти — /cash deposit з монетами в руці. Готівкою платять одне одному з рук.', [2.5, 2, 1.5])
.colored(PonderPalette.GREEN).placeNearTarget().attachKeyFrame()
scene.idle(120)
scene.text(100, '_Банк_ (термінал → Банк): стартовий та інвестиційний кредити для бізнесу, вклади під відсоток щодня.', [2.5, 1.5, 2.5])
.placeNearTarget().attachKeyFrame()
scene.idle(110)
scene.text(90, 'Кредит платиться щоденними внесками. Пропустиш тричі — _дефолт_: рахунок бізнесу заморожено, тендери заборонені.', [2.5, 1.5, 2.5])
.colored(PonderPalette.RED).placeNearTarget()
scene.idle(100)
}
// ---------------------------------------------------------------------------------------------
// 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)
scene.text(90, 'Уся незареєстрована земля _належить державі_. Будувати можна на своїх ділянках.', [2.5, 1, 2.5])
.placeNearTarget().attachKeyFrame()
scene.idle(100)
scene.overlay.showOutline(PonderPalette.GREEN, 'plot', util.select.fromTo(0, 0, 0, 4, 0, 4), 120)
scene.world.showSection([1, 1, 1, 3, 1, 3], Direction.DOWN)
scene.text(110, '_Ділянки_ орендують на ігрові дні або викуповують: термінал → Земля. Заходячи на ділянку, бачиш її назву над хотбаром.', [2.5, 1.5, 2.5])
.colored(PonderPalette.GREEN).placeNearTarget().attachKeyFrame()
scene.idle(120)
scene.text(100, 'Орендована ділянка — _приват_ бізнесу: чужі не ламають, а твої працівники мають доступ.', [2.5, 1.5, 2.5])
.placeNearTarget()
scene.idle(110)
scene.overlay.showOutline(PonderPalette.RED, 'ore', util.select.position(2, 1, 2), 100)
scene.text(100, '_Руда_ видобувається за _концесією_: купи дозвіл на руду й квоту на ділянці (термінал → Земля → Купити концесію).', [2.5, 1.5, 2.5])
.colored(PonderPalette.RED).placeNearTarget().attachKeyFrame()
scene.idle(110)
scene.text(80, 'За землю щодня — орендна плата або податок. Не заплатив 3 дні — ділянка повертається державі.', [2.5, 2.5, 2.5])
scene.idle(90)
}
// ---------------------------------------------------------------------------------------------
// 6. Робота: ринок праці і пошта
function jobsScene(scene, util) {
scene.showBasePlate()
scene.idle(10)
const post = scene.world.createEntity('minecraft:villager', [1, 1, 2.5])
scene.idle(10)
scene.text(90, 'Немає роботи? Термінал → Робота → _ринок праці_: допомога по безробіттю щодня, якщо ти був активний у грі.', [2.5, 2.5, 2.5])
.placeNearTarget().attachKeyFrame()
scene.idle(100)
scene.text(90, 'Хочеш заробляти більше — стань _поштарем_. Клікни по NPC пошти.', [1, 2.5, 2.5])
.colored(PonderPalette.BLUE).placeNearTarget().attachKeyFrame()
scene.showControls(60, [1, 2.3, 2.5], 'down').rightClick()
scene.idle(70)
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)
scene.text(100, 'Отримаєш _посилку_ з іменем адресата й _компас_, що вказує на нього. ПКМ компасом — мітка на місці (видно лише тобі).', [2, 1.5, 2.5])
.placeNearTarget().attachKeyFrame()
scene.idle(110)
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], 80)
scene.text(100, 'Адресат чекає в іншій частині світу. Принеси посилку й клікни по ньому — гроші на рахунок. Що далі, то дорожче.', [4, 2.5, 2.5])
.colored(PonderPalette.GREEN).placeNearTarget().attachKeyFrame()
scene.idle(110)
scene.text(80, 'На доставку — _2 ігрові дні_. Не встиг — адресат поїде, і посилка згорить.', [2.5, 2.5, 2.5])
.colored(PonderPalette.RED)
scene.idle(90)
scene.text(90, 'Або наймися до бізнесу: власник пропонує зарплату, ти приймаєш у терміналі → Бізнес → Прийняти запрошення.', [2.5, 2.5, 2.5])
scene.idle(100)
}
// ---------------------------------------------------------------------------------------------
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)
})
+12
View File
@@ -0,0 +1,12 @@
// Create RP — предмети збірки. Цей файл має бути ОДНАКОВИМ у серверній і клієнтській збірках:
// реєстр предметів сервера й клієнта мусить збігатися.
StartupEvents.registry('item', event => {
// «Довідник громадянина»: навести в інвентарі й затиснути W — туторіал Ponder (клієнтський client_scripts/createrp_ponder.js)
event.create('citizen_guide')
.displayName('Довідник громадянина')
.texture('minecraft:item/knowledge_book')
.maxStackSize(1)
.glow(true)
.tooltip('§7Наведи в інвентарі й затисни §fW§7 — як у Create')
})
+13
View File
@@ -0,0 +1,13 @@
name = "Better Advanced Tooltips"
filename = "better-advanced-tooltips-2101.1.0-build.5.jar"
side = "both"
[download]
url = "https://cdn.modrinth.com/data/iHLDc0eo/versions/uPFbnD32/better-advanced-tooltips-2101.1.0-build.5.jar"
hash-format = "sha512"
hash = "05b5cdad948d1735eab7a67a16aaf32814678c392014ec2ada61b8341c0ed1c1ac181cab1de9da3f2c4632592f4a1a5db254bd0543e6778897c8ccd260894142"
[update]
[update.modrinth]
mod-id = "iHLDc0eo"
version = "uPFbnD32"
+13
View File
@@ -0,0 +1,13 @@
name = "Easy NPC: Config UI"
filename = "easy_npc_config_ui-neoforge-1.21.1-7.14.0.jar"
side = "both"
[download]
url = "https://cdn.modrinth.com/data/uTGjf7vA/versions/am2FLyOh/easy_npc_config_ui-neoforge-1.21.1-7.14.0.jar"
hash-format = "sha512"
hash = "b5f6dcab0c1c228d399cd9c74cf3e5be8102d2e77e9b4017087896389662f893aca403063781168e780897bb63a74ed5b06ca9b183cda6014c05aab44407b6a1"
[update]
[update.modrinth]
mod-id = "uTGjf7vA"
version = "am2FLyOh"
+13
View File
@@ -0,0 +1,13 @@
name = "Easy NPC: Core"
filename = "easy_npc-neoforge-1.21.1-7.14.0.jar"
side = "both"
[download]
url = "https://cdn.modrinth.com/data/Epm6R3P2/versions/wpGE79aG/easy_npc-neoforge-1.21.1-7.14.0.jar"
hash-format = "sha512"
hash = "073f0bf6ef9e4ace88c4d51ca591906a40adf1098f07893858080265e775e5db8467bd6041b82e67787f9384b08e65a2451b8d932ab9533cb4023c43cb5198e9"
[update]
[update.modrinth]
mod-id = "Epm6R3P2"
version = "wpGE79aG"
+13
View File
@@ -0,0 +1,13 @@
name = "Easy NPC"
filename = "easy_npc_bundle-neoforge-1.21.1-7.14.0.jar"
side = "both"
[download]
url = "https://cdn.modrinth.com/data/CgGEe1h3/versions/rgleNqSl/easy_npc_bundle-neoforge-1.21.1-7.14.0.jar"
hash-format = "sha512"
hash = "7ebe0ebfed3157fe624896105bbad01c3d1c56ae768e995f5b7002609e2f8e60deba9d2ffc14f574517cf0fcef4493ca321946ad07d00e58815df4aecbec3ac1"
[update]
[update.modrinth]
mod-id = "CgGEe1h3"
version = "rgleNqSl"
+13
View File
@@ -0,0 +1,13 @@
name = "KubeJS"
filename = "kubejs-neoforge-2101.7.2-build.377.jar"
side = "both"
[download]
url = "https://cdn.modrinth.com/data/umyGl7zF/versions/THIGFPwf/kubejs-neoforge-2101.7.2-build.377.jar"
hash-format = "sha512"
hash = "fcdbee8790f8f39c106ab4bf606808c9c5bf0f13a41e216207a6fe4d15bf4a5722ce57078781e3a1823e7fdd2928e8e042d104d8ae255a36db8f12a9f46d8089"
[update]
[update.modrinth]
mod-id = "umyGl7zF"
version = "THIGFPwf"
+13
View File
@@ -0,0 +1,13 @@
name = "Open Parties and Claims"
filename = "open-parties-and-claims-neoforge-1.21.1-0.31.6.jar"
side = "both"
[download]
url = "https://cdn.modrinth.com/data/gF3BGWvG/versions/3i48dTzz/open-parties-and-claims-neoforge-1.21.1-0.31.6.jar"
hash-format = "sha512"
hash = "6f8f2d570b6f674a9180576524b3ba507a3ad046ff319353cee50738644bf46c03ca460fb7c6880eed76f07eb2a26a983166d2510951202af86b3e120b743181"
[update]
[update.modrinth]
mod-id = "gF3BGWvG"
version = "3i48dTzz"
+13
View File
@@ -0,0 +1,13 @@
name = "Ponder for KubeJS"
filename = "ponderjs-neoforge-1.21.1-2.4.0.jar"
side = "client"
[download]
url = "https://cdn.modrinth.com/data/5A34Stj8/versions/BqhDf7W8/ponderjs-neoforge-1.21.1-2.4.0.jar"
hash-format = "sha512"
hash = "6390c4bf631561c29a76b8b29a496d4b984bf847572940b28e551f2c2e3da4a8fb04b6a82cf98a7935792a7d3485cdc45c76f2bdf7f93799210262ba5f184955"
[update]
[update.modrinth]
mod-id = "5A34Stj8"
version = "BqhDf7W8"
+13
View File
@@ -0,0 +1,13 @@
name = "Rhino"
filename = "rhino-2101.2.8-build.91.jar"
side = "both"
[download]
url = "https://cdn.modrinth.com/data/sk9knFPE/versions/SqkDvOLG/rhino-2101.2.8-build.91.jar"
hash-format = "sha512"
hash = "e3d92f663bc07872a83b0a6474b30a75230e9f92a2844fd98da1842ec9a79712bcb7d8e76574cc11ae3aeceb47f2933c60ddd6cf41f3ad7027bd573623730945"
[update]
[update.modrinth]
mod-id = "sk9knFPE"
version = "SqkDvOLG"
+2 -2
View File
@@ -1,12 +1,12 @@
name = "Create RP" name = "Create RP"
author = "Pinecraft-CreateRP" author = "Pinecraft-CreateRP"
version = "0.1.0" version = "0.6.1"
pack-format = "packwiz:1.1.0" pack-format = "packwiz:1.1.0"
[index] [index]
file = "index.toml" file = "index.toml"
hash-format = "sha256" hash-format = "sha256"
hash = "82d2822700967bcd03c3e01038401304546e4a1c690ad35d680e38a55742001d" hash = "2a8313cb0a107c64dc9c434c0f331fdc545223c9d9293fb7fc57b85ca54256fa"
[versions] [versions]
minecraft = "1.21.1" minecraft = "1.21.1"
+46
View File
@@ -0,0 +1,46 @@
// Adds a Modrinth mod (and its required dependencies, recursively) to this packwiz pack.
// node tools/add-mod.mjs <slug-or-id> [...] → latest NeoForge 1.21.1 version
// node tools/add-mod.mjs <slug>@<version_number> → that exact version
// Writes mods/<slug>.pw.toml, then run: node tools/reindex.mjs
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
const UA = { 'User-Agent': 'Pinecraft-CreateRP/add-mod' };
const api = p => fetch('https://api.modrinth.com/v2' + p, { headers: UA }).then(r => {
if (!r.ok) throw new Error(`${p}: HTTP ${r.status}`);
return r.json();
});
const q = s => JSON.stringify(s);
const existing = new Set(fs.readdirSync(path.join(root, 'mods')).filter(f => f.endsWith('.pw.toml')).map(f => {
const t = fs.readFileSync(path.join(root, 'mods', f), 'utf8');
return (t.match(/^mod-id = "([^"]+)"/m) || [])[1];
}).filter(Boolean));
const sideOf = p => p.server_side === 'unsupported' ? 'client' : p.client_side === 'unsupported' ? 'server' : 'both';
async function add(spec, depth = 0) {
const [ref, wanted] = spec.split('@');
const project = await api(`/project/${ref}`);
const pad = ' '.repeat(depth);
if (existing.has(project.id)) { console.log(`${pad}= ${project.title} — already in the pack`); return; }
const versions = await api(`/project/${project.id}/version?loaders=${encodeURIComponent('["neoforge"]')}&game_versions=${encodeURIComponent('["1.21.1"]')}`);
const v = wanted ? versions.find(x => x.version_number === wanted) : versions[0];
if (!v) throw new Error(`${project.title}: no NeoForge 1.21.1 version${wanted ? ' ' + wanted : ''}`);
const f = v.files.find(x => x.primary) || v.files[0];
const toml = [
`name = ${q(project.title)}`, `filename = ${q(f.filename)}`, `side = ${q(sideOf(project))}`, '',
'[download]', `url = ${q(f.url)}`, 'hash-format = "sha512"', `hash = ${q(f.hashes.sha512)}`, '',
'[update]', '[update.modrinth]', `mod-id = ${q(project.id)}`, `version = ${q(v.id)}`, ''
].join('\n');
fs.writeFileSync(path.join(root, 'mods', `${project.slug}.pw.toml`), toml);
existing.add(project.id);
console.log(`${pad}+ ${project.title} ${v.version_number} (${sideOf(project)})`);
for (const d of v.dependencies.filter(d => d.dependency_type === 'required' && d.project_id)) {
await add(d.project_id, depth + 1);
}
}
for (const spec of process.argv.slice(2)) await add(spec);
+3 -1
View File
@@ -1,7 +1,7 @@
// Exports this packwiz pack as a Modrinth modpack (.mrpack) for Modrinth App / Prism "Import". // Exports this packwiz pack as a Modrinth modpack (.mrpack) for Modrinth App / Prism "Import".
// node tools/export-mrpack.mjs → dist/CreateRP-<version>.mrpack // node tools/export-mrpack.mjs → dist/CreateRP-<version>.mrpack
// Mods are referenced by their Modrinth CDN URL (sha1/sha512/size from the Modrinth API); // Mods are referenced by their Modrinth CDN URL (sha1/sha512/size from the Modrinth API);
// config/ goes into overrides/. Zipping uses Windows' bsdtar (tar -a) or `zip` on Linux. // config/ and kubejs/ go into overrides/. Zipping uses Windows' bsdtar (tar -a) or `zip` on Linux.
import fs from 'fs'; import fs from 'fs';
import path from 'path'; import path from 'path';
import { execFileSync } from 'child_process'; import { execFileSync } from 'child_process';
@@ -60,6 +60,8 @@ fs.rmSync(stage, { recursive: true, force: true });
fs.mkdirSync(path.join(stage, 'overrides'), { recursive: true }); fs.mkdirSync(path.join(stage, 'overrides'), { recursive: true });
fs.writeFileSync(path.join(stage, 'modrinth.index.json'), JSON.stringify(index, null, 2)); fs.writeFileSync(path.join(stage, 'modrinth.index.json'), JSON.stringify(index, null, 2));
fs.cpSync(path.join(root, 'config'), path.join(stage, 'overrides', 'config'), { recursive: true }); fs.cpSync(path.join(root, 'config'), path.join(stage, 'overrides', 'config'), { recursive: true });
// kubejs/assets: always-on client resources (CC terminal font with Cyrillic)
if (fs.existsSync(path.join(root, 'kubejs'))) fs.cpSync(path.join(root, 'kubejs'), path.join(stage, 'overrides', 'kubejs'), { recursive: true });
const out = path.join(root, 'dist', `CreateRP-${packVersion}.mrpack`); const out = path.join(root, 'dist', `CreateRP-${packVersion}.mrpack`);
fs.rmSync(out, { force: true }); fs.rmSync(out, { force: true });