नियमसेट की लेयर, अनुवाद और माइग्रेशन
खिलाड़ी किसी एक गेम के लिए जो रूपांतर चालू करते हैं उन्हें देने, नियमसेट के टेक्स्ट का अनुवाद करने, और शीट बदलने पर सेव किए गए मान नए ID पर ले जाने के लिए यह पेज इस्तेमाल करें। यह नियमसेट लेखकों के लिए है। शुरू करने से पहले Game Mode के नियमसेट लिखना पढ़ें।
लेयर: आपके अपने नियमसेट के रूपांतर
लेयर आपके नियमसेट का नाम वाला रूपांतर है जिसे खिलाड़ी गेम बनाते समय चालू करता है: कम जादू, कड़ी सर्दी, ज़्यादा कठोर कठिनाई। लेयर नियमसेट फ़ाइल में, वैकल्पिक layers ऐरे में रहती हैं, इसलिए वे उसके साथ जाती हैं और उन्हें इस्तेमाल करने वाले गेम से कभी गायब नहीं हो सकतीं। विज़ार्ड उन्हें आपके नियमसेट के नीचे टॉगल के रूप में दिखाता है, और चुनाव उस गेम के पूरे जीवन के लिए तय रहता है, बिल्कुल नियमसेट की तरह।
"layers": [
{
"id": "hard_winter",
"label": "Hard winter",
"summary": "Cold, hunger and short days. Everything is harder.",
"conflicts": ["mud_season"],
"gm": {
"guidance": "Hard winter is on. Let a failed check cost warmth, food or daylight as well as progress.",
"worldGuidance": "Hard winter is on. Build a world of closed roads, thin stores and rationed settlements."
},
"fields": [{ "id": "calling", "removeValues": ["Sailor"], "default": "Hauler" }],
"difficultyLadder": [{ "label": "Easy", "dc": 7 }],
"catalogs": [{ "id": "knacks", "hide": { "filter": "grit", "above": 0 } }]
},
{
"id": "mud_season",
"label": "Mud season",
"summary": "Thaw, flooded roads and slow going."
}
]लेयर क्या कर सकती है। सूची बंद है, और हर असर या तो कुछ सीमित करता है या टेक्स्ट जोड़ता है:
gm.guidanceआपकेgm.checkGuidanceके आखिर में जोड़ा जाता है, आपके अपने टेक्स्ट और किसी भी पहले की लेयर के टेक्स्ट के बाद।gm.worldGuidanceभी इसी तरहgm.worldGuidanceमें जोड़ा जाता है।fieldsकिसी enum फ़ील्ड से मान हटाता है।removeValuesउन मानों के नाम देता है जो फ़ील्ड में पहले से हैं, कम से कम एक का बचना ज़रूरी है, और अगर फ़ील्ड काdefaultउनमें से एक है तो लेयर उसकी जगह बचने वालाdefaultबताती है।difficultyLadderआपकी सीढ़ी को दूसरी सीढ़ी से बदलता है, आपके अपने हल करने के प्रकार के रूप में:dice-sumके लिए{label, dc}औरdice-poolके लिए{label, successes, target?}। उसकी ठीक वही जाँच होती है जो आपकी अपनी सीढ़ी की। जब कई सक्रिय लेयर इसे घोषित करती हैं, तो उनमें से आखिरी जीतती है।catalogsशीट एडिटर के पिकर से एंट्री छिपाता है। हर नियम उस कैटलॉग के घोषितfiltersमें से एक का नाम देता है और ठीक एक तुलना बताता है:numberफ़िल्टर के लिएaboveयाbelow,textयाtagsफ़िल्टर के लिएequalsयाnotIn। जो एंट्री वह फ़िल्टर सेट ही नहीं करती, वह कभी नहीं छिपती।currenciesसिक्के हटाता है:removeUnitsअकेले सिक्कों के नाम देता है औरremoveFamiliesपूरे परिवारों के। किसी परिवार का सबसे छोटा सिक्का सिर्फ़ अपने परिवार के साथ हटता है, ताकि बचा हर परिवार अब भी भुगतान कर सके और छुट्टा दे सके। लेयर चालू रहते कोई भी हटाया गया सिक्का न कमाता है, न उससे भुगतान करता है, न उसे चुनता है और न गिराता है, और बटुए वाली लाइन उसे छोड़ देती है। उसमें बताई गई कीमत उसी मूल्य पर, बचे हुए सबसे बड़े ऐसे सिक्के में बताई जाती है जो उसे ठीक-ठीक चुका सके: Gravewatch की लंबी रात crown को हटा देती है, इसलिए 3 crowns वाली पहरे की पिस्तौल 15 shillings की होती है। जिस आइटम का पूरा परिवार हट गया, उसकी कोई कीमत नहीं।itemsबदलता है कि चीज़ें कहाँ बिकती हैं और क्या गिरता है, कभी यह नहीं कि क्या मौजूद है।market.removeSellersआपके बाज़ार से विक्रेता हटाता है (कम से कम एक हमेशा बचता है: बिना विक्रेताओं वाला बाज़ार किसी को भी सब कुछ बेचने देता है, इसलिए ऐसा हटाव जो उसे खाली कर दे, दो लेयर के साथ मिलकर भी, नहीं किया जाता)।market.unsoldहर विक्रेता के माल से चीज़ें हटाता है, बाज़ार के अपने फ़िल्टर जैसे फ़िल्टर से (यह बाज़ार केunsoldमें जोड़ा जाता है)।lootTablesआपके पास पहले से मौजूद लूट टेबल को, ID से, उसी बनावट की टेबल से बदलता है, इसलिए उसका नाम देने वाला हर जीव, खतरे का स्तर और विक्रेता काstockबदली हुई टेबल रोल करता है; जब कई सक्रिय लेयर एक टेबल बदलती हैं, तो उनमें से आखिरी जीतती है। बिक्री से हटाया गया आइटम अब भी आइटम है: उसे साथ रखा जा सकता है, इस्तेमाल किया जा सकता है, लूट में पाया जा सकता है और Game Master उसे दे सकता है, और विक्रेता कीstockटेबल अब भी उसे रोल कर सकती है।
"items": {
"market": { "removeSellers": ["magic_dealer", "scribe"], "unsold": [{ "tag": "magical" }] },
"lootTables": [{ "id": "treasure_low", "label": "Pocket treasure", "entries": [{ "coins": "sp", "weight": 1, "count": "4d6" }] }]
}लेयर क्या नहीं कर सकती। वह enum मान नहीं जोड़ सकती, फ़ील्ड, स्किल, पूल या आराम नहीं जोड़ सकती, विक्रेता या लूट टेबल नहीं जोड़ सकती, हल करने का प्रकार नहीं बदल सकती, लाइव स्टेट या युद्ध की संख्याएँ नहीं छू सकती, और मॉडल कॉल नहीं जोड़ सकती। लेयर का _जोड़ा_ गया मान शीट के बाकी हर पढ़ने वाले के लिए अनजान होगा, इसलिए मान सिर्फ़ हटते हैं। इस सूची से आगे की कोई भी चीज़ खुद नियमसेट में बदलाव है, या दूसरा नियमसेट।
टकराव। conflicts उन लेयर के नाम देता है जो साथ चालू नहीं हो सकतीं। जोड़ी की एक तरफ़ नाम देना काफ़ी है। विज़ार्ड दूसरा टॉगल बंद कर देता है, और अगर किसी सेव चुनाव में किसी तरह दोनों हों, तो बाद में घोषित लेयर हटा दी जाती है, ताकि वही दो चुनाव हमेशा वही नियम दें।
हटाया गया मान पहले से रखने वाली शीट उसे रखती है। कुछ भी किसी कैरेक्टर को दोबारा नहीं लिखता। एडिटर वह मान देना बंद कर देता है, और जिस कैरेक्टर के पास वह पहले से था, वह उसे जैसा है वैसा दिखाता है। नए गेम में लेयर बंद करें तो मान फिर से मिलता है। छिपी कैटलॉग एंट्री के साथ भी यही है: वह पिकर से बाहर रहती है, और खिलाड़ी की पहले चुनी पंक्ति शीट पर बनी रहती है। लेयर के हटाए सिक्के जो किसी के पास पहले से हैं, उसके थैले में बने रहते हैं।
सीमाएँ। हर नियमसेट में 12 लेयर, और हर लेयर में दोनों टेक्स्ट मिलाकर 4000 अक्षरों के निर्देश। layers या मूल gm.worldGuidance घोषित करने वाले पैकेज वाले नियमसेट को Capability API 1.25 चाहिए, जिसकी लेयर सिक्के हटाती हैं उसे 1.64, और जिसकी लेयर उसके items बदलती हैं उसे 1.813। आपका इंपोर्ट किया नियमसेट उसे पढ़ने वाला Engine जाँचता है, इसलिए उसे कुछ नहीं चाहिए।
किसी और की लिखी लेयर (ऐसे नियमसेट के लिए कम जादू वाली लेयर जो आपने नहीं लिखा, अपनी अलग फ़ाइल में) बाद में जोड़ी जाने वाली चीज़ है। आज लेयर उसी नियमसेट के अंदर आती है जिसकी वह है।
अनुवाद
अनुवाद (Capability API 1.811)। किसी दूसरी भाषा में नियमसेट की दिखाई जाने वाली स्ट्रिंग उस भाषा के लिए एक अनुवाद में रखी जाती हैं, जिसका नाम भाषा के कोड पर होता है, जैसे Engine के अपने भाषा पैक के होते हैं (ru, pt-BR, zh-Hans)। आधिकारिक एजेंट कैटलॉग में हर अनुवाद नियमसेट की फ़ाइल के साथ रखा भाषा पैक होता है (नीचे देखें)। इसके बजाय आपके साझा किए जाने वाले नियमसेट पैकेज की फ़ाइल में वे अंदर भी हो सकते हैं, हर भाषा के लिए एक फ़ाइल, ruleset.json के साथ: locales/<language>.json, जो दूसरी फ़ाइलों की तरह मैनिफ़ेस्ट में सूचीबद्ध होती है। दोनों ही मामलों में, हर अनुवाद पैकेज का लोकलाइज़ेशन कैटलॉग है जिसमें ruleset सेक्शन होता है: हर कुंजी नियमसेट या उसके कैटलॉग की दिखाई जाने वाली स्ट्रिंग है, अंग्रेज़ी में शब्दशः, और उसका मान फ़ाइल की भाषा में वही स्ट्रिंग है।
{
"_meta": { "locale": "ru", "direction": "ltr" },
"package": { "name": "5e (SRD 5.1)" },
"ruleset": { "Prone": "Лежащий", "Fire Bolt": "Огненный снаряд", "Goblin": "Гоблин" }
}_meta.locale वही भाषा होनी चाहिए जिसके नाम पर फ़ाइल का नाम है, और फ़ाइल में $schema, _meta, package और ruleset के अलावा कुछ नहीं होता, हर मान टेक्स्ट होता है। खाली छोड़ी गई स्ट्रिंग का अनुवाद अभी नहीं हुआ है और वह अंग्रेज़ी में दिखती है; जिस फ़ाइल में ruleset सेक्शन नहीं है (पैकेज की अपनी अंग्रेज़ी लिस्टिंग, locales/en.json), वह किसी चीज़ का अनुवाद नहीं करती। अनुवाद सिर्फ़ दिखाने के लिए हैं: नियम, शीट कमांड और Game Master को बताई जाने वाली हर चीज़ अंग्रेज़ी ही पढ़ते रहते हैं। लड़ाई की स्क्रीन (नाम, स्थितियाँ, एक्शन, स्पेल, लॉग और टर्न क्रम) हर स्ट्रिंग को खिलाड़ी की भाषा में दिखाती है जहाँ नियमसेट के अनुवाद में वह मौजूद हो, पहले भाषा की अपनी फ़ाइल से और फिर उस भाषा की फ़ाइल से जिसका वह एक रूप है (pt-BR के लिए pt), और बाकी मामलों में अंग्रेज़ी में; "Goblin 2" के लिए "Goblin" का अनुवाद उसकी संख्या के साथ पढ़ा जाता है। अनुवाद वाली पैकेज फ़ाइल को Capability API 1.811 चाहिए। उसे इंपोर्ट करने पर सिर्फ़ उस भाषा का अनुवाद रखा जाता है जिस पर Engine सेट है (या उस भाषा का जिसका वह एक रूप है) और बाकी हटा दिए जाते हैं; नियमसेट को किसी दूसरी भाषा में पढ़ने के लिए Engine की भाषा बदलें और फ़ाइल फिर से इंपोर्ट करें, जो रखे गए अनुवाद की जगह ले लेती है। अनुवाद वर्ज़न का हिस्सा नहीं हैं, इसलिए सुधारे हुए अनुवाद के साथ वही वर्ज़न फिर से इंपोर्ट करने पर भी अनुवाद बदल दिया जाता है, और बिना अनुवाद वाली उसकी फ़ाइल पहले से रखे गए अनुवाद को रहने देती है।
कैटलॉग के नियमसेट की फ़ाइल के अंदर कभी locales/<language>.json नहीं होता (जिसमें होता है, उसे डाउनलोड करने से पहले ही अस्वीकार कर दिया जाता है)। उसके अनुवाद भाषा पैक होते हैं (Capability API 1.811): हर भाषा के लिए एक JSON फ़ाइल, <id>-<version>.<language>.json, जो <id>-<version>.ruleset.json के साथ प्रकाशित होती है और जिसमें ठीक वही होता है जो locales/<language>.json में होता है (_meta.locale में वही भाषा जिसके नाम पर फ़ाइल का नाम है, और ruleset सेक्शन)। कैटलॉग एंट्री उन्हें अपने artifact के साथ सूचीबद्ध करती है:
"locales": {
"ru": {
"url": "https://raw.githubusercontent.com/Pasta-Devs/Marinara-Agents/main/artifacts/ember-roads-1.0.0.ru.json",
"sha256": "<64 hex>",
"bytes": 812345,
"name": "Угольные дороги",
"description": "<the store card's description in Russian>"
}
}हर पैक का https URL उसी रूप का होता है जिस रूप का आर्टिफ़ैक्ट का होता है, उसके वर्ज़न और भाषा के नाम पर, साथ में उसका sha256 और आकार (अधिकतम 8 MB); नियमसेट अधिकतम 40 पैक सूचीबद्ध करता है, कभी en नहीं (अंग्रेज़ी खुद नियमसेट है), और उसका मैनिफ़ेस्ट Capability API 1.811 घोषित करता है। name और description उस भाषा में स्टोर कार्ड के नाम और विवरण हैं, इसलिए पैक फ़ेच किए बिना कार्ड Engine की भाषा में पढ़ा जा सकता है। इंस्टॉल करते समय नियमसेट की फ़ाइल और फिर सिर्फ़ उस भाषा का पैक फ़ेच होता है जिस पर Engine सेट है (या उस भाषा का जिसका वह एक रूप है), उसके आकार, चेकसम और भाषा की जाँच होती है, और उसे इंस्टॉल हुए वर्ज़न के साथ रखा जाता है। जब Engine की भाषा बदलती है (और हर बार जब उसमें पेज खुलता है), तो हर इंस्टॉल हुआ कैटलॉग नियमसेट, जो नई भाषा का पैक सूचीबद्ध करता है, उसे फ़ेच करता है और पुरानी भाषा का पैक हटा दिया जाता है। जो पैक मिल नहीं सकता (ऑफ़लाइन होने, सूचीबद्ध न होने, या कैटलॉग में सूचीबद्ध फ़ाइल न होने के कारण), वह नियमसेट को अंग्रेज़ी में रहने देता है; अगला इंस्टॉल या भाषा का बदलाव फिर कोशिश करता है। अपडेट पिछले वर्ज़न को उसके पैक के बिना रोलबैक के लिए रखता है: रोलबैक के बाद भाषा का अगला बदलाव उस वर्ज़न का पैक फिर फ़ेच करता है, अगर कैटलॉग अब भी उसे सूचीबद्ध करता है।
नए ID पर मान ले जाना: sheet.migrations
चीज़ें जोड़ने के लिए और कुछ नहीं चाहिए। जब नया लेआउट किसी मान को कहीं और ले जाता है (नाम बदला गया फ़ील्ड, एक स्तर जो हर क्लास का अलग स्तर बन जाता है, हिट डाइस का एक पूल जो हर डाइस का अलग पूल बन जाता है), तो sheet.migrations (Capability API 1.77) में बताएँ कैसे, ताकि पुराने लेआउट पर बना हर कैरेक्टर अपनी संख्याएँ रखे: लाइब्रेरी में, गेम में, पुराने सेव, ब्रांच और चेकपॉइंट में, और इंपोर्ट किए कार्ड में।
"migrations": [
{
"from": 3,
"steps": [
{ "rename": "field", "from": "xp", "to": "experience" },
{
"route": "level",
"by": "class",
"cases": [
{ "words": ["fighter"], "to": "level_fighter" },
{ "words": ["wizard"], "to": "level_wizard" }
],
"else": "level_other",
"default": 1
},
{
"routeLive": "pool",
"from": "hit_dice",
"cases": ["hit_dice_d6", "hit_dice_d8", "hit_dice_d10", "hit_dice_d12"],
"else": "hit_dice_d8"
}
]
}
]- हर एंट्री सेव हुई शीट को वर्ज़न
fromसेfrom + 1पर ले जाती है, और उस वर्ज़न या उससे पुराने पर सेव हुई हर शीट के लिए, क्रम से, चलती है। जारी हो जाने के बाद इसे कभी न हटाएँ: बहुत पहले सेव हुई शीट को अब भी इसकी ज़रूरत है। सिर्फ़ चीज़ें जोड़ने वाले वर्ज़न को किसी एंट्री की ज़रूरत नहीं। rename(ability,skill,saveयाfield): मान अपने नए ID पर कॉपी होता है। स्किल या सेव अपना बोनस साथ ले जाते हैं। rename किसी पहले की एंट्री के rename को आगे बढ़ा सकता है, या ऐसे फ़ील्ड को भर सकता है जिसे बाद काrouteआगे भेजता है; इंपोर्ट इस श्रृंखला को उसके अंत तक देखता है।route: एक फ़ील्ड का मान उस फ़ील्ड में जाता है जिसका नाम किसी दूसरे फ़ील्ड का टेक्स्ट देता है। कोई केस तब जीतता है जब उसके शब्दbyके टेक्स्ट में पूरे शब्दों के रूप में आएँ (सिर्फ़ अक्षर मिलकर शब्द बनाते हैं, इसलिए "Fighter3" fighter का नाम देता है), छोटे-बड़े अक्षर का फ़र्क किए बिना, और ठीक एक केस ऐसा करे। कोई नहीं, या कई ("Fighter 3 / Wizard 2", जिनके बीच एक संख्या बिना पूछे नहीं बाँटी जा सकती), तो मानelseमें जाता है।defaultउस शीट के लिए है जिसने कभी मान सेव नहीं किया।byऐसा फ़ील्ड है जो शीट में है, या जिसका नाम किसी पहले के लेआउट ने बदल दिया। लक्ष्य बिना डिफ़ॉल्ट वाले, या 0 या खाली डिफ़ॉल्ट वाले, number या text फ़ील्ड होते हैं: मान उनमें से एक में जाता है और बाकी हर एक अपना डिफ़ॉल्ट रखता है, इसलिए कोई और डिफ़ॉल्ट ऐसे स्तर की तरह पढ़ा जाता जो किसी ने नहीं दिया। जिस लक्ष्य को बाद का rename आगे ले जाता है, उसका वहाँ तक पीछा किया जाता है।routeLive(लाइव स्टेट काpoolयाtrack): सेव हुआ मानcasesमें से उसमें जाता है जिसे माइग्रेट हुई शीट दिखाती है (0 से ऊपर के अधिकतम वाला पूल, ऐसा ट्रैक जिसे शीट छिपाती नहीं), वरनाelseमें। जिन ट्रैक में मान जाता है, वे सब घाव ट्रैक होते हैं (वह निशान ले जाता है) या सब साधारण (वह संख्या ले जाता है)।setColumn(Capability API 1.794):{ "setColumn": { "list": "attacks", "where": { "name": ["Dagger", "Rapier"], "ability": ["str", "dex"] }, "column": "ability", "to": "finesse" } }सूची की हर उस पंक्ति के एक कॉलम का मान सेट करता है जिसकेwhereमें दिए गए हर कॉलम में सूचीबद्ध मानों में से कोई एक हो (टेक्स्ट मिलाते समय छोटे-बड़े अक्षर और दोनों सिरों के स्पेस का फ़र्क नहीं किया जाता; संख्या हूबहू मिलनी चाहिए)। इसका इस्तेमाल अपने नियमसेट में बेहतर नियम आने से पहले बनी पंक्तियों को ठीक करने के लिए करें, जैसे हथियार की एबिलिटी चुनने का विकल्प आने से पहले बनी अटैक पंक्तियाँ। सूची और इसमें नामित हर कॉलम शीट पर होना चाहिए।- बिल्ड के बाकी सभी चरण कॉपी करते हैं: पुराना मान वहीं रहता है जहाँ था, इसलिए आपके नियमसेट का पुराना वर्ज़न शीट को अब भी वैसे ही पढ़ता है जैसे पढ़ता था, और चरण अपने लक्ष्य में पहले से मौजूद मान को कभी दोबारा नहीं लिखता।
setColumnही ऐसा चरण है जो दोबारा लिखता है। - इंपोर्ट इन्हें अस्वीकार करता है:
sheet.versionया उससे ऊपर की एंट्री, एक ही वर्ज़न से दो एंट्री, ऐसा चरण जो ऐसे ID में लिखता है जो शीट में नहीं, दो बार सूचीबद्ध केस, और ऐसाrenameयाrouteLiveजो ऐसे ID से पढ़ता है जो शीट में अब भी है (दूर ले जाया गया ID फिर कभी इस्तेमाल नहीं होता, और यही इन चरणों को फिर से चलाना सुरक्षित बनाता है)। - शीट जब भी पढ़ी जाती हैं, माइग्रेट होती हैं, और नया लेआउट अगले एडिट पर सेव होता है। लाइव स्टेट का अपना कोई वर्ज़न नहीं होता, इसलिए
routeLiveहर रीड पर चलता है: पुरानी कुंजी हटा दी जाती है और उसका मान सिर्फ़ तब जाता है जब नई कुंजी अभी वहाँ न हो, इसलिए तब से खर्च हुआ या आराम से बदला मान कभी दोबारा नहीं लिखा जाता। वह कहाँ गया, यह अपडेट के बाद पहली बार लिखे जाने से तय होता है: बाद में ठीक की गई शीट (हाथ से हटाया गया क्लास स्तर) उसे फिर नहीं हिलाती। नया वर्ज़न आने पर पहले से चल रही लड़ाई पहले की तरह ही खत्म होती है।