• 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!

Load Npc's from lua

Void_

Banned User
Joined
Jan 7, 2018
Messages
9
Reaction score
12
Since I am unfamiliar with how the lua is retrieved in the sources, I used my own means of getting data from a lua file, with that said with this code you can call up npc scripts that are lua defined.

So let's get to it. Open up npc.cpp and find this
C++:
extern LuaEnvironment g_luaEnvironment;
and replace it with this
Code:
extern LuaEnvironment g_luaEnvironment, g_lua;

Next find this
C++:
Npc::Npc(const std::string& name) :
    Creature(),
    filename("data/npc/" + name + ".xml"),
    npcEventHandler(nullptr),
    masterRadius(-1),
    loaded(false)
{
    reset();
}
and replace it with this
C++:
Npc::Npc(const std::string& name) :
    Creature(),
    filename("data/npc/"+name+".lua"),
    npcEventHandler(nullptr),
    masterRadius(-1),
    loaded(false)
{
    reset();
}

Next find this
C++:
bool Npc::loadFromXml()

and place this above
C++:
static struct N {
    const char* name;
    int type;
}npclua[] = {
    { "name", LUA_TSTRING },
    { "script", LUA_TSTRING },
    { "skull", LUA_TSTRING },
    { "attackable", LUA_TNUMBER },
    { "floorchange", LUA_TNUMBER },
    { "speed", LUA_TNUMBER },
    { "currency", LUA_TNUMBER },
    { "walkinterval", LUA_TNUMBER },
    { "walkradius", LUA_TNUMBER },
    { "ignoreheight", LUA_TNUMBER },
    { "speechbubble", LUA_TNUMBER },
    { "health", LUA_TTABLE },
    { "look", LUA_TTABLE },
    { "parameters", LUA_TTABLE },
    { NULL, 0 }
}, npchealth[] = {
    { "now", LUA_TNUMBER },
    { "max", LUA_TNUMBER },
    { NULL, 0 }
}, npclook[] = {
    { "type", LUA_TNUMBER },
    { "body", LUA_TNUMBER },
    { "legs", LUA_TNUMBER },
    { "head", LUA_TNUMBER },
    { "feet", LUA_TNUMBER },
    { "addons", LUA_TNUMBER },
    { "typeex", LUA_TNUMBER },
    { "mount", LUA_TNUMBER },
    { NULL, 0 }
}, npcparameters[] = {
    { "key", LUA_TNUMBER },
    { "value", LUA_TNUMBER },
    { NULL, 0 }
};

