TyranoScript Tutorial Part 7: Notes
/ 4 min read
📚 TyranoScript Tutorial
- 📍 TyranoScript Tutorial Part 7: Notes
This post collects assorted notes and practical tips about TyranoScript—mostly as a memory aid so I won’t forget them after a long break.
Core object
There’s a function in tyrano.js that baffled me at first glance:
function object(o) { var f = object.f, i, len, n, prop; f.prototype = o; n = new f(); for (i = 1, len = arguments.length; i < len; ++i) for (prop in arguments[i]) n[prop] = arguments[i][prop]; return n;}object.f = function () {};
Rewritten a bit (the original declaration is delightfully old‑school), it becomes:
function object(o) { var f = function () {}; f.prototype = o; let obj = new f(); // Note i starts at 1; only subsequent arguments are merged into the object for (let i = 1; i < arguments.length; ++i) for (let prop in arguments[i]) obj[prop] = arguments[i][prop]; return obj;}
At first glance it looks like the classic interview prompt “implement new,” but it isn’t—there’s already a new in there, lol.
What this quirky function does is:
- Take an object
o
and put it on a temporary constructor’s prototype. - Instantiate an empty object just so it inherits from
o
(basically the same as Object.create). - Then merge any additional argument objects into that new object.
In short, the engine instance TYRANO
is produced by object(tyrano.core)
. When calling engine APIs, use TYRANO
rather than tyrano
.
After TYRANO.init
, loadModule
attaches everything under /tyrano/plugins/
to TYRANO.kag
’s prototype chain, which means—
You can then call anything from tyrano.plugin.kag
via TYRANO.kag
, for example:
TYRANO.kag.config.defaultSeVolume
— get the current SE volumeTYRANO.kag.tag.seopt
— change the SE volume
CG
[tb_cg id="cg_main0_1"]
unlocks the CG with id cg_main0_1
. If you search the source you’ll find it’s just a Builder macro.
[macro name="tb_cg"] [iscript] sf.cg_id[mp.id] = "on"; [endscript][endmacro]
Following this, TYRANO.kag.variable.sf.cg_id[mp.id]
tells you whether a CG has been unlocked.
Log
The backlog is cached at variable.tf.system.backlog
.
The function that updates the backlog is pushBackLog
, and it’s used in two places:
- The
pushlog
tag, which inserts a log via a tag. - The
showMessage
function, which inserts a log while displaying text. If you want to change the log format, change it there.
Note that the text shown in save slots also comes from here—be careful not to break it when adjusting formats.
Documentation
TyranoScript tag reference:
English -> http://tyranobuilder.com/tyranoscript-tags-reference/
Japanese -> https://tyrano.jp/tag/
Chinese -> As if that existed (・ω<) てへぺろ
Variables
There are three kinds of variables in TyranoScript:
sf
— system (global)f
— game variables (saved with your game data)tf
— temporary (lost when you close the game)
You can modify them via the eval
tag or iscript
. This works because evalScript
quietly calls saveSystemVariable
—not very obvious at first glance.
;This assigns a text string to a system variable[eval exp="sf.variable1 = 'Sample Text'"]
;This assigns a number to a game variable[eval exp="f.flag1 = 1000"]
;This assigns a temporary variable[eval exp="tf.flag1 = f.flag2"]
[iscript]sf.variable1 = 'Sample Text'f.flag1 = 1000tf.flag1 = f.flag2[endscript]
Settings
TYRANO.kag.tag.bgmopt.start.call(TYRANO, { volume: v, effect: "true", buf: "",});
current_msg_alpha — message opacity
screen_full
fullState
config.alreadyReadTextColor
config.autoRecordLabel
stat.already_read
This is fine before any script is loaded, but if you insert a call while a script is running, it will call nextOrder
by default and advance to the next line. In other words, changing bgmopt
(etc.) from the in‑game settings will push the message box to the next line.
TYRANO.kag.stat.is_strong_stop = true;TYRANO.kag.tag.bgmopt.start.call(TYRANO, { volume: v, effect: "true", buf: "",});TYRANO.kag.stat.is_strong_stop = false;
The snippet above avoids nextOrder
.
By the way, default configuration is loaded by loadConfig
from data\\system\\Config.tjs
.
Run a KS tag from JS
TYRANO.kag.ftag.startTag('tag')
stat
As mentioned above, kag.stat
is the key state store for Tyrano.
[ "map_label", "map_macro", "vertical", "f", "mp", "current_layer", "current_page", "is_stop", "is_wait", "is_trans", "is_wait_anim", "is_strong_stop", "strong_stop_recover_index", "is_nowait", "current_message_str", "current_save_str", "current_keyframe", "map_keyframe", "is_script", "buff_script", "is_html", "map_html", "cssload", "save_img", "stack", "set_text_span", "current_scenario", "is_skip", "is_auto", "current_bgm", "current_bgm_vol", "current_se", "enable_keyconfig", "current_bgmovie", "current_camera", "current_camera_layer", "is_move_camera", "is_wait_camera", "current_line", "is_hide_message", "is_click_text", "is_adding_text", "flag_ref_page", "ruby_str", "ch_speed", "skip_link", "log_join", "log_clear", "f_chara_ptext", "flag_glyph", "current_cursor", "font", "locate", "default_font", "sysview", "chara_pos_mode", "chara_effect", "chara_ptext", "chara_time", "chara_memory", "chara_anim", "pos_change_time", "chara_talk_focus", "chara_brightness_value", "chara_blur_value", "chara_talk_anim", "chara_talk_anim_time", "chara_talk_anim_value", "apply_filter_str", "video_stack", "is_wait_bgmovie", "charas", "jcharas", "play_bgm", "play_se", "map_se_volume", "map_bgm_volume", "map_vo", "vostart", "log_write", "buff_label_name", "already_read", "visible_menu_button", "title",];
This implies that when you add custom tags, you must plan for persistence. Otherwise you may encounter this: a special‑effect tag is running when you save, but after loading the save, the effect is gone.
The solution is to record the running state in stat
while the tag executes. In my case, I set a currentEffect
property and recorded its parameters. After updating stat
, restore the state when loading (the loadGameData
function in kag.menu.js
), and proactively clear it when no state exists.
Loading
setLayerHtml
, paired with getLayeyHtml
for saving.
Record stat.currentBG
in the bg
tag, then handle bg
specially inside setLayerHtml
.
When loading, be equally careful with nextOrder
. In my case, my custom setEffect
was invoked during load and contained a nextOrder
, which caused bizarre behavior after loading (like suddenly jumping to a meeting scene). Because it’s asynchronous, it’s hard to debug—this took me ages to track down 😂.
Save thumbnails
Keyword doSave