I didn't find this to be on a TODO list even not for 2.0
I'm wondering if there is still any kind of interest in it.
Summ and I have been working on it years ago.
It's an easy drag and drop system where the lua files get load on startup (or on occasional load)
It doesn't break backwards compatibility and works normaly alongside the other xml stuff.
It would give the ability to write long quests and such easily in one file for organisation manner.
I'll work towards a PR if there's some real interest, else the time ammount to rebase this on newest sources wouldn't be worth it.
It invokes metatables for:
with their corresponding functions to be able to set them up properly.
Supports:
Delayed for 1.4/2.0:
Here are some working examples:
Action
local shovel = Action()
local holes = {468, 481, 483}
function shovel.onUse(player, item, fromPosition, target, toPosition, isHotkey)
if toPosition.x == CONTAINER_POSITION then
return false
end
local tile = Tile(toPosition)
if not tile then
return false
end
local ground = tile:getGround()
if not ground then
return false
end
local groundId = ground:getId()
if isInArray(holes, groundId) then
ground:transform(groundId + 1)
ground:decay()
toPosition.z = toPosition.z + 1
tile:relocateTo(toPosition)
elseif groundId == 231 then
local randomValue = math.random(1, 100)
if randomValue == 1 then
Game.createItem(2159, 1, toPosition)
elseif randomValue > 95 then
Game.createMonster("Scarab", toPosition)
end
toPosition:sendMagicEffect(CONST_ME_POFF)
else
return false
end
return true
end
shovel:id(2554)
shovel:register()
Globalevents
local shutdownAtServerSave = false
local cleanMapAtServerSave = false
local function serverSave()
if shutdownAtServerSave then
Game.setGameState(GAME_STATE_SHUTDOWN)
else
Game.setGameState(GAME_STATE_CLOSED)
if cleanMapAtServerSave then
cleanMap()
end
Game.setGameState(GAME_STATE_NORMAL)
end
end
local function secondServerSaveWarning()
broadcastMessage("Server is saving game in one minute. Please logout.", MESSAGE_STATUS_WARNING)
addEvent(serverSave, 60000)
end
local function firstServerSaveWarning()
broadcastMessage("Server is saving game in 3 minutes. Please logout.", MESSAGE_STATUS_WARNING)
addEvent(secondServerSaveWarning, 120000)
end
local event = GlobalEvent("Server Save")
function event.onTime(interval)
broadcastMessage("Server is saving game in 5 minutes. Please logout.", MESSAGE_STATUS_WARNING)
Game.setGameState(GAME_STATE_STARTUP)
addEvent(firstServerSaveWarning, 120000)
return not shutdownAtServerSave
end
event:time("09:55:00")
event:register()
Creaturescripts
local login = CreatureEvent("PlayerLogin")
function login.onLogin(player)
local loginStr = "Welcome to " .. configManager.getString(configKeys.SERVER_NAME) .. "!"
if player:getLastLoginSaved() <= 0 then
loginStr = loginStr .. " Please choose your outfit."
player:sendOutfitWindow()
else
if loginStr ~= "" then
player:sendTextMessage(MESSAGE_STATUS_DEFAULT, loginStr)
end
loginStr = string.format("Your last visit was on %s.", os.date("%a %b %d %X %Y", player:getLastLoginSaved()))
end
player:sendTextMessage(MESSAGE_STATUS_DEFAULT, loginStr)
-- Stamina
nextUseStaminaTime[player.uid] = 0
-- Promotion
local vocation = player:getVocation()
local promotion = vocation:getPromotion()
if player:isPremium() then
local value = player:getStorageValue(STORAGEVALUE_PROMOTION)
if not promotion and value ~= 1 then
player:setStorageValue(STORAGEVALUE_PROMOTION, 1)
elseif value == 1 then
player:setVocation(promotion)
end
elseif not promotion then
player:setVocation(vocation:getDemotion())
end
-- Events
player:registerEvent("PlayerDeath")
player:registerEvent("DropLoot")
return true
end
login:register()
Talkactions
local talk = TalkAction("/pos")
function talk.onSay(player, words, param)
if player:getGroup():getAccess() and param ~= "" then
local split = param:split(",")
player:teleportTo(Position(split[1], split[2], split[3]))
else
local position = player:getPosition()
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "Your current position is: " .. position.x .. ", " .. position.y .. ", " .. position.z .. ".")
end
return false
end
talk:separator(" ")
talk:register()
Movements (stepin/stepout/additem/removeitem) with pre defined items.xml values
local campfireStepIn = MoveEvent()
campfireStepIn:type("stepin")
campfireStepIn:id(1423, 1424, 1425)
campfireStepIn:register()
local campfireAddItem = MoveEvent()
campfireAddItem:type("additem")
campfireAddItem:id(1423, 1424, 1425)
campfireAddItem:register()
Movements (stepin/stepout/additem/removeitem) with a lua script return value
local increasing = {[416] = 417, [426] = 425, [446] = 447, [3216] = 3217, [3202] = 3215, [11062] = 11063}
local decreasing = {[417] = 416, [425] = 426, [447] = 446, [3217] = 3216, [3215] = 3202, [11063] = 11062}
local tileStepIn = MoveEvent()
function tileStepIn.onStepIn(creature, item, position, fromPosition)
if not increasing[item.itemid] then
return true
end
local player = creature:getPlayer()
if player == nil or player:isInGhostMode() then
return true
end
item:transform(increasing[item.itemid])
if item.actionid >= 1000 then
if player:getLevel() < item.actionid - 1000 then
player:teleportTo(fromPosition, false)
position:sendMagicEffect(CONST_ME_MAGIC_BLUE)
player:sendTextMessage(MESSAGE_INFO_DESCR, "The tile seems to be protected against unwanted intruders.")
end
return true
end
if Tile(position):hasFlag(TILESTATE_PROTECTIONZONE) then
local lookPosition = player:getPosition()
lookPosition:getNextPosition(player:getDirection())
local depotItem = Tile(lookPosition):getItemByType(ITEM_TYPE_DEPOT)
if depotItem ~= nil then
local depotItems = player:getDepotChest(getDepotId(depotItem:getUniqueId()), true):getItemHoldingCount()
player:sendTextMessage(MESSAGE_STATUS_DEFAULT, "Your depot contains " .. depotItems .. " item" .. (depotItems > 1 and "s." or "."))
return true
end
end
if item.actionid ~= 0 and player:getStorageValue(item.actionid) <= 0 then
player:teleportTo(fromPosition, false)
position:sendMagicEffect(CONST_ME_MAGIC_BLUE)
player:sendTextMessage(MESSAGE_INFO_DESCR, "The tile seems to be protected against unwanted intruders.")
return true
end
return true
end
for k, v in pairs(increasing) do
tileStepIn:id(k)
end
tileStepIn:register()
local tileStepOut = MoveEvent()
function tileStepOut.onStepOut(creature, item, position, fromPosition)
if not decreasing[item.itemid] then
return true
end
if creature:isPlayer() and creature:isInGhostMode() then
return true
end
item:transform(decreasing[item.itemid])
return true
end
for k, v in pairs(decreasing) do
tileStepOut:id(k)
end
tileStepOut:register()
Movements (equip/deequip) with pre defined like movements.xml values
-- Equip armor(s) for sorceres and druids at any level
local equip = MoveEvent()
equip.onEquip = defaultEquip
equip:type("equip")
equip:slot("armor")
equip:vocation("sorcerer", true, false) -- showInDescription / lastVoc
equip:vocation("master sorcerer")
equip:vocation("druid", true, true)
equip:vocation("elder druid")
equip:id(8819, 8892, 8870, 8871)
equip:register()
Movements (equip/deequip) with lua script attached and combination of pre defined values
-- Equip armor(s) for sorceres and druids at any level
local equip = MoveEvent()
function equip.onEquip(player, item, slot)
print("I do work")
return true
end
equip:type("equip")
equip:slot("armor")
equip:vocation("sorcerer", true, false) -- showInDescription / lastVoc
equip:vocation("master sorcerer")
equip:vocation("druid", true, true)
equip:vocation("elder druid")
equip:id(8819, 8892, 8870, 8871)
equip:register()
Nice. 馃憤
This looks like the correct way of doing mods? (The obsolete XML pack interface used in some 0.4 distro was just messy).
Could you plop in a startup script that register multiple different actions in one file?
Edit: Just realized the mods system I was referring to was made by @slawkens. No offense meant, your system was innovative and awesome at the time. Just bothersome to debug as most code color highlight editors struggled separating XML and Lua scopes in the same file.
Yes that's mostly what it is meant for, so you don't have to split different or same actions into different files.
Which makes quests like POI and such a lot easier to manage.
It's not in the roadmap for 2.0 but a lengthy discussion about this topic exists in issue #1057. Based on that issue it seems like such a pull request would be welcomed.
Honestly, this idea is amazing. I think that pugixml now will be only for XML files, for example (items.xml, the XML folder etc ...)
question: how I can register dynamically action ids? for examples: new doors don't work with default script actions/scripts/others/doors.lua, because the difference of open door and the closed door is not one. 12356 (open door), 12357 (closed door). So I tried to create a key-values table to map and transform the item and make flatten unique table with keys and values to register the action. but Action():id(...) requires varargs and not a table
Either call action:id(id) multiple times for each id you want to register or action:id(unpack(yourTableWithIds)) where yourTableWithIds is something like {12356, 12357}
thanks, Summ! got it!
i have refactored some doors systems using script and looks pretty good.
https://github.com/gpedro/OTServBR-Global/blob/fix/doors/data/scripts/actions/newdoors.lua#L30-L32
Monster is not working.
Lua Script Error: [Scripts Interface]
D:\tfs\data\scripts\monsters\example.lua
D:\tfs\data\scripts\monsters\example.lua:90: attempt to index local 'mType' (a nil value)
stack traceback:
[C]: in function '__index'
D:\tfs\\data\scripts\monsters\example.lua:90: in main chunk
> example.lua [error]

