Skip to content

嵌入代碼

這一節需要用到各種代碼。

嵌入Python

Librian的嵌入Python可以用於實現劇本的邏輯,也可以成爲獨立的擴展功能。

這些代碼運行在同一個虛擬環境裏,在各處嵌入的代碼都會共享全局變量。如果你不希望這樣,也可以把你的代碼寫成Python文件然後 import

當然你可以用一些Python的黑魔法直接操作Librian(雖然我不會教你)

全局函數參考

fusion(s)
將字符串 s 編譯後顯示到ADV畫面中。

樣例:

潘大爺 「我試試這樣說話……」
```
hp = 150
hp -= 50
fusion(f'潘大爺 「我還有{hp}點生命值!」')
```
潘大爺 「感覺不錯。」

100


goto(path=None, lable=None)
跳轉到另一個路徑爲 path 的劇本的一個躍點 tag 的位置。
path 爲默認值將跳轉到當前劇本, lable 爲默認值將跳到那個劇本的開頭。

樣例:

```
hp -= 10
if hp < 0:
    goto('gameover.liber')
```
潘大爺 「看來我還活着。」

call(path=None, lable=None)
goto 跳轉相同,此外目標劇本演出結束後回到調用處。

choice(*li)
產生一組選項。每個參數爲一個選項,包含一個選項名和一個函數。

劇本寫法 中的跳轉語句 ? 〇〇 -> 〇〇,實際上是 choicecall 的語法糖。

? 接受治療 -> 壞結局.liber
? 放棄治療 -> 好結局.liber
? 蘿莉治療 -> 一章.liber, 原點

相當於

```
choice(
    ('接受治療', lambda: call('壞結局.liber')),
    ('放棄治療', lambda: call('好結局.liber')),
    ('蘿莉治療', lambda: call('一章.liber', '原點'))
)
```

adv_end()
使ADV演出結束。

别名

你也可以用中文來寫這些函數——

  • fusion = 同化 (沒錯這個不是「融合」而是「假魂的同化」ネフェシャドール・フュージョン)
  • goto = 跳轉 | 跳转
  • call = 調用 | 调用
  • choice = 產生選項 | 产生选项
  • adv_end = 演出終了 | 演出终了

樣例

一點也不好玩的RPG遊戲——

```
from random import randint
def 攻擊(a, b):
    傷害 = int(randint(8, 12) / 10 * a['攻擊力'])
    b['當前生命'] -= 傷害
    fusion(f"{a['名']}攻擊{b['名']}!造成{傷害}點傷害!{b['名']}的生命值{b['當前生命']}/{b['生命上限']}。")
def 淘汰之刃(a, b):
    b['當前生命'] = 0
    fusion(f"{a['名']}對{b['名']}使用淘汰之刃!{b['名']}的生命值{b['當前生命']}/{b['生命上限']}。")
大爺 = {'名': '大爺', '速度': 10, '攻擊力': 30, '當前生命': 100, '生命上限': 100}
敵人 = {'名': '敵人', '速度': 5, '攻擊力': 9, '當前生命': 80, '生命上限': 80}
```

```
if 大爺['速度'] > 敵人['速度']:
    大爺的回合 = True
    fusion('潘大爺 「智者先攻!」')
else:
    大爺的回合 = False
```

*決鬥開始

```
if 大爺的回合:
    choice(
        ('攻擊', lambda: 攻擊(大爺, 敵人)),
        ('淘汰之刃', lambda: 淘汰之刃(大爺, 敵人))
    )
else:
    攻擊(敵人, 大爺)
大爺的回合 = not 大爺的回合
```

```
if 敵人['當前生命'] <= 0 or 大爺['當前生命'] <= 0:
    adv_end()
else:
    goto(lable='決鬥開始')
```

一些坑

每次的代碼段總是會執行到底, goto, call, fusion 並不是即時的,他們真正的作用只是改變了劇本棧的順序,這導致在一個塊中多次調用會产生出乎意料的演出順序。

(我雖然想將讀者的實例改爲遞歸的來解決這個問題,但是卻發現這樣存在一個不能存檔的問題。)

舉這樣一個例子:

```
call('第一章.liber')
call('第二章.liber')
```

作家的想法是想要先演出第一章,第一章結束之後返回調用點,然後演出第二章。
但實際上的執行順序是 call('第一章.liber') -> call('第二章.liber') -> 演出第二章 -> 演出第一章。

因爲在 call 時候劇本的棧頂被先後壓入了第一章和第二章,成爲 (.., 當前劇本, 第一章, 第二章),第二章在棧頂導致先演出。

我想過的解決辦法是在每一次 call 的時候直接重建一個讀者實例,然後直接進入這個新實例執行,在這個實例執行完畢之後就可以回到調用點執行之後的語句了……但問題是存檔時只能儲存劇本棧不能儲存調用棧,也就是無法在新劇本執行完畢之後返回調用點。

也就是說,由於這個問題,這個做法暫時只能寫成:

```
call('第一章.liber')
```

```
call('第二章.liber')
```

嵌入JavaScript

如果你想要直接操作前端來做一些很酷的事情,也可以試着嵌入JavaScript代碼。

樣例:

alert('你好呀!')

不行我想不出來,以後再補吧(笑)。

嵌入HTML

在前端有一個層 <div id='html疊加'> ,你可以直接往其中寫入HTML代碼。

每次使用HTML代碼段,都會將上次的代碼覆蓋。

樣例在 劇本寫法CSS與HTML

總表

語言類型 重複使用 作用域 存檔
Python 疊加 共享 存檔
JavaScript 疊加,但在停滯點之間會覆蓋 全局 不存檔
HTML 覆蓋 - 存檔
CSS 覆蓋 - 存檔
SASS/SCSS 覆蓋 - 存檔

現在 HTML / CSS / SASS / SCSS 共用同一個空間,它們也會互相覆蓋。