Now look for this again
C++:
bool Npc::loadFromXml()
and replace all that code in that method with this
C++:
bool Npc::loadFromXml()
{
    lua_State *L = luaL_newstate();
    std::string str;

    if (!L) {
        throw std::runtime_error("Failed to allocate memory for npc");
    }

    luaL_openlibs(L);
    if (luaL_dofile(L, filename.c_str())) {
        std::cout << "[Error - NPC] " << lua_tostring(L, -1) << std::endl;
        lua_close(L);
        return false;
    }

    lua_getglobal(L, "npc");
    for (int i = 1; ; i++) {
        lua_rawgeti(L, -1, 1);
        if (lua_isnil(L, -1)) {
            lua_pop(L, 1);
            break;
        }

        luaL_checktype(L, -1, LUA_TTABLE);
        for (int npcIndex = 0; npclua[npcIndex].name != NULL; npcIndex++) {
            lua_getfield(L, -1, npclua[npcIndex].name);
            luaL_checktype(L, -1, npclua[npcIndex].type);
            str = npclua[npcIndex].name;
            switch (lua_type(L, -1)) {
                case LUA_TSTRING:
                    if (str == "name") {
                        name = g_lua.getString(L, -1);
                    }
                    else if (str == "script"){
                        std::string sc = lua_tostring(L, -1);
                        npcEventHandler = new NpcEventsHandler(sc, this);
                        if (!npcEventHandler->isLoaded()) {
                            delete npcEventHandler;
                            npcEventHandler = nullptr;
                            return false;
                        }
                    }
                    else if (str == "skull") {
                        setSkull(getSkullType(lua_tostring(L, -1) ));
                       
                    }
                    break;
                case LUA_TNUMBER:
                    if (str == "attackable") {
                        attackable = (lua_tonumber(L, -1) != 0);

                    }
                    else if (str == "floorchange") {
                        floorChange = (lua_tonumber(L, -1) != 0);
                       
                    }
                    else if (str == "speed") {
                        baseSpeed = g_lua.getNumber<uint32_t>(L, -1);
                       
                    }
                    else if (str == "walkinterval") {
                        walkTicks = g_lua.getNumber<uint32_t>(L, -1);
                       
                    }
                    else if (str == "walkradius") {
                        masterRadius = g_lua.getNumber<int32_t>(L, -1);
                       
                    }
                    else if (str == "ignoreheight") {
                        ignoreHeight = (lua_tonumber(L, -1) != 0);
                       
                    }
                    else if (str == "speechbubble") {
                        uint32_t speech = g_lua.getNumber<uint32_t>(L, -1);
                        if(speech != 0){
                            speechBubble = speech;
                        }
                       
                    }
                    break;
                case LUA_TTABLE:
                    if (str == "health") {
                        for (int h = 0; npchealth[h].name != NULL; h++) {
                            lua_getfield(L, -1, npchealth[h].name);
                            str = npchealth[h].name;
                            if (str == "now") {
                                health = g_lua.getNumber<int32_t>(L, -1);
                                if(!health || health < 0){
                                    health = 100;
                                }
                            }
                            else if (str == "max") {
                                healthMax = g_lua.getNumber<int32_t>(L, -1);
                                if(!healthMax || healthMax < 0){
                                    healthMax = 100;
                                }
                            }
                            lua_pop(L, 1);
                        }
                    }
                    else if (str == "look") {
                        for (int l = 0; npclook[l].name != NULL; l++) {
                            lua_getfield(L, -1, npclook[l].name);
                            str = npclook[l].name;
                            if (str == "type") {
                                uint16_t lt = g_lua.getNumber<uint16_t>(L, -1);
                                if(lt != 0){
                                    defaultOutfit.lookType = lt;
                                }
                            }
                            else if (str == "head") {
                                uint16_t hd = g_lua.getNumber<uint16_t>(L, -1);
                                if(hd != 0){
                                    defaultOutfit.lookHead = hd;
                                }
                            }
                            else if (str == "body") {
                                defaultOutfit.lookBody = g_lua.getNumber<uint16_t>(L, -1);
                            }
                            else if (str == "legs") {
                                defaultOutfit.lookLegs = g_lua.getNumber<uint16_t>(L, -1);
                            }
                            else if (str == "feet") {
                                defaultOutfit.lookFeet = g_lua.getNumber<uint16_t>(L, -1);
                            }
                            else if (str == "addons") {
                                defaultOutfit.lookAddons = g_lua.getNumber<uint16_t>(L, -1);
                            }
                            else if (str == "typeex") {
                                uint16_t tx = g_lua.getNumber<uint16_t>(L, -1);
                                if(tx != 0){
                                    defaultOutfit.lookTypeEx = tx;
                                }
                            }
                            else if (str == "mount") {
                                defaultOutfit.lookMount = g_lua.getNumber<uint16_t>(L, -1);
                            }
                            lua_pop(L, 1);
                        }
                        currentOutfit = defaultOutfit;
                    }
                    else if (str == "parameters") {
                        if (lua_objlen(L, -1) > 0) {
                            std::string key, value;
                            for (int i = 1; ; i++) {
                                lua_rawgeti(L, -1, i);
                                if (lua_isnil(L, -1)) {
                                    lua_pop(L, 1);
                                    break;
                                }
                                for (int p = 0; npcparameters[p].name != NULL; p++) {
                                    lua_getfield(L, -1, npcparameters[p].name);
                                    str = npcparameters[p].name;
                                    if (str == "key") {
                                        key = g_lua.getString(L, -1);
                                    }
                                    else if (str == "value") {
                                        parameters[key] = g_lua.getString(L, -1);
                                    }
                                    lua_pop(L, 1);
                                }
                                lua_pop(L, 1);
                            }
                        }
                    }
                    break;
                }
                lua_pop(L, 1);
            }
    }
    lua_close(L);
    return true;
}
 
Correction, This is how they are defined.
Lua:
npc = {
    {
        name = "The Oracle Of Life",
        script = "The Oracle.lua",
        skull = tostring(0),
        attackable = 0,
        floorchange = 0,
        speed = 0,
        walkinterval = 0,
        walkradius = 0,
        ignoreheight = 0,
        speechbubble = 3,
        health = { now = 100, max = 100 },
        look = {type = 0, head = 0, body = 0, legs = 0, feet = 0, addons = 0, typeex = 1448, mount = 0},
        parameters = {}
    }
}
 
are you able to implement cords, radius too, so we don't have to use map editor for placement of creatures?

thanks for sharing
 
are you able to implement cords, radius too, so we don't have to use map editor for placement of creatures?

thanks for sharing
What you are referring to and what this code change does are two different things.
 
well sure, but i see it got alot of stuff, just not that :p just tought it would be nice to have

i meant Npc's, not creatures btw : P
 
well sure, but i see it got alot of stuff, just not that :p just tought it would be nice to have

i meant Npc's, not creatures btw : P
I posted something in the mod & lua section in resources which i believe is exactly what you are looking for :)
 
thats cool, but not exactly, i meant

Lua:
npc = {
    {
         position = {x,y,z},
         radius = x
    }
}
 
thats cool, but not exactly, i meant

Lua:
npc = {
    {
         position = {x,y,z},
         radius = x
    }
}
That isn't how an npc is loaded on the map the server reads the spawn file 1st and then it looks for the monster or npc that is associated with the position. The method in the other thread i provide doesn't work with the spawn file it uses the startup script and spawns the npc's. The script is the alternative and is editable.
 
Back
Top