Пример #1
0
        /// <summary>
        /// Sends dialog select message to client, showing a message and a
        /// list of options to select from.
        /// </summary>
        /// <remarks>
        /// Select can take an arbitrary amount of options.
        ///
        /// Parameters:
        /// - string message
        /// - string options...
        ///
        /// Result:
        /// The number of the selected option, starting from 1.
        /// Returns 0 on error.
        /// </remarks>
        /// <param name="L"></param>
        /// <returns></returns>
        private int select(IntPtr L)
        {
            // Check arguments and return 0 on error
            var argc = Melua.lua_gettop(L);

            if (argc == 0)
            {
                Log.Warning("select: No arguments.");
                Melua.lua_pushinteger(L, 0);
                return(1);
            }

            var conn = this.GetConnectionFromState(L);

            // Get arguments, first argument is the message, everything afterwards
            // is one option to select from.
            var args = new string[argc];

            for (int i = 1; i <= argc; ++i)
            {
                var arg = Melua.luaL_checkstring(L, i);
                this.HandleCustomCode(conn, ref arg);
                args[i - 1] = arg;
            }

            Melua.lua_pop(L, argc);

            this.AttachNpcName(conn, ref args[0]);

            Send.ZC_DIALOG_SELECT(conn, args);

            return(Melua.lua_yield(L, 1));
        }
Пример #2
0
        /// <summary>
        /// Spawns monster.
        /// </summary>
        /// <remarks>
        /// Parameters:
        /// - int    monsterId
        /// - string mapName
        /// - float  x
        /// - float  y
        /// - float  z
        /// </remarks>
        /// <param name="L"></param>
        /// <returns></returns>
        private int spawn(IntPtr L)
        {
            var monsterId = Melua.luaL_checkinteger(L, 1);
            var mapName   = Melua.luaL_checkstring(L, 2);
            var x         = (float)Melua.luaL_checknumber(L, 3);
            var y         = (float)Melua.luaL_checknumber(L, 4);
            var z         = (float)Melua.luaL_checknumber(L, 5);

            Melua.lua_pop(L, 5);

            var map = ChannelServer.Instance.World.GetMap(mapName);

            if (map == null)
            {
                return(Melua.melua_error(L, "Map '{0}' not found.", mapName));
            }

            var monster = new Monster(monsterId, NpcType.Monster);

            monster.Position = new Position(x, y, z);

            map.AddMonster(monster);

            return(0);
        }
Пример #3
0
        private int addelement(IntPtr L)
        {
            if (!IsXmlFileLoaded())
            {
                return(Melua.melua_error(L, "No XML file loaded."));
            }

            var selector = Melua.luaL_checkstring(L, 1);
            var xml      = Melua.luaL_checkstring(L, 2);

            Melua.lua_pop(L, 2);

            if (!IsXPathValid(selector))
            {
                return(Melua.melua_error(L, "Invalid XPath."));
            }

            XElement element;

            try
            {
                element = XElement.Parse(xml);
            }
            catch (XmlException ex)
            {
                return(Melua.melua_error(L, "Failed to parse XML element: {0}", ex.Message));
            }

            var modder = _loadedXmlModder;

            _modPack.AddMod(new XmlElementAdder(modder, selector, element));

            return(0);
        }
Пример #4
0
        /// <summary>
        /// Sends dialog input message, showing a message and a text field,
        /// for the user to put in a string.
        /// </summary>
        /// <remarks>
        /// Parameters:
        /// - string message
        ///
        /// Result:
        /// The string put in by the user.
        /// Returns empty string on error.
        /// </remarks>
        /// <param name="L"></param>
        /// <returns></returns>
        private int input(IntPtr L)
        {
            // Check arguments and return empty string on error
            var argc = Melua.lua_gettop(L);

            if (argc == 0)
            {
                Log.Warning("input: No arguments.");
                Melua.lua_pushstring(L, "");
                return(1);
            }

            var conn = this.GetConnectionFromState(L);

            // Get message
            var msg = Melua.luaL_checkstring(L, 1);

            Melua.lua_pop(L, 1);

            this.HandleCustomCode(conn, ref msg);
            this.AttachNpcName(conn, ref msg);

            Send.ZC_DIALOG_STRINGINPUT(conn, msg);

            return(Melua.lua_yield(L, 1));
        }
