Beispiel #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));
        }
Beispiel #2
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));
        }
Beispiel #3
0
        /// <summary>
        /// Pushes the arguments onto the Lua stack.
        /// </summary>
        /// <param name="NL"></param>
        /// <param name="args"></param>
        private static void PushArguments(IntPtr NL, params object[] args)
        {
            foreach (var arg in args)
            {
                switch (arg)
                {
                case byte v: Melua.lua_pushinteger(NL, v); break;

                case bool v: Melua.lua_pushboolean(NL, v); break;

                case short v: Melua.lua_pushinteger(NL, v); break;

                case int v: Melua.lua_pushinteger(NL, v); break;

                case float v: Melua.lua_pushnumber(NL, v); break;

                case double v: Melua.lua_pushnumber(NL, v); break;

                case string v: Melua.lua_pushstring(NL, v); break;

                default:
                {
                    Log.Warning("ScriptManager.PushArguments: Invalid argument type '{0}', pushing 'int 0' instead.", arg.GetType().Name);
                    Melua.lua_pushinteger(NL, 0);
                    break;
                }
                }
            }
        }
Beispiel #4
0
        /// <summary>
        /// Removes the specified amount of items with the given id from
        /// character's inventory.
        /// </summary>
        /// <remarks>
        /// Parameters:
        /// - int itemId
        /// - int amount
        ///
        /// Result:
        /// - int removedCount
        /// </remarks>
        /// <param name="L"></param>
        /// <returns></returns>
        private int removeitem(IntPtr L)
        {
            var conn      = this.GetConnectionFromState(L);
            var character = conn.SelectedCharacter;

            var itemId = Melua.luaL_checkinteger(L, 1);
            var amount = Melua.luaL_checkinteger(L, 2);

            Melua.lua_pop(L, 2);

            var itemData = ChannelServer.Instance.Data.ItemDb.Find(itemId);

            if (itemData == null)
            {
                return(Melua.melua_error(L, "Unknown item id."));
            }

            amount = Math.Max(0, amount);

            var removed = character.Inventory.Remove(itemId, amount, InventoryItemRemoveMsg.Given);

            Melua.lua_pushinteger(L, removed);

            return(1);
        }
Beispiel #5
0
        /// <summary>
        /// Returns table, containing information about the current date/time.
        /// </summary>
        /// <remarks>
        /// Result:
        /// {
        ///		integer year,     -- Current year
        ///		integer month,    -- Current month
        ///		integer day,      -- Current day
        ///		integer weekday,  -- Day of the week (0-6), starting on Sunday
        ///		integer yearday,  -- Day of the current year
        ///		integer hour,     -- Current hours (0-23)
        ///		integer min,      -- Current minutes (0-59)
        ///		integer sec,      -- Current seconds (0-59)
        ///		integer msec,     -- Current milliseconds (0-999)
        ///		boolean isdst,    -- Is Daylight Saving Time?
        ///		integer unixts,   -- Unix timestamp
        /// }
        /// </remarks>
        /// <param name="L"></param>
        /// <returns></returns>
        private int gettime(IntPtr L)
        {
            var now = DateTime.Now;

            // TODO: Could a general table generation like this be cached?

            Melua.lua_newtable(L);

            Melua.lua_pushstring(L, "year");
            Melua.lua_pushinteger(L, now.Year);
            Melua.lua_settable(L, -3);

            Melua.lua_pushstring(L, "month");
            Melua.lua_pushinteger(L, now.Month);
            Melua.lua_settable(L, -3);

            Melua.lua_pushstring(L, "day");
            Melua.lua_pushinteger(L, now.Day);
            Melua.lua_settable(L, -3);

            Melua.lua_pushstring(L, "weekday");
            Melua.lua_pushinteger(L, (int)now.DayOfWeek);
            Melua.lua_settable(L, -3);

            Melua.lua_pushstring(L, "yearday");
            Melua.lua_pushinteger(L, now.DayOfYear);
            Melua.lua_settable(L, -3);

            Melua.lua_pushstring(L, "hour");
            Melua.lua_pushinteger(L, now.Hour);
            Melua.lua_settable(L, -3);

            Melua.lua_pushstring(L, "min");
            Melua.lua_pushinteger(L, now.Minute);
            Melua.lua_settable(L, -3);

            Melua.lua_pushstring(L, "sec");
            Melua.lua_pushinteger(L, now.Second);
            Melua.lua_settable(L, -3);

            Melua.lua_pushstring(L, "msec");
            Melua.lua_pushinteger(L, now.Millisecond);
            Melua.lua_settable(L, -3);

            Melua.lua_pushstring(L, "isdst");
            Melua.lua_pushboolean(L, now.IsDaylightSavingTime());
            Melua.lua_settable(L, -3);

            Melua.lua_pushstring(L, "unixts");
            Melua.lua_pushinteger(L, (int)(now.ToUniversalTime().Subtract(UnixEpoch)).TotalSeconds);
            Melua.lua_settable(L, -3);

            return(1);
        }
