Rewrite in fennel

master
yw05 2021-06-15 16:50:29 +02:00
parent f0ff9d1a1b
commit ed4458993a
4 changed files with 384 additions and 130 deletions

View File

@ -2,4 +2,5 @@
(tab-width . 8))
(lua-mode (lua-indent-level . 8)
(lua-indent-close-paren-align . nil)
(lua-indent-nested-block-content-align . nil)))
(lua-indent-nested-block-content-align . nil))
(fennel-mode (indent-tabs-mode . nil)))

View File

@ -1,4 +1,8 @@
# Advtrains remote
This mod allows you to remotely control a train in Minetest.
remotely control a train in Minetest
## Notes
* This mod is written in [Fennel Lisp](https://fennel-lang.org/). Do **not** file pull requests against `init.lua`.
* When filing a bug report, please give the commit hash (with `git rev-parse HEAD`) or the content of the `init.lua` file, as the default traceback function is not aware of the use of fennel.
* Translations are not yet accepted.

123
init.fnl Normal file
View File

@ -0,0 +1,123 @@
(macro S [...] `(minetest.translate "train_remote" ,...))
(macro Sf [...] `(minetest.formspec_escape (S ,...)))
(macro toint [n]
`(let [n# (tonumber ,n)]
(if n# (math.floor n#) nil)))
(macro check-wagon-access [pname wagon]
`(let [w# ,wagon]
(advtrains.check_driving_couple_protection pname w#.owner w#.whitelist)))
(macro check-train-access [pname trainid]
`(let [pn# ,pname tid# ,trainid]
(if (not (minetest.get_player_by_name pn#))
(values false (S "Player is not online"))
(let [t# (. advtrains.trains tid#)]
(if (not t#) (values false (S "No train with ID @1" tid#))
(let [tps# t#.trainparts]
(local n# (length tps#))
(local wagons# advtrains.wagons)
(var i# 0)
(var contp# true)
(while (and (<= i# n#) contp#)
(let [w# (. wagons# (. tps# i#))]
(if (and w# (check-wagon-access pn# w#))
(set contp# false)
(set i# (+ 1 i#)))))
(not contp#)))))))
(macro leverof [train]
`(let [t# ,train]
(if (not t#) nil
(and (= t#.velocity 0) (not t#.active_control)) 1
t#.hud_lzb_effect_tmr 1
(or t#.lever 3))))
(local fsversion 3)
(local fstext-train "
size[11.5,6]
label[0.5,0.5;%s]
button[6,0.5;5,1;update;%s]
label[0.5,1;%s]textlist[0.5,1.5;5,2.5;lever;%s,%s,%s,%s,%s;%d;false]
label[6,2;%s]textlist[6,2.5;5,1.5;door;%s,%s,%s;%d;false]
button[0.5,4.5;5,1;reverse;%s]
textlist[6,4.5;5,1;ars;%s,%s;%d;false]
")
(macro fsformat [fmt ...]
(let [argv [...] oargs ['string.format fmt]]
(for [i 1 (length argv)]
(tset oargs (+ (length oargs) 1)
(if (sequence? (. argv i))
(list 'Sf (unpack (. argv i)))
(. argv i))))
(list (unpack oargs))))
(macro show-train-remote-formspec [pname trainid]
`(let [pn# ,pname tid# ,trainid]
(if (not (check-train-access pn# tid#)) nil
(let [t# (. advtrains.trains tid#)]
(local fs# (fsformat fstext-train
["Remote control for @1" tid#]
["Update"]
["Lever"]
["Accelerate"]
["Neutral"]
["Roll"]
["Regular brake"]
["Emergency brake"]
(- 5 (leverof t#))
["Door control"]
["Open left"]
["Close both"]
["Open right"]
(+ (or t#.door_open 0) 2)
["Reverse train"]
["Enable ARS"]
["Disable ARS"]
(or (and advtrains.interlocking t#.ars_disable 2) 1)))
(minetest.show_formspec pn# (.. "train_remote:" tid#) fs#)))))
(macro get-textlist [field max]
`(let [et# (minetest.explode_textlist_event ,field)]
(if (not et#) nil
(and (or (= et#.type :CHG) (= et#.type :DCL))
(>= et#.index 1) (<= et#.index ,max))
et#.index
nil)))
(minetest.register_on_player_receive_fields
(fn [player formname fields]
(let [pname (player:get_player_name) trainid (string.match formname "^train_remote:(%S+)$")]
(if (not trainid) nil
(not (check-train-access pname trainid)) nil
(let [t (. advtrains.trains trainid)]
(if fields.door
(let [dside (get-textlist fields.door 3)]
(if dside (tset t :door_open (- dside 2))))
fields.lever
(let [tlev (get-textlist fields.lever 5)]
(if (and tlev (not t.lzb_effect_tmr))
(tset t :ctrl_user (- 5 tlev))))
fields.reverse
(when (<= t.velocity 0)
(advtrains.invert_train trainid)
(advtrains.atc.train_reset_command t))
fields.ars
(if advtrains.interlocking
(let [e (get-textlist fields.ars 2)]
(if e (advtrains.interlocking.ars_set_disable t (= e 2))))))
(show-train-remote-formspec pname trainid))))))
(minetest.register_chatcommand
"train_remote"
{ :params
"<ID>"
:description
(S "Remotely control the train with the given ID")
:func
(fn [pname trainid]
(let [(accessp msg) (check-train-access pname trainid)]
(if (not accessp) (values false msg)
(do (show-train-remote-formspec pname trainid) nil))))})

382
init.lua
View File

@ -1,130 +1,256 @@
local S = minetest.get_translator("train_remote")
local function Sf(...)
return minetest.formspec_escape(S(...))
local fsversion = 3
local fstext_train = "\nsize[11.5,6]\nlabel[0.5,0.5;%s]\nbutton[6,0.5;5,1;update;%s]\nlabel[0.5,1;%s]textlist[0.5,1.5;5,2.5;lever;%s,%s,%s,%s,%s;%d;false]\nlabel[6,2;%s]textlist[6,2.5;5,1.5;door;%s,%s,%s;%d;false]\nbutton[0.5,4.5;5,1;reverse;%s]\ntextlist[6,4.5;5,1;ars;%s,%s;%d;false]\n"
local function _0_(player, formname, fields)
local pname = player:get_player_name()
local trainid = string.match(formname, "^train_remote:(%S+)$")
if not trainid then
return nil
else
local _1_
do
local pn_0_ = pname
local tid_0_ = trainid
if not minetest.get_player_by_name(pn_0_) then
minetest.translate("train_remote", "Player is not online")
_1_ = false
else
local t_0_ = advtrains.trains[tid_0_]
if not t_0_ then
minetest.translate("train_remote", "No train with ID @1", tid_0_)
_1_ = false
else
local tps_0_ = t_0_.trainparts
local n_0_ = #tps_0_
local wagons_0_ = advtrains.wagons
local i_0_ = 0
local contp_0_ = true
while ((i_0_ <= n_0_) and contp_0_) do
local w_0_ = (wagons_0_)[(tps_0_)[i_0_]]
local function _4_()
local w_0_0 = w_0_
return advtrains.check_driving_couple_protection(pname, w_0_0.owner, w_0_0.whitelist)
end
if (w_0_ and _4_()) then
contp_0_ = false
else
i_0_ = (1 + i_0_)
end
end
_1_ = not contp_0_
end
end
end
if not _1_ then
return nil
else
local t = advtrains.trains[trainid]
if fields.door then
local dside
do
local et_0_ = minetest.explode_textlist_event(fields.door)
if not et_0_ then
dside = nil
elseif (((et_0_.type == "CHG") or (et_0_.type == "DCL")) and (et_0_.index >= 1) and (et_0_.index <= 3)) then
dside = et_0_.index
else
dside = nil
end
end
if dside then
t["door_open"] = (dside - 2)
end
elseif fields.lever then
local tlev
do
local et_0_ = minetest.explode_textlist_event(fields.lever)
if not et_0_ then
tlev = nil
elseif (((et_0_.type == "CHG") or (et_0_.type == "DCL")) and (et_0_.index >= 1) and (et_0_.index <= 5)) then
tlev = et_0_.index
else
tlev = nil
end
end
if (tlev and not t.lzb_effect_tmr) then
t["ctrl_user"] = (5 - tlev)
end
elseif fields.reverse then
if (t.velocity <= 0) then
advtrains.invert_train(trainid)
advtrains.atc.train_reset_command(t)
end
elseif fields.ars then
if advtrains.interlocking then
local e
do
local et_0_ = minetest.explode_textlist_event(fields.ars)
if not et_0_ then
e = nil
elseif (((et_0_.type == "CHG") or (et_0_.type == "DCL")) and (et_0_.index >= 1) and (et_0_.index <= 2)) then
e = et_0_.index
else
e = nil
end
end
if e then
advtrains.interlocking.ars_set_disable(t, (e == 2))
end
end
end
local pn_0_ = pname
local tid_0_ = trainid
local _3_
do
local pn_0_0 = pn_0_
local tid_0_0 = tid_0_
if not minetest.get_player_by_name(pn_0_0) then
minetest.translate("train_remote", "Player is not online")
_3_ = false
else
local t_0_ = advtrains.trains[tid_0_0]
if not t_0_ then
minetest.translate("train_remote", "No train with ID @1", tid_0_0)
_3_ = false
else
local tps_0_ = t_0_.trainparts
local n_0_ = #tps_0_
local wagons_0_ = advtrains.wagons
local i_0_ = 0
local contp_0_ = true
while ((i_0_ <= n_0_) and contp_0_) do
local w_0_ = (wagons_0_)[(tps_0_)[i_0_]]
local function _6_()
local w_0_0 = w_0_
return advtrains.check_driving_couple_protection(pname, w_0_0.owner, w_0_0.whitelist)
end
if (w_0_ and _6_()) then
contp_0_ = false
else
i_0_ = (1 + i_0_)
end
end
_3_ = not contp_0_
end
end
end
if not _3_ then
return nil
else
local t_0_ = advtrains.trains[tid_0_]
local fs_0_
local function _4_()
local t_0_0 = t_0_
if not t_0_0 then
return nil
elseif ((t_0_0.velocity == 0) and not t_0_0.active_control) then
return 1
elseif t_0_0.hud_lzb_effect_tmr then
return 1
else
return (t_0_0.lever or 3)
end
end
fs_0_ = string.format(fstext_train, minetest.formspec_escape(minetest.translate("train_remote", "Remote control for @1", tid_0_)), minetest.formspec_escape(minetest.translate("train_remote", "Update")), minetest.formspec_escape(minetest.translate("train_remote", "Lever")), minetest.formspec_escape(minetest.translate("train_remote", "Accelerate")), minetest.formspec_escape(minetest.translate("train_remote", "Neutral")), minetest.formspec_escape(minetest.translate("train_remote", "Roll")), minetest.formspec_escape(minetest.translate("train_remote", "Regular brake")), minetest.formspec_escape(minetest.translate("train_remote", "Emergency brake")), (5 - _4_()), minetest.formspec_escape(minetest.translate("train_remote", "Door control")), minetest.formspec_escape(minetest.translate("train_remote", "Open left")), minetest.formspec_escape(minetest.translate("train_remote", "Close both")), minetest.formspec_escape(minetest.translate("train_remote", "Open right")), ((t_0_.door_open or 0) + 2), minetest.formspec_escape(minetest.translate("train_remote", "Reverse train")), minetest.formspec_escape(minetest.translate("train_remote", "Enable ARS")), minetest.formspec_escape(minetest.translate("train_remote", "Disable ARS")), ((advtrains.interlocking and t_0_.ars_disable and 2) or 1))
return minetest.show_formspec(pn_0_, ("train_remote:" .. tid_0_), fs_0_)
end
end
end
end
local function toint(n)
local m = tonumber(n)
if n then
return math.floor(n)
else
return nil
end
minetest.register_on_player_receive_fields(_0_)
local function _1_(pname, trainid)
local accessp, msg = nil, nil
do
local pn_0_ = pname
local tid_0_ = trainid
if not minetest.get_player_by_name(pn_0_) then
accessp, msg = false, minetest.translate("train_remote", "Player is not online")
else
local t_0_ = advtrains.trains[tid_0_]
if not t_0_ then
accessp, msg = false, minetest.translate("train_remote", "No train with ID @1", tid_0_)
else
local tps_0_ = t_0_.trainparts
local n_0_ = #tps_0_
local wagons_0_ = advtrains.wagons
local i_0_ = 0
local contp_0_ = true
while ((i_0_ <= n_0_) and contp_0_) do
local w_0_ = (wagons_0_)[(tps_0_)[i_0_]]
local function _2_()
local w_0_0 = w_0_
return advtrains.check_driving_couple_protection(pname, w_0_0.owner, w_0_0.whitelist)
end
if (w_0_ and _2_()) then
contp_0_ = false
else
i_0_ = (1 + i_0_)
end
end
accessp, msg = not contp_0_
end
end
end
if not accessp then
return false, msg
else
do
local pn_0_ = pname
local tid_0_ = trainid
local _2_
do
local pn_0_0 = pn_0_
local tid_0_0 = tid_0_
if not minetest.get_player_by_name(pn_0_0) then
minetest.translate("train_remote", "Player is not online")
_2_ = false
else
local t_0_ = advtrains.trains[tid_0_0]
if not t_0_ then
minetest.translate("train_remote", "No train with ID @1", tid_0_0)
_2_ = false
else
local tps_0_ = t_0_.trainparts
local n_0_ = #tps_0_
local wagons_0_ = advtrains.wagons
local i_0_ = 0
local contp_0_ = true
while ((i_0_ <= n_0_) and contp_0_) do
local w_0_ = (wagons_0_)[(tps_0_)[i_0_]]
local function _5_()
local w_0_0 = w_0_
return advtrains.check_driving_couple_protection(pname, w_0_0.owner, w_0_0.whitelist)
end
if (w_0_ and _5_()) then
contp_0_ = false
else
i_0_ = (1 + i_0_)
end
end
_2_ = not contp_0_
end
end
end
if not _2_ then
else
local t_0_ = advtrains.trains[tid_0_]
local fs_0_
local function _3_()
local t_0_0 = t_0_
if not t_0_0 then
return nil
elseif ((t_0_0.velocity == 0) and not t_0_0.active_control) then
return 1
elseif t_0_0.hud_lzb_effect_tmr then
return 1
else
return (t_0_0.lever or 3)
end
end
fs_0_ = string.format(fstext_train, minetest.formspec_escape(minetest.translate("train_remote", "Remote control for @1", tid_0_)), minetest.formspec_escape(minetest.translate("train_remote", "Update")), minetest.formspec_escape(minetest.translate("train_remote", "Lever")), minetest.formspec_escape(minetest.translate("train_remote", "Accelerate")), minetest.formspec_escape(minetest.translate("train_remote", "Neutral")), minetest.formspec_escape(minetest.translate("train_remote", "Roll")), minetest.formspec_escape(minetest.translate("train_remote", "Regular brake")), minetest.formspec_escape(minetest.translate("train_remote", "Emergency brake")), (5 - _3_()), minetest.formspec_escape(minetest.translate("train_remote", "Door control")), minetest.formspec_escape(minetest.translate("train_remote", "Open left")), minetest.formspec_escape(minetest.translate("train_remote", "Close both")), minetest.formspec_escape(minetest.translate("train_remote", "Open right")), ((t_0_.door_open or 0) + 2), minetest.formspec_escape(minetest.translate("train_remote", "Reverse train")), minetest.formspec_escape(minetest.translate("train_remote", "Enable ARS")), minetest.formspec_escape(minetest.translate("train_remote", "Disable ARS")), ((advtrains.interlocking and t_0_.ars_disable and 2) or 1))
minetest.show_formspec(pn_0_, ("train_remote:" .. tid_0_), fs_0_)
end
end
return nil
end
end
local function check_train_access(pname, trainid)
if not minetest.get_player_by_name(pname) then
return false, S("Player is not online")
end
local t = advtrains.trains[trainid]
if not t then
return false, S("No train with ID @1", trainid)
end
for i = 1, #t.trainparts, 1 do
local w = advtrains.wagons[t.trainparts[i]]
if w and advtrains.check_driving_couple_protection(pname, w.owner, w.whitelist) then
return true
end
end
return false, S("No access to train @1", trainid)
end
-- From advtrains
local function leverof(train)
if not train then return nil end
local tlev = train.lever or 3
if train.velocity == 0 and not train.active_control then tlev = 1 end
if train.hud_lzb_effect_tmr then tlev = 1 end
return tlev
end
local fstext_remote = [[
formspec_version[3]
size[11.5,6]
label[0.5,0.5;%s]
button[6,0.5;5,1;update;%s]
label[0.5,1;%s]textlist[0.5,1.5;5,2.5;lever;%s,%s,%s,%s,%s;%d;false]
label[6,2;%s]textlist[6,2.5;5,1.5;door;%s,%s,%s;%d;false]
button[0.5,4.5;5,1;reverse;%s]
textlist[6,4.5;5,1;ars;%s,%s;%d;false]
]]
local function show_train_remote_formspec(pname, trainid)
if not check_train_access(pname, trainid) then return end
local t = advtrains.trains[trainid]
local fs = string.format(fstext_remote,
Sf("Remote control for @1", trainid),
Sf("Update"),
Sf("Lever"),
Sf("Accelerate"),
Sf("Neutral"),
Sf("Roll"),
Sf("Regular brake"),
Sf("Emergency brake"),
5-leverof(t),
Sf("Door control"),
Sf("Open left"),
Sf("Close both"),
Sf("Open right"),
(t.door_open or 0)+2,
Sf("Reverse train"),
Sf("Enable ARS"),
Sf("Disable ARS"),
advtrains.interlocking and t.ars_disable and 2 or 1
)
minetest.show_formspec(pname, "train_remote_" .. trainid, fs)
end
local function get_textlist(field, max)
local et = minetest.explode_textlist_event(field)
if not et then return nil end
if et.type == "CHG" or et.type == "DCL"
and et.index >= 1 and et.index <= max then
return et.index
end
return nil
end
minetest.register_on_player_receive_fields(function(player, formname, fields)
local pname = player:get_player_name()
local trainid = string.match(formname, "^train_remote_(%S+)$")
if not trainid then return end
if not check_train_access(pname, trainid) then return end
local t = advtrains.trains[trainid]
if fields.door then
local dside = get_textlist(fields.door, 3)
if dside then
t.door_open = dside - 2
end
elseif fields.lever then
local tlev = get_textlist(fields.lever, 5)
if tlev and not t.lzb_effect_tmr then
t.ctrl_user = 5-tlev
end
elseif fields.reverse then
if t.velocity <= 0 then
advtrains.invert_train(trainid)
advtrains.atc.train_reset_command(t)
end
elseif fields.ars then
if advtrains.interlocking then
local e = get_textlist(fields.ars, 2)
if e then
advtrains.interlocking.ars_set_disable(t, e == 2)
end
end
end
show_train_remote_formspec(pname, trainid)
end)
minetest.register_chatcommand("train_remote", {
params = "<ID>",
description = "Remotely control the train",
func = function(pname, trainid)
local accessp, msg = check_train_access(pname, trainid)
if not accessp then
return false, msg
end
show_train_remote_formspec(pname, trainid)
end
})
return minetest.register_chatcommand("train_remote", {description = minetest.translate("train_remote", "Remotely control the train with the given ID"), func = _1_, params = "<ID>"})