Пример #5
0
        private int loadxmlfile(IntPtr L)
        {
            var fileName = Melua.luaL_checkstring(L, 1);

            Melua.lua_pop(L, 1);

            fileName = ModPack.NormalizePath(fileName);

            if (!fileName.EndsWith(".xml") && !fileName.EndsWith(".xml.compiled"))
            {
                return(Melua.melua_error(L, "Expected XML file extension."));
            }

            if (!FileExistsInPackages(fileName))
            {
                return(Melua.melua_error(L, "File '{0}' not found in packages.", fileName));
            }

            try
            {
                _loadedXmlFile   = fileName;
                _loadedXmlModder = _modPack.GetXmlModder(fileName);

                return(0);
            }
            catch (XmlException ex)
            {
                _loadedXmlFile   = null;
                _loadedXmlModder = null;

                return(Melua.melua_error(L, "Failed to parse XML: '{0}'", ex.Message));
            }
        }
Пример #6
0
        /// <summary>
        /// Sends dialog numberrange message, showing a message and a small text field,
        /// for the user to put in a number.
        /// </summary>
        /// <remarks>
        /// NUMBERRANGE uses CZ_DIALOG_SELECT for its response,
        /// which means the number range is that of a byte, 0~255.
        ///
        /// Parameters:
        /// - string message
        /// - int min (optional, defaults to 0)
        /// - int max (optional, defaults to 255)
        ///
        /// Result:
        /// The number put in by the user.
        /// Returns 0 on error.
        /// </remarks>
        /// <param name="L"></param>
        /// <returns></returns>
        private int numinput(IntPtr L)
        {
            // Check arguments and return 0 on error
            var argc = Melua.lua_gettop(L);

            if (argc == 0)
            {
                Log.Warning("numinput: No arguments.");
                Melua.lua_pushinteger(L, 0);
                return(1);
            }

            var conn = this.GetConnectionFromState(L);

            int min = 0, max = 255;

            // Get arguments
            var msg = Melua.luaL_checkstring(L, 1);

            if (argc >= 3)
            {
                min = Melua.luaL_checkinteger(L, 2);
                max = Melua.luaL_checkinteger(L, 3);
            }

            Melua.lua_pop(L, argc);

            this.HandleCustomCode(conn, ref msg);
            this.AttachNpcName(conn, ref msg);

            Send.ZC_DIALOG_NUMBERRANGE(conn, msg, min, max);

            return(Melua.lua_yield(L, 1));
        }
Пример #7
0
        private int require(IntPtr L)
        {
            var path = Melua.luaL_checkstring(L, 1);

            Melua.lua_pop(L, 1);

            return(this.DoPath(L, path, true));
        }
Пример #8
0
        private int include(IntPtr L)
        {
            var path = Melua.luaL_checkstring(L, 1);

            Melua.lua_pop(L, 1);

            return(this.DoPath(L, path, false));
        }
Пример #9
0
        //-----------------------------------------------------------------//
        // SCRIPT FUNCTIONS												   //
        //-----------------------------------------------------------------//

        /// <summary>
        /// Prints message in console using Console.WriteLine.
        /// </summary>
        /// <remarks>
        /// Parameters:
        /// - string message
        /// </remarks>
        /// <param name="L"></param>
        /// <returns></returns>
        private int print(IntPtr L)
        {
            var msg = Melua.luaL_checkstring(L, 1);

            Melua.lua_pop(L, 1);

            Console.WriteLine(msg);

            return(0);
        }
Пример #10
0
        //-----------------------------------------------------------------//
        // SCRIPT FUNCTIONS												   //
        //-----------------------------------------------------------------//

        /// <summary>
        /// Prints and logs debug message.
        /// </summary>
        /// <remarks>
        /// Parameters:
        /// - string message
        /// </remarks>
        /// <param name="L"></param>
        /// <returns></returns>
        private int logdebug(IntPtr L)
        {
            var msg = Melua.luaL_checkstring(L, 1);

            Melua.lua_pop(L, 1);

            Log.Debug(msg);

            return(0);
        }
