• 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!
  • 2026 staff recruitment is open! Check it out and consider applying!

Lua onOutfit or i need new function like onMount?

Exedion

Active Member
Joined
Jun 11, 2007
Messages
629
Reaction score
30
Greetings everyone, I hope you are all well, I want to know if when used on the client mount actions (as the roller shutter appears giving right click on the character, choosing mount and dismount or do "ctrl +r") can execute the function "onOutfit" or i need a new function in sourcers like "onMount"??
 
Which server version are you using?
The easiest way to answer that would be by testing it yourself as it takes like 20 sec.
registerEvent(cid, "outfitTest")

LUA:
function onOutfit(cid)
print("Outfit Test executed, did you only mount or really change the outfit?")
return true
end
 
Which server version are you using?
The easiest way to answer that would be by testing it yourself as it takes like 20 sec.
registerEvent(cid, "outfitTest")

LUA:
function onOutfit(cid)
print("Outfit Test executed, did you only mount or really change the outfit?")
return true
end

thanks... i test and not work... tfs need onMount/onDismount creature event and others like onSoulChange for soulpoints
 
Lol@Summ

I know for a damn fact your are smarter than that. You MUST be just fucking with him. That's so mean.

Exedion, there is a section in creaturescripts.cpp that is very helpful that looks like this

Code:
std::string CreatureEvent::getScriptEventName() const
{
    switch(m_type)
    {
        case CREATURE_EVENT_LOGIN:
            return "onLogin";
        case CREATURE_EVENT_LOGOUT:
            return "onLogout";
        case CREATURE_EVENT_CHANNEL_JOIN:
            return "onJoinChannel";
        case CREATURE_EVENT_CHANNEL_LEAVE:
            return "onLeaveChannel";
        case CREATURE_EVENT_THINK:
            return "onThink";
        case CREATURE_EVENT_ADVANCE:
            return "onAdvance";
        case CREATURE_EVENT_LOOK:
            return "onLook";
        case CREATURE_EVENT_DIRECTION:
            return "onDirection";
        case CREATURE_EVENT_OUTFIT:
            return "onOutfit";
        case CREATURE_EVENT_MAIL_SEND:
            return "onSendMail";
        case CREATURE_EVENT_MAIL_RECEIVE:
            return "onReceiveMail";
        case CREATURE_EVENT_TRADE_REQUEST:
            return "onTradeRequest";
        case CREATURE_EVENT_TRADE_ACCEPT:
            return "onTradeAccept";
        case CREATURE_EVENT_TEXTEDIT:
            return "onTextEdit";
        case CREATURE_EVENT_REPORTBUG:
            return "onReportBug";
        case CREATURE_EVENT_STATSCHANGE:
            return "onStatsChange";
        case CREATURE_EVENT_COMBAT_AREA:
            return "onAreaCombat";
        case CREATURE_EVENT_PUSH:
            return "onPush";
        case CREATURE_EVENT_TARGET:
            return "onTarget";
        case CREATURE_EVENT_FOLLOW:
            return "onFollow";
        case CREATURE_EVENT_COMBAT:
            return "onCombat";
        case CREATURE_EVENT_ATTACK:
            return "onAttack";
        case CREATURE_EVENT_CAST:
            return "onCast";
        case CREATURE_EVENT_KILL:
            return "onKill";
        case CREATURE_EVENT_DEATH:
            return "onDeath";
        case CREATURE_EVENT_PREPAREDEATH:
            return "onPrepareDeath";
        case CREATURE_EVENT_NONE:
        default:
            break;
    }

    return "";
}