I noticed something wrong with the formula.
Monster is not working.
Lua Script Error: [Scripts Interface] D:\tfs\data\scripts\monsters\example.lua D:\tfs\data\scripts\monsters\example.lua:90: attempt to index local 'mType' (a nil value) stack traceback: [C]: in function '__index' D:\tfs\\data\scripts\monsters\example.lua:90: in main chunk > example.lua [error]You can use
Game.createMonsterType(...)
I noticed something wrong with the formula.
The formula is exactly the same as the default one, maybe your monster has fire % resistence.
Monster is not working.
Lua Script Error: [Scripts Interface] D:\tfs\data\scripts\monsters\example.lua D:\tfs\data\scripts\monsters\example.lua:90: attempt to index local 'mType' (a nil value) stack traceback: [C]: in function '__index' D:\tfs\\data\scripts\monsters\example.lua:90: in main chunk > example.lua [error]You can use
Game.createMonsterType(...)
I noticed something wrong with the formula.The formula is exactly the same as the default one, maybe your monster has fire % resistence.
Not a monster, it's in the player
The Game.createMonsterType solved the problem of monster, thanks

Does not it work in a similar way to the formula of monsters elements? Because the base is 100% and -100 (positive damage) and 100+ (negative damage)?
I noticed that by changing the number to 170/200 the damage was in 80/100 lathes, but not less than 80
Does not it work in a similar way to the formula of monsters elements? Because the base is 100% and -100 (positive damage) and 100+ (negative damage)?
I noticed that by changing the number to 170/200 the damage was in 80/100 lathes, but not less than 80
players take half the supposed damage, theres nothing wrong.
ohh, sorry ... kkkkkkk
long time away from tibia
The last part of "revscriptsys" core: NPC's has been postponed for a future release due to alot of work needed to get it done, alot of testing etc. That means this issue as of now is completed, and a new issue will be created for future milestones. This issue represents what to expect in 1.3.
Beside the NPC components, revscriptsys is working, and its pretty awesome! Lets give it a good go, iron out the last bugs should we find them, and tag a release soon!
Most helpful comment
The last part of "revscriptsys" core: NPC's has been postponed for a future release due to alot of work needed to get it done, alot of testing etc. That means this issue as of now is completed, and a new issue will be created for future milestones. This issue represents what to expect in 1.3.
Beside the NPC components, revscriptsys is working, and its pretty awesome! Lets give it a good go, iron out the last bugs should we find them, and tag a release soon!