Пример #11
0
        private int removeelements(IntPtr L)
        {
            if (!IsXmlFileLoaded())
            {
                return(Melua.melua_error(L, "No XML file loaded."));
            }

            var selectors = new HashSet <string>();

            if (Melua.lua_isstring(L, -1))
            {
                var selector = Melua.luaL_checkstring(L, 1);
                Melua.lua_pop(L, 1);

                if (!IsXPathValid(selector))
                {
                    return(Melua.melua_error(L, "Invalid XPath."));
                }

                selectors.Add(selector);
            }
            else if (Melua.lua_istable(L, -1))
            {
                Melua.lua_pushnil(L);
                while (Melua.lua_next(L, -2) != 0)
                {
                    var selector = Melua.luaL_checkstring(L, -1);
                    Melua.lua_pop(L, 1);

                    if (!IsXPathValid(selector))
                    {
                        return(Melua.melua_error(L, "Invalid XPath."));
                    }

                    selectors.Add(selector);
                }
            }
            else
            {
                return(Melua.melua_error(L, "Invalid argument type '{0}'.", Melua.luaL_typename(L, -1)));
            }

            var modder = _loadedXmlModder;

            foreach (var selector in selectors)
            {
                _modPack.AddMod(new XmlElementRemover(modder, selector));
            }

            return(0);
        }
Пример #12
0
        /// <summary>
        /// Sends dialog message to client.
        /// </summary>
        /// <remarks>
        /// If message is a localization key (e.g. "ETC_20150317_000015"),
        /// the string is wrapped in a dict code, so the client looks it up
        /// in its dictionary.
        ///
        /// Parameters:
        /// - string message
        /// </remarks>
        /// <param name="L"></param>
        /// <returns></returns>
        private int msg(IntPtr L)
        {
            var conn = this.GetConnectionFromState(L);

            var msg = Melua.luaL_checkstring(L, 1);

            Melua.lua_pop(L, 1);

            this.HandleCustomCode(conn, ref msg);
            this.AttachNpcName(conn, ref msg);

            Send.ZC_DIALOG_OK(conn, msg);

            return(Melua.lua_yield(L, 0));
        }