std::string CreatureEvent::getScriptEventParams() const
{
    switch(m_type)
    {
        case CREATURE_EVENT_LOGIN:
            return "cid";
        case CREATURE_EVENT_LOGOUT:
            return "cid, forceLogout";
        case CREATURE_EVENT_CHANNEL_JOIN:
        case CREATURE_EVENT_CHANNEL_LEAVE:
            return "cid, channel, users";
        case CREATURE_EVENT_ADVANCE:
            return "cid, skill, oldLevel, newLevel";
        case CREATURE_EVENT_LOOK:
            return "cid, thing, position, lookDistance";
        case CREATURE_EVENT_MAIL_SEND:
            return "cid, receiver, item, openBox";
        case CREATURE_EVENT_MAIL_RECEIVE:
            return "cid, sender, item, openBox";
        case CREATURE_EVENT_TRADE_REQUEST:
        case CREATURE_EVENT_TRADE_ACCEPT:
            return "cid, target, item";
        case CREATURE_EVENT_TEXTEDIT:
            return "cid, item, newText";
        case CREATURE_EVENT_REPORTBUG:
            return "cid, comment";
        case CREATURE_EVENT_THINK:
            return "cid, interval";
        case CREATURE_EVENT_DIRECTION:
        case CREATURE_EVENT_OUTFIT:
            return "cid, old, current";
        case CREATURE_EVENT_STATSCHANGE:
            return "cid, attacker, type, combat, value";
        case CREATURE_EVENT_COMBAT_AREA:
            return "cid, ground, position, aggressive";
        case CREATURE_EVENT_PUSH:
        case CREATURE_EVENT_TARGET:
        case CREATURE_EVENT_FOLLOW:
        case CREATURE_EVENT_COMBAT:
        case CREATURE_EVENT_ATTACK:
        case CREATURE_EVENT_CAST:
            return "cid, target";
        case CREATURE_EVENT_KILL:
#ifndef __WAR_SYSTEM__
            return "cid, target, damage, flags";
#else
            return "cid, target, damage, flags, war";
#endif
        case CREATURE_EVENT_DEATH:
            return "cid, corpse, deathList";
        case CREATURE_EVENT_PREPAREDEATH:
            return "cid, deathList";
        case CREATURE_EVENT_NONE:
        default:
            break;
    }

    return "";
}

refer to this section in your server sources to see what all is available, and how they work.

Also, if you look at the extended opcode patch for OTClient, it's a great example of how to add a new creature event like your seeking.

edit: having examined the code...
internalCreatureChangeOutfit is the function that triggers onOutfit creature events. Player::setMounted calls internalCreatureChangeOutfit but sets the forced flag to true, which means onOutfit does not get called.

you can change the following line in player.cpp, inside the void Player::setMounted(bool mounting) function
g_game.internalCreatureChangeOutfit(this, defaultOutfit, truefalse);

however this may have unintended effects, as it means onOutfit is triggered everytime a player changes their mount status. However of this I'm not certain.

nevermind the below... don't expect edits... lol, just experimenting with adding a simple creature event specifically for changing mount status.
Code:
//header file
//add to enum list
        CREATURE_EVENT_MOUNTSTATUS,
//add to scripting section
        uint32_t executeMountStatus(Player* player, bool mounted);

//cpp file
//insert each into their respective obvious appropriate list
    else if(tmpStr == "mountstatus")
        m_type = CREATURE_EVENT_MOUNTSTATUS;

        case CREATURE_EVENT_MOUNTSTATUS:
            return "onMountStatus";

        case CREATURE_EVENT_MOUNTSTATUS:
            return "cid, mounted";


//game.cpp
//insert into Game::playerChangeMountStatus

    bool deny = false;
    CreatureEventList mountEvents = player->getCreatureEvents(CREATURE_EVENT_MOUNT);
    for(CreatureEventList::iterator it = mountEvents.begin(); it != mountEvents.end(); ++it)
    {
        if(!(*it)->executeTextEdit(player, status))
            deny = true;
    }
 
Last edited:
Lol@Summ

I know for a damn fact your are smarter than that. You MUST be just fucking with him. That's so mean.

Exedion, there is a section in creaturescripts.cpp that is very helpful that looks like this

