Luaの変数をNScripterの文字列変数に保存する。
たとえば、ゲームのキャラクターのデータをnslua側でテーブルの形で持っているとします。
local chara = {} chara["技術点"] = 10 chara["体力点"] = 20 chara["装備"] = {} chara["装備"]["右手"] = "幅広の剣" chara["装備"]["左手"] = "革の盾"
これをNScripterの文字列変数に折りたたんで格納すると、NScripter側でsaveすることで状態を保存できます。
ec.save_object(chara, 100) -- 文字列変数100番に格納する。
復帰させる時はこうします。
ec.load_object(chara, 100) -- 100番の中身を展開し、charaの中身をそれに書き換える。
保存できるのは、Luaのテーブル・文字列(255文字まで)・数値(整数のみ)・真偽値の4種類だけです。
スクリプト
下記のスクリプトを適当なファイル(たとえば、ec.lua)にコピペして保存して、system.luaの中から
NL_dofile("ec.lua")
等してください。
-- expand and convergence module("ec", package.seeall) function head_chop(t) -- テーブルの先頭を切り落として返す。 return table.remove(t, 1) end function head_letter(t) -- テーブルの先頭を切り落として文字にして返す。 return string.char(head_chop(t)) end function load_object(t, num) -- 何かをNScripterから読み出した状態に変更する。 if type(t) ~= "table" then return nil end -- テーブルしか受け付けません。 local temp = object_expand(NSGetStrValue(num)) if type(temp) ~= "table" then return nil end -- 読み出したものもテーブルでないとダメ。 table_copy(temp, t) return t end function table_copy(from, to) -- テーブルの中身をコピーする。 if type(from) ~= "table" then return nil end if type(to) ~= "table" then return nil end for k, v in pairs(to) do if type(from[k]) == "nil" then to[k] = nil end end for k, v in pairs(from) do to[k] = v end return to end function save_object(ob, num) -- 何かをNScripterの文字列変数に格納する。 NSSetStrValue(num, object_convergence(ob)) end function object_expand(str) return expand({str:byte(1, str:len())}) end function object_convergence(ob) -- 何かを収束させる。 return convergence(ob) end function expand(str_table) -- 何かを展開させる。 local vt = head_letter(str_table) if vt == "n" then return expand_num(str_table) end if vt == "s" then return expand_str(str_table) end if vt == "b" then return expand_bool(str_table) end if vt == "t" then return expand_table(str_table) end return nil end function convergence(v) -- 何かを収束させる。 local vt = type(v) if vt == "number" then return convergence_num(v) end if vt == "string" then return convergence_str(v) end if vt == "boolean" then return convergence_bool(v) end if vt == "table" then return convergence_table(v) end return "" end function expand_num(str_table) -- 数値を展開する。 local num = 0 local sign = head_letter(str_table) -- 最初の数値を取得。 if sign == "z" then return 0 end -- 0ならば0を返す。 local digit = head_chop(str_table) -- 桁数を取得。 for i = 1, digit do num = num * 256 num = num + head_chop(str_table) end if sign == "m" then num = 0 - num end return num end function convergence_num(num) -- 数値を収束させる。 num = math.floor(num) if num == 0 then return "nz" end local sign = "" if num < 0 then sign = "m" else sign = "p" end num = math.abs(num) -- 絶対値化 local temp = "" while num > 0 do temp = string.char(num % 256)..temp num = math.floor(num / 256) end return "n"..sign..string.char(temp:len())..temp end function expand_str(str_table) -- 文字列を展開させる。 local length = head_chop(str_table) if length == 0 then return "" end local str = "" for i = 1, length do str = str .. head_letter(str_table) end return str end function convergence_str(str) -- 文字列を収束させる。 return "s"..string.char(str:len())..str end function expand_bool(str_table) -- ブーリアンを展開させる。 if head_letter(str_table) == "t" then return true else return false end end function convergence_bool(bool) -- ブーリアンを収束させる。 if bool then return "bt" else return "bf" end end function expand_table(str_table) -- テーブルを展開させる。 local t = {} local k local v while "e" ~= string.char(str_table[1]) do k = expand(str_table) v = expand(str_table) t[k] = v end head_letter(str_table) return t end function convergence_table(t) -- テーブルを収束させる。 local str = "" for k, v in pairs(t) do str = str .. convergence(k) .. convergence(v) end return "t"..str.."e" end