Пример #13
0
        public void createtable()
        {
            var L = Melua.luaL_newstate();

            Melua.melua_openlibs(L);

            var rnd = new Random(Environment.TickCount);

            var foo      = 0;
            var bar      = "";
            var xyz      = "";
            var checkFoo = rnd.Next();
            var checkBar = rnd.Next().ToString("X8").Substring(1, 6);
            var checkXyz = rnd.Next().ToString("X8").Substring(2, 5);

            Melua.melua_register(L, "getdata", NL =>
            {
                Melua.melua_createtable(NL);
                Melua.melua_createfield(NL, "foo", checkFoo);
                Melua.melua_createfield(NL, "bar", checkBar);

                Melua.melua_startsubtable(NL, "foobar");
                Melua.melua_createfield(NL, "xyz", checkXyz);
                Melua.melua_endsubtable(NL);

                return(1);
            });

            Melua.melua_register(L, "checkdata", NL =>
            {
                foo = Melua.luaL_checkinteger(NL, 1);
                bar = Melua.luaL_checkstring(NL, 2);
                xyz = Melua.luaL_checkstring(NL, 3);

                Melua.lua_settop(L, 0);

                return(0);
            });

            var result = Melua.luaL_dostring(L, @"
local data = getdata()
checkdata(data.foo, data.bar, data.foobar.xyz)
");

            Assert.Equal(checkFoo, foo);
            Assert.Equal(checkBar, bar);
            Assert.Equal(checkXyz, xyz);
        }
Пример #14
0
        private int setattributes(IntPtr L)
        {
            if (!IsXmlFileLoaded())
            {
                return(Melua.melua_error(L, "No XML file loaded."));
            }

            var modder = _loadedXmlModder;

            var selector = Melua.luaL_checkstring(L, 1);

            if (!IsXPathValid(selector))
            {
                return(Melua.melua_error(L, "Invalid XPath."));
            }

            if (Melua.lua_isstring(L, 2) && Melua.lua_isstring(L, 3))
            {
                var attributeName  = Melua.lua_tostring(L, 2);
                var attributeValue = Melua.lua_tostring(L, 3);
                Melua.lua_pop(L, 2);

                _modPack.AddMod(new XmlAttributeSetter(modder, selector, attributeName, attributeValue));
            }
            else if (Melua.lua_istable(L, 2))
            {
                Melua.lua_pushnil(L);
                while (Melua.lua_next(L, -2) != 0)
                {
                    var attributeName  = Melua.luaL_checkstring(L, -2);
                    var attributeValue = Melua.luaL_checkstring(L, -1);
                    Melua.lua_pop(L, 1);

                    _modPack.AddMod(new XmlAttributeSetter(modder, selector, attributeName, attributeValue));
                }

                Melua.lua_pop(L, 1);
            }
            else
            {
                return(Melua.melua_error(L, "Invalid argument type."));
            }

            Melua.lua_pop(L, 1);

            return(0);
        }
Пример #15
0
        private int replace(IntPtr L)
        {
            if (!IsXmlFileLoaded())
            {
                return(Melua.melua_error(L, "No XML file loaded."));
            }

            var search  = Melua.luaL_checkstring(L, 1);
            var replace = Melua.luaL_checkstring(L, 2);

            Melua.lua_pop(L, 2);

            var modder = _loadedXmlModder;

            _modPack.AddMod(new XmlReplacer(modder, search, replace));

            return(0);
        }
Пример #16
0
        private int replacefile(IntPtr L)
        {
            var targetPath = Melua.luaL_checkstring(L, 1);
            var sourcePath = Melua.luaL_checkstring(L, 2);

            Melua.lua_pop(L, 2);

            targetPath = ModPack.NormalizePath(targetPath);
            sourcePath = ModPack.NormalizePath(sourcePath);

            var outPath    = Path.Combine("data", targetPath);
            var localPath  = Path.Combine(_cwd, sourcePath);
            var packPath   = sourcePath;
            var packReader = _modPack.GetPackReader();

            if (File.Exists(localPath))
            {
                if (!IsInsideCwd(localPath))
                {
                    return(Melua.melua_error(L, "Invalid path. ({0})", localPath));
                }

                _modPack.AddMod(new FileCopier(localPath, outPath));
            }
            else if (packReader.Exists(packPath))
            {
                var entry = packReader.GetEntry(packPath);
                var data  = entry.GetData();

                _modPack.AddMod(new FileSetter(outPath, data));
            }
            else
            {
                // TODO: Replace with string?
                return(Melua.melua_error(L, "File not found: {0}", sourcePath));
            }

            return(0);
        }
Пример #17
0
        /// <summary>
        /// Warps player to given location.
        /// </summary>
        /// <remarks>
        /// Parameters:
        /// - string mapName
        /// - number x
        /// - number y
        /// - number z
        /// </remarks>
        /// <param name="L"></param>
        /// <returns></returns>
        private int warp(IntPtr L)
        {
            var conn = this.GetConnectionFromState(L);

            var mapName = Melua.luaL_checkstring(L, 1);
            var x       = (float)Melua.luaL_checknumber(L, 2);
            var y       = (float)Melua.luaL_checknumber(L, 3);
            var z       = (float)Melua.luaL_checknumber(L, 4);

            Melua.lua_pop(L, 4);

            try
            {
                conn.SelectedCharacter.Warp(mapName, x, y, z);
            }
            catch (ArgumentException ex)
            {
                Melua.lua_pushstring(L, ex.Message);
                Melua.lua_error(L);
            }

            return(0);
        }
Пример #18
0
        /// <summary>
        /// Instructs client to open the shop with the given name
        /// and stops script until shop is closed.
        /// </summary>
        /// <remarks>
        /// Parameters:
        /// - string shopName
        /// </remarks>
        /// <param name="L"></param>
        /// <returns></returns>
        private int openshop(IntPtr L)
        {
            var conn = this.GetConnectionFromState(L);

            var shopName = Melua.luaL_checkstring(L, 1);

            if (shopName.Length > 32)
            {
                shopName = shopName.Substring(0, 32);
            }

            Melua.lua_pop(L, 1);

            if (!ChannelServer.Instance.Data.ShopDb.Exists(shopName))
            {
                return(Melua.melua_error(L, "Shop '{0}' not found.", shopName));
            }

            conn.ScriptState.CurrentShop = shopName;
            Send.ZC_DIALOG_TRADE(conn, shopName);

            return(Melua.lua_yield(L, 0));
        }
Пример #19
0
        /// <summary>
        /// Adds NPC to world.
        /// </summary>
        /// <remarks>
        /// The parameter `dialogFunctionName` can be the name of a Lua
        /// function name, the name of a client-side dialog, or a
        /// localization key. A client-side dialog controls the NPC name
        /// and appearance, while a localization key will simply send the
        /// key in one message. A Lua function allows for completely
        /// custom dialog.
        ///
        /// Parameters:
        /// - int monsterId
        /// - string name / dictId
        /// - string mapName
        /// - number x
        /// - number y
        /// - number z
        /// - int    direction
        /// - string dialogFunctionName
        /// </remarks>
        /// <param name="L"></param>
        /// <returns></returns>
        private int addnpc(IntPtr L)
        {
            var monsterId = Melua.luaL_checkinteger(L, 1);
            var name      = Melua.luaL_checkstring(L, 2);
            var mapName   = Melua.luaL_checkstring(L, 3);
            var x         = (float)Melua.luaL_checknumber(L, 4);
            var y         = (float)Melua.luaL_checknumber(L, 5);
            var z         = (float)Melua.luaL_checknumber(L, 6);
            var direction = Melua.luaL_checkinteger(L, 7);
            var dialog    = Melua.luaL_checkstring(L, 8);

            Melua.lua_pop(L, 8);

            var map = ChannelServer.Instance.World.GetMap(mapName);

            if (map == null)
            {
                return(Melua.melua_error(L, "Map '{0}' not found.", mapName));
            }

            // Wrap name in localization code if applicable
            if (this.IsLocalizationKey(name))
            {
                name = this.WrapLocalizationKey(name);
            }

            var monster = new Monster(monsterId, NpcType.NPC);

            monster.Name       = name;
            monster.DialogName = dialog;
            monster.Position   = new Position(x, y, z);
            monster.Direction  = new Direction(direction);

            map.AddMonster(monster);

            return(0);
        }
Пример #20
0
        /// <summary>
        /// Adds warp to world.
        /// </summary>
        /// <remarks>
        /// Parameters:
        /// - string warpName
        /// - number direction
        /// - string fromMapName
        /// - number fromX
        /// - number fromY
        /// - number fromZ
        /// - string toMapName
        /// - number toX
        /// - number toY
        /// - number toZ
        /// </remarks>
        /// <param name="L"></param>
        /// <returns></returns>
        private int addwarp(IntPtr L)
        {
            var warpName    = Melua.luaL_checkstring(L, 1);
            var direction   = Melua.luaL_checknumber(L, 2);
            var fromMapName = Melua.luaL_checkstring(L, 3);
            var fromX       = (float)Melua.luaL_checknumber(L, 4);
            var fromY       = (float)Melua.luaL_checknumber(L, 5);
            var fromZ       = (float)Melua.luaL_checknumber(L, 6);
            var toMapName   = Melua.luaL_checkstring(L, 7);
            var toX         = (float)Melua.luaL_checknumber(L, 8);
            var toY         = (float)Melua.luaL_checknumber(L, 9);
            var toZ         = (float)Melua.luaL_checknumber(L, 10);

            Melua.lua_pop(L, 10);

            // Check "from" map data
            var fromMapData = ChannelServer.Instance.Data.MapDb.Find(fromMapName);

            if (fromMapData == null)
            {
                return(Melua.melua_error(L, "Map '{0}' not found in data.", fromMapName));
            }

            // Check map in world
            var map = ChannelServer.Instance.World.GetMap(fromMapData.Id);

            if (map == null)
            {
                return(Melua.melua_error(L, "Map '{0}' not found in world.", fromMapName));
            }

            // Check "to" map data
            var toMapData = ChannelServer.Instance.Data.MapDb.Find(toMapName);

            if (toMapData == null)
            {
                return(Melua.melua_error(L, "Map '{0}' not found in data.", toMapName));
            }

            // It would be pointless to check the "to map in world" here,
            // since the target map could easily be on an entirely different
            // server. *This* channel may not have that map.

            // Get name, preferably a localization key
            var name = toMapName;

            if (toMapData.LocalKey != "?")
            {
                name = this.WrapLocalizationKey(toMapData.LocalKey);
            }

            // Create a warping monster...
            var monster = new Monster(40001, NpcType.NPC);

            monster.Name         = name;
            monster.WarpName     = warpName;
            monster.Position     = new Position(fromX, fromY, fromZ);
            monster.Direction    = new Direction(direction);
            monster.WarpLocation = new Location(toMapData.Id, toX, toY, toZ);

            map.AddMonster(monster);

            return(0);
        }
Пример #21
0
        /// <summary>
        /// Gets or sets a scripting variable.
        /// </summary>
        /// <remarks>
        /// Scripting variables are separate from Lua variables and exist
        /// across script and playing sessions. How the variable is saved
        /// depends on the used prefix.
        ///
        /// Variable names may contain the following characters, apart from
        /// the prefixes, and must start with a character:
        /// abcdefghijklmnopqrstuvwxyz0123456789_
        ///
        /// Prefixes:
        /// ""   - Permanent variable attached to the character.
        /// "@"  - Temporary variable attached to the character.
        /// "#"  - Permanent variable attached to the account.
        /// "$"  - Permanent global variable.
        /// "$@" - Temporary global variable.
        ///
        /// Parameters:
        /// - string variableName
        /// - (optional) T value
        ///
        /// Result:
        /// - T value
        /// </remarks>
        /// <param name="L"></param>
        /// <returns></returns>
        private int var(IntPtr L)
        {
            var conn      = this.GetConnectionFromState(L);
            var character = conn.SelectedCharacter;

            // Get parameters
            var argc = Melua.lua_gettop(L);
            var name = Melua.luaL_checkstring(L, 1).Trim();

            object value = null;

            if (argc == 2)
            {
                if (Melua.lua_isnumber(L, 2))
                {
                    value = Melua.lua_tonumber(L, 2);
                }
                else if (Melua.lua_isstring(L, 2))
                {
                    value = Melua.lua_tostring(L, 2);
                }
                else if (Melua.lua_isboolean(L, 2))
                {
                    value = Melua.lua_toboolean(L, 2);
                }
                else
                {
                    return(Melua.melua_error(L, "Unsupported variable type."));
                }
            }

            Melua.lua_pop(L, argc);

            // Get variable manager and trim name
            VariableManager vars;

            if (name.StartsWith("$@"))
            {
                vars = this.Variables.Temp;
                name = name.Substring(2);
            }
            else if (name.StartsWith("$"))
            {
                vars = this.Variables.Perm;
                name = name.Substring(1);
            }
            else if (name.StartsWith("#"))
            {
                vars = conn.Account.Variables.Perm;
                name = name.Substring(1);
            }
            else if (name.StartsWith("@"))
            {
                vars = character.Variables.Temp;
                name = name.Substring(1);
            }
            else
            {
                vars = character.Variables.Perm;
            }

            // Check name syntax, if we want to add more prefixes later on,
            // we can't have special characters in names.
            if (!VarNameCheck.IsMatch(name))
            {
                return(Melua.melua_error(L, "Invalid variable name."));
            }

            // Update or get value
            if (value == null)
            {
                value = vars[name];
            }
            else
            {
                vars[name] = value;
            }

            // Push return value
            if (value == null)
            {
                Melua.lua_pushnil(L);
            }
            else if (value is string)
            {
                Melua.lua_pushstring(L, (string)value);
            }
            else if (value is double)
            {
                Melua.lua_pushnumber(L, (double)value);
            }
            else if (value is float)
            {
                Melua.lua_pushnumber(L, (float)value);
            }
            else if (value is int)
            {
                Melua.lua_pushinteger(L, (int)value);
            }
            else if (value is bool)
            {
                Melua.lua_pushboolean(L, (bool)value);
            }
            else
            {
                return(Melua.melua_error(L, "Unsupported variable type '{0}'.", value.GetType().Name));
            }

            return(1);
        }