Code:
std::string CreatureEvent::getScriptEventName() const
{
    switch(m_type)
    {
        case CREATURE_EVENT_LOGIN:
            return "onLogin";
        case CREATURE_EVENT_LOGOUT:
            return "onLogout";
        case CREATURE_EVENT_CHANNEL_JOIN:
            return "onJoinChannel";
        case CREATURE_EVENT_CHANNEL_LEAVE:
            return "onLeaveChannel";
        case CREATURE_EVENT_THINK:
            return "onThink";
        case CREATURE_EVENT_ADVANCE:
            return "onAdvance";
        case CREATURE_EVENT_LOOK:
            return "onLook";
        case CREATURE_EVENT_DIRECTION:
            return "onDirection";
        case CREATURE_EVENT_OUTFIT:
            return "onOutfit";
        case CREATURE_EVENT_MAIL_SEND:
            return "onSendMail";
        case CREATURE_EVENT_MAIL_RECEIVE:
            return "onReceiveMail";
        case CREATURE_EVENT_TRADE_REQUEST:
            return "onTradeRequest";
        case CREATURE_EVENT_TRADE_ACCEPT:
            return "onTradeAccept";
        case CREATURE_EVENT_TEXTEDIT:
            return "onTextEdit";
        case CREATURE_EVENT_REPORTBUG:
            return "onReportBug";
        case CREATURE_EVENT_STATSCHANGE:
            return "onStatsChange";
        case CREATURE_EVENT_COMBAT_AREA:
            return "onAreaCombat";
        case CREATURE_EVENT_PUSH:
            return "onPush";
        case CREATURE_EVENT_TARGET:
            return "onTarget";
        case CREATURE_EVENT_FOLLOW:
            return "onFollow";
        case CREATURE_EVENT_COMBAT:
            return "onCombat";
        case CREATURE_EVENT_ATTACK:
            return "onAttack";
        case CREATURE_EVENT_CAST:
            return "onCast";
        case CREATURE_EVENT_KILL:
            return "onKill";
        case CREATURE_EVENT_DEATH:
            return "onDeath";
        case CREATURE_EVENT_PREPAREDEATH:
            return "onPrepareDeath";
        case CREATURE_EVENT_NONE:
        default:
            break;
    }

    return "";
}

std::string CreatureEvent::getScriptEventParams() const
{
    switch(m_type)
    {
        case CREATURE_EVENT_LOGIN:
            return "cid";
        case CREATURE_EVENT_LOGOUT:
            return "cid, forceLogout";
        case CREATURE_EVENT_CHANNEL_JOIN:
        case CREATURE_EVENT_CHANNEL_LEAVE:
            return "cid, channel, users";
        case CREATURE_EVENT_ADVANCE:
            return "cid, skill, oldLevel, newLevel";
        case CREATURE_EVENT_LOOK:
            return "cid, thing, position, lookDistance";
        case CREATURE_EVENT_MAIL_SEND:
            return "cid, receiver, item, openBox";
        case CREATURE_EVENT_MAIL_RECEIVE:
            return "cid, sender, item, openBox";
        case CREATURE_EVENT_TRADE_REQUEST:
        case CREATURE_EVENT_TRADE_ACCEPT:
            return "cid, target, item";
        case CREATURE_EVENT_TEXTEDIT:
            return "cid, item, newText";
        case CREATURE_EVENT_REPORTBUG:
            return "cid, comment";
        case CREATURE_EVENT_THINK:
            return "cid, interval";
        case CREATURE_EVENT_DIRECTION:
        case CREATURE_EVENT_OUTFIT:
            return "cid, old, current";
        case CREATURE_EVENT_STATSCHANGE:
            return "cid, attacker, type, combat, value";
        case CREATURE_EVENT_COMBAT_AREA:
            return "cid, ground, position, aggressive";
        case CREATURE_EVENT_PUSH:
        case CREATURE_EVENT_TARGET:
        case CREATURE_EVENT_FOLLOW:
        case CREATURE_EVENT_COMBAT:
        case CREATURE_EVENT_ATTACK:
        case CREATURE_EVENT_CAST:
            return "cid, target";
        case CREATURE_EVENT_KILL:
#ifndef __WAR_SYSTEM__
            return "cid, target, damage, flags";
#else
            return "cid, target, damage, flags, war";
#endif
        case CREATURE_EVENT_DEATH:
            return "cid, corpse, deathList";
        case CREATURE_EVENT_PREPAREDEATH:
            return "cid, deathList";
        case CREATURE_EVENT_NONE:
        default:
            break;
    }

    return "";
}

refer to this section in your server sources to see what all is available, and how they work.

Also, if you look at the extended opcode patch for OTClient, it's a great example of how to add a new creature event like your seeking.

edit: having examined the code...
internalCreatureChangeOutfit is the function that triggers onOutfit creature events. Player::setMounted calls internalCreatureChangeOutfit but sets the forced flag to true, which means onOutfit does not get called.

you can change the following line in player.cpp, inside the void Player::setMounted(bool mounting) function
g_game.internalCreatureChangeOutfit(this, defaultOutfit, truefalse);

however this may have unintended effects, as it means onOutfit is triggered everytime a player changes their mount status. However of this I'm not certain.

nevermind the below... don't expect edits... lol, just experimenting with adding a simple creature event specifically for changing mount status.
Code:
//header file
//add to enum list
        CREATURE_EVENT_MOUNTSTATUS,
