Напиши скрипт для моего мода на игру Baba Is You. Вот мой концепт правила. Пока что назови слово testrule. Я воссоздаю другую игру в Baba Is You. X Is Testrule. Это правило будет сочетать в себе несколько правил для более компактных условий. Если объект нельзя толкать в какую-либо сторону (например, вправо) то testrule действует как слова not push. После этого скрипт ищет объекты с таким же поворотом (влево, вправо, вверх, вниз) и телепортирует объект на X на такой же объект с таким же поворотом. Если такого объекта не найдено то правило не действует (отменяется поведение not push).

Пиши на lua.

Вот примеры скриптов из оригинальной игры

1 Код:
function dopush(unitid,ox,oy,dir,pulling_,x_,y_,reason,pusherid)
local pid2 = tostring(ox + oy * roomsizex) .. tostring(unitid)
pushedunits[pid2] = 1

local x,y = 0,0
local unit = {}
local name = ""
local pushsound = false

if (unitid ~= 2) then
	unit = mmf.newObject(unitid)
	x,y = unit.values[XPOS],unit.values[YPOS]
	name = getname(unit)
else
	x = x_
	y = y_
	name = "empty"
end

local pulling = false
if (pulling_ ~= nil) then
	pulling = pulling_
end

local swaps = findfeatureat(nil,"is","swap",x+ox,y+oy,{"still"})