Beispiel #6
0
        public void typename()
        {
            var L = Melua.luaL_newstate();

            Melua.lua_pushinteger(L, 123);
            Assert.Equal("number", Melua.luaL_typename(L, -1));

            Melua.lua_pushstring(L, "123");
            Assert.Equal("string", Melua.luaL_typename(L, -1));

            Melua.lua_newtable(L);
            Assert.Equal("table", Melua.luaL_typename(L, -1));
        }
Beispiel #7
0
        public void type()
        {
            var L = Melua.luaL_newstate();

            Melua.lua_pushinteger(L, 123);
            Assert.Equal(Melua.LUA_TNUMBER, Melua.lua_type(L, -1));

            Melua.lua_pushstring(L, "123");
            Assert.Equal(Melua.LUA_TSTRING, Melua.lua_type(L, -1));

            Melua.lua_newtable(L);
            Assert.Equal(Melua.LUA_TTABLE, Melua.lua_type(L, -1));
        }
Beispiel #8
0
        /// <summary>
        /// Returns a table with information about the player.
        /// </summary>
        /// <remarks>
        /// Result:
        /// {
        ///		string  name,     -- Character's name
        ///		string  teamName, -- Character's team name
        ///		integer gender,   -- Character's gender
        ///		integer level,    -- Character's level
        ///		integer hp,       -- Character's HP
        ///		integer maxHp,    -- Character's max HP
        ///		integer sp,       -- Character's SP
        ///		integer maxSp,    -- Character's max SP
        ///		integer stamina,  -- Character's stamina
        ///		integer hair,     -- Character's hair
        /// }
        /// </remarks>
        /// <param name="L"></param>
        /// <returns></returns>
        private int getpc(IntPtr L)
        {
            var conn      = this.GetConnectionFromState(L);
            var character = conn.SelectedCharacter;

            Melua.lua_newtable(L);

            Melua.lua_pushstring(L, "name");
            Melua.lua_pushstring(L, character.Name);
            Melua.lua_settable(L, -3);

            Melua.lua_pushstring(L, "teamName");
            Melua.lua_pushstring(L, character.TeamName);
            Melua.lua_settable(L, -3);

            Melua.lua_pushstring(L, "gender");
            Melua.lua_pushinteger(L, (int)character.Gender);
            Melua.lua_settable(L, -3);

            Melua.lua_pushstring(L, "level");
            Melua.lua_pushinteger(L, character.Level);
            Melua.lua_settable(L, -3);

            Melua.lua_pushstring(L, "hp");
            Melua.lua_pushinteger(L, character.Hp);
            Melua.lua_settable(L, -3);

            Melua.lua_pushstring(L, "maxHp");
            Melua.lua_pushinteger(L, character.MaxHp);
            Melua.lua_settable(L, -3);

            Melua.lua_pushstring(L, "sp");
            Melua.lua_pushinteger(L, character.Sp);
            Melua.lua_settable(L, -3);

            Melua.lua_pushstring(L, "maxSp");
            Melua.lua_pushinteger(L, character.MaxSp);
            Melua.lua_settable(L, -3);

            Melua.lua_pushstring(L, "stamina");
            Melua.lua_pushinteger(L, character.Stamina);
            Melua.lua_settable(L, -3);

            Melua.lua_pushstring(L, "hair");
            Melua.lua_pushinteger(L, character.Hair);
            Melua.lua_settable(L, -3);

            return(1);
        }
Beispiel #9
0
        /// <summary>
        /// Returns amount of items with the given id in character's inventory.
        /// </summary>
        /// <remarks>
        /// Parameters:
        /// - int itemId
        ///
        /// Result:
        /// - int amount
        /// </remarks>
        /// <param name="L"></param>
        /// <returns></returns>
        private int countitem(IntPtr L)
        {
            var conn      = this.GetConnectionFromState(L);
            var character = conn.SelectedCharacter;

            var itemId = Melua.luaL_checkinteger(L, 1);

            Melua.lua_pop(L, 1);

            var result = character.Inventory.CountItem(itemId);

            Melua.lua_pushinteger(L, result);

            return(1);
        }
Beispiel #10
0
        public void tostring()
        {
            var L = Melua.luaL_newstate();

            Melua.lua_pushinteger(L, 123);
            var str = Melua.lua_tostring(L, -1);

            Assert.Equal("123", str);

            Melua.lua_newtable(L);
            Assert.Equal(null, Melua.lua_tostring(L, -1));

            Melua.lua_pushstring(L, "foobar");
            Assert.Equal("foobar", Melua.lua_tostring(L, -1));
        }