//add to scripting section
        uint32_t executeMountStatus(Player* player, bool mounted);

//cpp file
//insert each into their respective obvious appropriate list
    else if(tmpStr == "mountstatus")
        m_type = CREATURE_EVENT_MOUNTSTATUS;

        case CREATURE_EVENT_MOUNTSTATUS:
            return "onMountStatus";

        case CREATURE_EVENT_MOUNTSTATUS:
            return "cid, mounted";


//game.cpp
//insert into Game::playerChangeMountStatus

    bool deny = false;
    CreatureEventList mountEvents = player->getCreatureEvents(CREATURE_EVENT_MOUNT);
    for(CreatureEventList::iterator it = mountEvents.begin(); it != mountEvents.end(); ++it)
    {
        if(!(*it)->executeTextEdit(player, status))
            deny = true;
    }

thanks lessaire, i making my version, but your version is better, i take a look... can you help me with a creature event for soul points?
 
Lol@Summ

I know for a damn fact your are smarter than that. You MUST be just fucking with him. That's so mean.

That has nothing to do with being smart, if people don't include the version they are using I won't even bother looking into the sources.
It makes no sense to assume that everyone is using the latest TFS.

You failed at if(!(*it)->executeTextEdit(player, status))
 
I meant it would be far faster to direct _him_ to look at _his sources_ that to reload a running server.

As far as the C++ code, it wasn't complete and that detail was upfront. It started to become too much work for something I wouldn't even use myself. I was copy-paste-editing similar sections of code for my desired purpose as a template. Tell me you never do the same.

Is this better?

Code:
//creaturescripts.h
//add to enum list
        CREATURE_EVENT_MOUNTSTATUS,
//add to scripting section
        uint32_t executeMountStatus(Player* player, bool mounted);

//creaturescripts.cpp
//insert each into their respective obvious appropriate list
    else if(tmpStr == "mountstatus")
        m_type = CREATURE_EVENT_MOUNTSTATUS;

        case CREATURE_EVENT_MOUNTSTATUS:
            return "onMountStatus";

        case CREATURE_EVENT_MOUNTSTATUS:
            return "cid, mounted";



uint32_t CreatureEvent::executeMountStatus(Player* player, bool mounted)
{
    //onMountStatus(cid, mounted)
    if(m_interface->reserveEnv())
    {
        ScriptEnviroment* env = m_interface->getEnv();
        if(m_scripted == EVENT_SCRIPT_BUFFER)
        {
            env->setRealPos(player->getPosition());
            std::stringstream scriptstream;
            scriptstream << "local cid = " << env->addThing(player) << std::endl;

            scriptstream << "local mounted = " << (mounted ? "true" : "false") << std::endl;

            if(m_scriptData)
                scriptstream << *m_scriptData;

            bool result = true;
            if(m_interface->loadBuffer(scriptstream.str()))
            {
                lua_State* L = m_interface->getState();
                result = m_interface->getGlobalBool(L, "_result", true);
            }

            m_interface->releaseEnv();
            return result;
        }
        else
        {
            #ifdef __DEBUG_LUASCRIPTS__
            char desc[35];
            sprintf(desc, "%s", player->getName().c_str());
            env->setEvent(desc);
            #endif

            env->setScriptId(m_scriptId, m_interface);
            env->setRealPos(player->getPosition());

            lua_State* L = m_interface->getState();
            m_interface->pushFunction(m_scriptId);

            lua_pushnumber(L, env->addThing(player));
            lua_pushboolean(L, mounted);

            bool result = m_interface->callFunction(4);
            m_interface->releaseEnv();
            return result;
        }
    }
    else
    {
        std::clog << "[Error - CreatureEvent::executeAdvance] Call stack overflow." << std::endl;
        return 0;
    }
}



//game.cpp
//insert into Game::playerChangeMountStatus

    bool deny = false;
    CreatureEventList mountEvents = player->getCreatureEvents(CREATURE_EVENT_MOUNT);
    for(CreatureEventList::iterator it = mountEvents.begin(); it != mountEvents.end(); ++it)
    {
        if(!(*it)->executeMountStatus(player, status))
            deny = true;
    }
 
I didn't actually test that, but it it's functional, your question is answered already->

//insert into Game::playerChangeMountStatus

So only when you actually change your mount status.
 
You have to change this in source code (files: player.cpp, creaturevents.cpp, creatureevents.h).
 
Back
Top