• 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.X+ TFS 1.4.2+OTC mehah - Is there a way to force mount a player and/or change outfit when entering Protection zone

lukatxd

Board Moderator
Staff member
Board Moderator
Joined
Dec 9, 2010
Messages
143
Solutions
1
Reaction score
66
I'm thinking of making a sci-fi/mecha/robots custom server and I'm looking for guidance since I'm kinda struggling with a few points, kinda getting the hang of the code flow.

Here's my line of tought:
- Robots are mounts -> Change mount change robots -> by changing a robot, change player vocation, appearance out of PZ (techinically mounted)

Issues:
  • I could NOT compile TFS (another difficulty that I feel i'll have to deal with eventually) so I'm trying to make everything work using only lua scripts.
  • Mounting is not in lua script, I believe OTC is calling "
    C++:
    toggleMount
    " directly to c++
  • I cant intercept the toggleMount to do stuff before or after

What I tought could be a solution:
- Use or equip an item that:
--- sets a storageValue for the selected mount storage value (already exists)
--- do the stuff it has to do
--- then force mount a player when leaving PZ.

- Use or equip an item that:
--- sets a storageValue specifically for this, not related to Tibia mount
--- do the stuff it has to do
--- stores looktypes of "mounted" and have another one store for "not mounted" and change player appearance when entering or leaving PZ
--- not using the
LUA:
doCreatureSetOutfit
method and altering player outfit directly seems a better option for login/logoff purposes.

With all that said, comes the real question that is in the title, how/when can I detect that player has gotten the condition "In protection zone"? I dont think checking every step would be ideal. And then can I force mount from lua the same way OTC does calling player:toggleMount ?



Edit: I've been searching for this stuff for days... but right after I posted it I found the SWIMMING examples. I guess I'll just make a new tile item for the cities and have the functions stepIn/stepOut to turn players back to their human outfits.
 
Last edited:
If you are staying lua-only for now, I would stop fighting the real mount system.

On stock TFS 1.4.2:
  • there is no nice lua event for "player entered/leaved protection zone"
  • player:toggleMount() is not exposed to lua
  • real mounts are also blocked in PZ in source anyway

So your best lua-only solution is basically the one you found:
use your own robot storage + StepIn/StepOut on the city/PZ border + reapply on login.

I also would NOT use the real Tibia mount storage yet.
Store the selected robot in your own storage and treat the mount system as cosmetic only until you compile.

Lua-only version

1.
Pick one actionid for your city border tiles, example:
45000

Put that actionid on the tiles where players cross between PZ and outside.

2.
Open:
data/movements/movements.xml

Add:

XML:
<movevent type="StepIn" actionid="45000" script="robot_pz.lua" />
<movevent type="StepOut" actionid="45000" script="robot_pz.lua" />

3.
Create:
data/movements/scripts/robot_pz.lua

LUA:
local ROBOT_STORAGE = 50000

local ROBOTS = {
    [1] = {
        human = {lookType = 128, lookHead = 114, lookBody = 114, lookLegs = 114, lookFeet = 114},
        robot = {lookType = 129, lookHead = 0, lookBody = 94, lookLegs = 94, lookFeet = 114},
        humanVoc = 1,
        robotVoc = 5
    },
    [2] = {
        human = {lookType = 136, lookHead = 78, lookBody = 78, lookLegs = 58, lookFeet = 95},
        robot = {lookType = 130, lookHead = 0, lookBody = 114, lookLegs = 114, lookFeet = 114},
        humanVoc = 2,
        robotVoc = 6
    }
}

local function applyRobotState(player, inPz)
    local cfg = ROBOTS[player:getStorageValue(ROBOT_STORAGE)]
    if not cfg then
        return true
    end

    if inPz then
        player:setOutfit(cfg.human)
        player:setVocation(cfg.humanVoc)
    else
        player:setOutfit(cfg.robot)
        player:setVocation(cfg.robotVoc)
    end

    return true
end

function onStepIn(creature, item, position, fromPosition)
    if not creature or not creature:isPlayer() then
        return true
    end

    return applyRobotState(creature, true)
end

function onStepOut(creature, item, position, fromPosition)
    if not creature or not creature:isPlayer() then
        return true
    end

    return applyRobotState(creature, false)
end

4.
Open:
data/creaturescripts/creaturescripts.xml

Add:

XML:
<event type="login" name="RobotLogin" script="robot_login.lua" />

5.
Create:
data/creaturescripts/scripts/robot_login.lua

LUA:
local ROBOT_STORAGE = 50000

local ROBOTS = {
    [1] = {
        human = {lookType = 128, lookHead = 114, lookBody = 114, lookLegs = 114, lookFeet = 114},
        robot = {lookType = 129, lookHead = 0, lookBody = 94, lookLegs = 94, lookFeet = 114},
        humanVoc = 1,
        robotVoc = 5
    },
    [2] = {
        human = {lookType = 136, lookHead = 78, lookBody = 78, lookLegs = 58, lookFeet = 95},
        robot = {lookType = 130, lookHead = 0, lookBody = 114, lookLegs = 114, lookFeet = 114},
        humanVoc = 2,
        robotVoc = 6
    }
}

local function applyRobotState(player, inPz)
    local cfg = ROBOTS[player:getStorageValue(ROBOT_STORAGE)]
    if not cfg then
        return true
    end

    if inPz then
        player:setOutfit(cfg.human)
        player:setVocation(cfg.humanVoc)
    else
        player:setOutfit(cfg.robot)
        player:setVocation(cfg.robotVoc)
    end

    return true
end

function onLogin(player)
    local tile = player:getTile()
    local inPz = tile and tile:hasFlag(TILESTATE_PROTECTIONZONE)

    applyRobotState(player, inPz)
    return true
end

6.
When the player selects a robot, set:
ROBOT_STORAGE = robotId

That is enough to make:
  • inside PZ = human form / human vocation
  • outside PZ = robot form / robot vocation
  • login inside temple = correct form reapplied

So yes, lua-only is doable, I would just fake the whole mount state for now instead of trying to intercept the real one.

If you compile later, then the clean source places are:

- src/player.cpp
Player::onChangeZone(ZoneType_t zone)
This is the real hook for zone changes.

- src/player.cpp
bool Player::toggleMount(bool mount)
This is the real mount logic.

- src/luascript.h
add declaration:
C++:
static int luaPlayerToggleMount(lua_State* L);

- src/luascript.cpp
register it near addMount/removeMount/hasMount:
C++:
registerMethod("Player", "toggleMount", LuaScriptInterface::luaPlayerToggleMount);

- src/luascript.cpp
add implementation:
C++:
int LuaScriptInterface::luaPlayerToggleMount(lua_State* L)
{
    Player* player = getUserdata<Player>(L, 1);
    if (!player) {
        lua_pushnil(L);
        return 1;
    }

    pushBoolean(L, player->toggleMount(getBoolean(L, 2)));
    return 1;
}

And if you want REAL mounts inside PZ too, open:
src/player.cpp

Find:
bool Player::toggleMount(bool mount)

and remove/change this block:

C++:
if (!group->access && tile->hasFlag(TILESTATE_PROTECTIONZONE)) {
    sendCancelMessage(RETURNVALUE_ACTIONNOTPERMITTEDINPROTECTIONZONE);
    return false;
}

So short version:
lua-only right now = border tiles + storages + login reapply
compile later = expose toggleMount + patch Player::onChangeZone / Player::toggleMount
 
I really would consider prioritizing your work-station to be able to compile TFS/OTClient before you start developing anything.
There will come a time, even just a small value change needs to be made through sources, and you do not want to figgle around with not able to compile at that point.

Better get this working sooner rather than later!
 

Similar threads

Back
Top