Beispiel #11
0
        /// <summary>
        /// Resumes script after yielding.
        /// </summary>
        /// <param name="conn"></param>
        /// <param name="argument"></param>
        public void Resume(ChannelConnection conn, params object[] arguments)
        {
            if (conn.ScriptState.LuaThread == null)
            {
                Send.ZC_DIALOG_CLOSE(conn);
                Log.Warning("ScriptManager: Resume on empty ScriptState from user '{0}'.", conn.Account.Name);
                return;
            }

            var NL   = conn.ScriptState.LuaThread.L;
            var argc = (arguments != null ? arguments.Length : 0);

            // Reset current shop in case we came from one.
            conn.ScriptState.CurrentShop = null;

            if (argc != 0)
            {
                foreach (var arg in arguments)
                {
                    if (arg is byte)
                    {
                        Melua.lua_pushinteger(NL, (byte)arg);
                    }
                    else if (arg is short)
                    {
                        Melua.lua_pushinteger(NL, (short)arg);
                    }
                    else if (arg is int)
                    {
                        Melua.lua_pushinteger(NL, (int)arg);
                    }
                    else if (arg is string)
                    {
                        Melua.lua_pushstring(NL, (string)arg);
                    }
                    else
                    {
                        Log.Warning("ScriptManager.Resume: Invalid argument type '{0}'.", arg.GetType().Name);
                        Melua.lua_pushinteger(NL, 0);
                    }
                }

                // If arguments were passed, we can assume we're coming from
                // a selection handler, which's windows don't disappear when
                // sending the next message. So let's close it before
                // continuing.
                Send.ZC_DIALOG_CLOSE(conn);
            }

            var result = Melua.lua_resume(NL, argc);

            // Log error if result is not success or yield
            if (result != 0 && result != Melua.LUA_YIELD)
            {
                Log.Error("ScriptManager.Call: Error while resuming script for {0}.\n{1}", conn.Account.Name, Melua.lua_tostring(NL, -1));
                result = 0;                 // Set to 0 to close dialog on error
            }

            // Close dialog if end of function was reached
            if (result == 0)
            {
                // Only close from here if the end was reached after an
                // argument-less resume, since close is already called
                // from the argument handling to get rid of the selection
                // dialog.
                if (argc == 0)
                {
                    Send.ZC_DIALOG_CLOSE(conn);
                }

                conn.ScriptState.Reset();
            }
        }
Beispiel #12
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);
        }
Beispiel #13
0
        public void userdata()
        {
            var L = Melua.luaL_newstate();

            Melua.melua_opensafelibs(L);

            var n1 = 0;

            // Ctor
            Melua.luaL_register(L, "Test", new[]
            {
                new MeluaLib.Melua.LuaLib("new", NL =>
                {
                    var test = new UserDataTest()
                    {
                        N1 = 1234
                    };
                    var size = Marshal.SizeOf(test);

                    var ptr = Melua.lua_newuserdata(L, size);
                    Melua.luaL_getmetatable(L, "Melua.Test");
                    Melua.lua_setmetatable(L, -2);

                    Marshal.StructureToPtr(test, ptr, true);

                    return(1);
                })
            });

            // Meta table for test userdata type
            Melua.luaL_newmetatable(L, "Melua.Test");
            Melua.lua_pushstring(L, "__index");
            Melua.lua_pushvalue(L, -2);
            Melua.lua_settable(L, -3);

            Melua.luaL_register(L, null, new[]
            {
                new MeluaLib.Melua.LuaLib("setN1", _ =>
                {
                    var ptr = Melua.luaL_checkudata(L, 1, "Melua.Test");
                    var val = Melua.luaL_checkinteger(L, 2);

                    // Either marshal back and forth or use unsafe
                    var test = (UserDataTest)Marshal.PtrToStructure(ptr, typeof(UserDataTest));
                    test.N1  = val;
                    Marshal.StructureToPtr(test, ptr, true);

                    //unsafe
                    //{
                    //	var test = (UserDataTest*)ptr;
                    //	test->N1 = val;
                    //}

                    return(0);
                }),
                new MeluaLib.Melua.LuaLib("getN1", _ =>
                {
                    var ptr  = Melua.luaL_checkudata(L, 1, "Melua.Test");
                    var test = (UserDataTest)Marshal.PtrToStructure(ptr, typeof(UserDataTest));

                    Melua.lua_pushinteger(L, test.N1);

                    return(1);
                })
            });

            // Test method
            Melua.melua_register(L, "testgetn1", _ =>
            {
                n1 = Melua.lua_tointeger(L, -1);

                return(0);
            });

            var result = Melua.luaL_dostring(L, @"
local t = Test.new()
t:setN1(5678)
testgetn1(t:getN1())
");

            if (result != 0)
            {
                throw new Exception(Melua.lua_tostring(L, -1));
            }

            Assert.Equal(n1, 5678);
        }