NSCOMのチュートリアルやってみる

luasubと言うdefine節専用の命令が増えた。
これはdefsubのLua版であり、その命令の実体をsysytem.lua(もしくはその中からdofileで呼ばれるファイル)内に記述する。
たとえば、00.txtのdefine節に

luasub sample_function

と記述した場合、system.lua内では、最低でも、

function NSCOM_sample_function()
end

と記述しなければならない。
そして意味のある命令を作ろうと思えば、引数の受け渡しなどをLuaで記述しなければならない。

実際に作ってみる

実は引数が一つの命令を作るのはそれほど難しくはないのだが、引数が複数になると途端にトラップが発動してしまうので、注意が必要だ。これで私も30分は悩んだ。
サンプルとして、max命令を作ってみる。

書式
max 数値変数,数値,数値
説明
第二引数から第三引数までの数値変数の中で、最大の数値を持つ数値変数の番号を返す。
補足
もし、最大の数値が複数あった場合は、その中で最初のものが選ばれる。
mov %100,0
mov %101,-3
mov %102,6

max %0,100,102
%0 ; 102と表示される

こんな感じ。

00.txt

*define
luasub max
game
*start
; 状況を定義
for %0=100 to 109
rnd2 %%0,-10,10
%%0 /
next

; 実行
max %0,100,109
 
最大値は変数番号%0の、%%0です。
click
end

system.lua

function NSCOM_max() -- 関数宣言の後には必ず()をつけよう。
	local res = NSPopIntRef() -- 第一引数の数値変数の番号を取得する。
	NSPopComma() -- これがポイント。これがないと、第一引数にずっととどまり続ける。
	local sn = NSPopInt() -- 第二引数の数値を取得
	NSPopComma() -- 同じく、これがないと第二引数にとどまり続ける。
	local en = NSPopInt() -- 第三引数の数値を取得
	
	if sn > en then -- 数値が逆転していた場合、スワップしないと。
		sn, en = en, sn -- ワオ! Perlチックsyntax sugar!
	end -- 他の言語経験者がよく忘れるのが、ifに対するendだろう。
	
	local max = sn
	local max_num = NSGetIntValue(sn) -- 最初の数値を取得する。
	for num = sn+1, en do -- for文もちょっと独特なんだよなあ。
		local temp = NSGetIntValue(num)
		if temp > max_num then
			max = num
			max_num = temp
		end
	end -- 手動でmax処理してるけど野暮ったいとか言わないで!
	
	NSSetIntValue(res, max) -- 第一引数の数値変数に戻す
	return true -- 念のため
end

実行例


デバッグのポイント

system.lua内で、Luaシンタックスエラーがあると、エラーメッセージが出る。
上記の例だと、

[string "function NSCOM_max() -- 関数宣言の後には必ず()をつけよう。…"]:(エラー行): エラー内容

こんな風になる。エラーを起こした行数に注目してきっちりバグをとろう。ifの後のendを忘れてないか? たとえば、上記の例最初のifのendをコメントアウトすると、こんなエラーが出る。

[string "function NSCOM_max() -- 関数宣言の後には必ず()をつけよう。…"]:25: 'end' excepted (to close 'function' at line 1) near '<eof>'

この場合は、エラー行が信用ならないので、全てのfunction, if, for ,repeat, while……などを調べてendの有無を一つずつ確認していくべし。

作った後で

例が悪かったような気がする。これ別に普通にNScripterのネイティブで組んでいいレベルの内容。