• There is NO official Otland's Discord server and NO official Otland's server list. The Otland's Staff does not manage any Discord server or server list. Moderators or administrator of any Discord server or server lists have NO connection to the Otland's Staff. Do not get scammed!

[TFS 1.2] Luascript channel

zbizu

Legendary OT User
Joined
Nov 22, 2010
Messages
3,323
Solutions
26
Reaction score
2,694
Location
Poland
direct lua script execution via chatchannel
ZpotgoD.png


default values:
player - your userdata
cid - your uid

Updated!
New features brought to you by @LaloHao @Summ and @Non Sequitur
- added sandbox
- multiple lines support
- tested on 1.2

chatchannels.xml:
Code:
<channel id="9" name="Lua_advanced" public="1" script="execute.lua" />

execute.lua
Code:
local CHAT_ID = 9

function canJoin(player)
	return player:getAccountType() >= ACCOUNT_TYPE_GOD
end

local function InteractiveConsole(env)
	return coroutine.wrap(function(inp, out, err)
		local sandbox = setmetatable({ }, 
			{
				__index = function(t, index)
					return rawget(t, index) or env[index] or _G[index]
				end
			}
		)
		sandbox._G = sandbox
		sandbox.os = {
			time = function() return os.time() end
		}
		sandbox.io = { }
		sandbox.debug = { }
		sandbox.pcall = { }
		sandbox.loadstring = { }
		sandbox.error = err	
		sandbox.print = function(...)
			local r = {}
			for _, v in ipairs({...}) do
				table.insert(r, tostring(v))
			end
			local s = table.concat(r, string.rep(' ', 4))
			return out(#s > 0 and s or 'nil')
		end		

		local chunks = {}
		local level = 1

		while true do
			table.insert(chunks, coroutine.yield())

			local func, e = loadstring(table.concat(chunks, ' '), 'console')
			if func then			
				setfenv(func, sandbox)
				inp(string.rep('>', level) .. ' ' .. chunks[#chunks])
				local s, e = pcall(func)
				if not s then
					err(e)
				end

				chunks = { }
				level = 1
			else
				if not e:find('near \'<eof>\'$') then
					inp(string.rep('>', level) .. ' ' .. chunks[#chunks])
					chunks = { }
					level = 1
					err(e)
				else					
					inp(string.rep('>', level) .. ' ' .. chunks[#chunks])
					level = 2
				end
			end
		end
	end)
end

local consoles = { }

function onSpeak(player, type, message)
	if player:getAccountType() < ACCOUNT_TYPE_GOD then
		return false
	end

	local pid = player:getId()
	
	local console = consoles[pid]
	if not console then
		console = InteractiveConsole {
			player = player,
			cid = pid,
		}

		console(
			function(inp)
				local player = Player(pid)
				if player then
					player:sendChannelMessage(player:getName(), inp, TALKTYPE_CHANNEL_Y, CHAT_ID)
				end
			end,
			
			function(s)
				local player = Player(pid)
				if player then
					player:sendChannelMessage(nil, s, TALKTYPE_CHANNEL_O, CHAT_ID)
				end
			end,

			function(e)
				local player = Player(pid)
				if player then
					player:sendChannelMessage(nil, e, TALKTYPE_CHANNEL_R1, CHAT_ID)
				end
			end
		)

		consoles[pid] = console
	end

	console(message)
	return false
end

- no sandbox
- tested on 1.1
- no multiple lines support

H8EEQcz.jpg


chatchannels.xml:
Code:
<channel id="9" name="Lua" script="execute.lua" />

execute.lua:
Code:
function canJoin(player)
   return player:getAccountType() >= ACCOUNT_TYPE_GOD
end

function onSpeak(player, type, message)
   if not player:getAccountType() >= ACCOUNT_TYPE_GOD then
     return false
   end
  
   local pos = Position(player:getPosition())
   local tile = Tile(pos)

   _G["cid"] = player:getId()
   _G["player"] = player
   _G["creature"] = Creature(player:getId())
   _G["pos"] = pos
   _G["tile"] = tile
   _G["container"] = player:getSlotItem(CONST_SLOT_BACKPACK)
   _G["group"] = player:getGroup()
   _G["vocation"] = player:getVocation()
   _G["town"] = player:getTown()
   _G["house"] = tile:getHouse()
   _G["party"] = player:getParty()
  
   local res, err = loadstring(message)
   if res then
     local ret, err = pcall(res)
     if not ret then
       player:sendChannelMessage(player:getName(), "Lua Script Error: " .. err .. ".", TALKTYPE_CHANNEL_O, 9)
       return false
     end
   else
     player:sendChannelMessage(player:getName(), "Lua Script Error: " .. err .. ".", TALKTYPE_CHANNEL_O, 9)
     return false
   end
   player:sendChannelMessage("", player:getName() .. ">>  " .. message, TALKTYPE_CHANNEL_Y, 9)
   return false
end
 
Last edited:
Actually I should work hard on another thing, but my procastination leads me to write these scripts.

You should stop releasing all these scripts and use them on your own server.. this community is not as generous as you are when it comes to sharing content all your doing is feeding to the ignorance of others.. in that people don't develop problem solving skills of their own.

The thing you are teaching them is I don't need to learn anything at all, all I need to do is download a server and then search for ready made scripts and ask someone to modify those scripts or use support & request to request scripts to be made.. I am guilty of making / modifying scripts for others as well so I am part of the problem too, but at least I acknowledge it.

I don't see much of a point anymore for "helping" people on these forums or releasing content because no one is learning anything and there is no encouragement for them to do so.

With that said see you all :)
 
You should stop releasing all these scripts and use them on your own server.. this community is not as generous as you are when it comes to sharing content all your doing is feeding to the ignorance of others.. in that people don't develop problem solving skills of their own.

The thing you are teaching them is I don't need to learn anything at all, all I need to do is download a server and then search for ready made scripts and ask someone to modify those scripts or use support & request to request scripts to be made.. I am guilty of making / modifying scripts for others as well so I am part of the problem too, but at least I acknowledge it.

I don't see much of a point anymore for "helping" people on these forums or releasing content because no one is learning anything and there is no encouragement for them to do so.

With that said see you all :)
tl;dr

btw he used to have a server and worked on it, but the problem is not only the community, but players too since they don't give a shit if admin worked hard on his server, all they do is whine, I'm glad to see zbizu releasing things to the community even if we don't really deserve them
 
Anyways, it's great to see all these releases you've done @zbizu, it will definitely make it easier for people to start 1.x servers. And even your evorpg project was a huge help for me when I worked on my server, glad to see your still helping the community since it's really necessary if we want to get past the 8.6/0.4 epidemic :p
 
Last edited by a moderator:
Didn't thought that this thread would gain so much attention.

@Jotran
Your way of thinking is wrong on so many levels. Look at work of otland support team. They're not spoiling others, they're helping. It's easy to notice when someone requests too much help, without doing anything on his own. I post useful scripts and fix them if they're bugged, that's all. If someone asks me for help with his script via pm I only explain what has to be done instead of posting full script.

@Evil Puncker
I stopped hosting mystera because:
- tps had terrible allocation
- There was a bug that I could't fix, I didn't know what was causing it. It was related to game.LoadMap() and it was fixed later by tfs devs.

@StreamSide
What does it do? Why it's so long?

@Ahilphino
Stop it, seriously. Nobody cares if someone is Breed or not.

@Mr. Greyshade
gr8 m8 r8 8/8 xD
 
The idea is awesome.

I thought it might be fun to have a little editor so I extended your script a bit.
Let's say you want to use a certain function often then you can just create a script for it.

Example:
Say: script
-> Enters scripting mode
Say: function greetPlayer(cid)
Say: local player = Player(cid)
Say: if player then
Say: player:say('Greetings, new player!', TALKTYPE_MONSTER_SAY)
Say: end
Say: end
Say: addEvent(greetPlayer, 500, cid)
Say: execute
-> Will execute the script as far as you have gotten
Say: whoopsie
-> You made some mistake
Say: commentLine
-> Last line will be turned into a comment
Say: save
-> You will be prompted for a script name
Say: greet
-> Script is saved as 'greet'

Say: execute <script_name> (e.g. execute greet)
-> Execute your saved script :)

bc67c5c86b7f3b9edc7a511bcc6a3b40.png

de302eb64254e4ce8c014fb100bfb047.png


Code:
function canJoin(player)
    return player:getAccountType() >= ACCOUNT_TYPE_GOD
end

local ACTIVITY_NONE = 0
local ACTIVITY_SCRIPT = 1
local ACTIVITY_SAVING = 2

local activity = { }
local scripts = { }
local currentScript = { }

local function runScript(player, message)
    local pos = player:getPosition()
    local tile = Tile(pos)

    _G['cid'] = player.uid
    _G['player'] = player
    _G['creature'] = player
    _G['pos'] = pos
    _G['tile'] = tile
    _G['container'] = player:getSlotItem(CONST_SLOT_BACKPACK)
    _G['group'] = player:getGroup()
    _G['vocation'] = player:getVocation()
    _G['town'] = player:getTown()
    _G['house'] = tile:getHouse()
    _G['party'] = player:getParty()

    local res, err = loadstring(message)
    if not res then
        player:sendChannelMessage(player:getName(), 'Lua Script Error: ' .. err .. '.', TALKTYPE_CHANNEL_O, 9)
        return false
    end

    local ret, err = pcall(res)
    if not ret then
        player:sendChannelMessage(player:getName(), 'Lua Script Error: ' .. err .. '.', TALKTYPE_CHANNEL_O, 9)
        return false
    end

    player:sendChannelMessage('', player:getName() .. ' >> ' .. message, TALKTYPE_CHANNEL_Y, 9)
end

local function saveScript(player, message)
    local playerId = player.uid
    if not scripts[playerId] then
        scripts[playerId] = {}
    end

    scripts[playerId][message] = currentScript[playerId]
    currentScript[playerId] = nil
    player:sendChannelMessage('', 'Your current script has been saved as: ' .. message, TALKTYPE_CHANNEL_O, 9)
    activity[playerId] = ACTIVITY_NONE
end

local function executeCurrentScript(player, message)
    runScript(player, '\n' .. table.concat(currentScript[player.uid], '\n'))
end

local function saveCurrentScript(player, message)
    activity[player.uid] = ACTIVITY_SAVING
    player:sendChannelMessage('', 'Under which name do you want to save the script?', TALKTYPE_CHANNEL_O, 9)
end

local function viewCurrentScript(player, message)
    player:sendChannelMessage('', '- - - - - - - - - Script - - - - - - - - -', TALKTYPE_CHANNEL_Y, 9)

    local playerId = player.uid
    for i = 1, #currentScript[playerId] do
        player:sendChannelMessage('', '| ' .. currentScript[playerId][i], TALKTYPE_CHANNEL_Y, 9)
    end

    player:sendChannelMessage('', '- - - - - - - - - - - - - - - - - - - - - -', TALKTYPE_CHANNEL_Y, 9)
end

local function commentLineCurrentScript(player, message)
    local script = currentScript[player.uid]
    if #script == 0 then
        player:sendChannelMessage('', 'There is no line which can be turned into a comment.', TALKTYPE_CHANNEL_O, 9)
    else
        script[#script] = '-- ' .. script[#script]
        viewCurrentScript(player, message)
    end
end

local function appendCurrentScript(player, message)
    table.insert(currentScript[player.uid], message)
    viewCurrentScript(player, message)
end

local function executeScript(player, message, param)
    local scriptList = scripts[player.uid]
    if scriptList then
        local script = scripts[player.uid][param]
        if not script then
            player:sendChannelMessage('', 'Script \'' .. param .. '\' could not be found.', TALKTYPE_CHANNEL_O, 9)
            return false
        end

        runScript(player, '\n' .. table.concat(script, '\n'))
    else
        player:sendChannelMessage('', 'You did not create any script which could be executed.', TALKTYPE_CHANNEL_O, 9)
    end
end

local function enterScriptMode(player, message)
    activity[player.uid] = ACTIVITY_SCRIPT
    currentScript[player.uid] = {}
    player:sendChannelMessage('', 'Script mode entered!', TALKTYPE_CHANNEL_O, 9)
end

local commands = {
    [ACTIVITY_SAVING] = {saveScript},
    [ACTIVITY_SCRIPT] = {
        {'execute', executeCurrentScript},
        {'save', saveCurrentScript},
        {'commentLine', commentLineCurrentScript},
        appendCurrentScript
    },
    [ACTIVITY_NONE] = {
        {'execute', executeScript, hasParam = true},
        {'script', enterScriptMode},
        runScript
    }
}

function onSpeak(player, _type, message)
    if not(player:getAccountType() >= ACCOUNT_TYPE_GOD) then
        return false
    end

    local actions = commands[activity[player.uid] or ACTIVITY_NONE]
    if not actions then
        return false
    end

    for _, action in ipairs(actions) do
        if type(action) == 'table' then
            if action.hasParam and message:sub(1, #action[1]) == action[1] then
                action[2](player, message, message:sub(#action[1] + 2, #message))
                break
            elseif message == action[1] then
                action[2](player, message)
                break
            end
        else
            action(player, message)
            break
        end
    end
    return false
end
 
Last edited:
Nice. Keep posting updates if you get more ideas.
Oh and please use player's name parameter so everyone on channel can see who casted that command.
 
player:sendChannelMessage is only visible to the player you send the message to.
I assume it is better if everyone only sees his own scripts.
 
Back
Top