if (swaps ~= nil) and ((unitid ~= 2) or ((unitid == 2) and (pulling == false))) then
	for a,b in ipairs(swaps) do
		if (pulling == false) or (pulling and (b ~= pusherid)) then
			local alreadymoving = findupdate(b,"update")
			local valid = true
			
			if (#alreadymoving > 0) then
				valid = false
			end
			
			if valid then
				addaction(b,{"update",x,y,nil})
			end
		end
	end
end

if pulling then
	local swap = hasfeature(name,"is","swap",unitid,x,y,{"still"})
	
	if swap then
		local swapthese = findallhere(x+ox,y+oy)
		
		for a,b in ipairs(swapthese) do
			if (b ~= pusherid) then
				local alreadymoving = findupdate(b,"update")
				local valid = true
				
				if (#alreadymoving > 0) then
					valid = false
				end
				
				if valid and (b ~= 2) then
					addaction(b,{"update",x,y,nil})
					pushsound = true
				end
			end
		end
	end
end

local hm = 0
local tileid = x + y * roomsizex
local moveid = tostring(tileid) .. name .. tostring(dir)

if (movemap[moveid] == nil) then
	movemap[moveid] = {}
end

if (movemap[moveid]["push"] == nil) then
	movemap[moveid]["push"] = 0
	movemap[moveid]["pull"] = 0
	movemap[moveid]["result"] = 0
end

local movedata = movemap[moveid]

if (HACK_MOVES < 10000) then
	local hmlist,hms,specials = check(unitid,x,y,dir,false,reason)
	local pullhmlist,pullhms,pullspecials = check(unitid,x,y,dir,true,reason)
	local result = 0
	
	local weak = hasfeature(name,"is","weak",unitid,x_,y_)
	
	if (movedata.result == 0) then
		for i,obs in pairs(hmlist) do
			local done = false
			while (done == false) do
				if (obs == 0) then
					result = math.max(0, result)
					done = true
				elseif (obs == 1) or (obs == -1) then
					if (pulling == false) or (pulling and (hms[i] ~= pusherid)) then
						result = math.max(2, result)
						done = true
					else
						result = math.max(0, result)
						done = true
					end
				else
					if (pulling == false) or (pulling and (hms[i] ~= pusherid)) then
						result = math.max(1, result)
						done = true
					else
						result = math.max(0, result)
						done = true
					end
				end
			end
		end
		
		movedata.result = result + 1
	else
		result = movedata.result - 1
		done = true
	end
	
	local finaldone = false
	
	while (finaldone == false) and (HACK_MOVES < 10000) do
		if (result == 0) then
			table.insert(movelist, {unitid,ox,oy,dir,specials,x,y})
			--move(unitid,ox,oy,dir,specials)
			pushsound = true
			finaldone = true
			hm = 0
			
			if (pulling == false) and (movedata.pull == 0) then
				for i,obs in ipairs(pullhmlist) do
					if (obs < -1) or (obs > 1) and (obs ~= pusherid) then
						if (obs ~= 2) then
							table.insert(movelist, {obs,ox,oy,dir,pullspecials,x,y})
							pushsound = true
							--move(obs,ox,oy,dir,specials)
						end
						
						local pid = tostring(x-ox + (y-oy) * roomsizex) .. tostring(obs)
						
						if (pushedunits[pid] == nil) then
							pushedunits[pid] = 1
							
							hm = dopush(obs,ox,oy,dir,true,x-ox,y-oy,reason,unitid)
						end
						
						movedata.pull = 1
					end
				end
			end
		elseif (result == 1) then
			if (movedata.push == 0) then
				for i,v in ipairs(hmlist) do
					if (v ~= -1) and (v ~= 0) and (v ~= 1) then
						local pid = tostring(x+ox + (y+oy) * roomsizex) .. tostring(v)
						
						if (pulling == false) or (pulling and (hms[i] ~= pusherid)) and (pushedunits[pid] == nil) then
							pushedunits[pid] = 1
							hm = dopush(v,ox,oy,dir,false,x+ox,y+oy,reason,unitid)
						end
					end
				end
			else
				hm = movedata.push - 1
			end
			
			movedata.push = hm + 1
			
			if (hm == 0) then
				result = 0
			else
				result = 2
			end
		elseif (result == 2) then
			hm = 1
			
			if (weak ~= nil) then
				delete(unitid,x,y)
				
				local pmult,sound = checkeffecthistory("weak")
				setsoundname("removal",1,sound)
				generaldata.values[SHAKE] = 3
				MF_particles("destroy",x,y,5 * pmult,0,3,1,1)
				result = 0
				hm = 0
			end
			
			finaldone = true
		end
	end
	
	if pulling and (HACK_MOVES < 10000) then
		hmlist,hms,specials = check(unitid,x,y,dir,pulling,reason)
		hm = 0
	
		for i,obs in pairs(hmlist) do
			if (obs < -1) or (obs > 1) then
				local pid = tostring(x - ox + (y - oy) * roomsizex) .. tostring(obs)
				
				if (obs ~= 2) and (pushedunits[pid] == nil) then
					table.insert(movelist, {obs,ox,oy,dir,specials,x,y})
					pushsound = true
				end
				
				if (pushedunits[pid] == nil) then
					pushedunits[pid] = 1
					hm = dopush(obs,ox,oy,dir,pulling,x-ox,y-oy,reason,unitid)
				end
			end
		end
		
		if (movedata.pull == 0) then
			movedata.pull = hm + 1
		else
			hm = movedata.pull - 1
		end
	end
	
	if pushsound and (generaldata2.strings[TURNSOUND] == "") then
		setsoundname("turn",5)
	end
end

HACK_MOVES = HACK_MOVES + 1

return hm

end

2 код:

function diceblock()
condstatus = {}

if (condfeatureindex["often"] ~= nil) then
for i,v in ipairs(condfeatureindex["often"]) do
local conds = v[2]

local identifier = tostring(conds)

if (condstatus[identifier] == nil) then
	condstatus[identifier] = {}
end

local data = condstatus[identifier]

--[[
for a,b in ipairs(conds) do
	if (b[1] == "often") or (b[1] == "not often") then
		local rnd = fixedrandom(1,4)
		
		local id = "often" .. tostring(a)
		
		data[id] = rnd
	end
end
]]--

end

end

if (condfeatureindex["seldom"] ~= nil) then
for i,v in ipairs(condfeatureindex["seldom"]) do
local conds = v[2]

local identifier = tostring(conds)

if (condstatus[identifier] == nil) then
	condstatus[identifier] = {}
end

local data = condstatus[identifier]

--[[
for a,b in ipairs(conds) do
	if (b[1] == "seldom") or (b[1] == "not seldom") then
		local rnd = fixedrandom(1,6)
		
		local id = "seldom" .. tostring(a)
		
		data[id] = rnd
	end
end
]]--

end

end

end

3 Код:

feeling = function(params,checkedconds,checkedconds_,cdata)
		local allfound = 0
		local alreadyfound = {}
		local name,unitid,x,y,limit = cdata.name,cdata.unitid,cdata.x,cdata.y,cdata.limit
		
		if (#params > 0) then
			for a,b in ipairs(params) do
				local pname = b
				local pnot = false
				if (string.sub(b, 1, 4) == "not ") then
					pnot = true
					pname = string.sub(b, 5)
				end
				
				local bcode = b .. "_" .. tostring(a)
				
				if (featureindex[name] ~= nil) then
					for c,d in ipairs(featureindex[name]) do
						local drule = d[1]
						local dconds = d[2]
						
						if (checkedconds[tostring(dconds)] == nil) then
							if (pnot == false) then
								if (drule[1] == name) and (drule[2] == "is") and (drule[3] == b) then
									checkedconds[tostring(dconds)] = 1
									
									if (alreadyfound[bcode] == nil) and testcond(dconds,unitid,x,y,nil,limit,checkedconds) then
										alreadyfound[bcode] = 1
										allfound = allfound + 1
										break
									end
								end
							else
								if (string.sub(drule[3], 1, 4) ~= "not ") then
									local obj = unitreference["text_" .. drule[3]]
									
									if (obj ~= nil) then
										local objtype = getactualdata_objlist(obj,"type")
										
										if (objtype == 2) then
											if (drule[1] == name) and (drule[2] == "is") and (drule[3] ~= pname) then
												checkedconds[tostring(dconds)] = 1
												
												if (alreadyfound[bcode] == nil) and testcond(dconds,unitid,x,y,nil,limit,checkedconds) then
													alreadyfound[bcode] = 1
													allfound = allfound + 1
													break
												end
											end
										end
									end
								end
							end
						end
					end
				end
			end
		else
			return false,checkedconds,true
		end
		
		--MF_alert(tostring(cdata.debugname) .. ", " .. tostring(allfound) .. ", " .. tostring(#params))
		
		return (allfound == #params),checkedconds,true
	end,

Модхуки:

mod_hook_functions =
{
level_start =
{
-- Functions added to this table will be called on level start.
},
level_end =
{
-- Functions added to this table will be called on level end.
},
level_win =
{
-- Functions added to this table will be called on level win, before running any of the winning-related code.
},
level_win_after =
{
-- Functions added to this table will be called on level win, after running the winning-related code.
},
level_restart =
{
-- Functions added to this table will be called when the player restarts a level.
},
rule_update =
{
-- Functions added to this table will be called when rules are updated. Extra data: {is_this_a_repeated_update [false = no, true = yes]} <-- the extra variable is true e.g. when Word-related rules require the rules to be refreshed multiple times in a row.
},
rule_baserules =
{
-- Functions added to this table will be called as the game adds the base rules into the rule list (i.e. ones that aren't visible in the rule list). You can use addbaserule(word 1, word 2, word 3) here to add your own base rules.
},
rule_update_after =
{
-- Functions added to this table will be called after rules have been updated. Extra data: {is_this_a_repeated_update [false = no, true = yes]} <-- the extra variable is true e.g. when Word-related rules require the rules to be refreshed multiple times in a row.
},
command_given =
{
-- Functions added to this table will be called when a player command starts resolving. Extra data: {command, player_id}
},
turn_auto =
{
-- Functions added to this table will be called when a turn starts resolving due to 'Level Is Auto'. Extra data: {player_1_direction, player_2_direction, is_a_player_moving [false = no, true = yes]}
},
turn_end =
{
-- Functions added to this table will be called when a turn end. Extra data: {player_found [0 = no, 1 = yes]}
},
always =
{
-- Functions added to this table will be called every frame. This can get quite slow, so be aware of that! Extra data: {time_from_game_start}
},
effect_once =
{
-- Functions added to this table will be called once at the end of every turn.
},
effect_always =
{
-- Functions added to this table will be called every frame when you're playing a level.
},
undoed =
{
-- Functions added to this table will be called when the player does an undo input.
},
undoed_after =
{
-- Functions added to this table will be called after undo has taken effect.
},
levelpack_end =
{
-- Functions added to this table will be called when the player does the Level Is End ending in a levelpack. Note that if any functions are run here, the normal victory effects won't be displayed.
},
levelpack_done =
{
-- Functions added to this table will be called when the player does the All Is Done ending in a levelpack. Note that if any functions are run here, the normal victory effects won't be displayed.
},
text_input_ok =
{
-- Functions added to this table will be called when the user has input text in the text input dialogue and pressed OK. Extra data: {sanitized_text}
},
}

buttonclick_list = {}

function do_mod_hook(name,extra_)
local extra = extra_ or {}
local mods_run = false

if (mod_hook_functions[name] ~= nil) then
	for i,v in pairs(mod_hook_functions[name]) do
		if (type(v) == "function") then
			v(extra)
			mods_run = true
		end
	end
end

return mods_run

end

function buttonclicked(name,unitid)
if (string.len(name) > 0) and (buttonclick_list[name] ~= nil) then
buttonclick_listname
end
end

function setupmods_global()
local files = MF_filelist("Data/Lua/","*.lua")

table.sort(files)

for i,file in ipairs(files) do
	print("Added custom lua file " .. file)
	dofile("Data/Lua/" .. file)
end

end

function setupmods_levelpack()
local world = generaldata.strings[WORLD]
local files = MF_filelist("Data/Worlds/" .. world .. "/Lua/","*.lua")

--MF_alert(world .. ": " .. tostring(#files))

table.sort(files)

for i,file in ipairs(files) do
	print("Added custom levelpack (" .. world .. ") lua file " .. file)
	dofile("Data/Worlds/" .. world .. "/Lua/" .. file)
end

modsinuse = true

end

Пиши скрипт полностью