From f9ad932717a674cc78735d6424cbabe89adec60f Mon Sep 17 00:00:00 2001 From: Ruin0x11 Date: Thu, 9 Sep 2021 13:08:52 -0700 Subject: [PATCH 01/17] Typechecking, version 1 --- src/.luacheckrc | 1 + src/boot.lua | 5 +- src/internal/env.lua | 3 + src/scratch/2021-09-09_11-36-07.lua | 15 ++ src/util/class.lua | 2 - src/util/types.lua | 368 ++++++++++++++++++++++++++++ 6 files changed, 390 insertions(+), 4 deletions(-) create mode 100644 src/scratch/2021-09-09_11-36-07.lua create mode 100644 src/util/types.lua diff --git a/src/.luacheckrc b/src/.luacheckrc index 97fc9c9de..3c639bb6b 100644 --- a/src/.luacheckrc +++ b/src/.luacheckrc @@ -12,6 +12,7 @@ globals = { "_IS_LOVEJS", "love", "class", + "types", "inspect", "fun", "_ppr", diff --git a/src/boot.lua b/src/boot.lua index 013dfd52f..95580ce47 100644 --- a/src/boot.lua +++ b/src/boot.lua @@ -42,10 +42,11 @@ if _DEBUG then _CONSOLE = true end -class = require("util.class") - require("ext") +class = require("util.class") +types = require("util.types") + inspect = require("thirdparty.inspect") fun = require("thirdparty.fun") diff --git a/src/internal/env.lua b/src/internal/env.lua index 559581919..66e1c46c8 100644 --- a/src/internal/env.lua +++ b/src/internal/env.lua @@ -62,6 +62,9 @@ local SANDBOX_GLOBALS = { -- OOP library "class", + -- Typechecking + "types", + -- misc. globals "inspect", "fun", diff --git a/src/scratch/2021-09-09_11-36-07.lua b/src/scratch/2021-09-09_11-36-07.lua new file mode 100644 index 000000000..1b63a7903 --- /dev/null +++ b/src/scratch/2021-09-09_11-36-07.lua @@ -0,0 +1,15 @@ +print(inspect(types)) + +print(inspect(types.check(1, types.number))) +print(types.check(false, types.number)) +print(types.check({a = 1}, types.fields { a = types.string })) + +local InstancedMap = require("api.InstancedMap") +local m = InstancedMap:new(10, 10) + +print(types.check({a = {b = m}}, types.fields { a = types.fields { b = types.string }})) +print(types.check({a = {b = m}}, types.fields { a = types.fields { b = types.class(InstancedMap) }})) + +-- Local Variables: +-- open-nefia-always-send-to-repl: t +-- End: diff --git a/src/util/class.lua b/src/util/class.lua index 5435cf9be..3488dc372 100644 --- a/src/util/class.lua +++ b/src/util/class.lua @@ -496,14 +496,12 @@ function class.uses_interface(klass_or_iface, iface) for _, i in ipairs(ifaces) do if iface == i then - print("find " .. " " .. klass_or_iface.__name .. " " .. iface.__name .. " " .. i.__name) return true end local children = _iface_children[iface] or {} for _, child in ipairs(children) do if class.uses_interface(klass_or_iface, child) then - print("find " .. " " .. klass_or_iface.__name .. " " .. iface.__name .. " " .. i.__name) return true end end diff --git a/src/util/types.lua b/src/util/types.lua new file mode 100644 index 000000000..4536b97dd --- /dev/null +++ b/src/util/types.lua @@ -0,0 +1,368 @@ +local types = {} + +local ctxt_mt = {} +ctxt_mt.__index = ctxt_mt + +function ctxt_mt:push(key, value) + self.stack[#self.stack+1] = { + key = key, + value = value + } +end + +function ctxt_mt:pop() + self.stack[#self.stack] = nil +end + +local function smart_quote(str) + if str:match('"') and not str:match("'") then + return "'" .. str .. "'" + end + return '"' .. str:gsub('"', '\\"') .. '"' +end + +local INSPECT_OPTIONS = { + newline = " ", indent = "", max_length = 16, +} + +local function get_name(obj) + if type(obj) == "string" then + return smart_quote(obj) + elseif type(obj) == "table" then + if class.is_class_instance(obj) then + return tostring(obj) + end + return inspect(obj, INSPECT_OPTIONS) + end + + return tostring(obj) +end + +function ctxt_mt:make_trail(obj) + local seen = {obj = true} + local s = { get_name(obj, seen) } + for _, entry in ipairs(self.stack) do + s[#s+1] = "[" + s[#s+1] = get_name(entry.key) + s[#s+1] = "]" + if entry.value then + s[#s+1] = " -> " + s[#s+1] = get_name(entry.value) + end + end + return table.concat(s) +end + +local function make_ctxt() + local t = { + stack = {} + } + return setmetatable(t, ctxt_mt) +end + +local names = {} + +-- +-- single-value checkers +-- + +local function primitive(ty) + return function(obj, _ctxt) + if type(obj) == ty then + return true + end + return false, ty + end +end + +local primitives = { + "nil", + "boolean", + "string", + "table", + "function", + "userdata", + "thread" +} + +for _, ty in ipairs(primitives) do + types[ty] = primitive(ty) +end + +local function is_nan(obj) + -- According to IEEE 754, a nan value is considered not equal to any value, + -- including itself. + return obj ~= obj +end + +function types.number(obj, _ctxt) + if type(obj) == "number" and not is_nan(obj) then + return true + end + return false, names[types.number] +end + +function types.nan(obj, _ctxt) + if type(obj) == "number" and is_nan(obj) then + return true + end + return false, names[types.nan] +end + +function types.integer(obj, _ctxt) + if math.type(obj) == "integer" and not is_nan(obj) then + return true + end + return false, names[types.integer] +end + +function types.float(obj, _ctxt) + if math.type(obj) == "float" and not is_nan(obj) then + return true + end + return false, names[types.float] +end + +function types.class_type(obj, _ctxt) + if class.is_class(obj) then + return true + end + + return false, "class type" +end + +function types.interface_type(obj, _ctxt) + if class.is_class(obj) then + return true + end + + return false, "interface type" +end + +-- +-- higher-order checkers +-- + +local function is_enum(tbl) + -- see api/Enum.lua + return tbl.__enum == true +end + +function types.enum(enum) + assert(is_enum(enum), ("%s is not an enum"):format(enum)) + return function(obj, _ctxt) + if enum:has_value(obj) then + return true + end + + return false, ("member of %s"):format(enum) + end +end + +function types.class(klass) + assert(class.is_class(klass), ("%s is not a class"):format(klass)) + return function(obj, _ctxt) + if class.is_an(klass, obj) then + return true + end + + return false, tostring(klass) + end +end + +function types.implements(iface) + assert(class.is_interface(iface), ("%s is not an interface"):format(iface)) + return function(obj, _ctxt) + if class.is_an(iface, obj) then + return true + end + + return false, tostring(iface) + end +end + +function types.optional(checker) + return function(obj, ctxt) + if obj == nil then + return true + end + + local ok, err = checker(obj, ctxt) + if not ok then + return false, ("optional<%s>"):format(err) + end + + return true + end +end + +function types.keys(checker) + return function(obj, ctxt) + if not types.table(obj, ctxt) then + return false, "table" + end + + for key, _ in pairs(obj) do + ctxt:push(key) + local ok, err = checker(key) + if not ok then + return false, err + end + ctxt:pop() + end + + return true + end +end + +function types.values(checker) + return function(obj, ctxt) + if not types.table(obj, ctxt) then + return false, "table" + end + + for key, val in pairs(obj) do + ctxt:push_value(key, val) + local ok, err = checker(val) + if not ok then + return false, err + end + ctxt:pop() + end + + return true + end +end + +function types.map(key_checker, value_checker) + return function(obj, ctxt) + if not types.table(obj, ctxt) then + return false, "table" + end + + for key, val in pairs(obj) do + ctxt:push(key) + local ok, err = key_checker(key, ctxt) + if not ok then + return false, err + end + ctxt:pop() + + ctxt:push_value(key, val) + ok, err = value_checker(val, ctxt) + if not ok then + return false, err + end + ctxt:pop() + end + + return true + end +end + +function types.set(value_checker) + return types.map(types.boolean, value_checker) +end + +function types.any(...) + local checkers = { ... } + + return function(obj, ctxt) + for _, checker in ipairs(checkers) do + if checker(obj, ctxt) then + return true + end + end + + local s = {} + for _, checker in ipairs(checkers) do + s[#s+1] = names[checker] + end + return false, ("any<%s>"):format(table.concat(s, ", ")) + end +end + +function types.all(...) + local checkers = { ... } + + return function(obj, ctxt) + for i, checker in ipairs(checkers) do + local ok, err = checker(obj, ctxt) + if not ok then + return false, err + end + end + + return true + end +end + +function types.fields(kvs) + return function(obj, ctxt) + if not types.table(obj, ctxt) then + return false, "table" + end + + for key, checker in pairs(kvs) do + ctxt:push(key) + local ok, err = checker(obj[key], ctxt) + if not ok then + return false, err + end + ctxt:pop() + end + + return true + end +end + +function types.fields_strict(kvs) + return function(obj, ctxt) + if not types.table(obj, ctxt) then + return false + end + + for key, val in pairs(obj) do + local checker = kvs[key] + if not checker then + return false + end + + ctxt:push(key) + if not checker(val, ctxt) then + return false + end + ctxt:pop() + end + + return true + end +end + +for key, checker in pairs(types) do + names[checker] = key +end + +function types.check(obj, checker) + local ctxt = make_ctxt() + local success, needed_ty = checker(obj, ctxt) + if not success then + needed_ty = needed_ty or "" + return false, ("Typecheck failed - Value is not of type \"%s\": %s"):format(needed_ty, ctxt:make_trail(obj)) + end + return true +end + +function types.wrap(checker) + return function(obj) + return types.check(obj, checker) + end +end + +function types.wrap_strict(checker) + return function(obj) + return assert(types.check(obj, checker)) + end +end + +return types From f9d745019b2343384f36f328823876a63522dd48 Mon Sep 17 00:00:00 2001 From: Ruin0x11 Date: Thu, 9 Sep 2021 13:49:14 -0700 Subject: [PATCH 02/17] Typechecking, version 2 --- src/scratch/2021-09-09_11-36-07.lua | 4 +- src/util/types.lua | 427 +++++++++++++++++++++------- 2 files changed, 321 insertions(+), 110 deletions(-) diff --git a/src/scratch/2021-09-09_11-36-07.lua b/src/scratch/2021-09-09_11-36-07.lua index 1b63a7903..d7e33026e 100644 --- a/src/scratch/2021-09-09_11-36-07.lua +++ b/src/scratch/2021-09-09_11-36-07.lua @@ -3,12 +3,14 @@ print(inspect(types)) print(inspect(types.check(1, types.number))) print(types.check(false, types.number)) print(types.check({a = 1}, types.fields { a = types.string })) +print(types.check({a = "b"}, types.fields { a = types.string })) local InstancedMap = require("api.InstancedMap") local m = InstancedMap:new(10, 10) print(types.check({a = {b = m}}, types.fields { a = types.fields { b = types.string }})) -print(types.check({a = {b = m}}, types.fields { a = types.fields { b = types.class(InstancedMap) }})) +print(types.check({a = {b = m}}, types.fields { a = types.fields { b = types.instance_of(InstancedMap) }})) +print(types.check(m, types.instance_of(InstancedMap))) -- Local Variables: -- open-nefia-always-send-to-repl: t diff --git a/src/util/types.lua b/src/util/types.lua index 4536b97dd..168da48bb 100644 --- a/src/util/types.lua +++ b/src/util/types.lua @@ -60,19 +60,31 @@ local function make_ctxt() return setmetatable(t, ctxt_mt) end -local names = {} - -- -- single-value checkers -- -local function primitive(ty) - return function(obj, _ctxt) - if type(obj) == ty then - return true - end - return false, ty +local ITypeChecker = class.interface("ITypeChecker", { check = "function" }) + +local function is_type_checker(obj) + if not class.is_an(ITypeChecker, obj) then + return false, ("%s is not a type checker"):format(obj) + end + return true +end + +local primitive_checker = class.class("primitive_checker", ITypeChecker) +function primitive_checker:init(ty) + self.type = ty +end +function primitive_checker:check(obj, ctxt) + if type(obj) == self.type then + return true end + return false, tostring(self) +end +function primitive_checker:__tostring() + return self.type end local primitives = { @@ -86,7 +98,7 @@ local primitives = { } for _, ty in ipairs(primitives) do - types[ty] = primitive(ty) + types[ty] = primitive_checker:new(ty) end local function is_nan(obj) @@ -95,217 +107,390 @@ local function is_nan(obj) return obj ~= obj end -function types.number(obj, _ctxt) - if type(obj) == "number" and not is_nan(obj) then - return true +do + local number_checker = class.class("primitive_checker", ITypeChecker) + function number_checker:check(obj, _ctxt) + if type(obj) == "number" and not is_nan(obj) then + return true + end + return false, tostring(self) end - return false, names[types.number] + function number_checker:__tostring() + return "number" + end + types.number = number_checker:new() end -function types.nan(obj, _ctxt) - if type(obj) == "number" and is_nan(obj) then - return true +do + local nan_checker = class.class("nan_checker", ITypeChecker) + function nan_checker:check(obj, _ctxt) + if type(obj) == "number" and is_nan(obj) then + return true + end + return false, tostring(self) end - return false, names[types.nan] + function nan_checker:__tostring() + return "nan" + end + types.nan = nan_checker:new() end -function types.integer(obj, _ctxt) - if math.type(obj) == "integer" and not is_nan(obj) then - return true +do + local integer_checker = class.class("integer_checker", ITypeChecker) + function integer_checker:check(obj, _ctxt) + if math.type(obj) == "integer" and not is_nan(obj) then + return true + end + return false, tostring(self) + end + function integer_checker:__tostring() + return "integer" end - return false, names[types.integer] + types.integer = integer_checker:new() end -function types.float(obj, _ctxt) - if math.type(obj) == "float" and not is_nan(obj) then - return true +do + local float_checker = class.class("float_checker", ITypeChecker) + function float_checker:check(obj, _ctxt) + if math.type(obj) == "float" and not is_nan(obj) then + return true + end + return false, tostring(self) end - return false, names[types.float] + types.float = float_checker:new() end -function types.class_type(obj, _ctxt) - if class.is_class(obj) then - return true - end +do + local class_type_checker = class.class("class_type_checker", ITypeChecker) + function class_type_checker:check(obj, _ctxt) + if class.is_class(obj) then + return true + end - return false, "class type" + return false, tostring(self) + end + function class_type_checker:__tostring() + return "class type" + end + types.class_type = class_type_checker:new() end -function types.interface_type(obj, _ctxt) - if class.is_class(obj) then - return true +do + local interface_type_checker = class.class("interface_type_checker", ITypeChecker) + function interface_type_checker:check(obj, _ctxt) + if class.is_interface(obj) then + return true + end + + return false, tostring(self) + end + function interface_type_checker:__tostring() + return "interface type" end + types.interface_type = interface_type_checker:new() +end + +local function is_enum(tbl) + -- see api/Enum.lua + return tbl.__enum == true +end - return false, "interface type" +do + local enum_type_checker = class.class("enum_type_checker", ITypeChecker) + function enum_type_checker:check(obj, _ctxt) + if is_enum(obj) then + return true + end + + return false, tostring(self) + end + function enum_type_checker:__tostring() + return "enum type" + end + types.enum_type = enum_type_checker:new() end -- -- higher-order checkers -- -local function is_enum(tbl) - -- see api/Enum.lua - return tbl.__enum == true +local function wrap(klass) + return function(...) + return klass:new(...) + end end -function types.enum(enum) - assert(is_enum(enum), ("%s is not an enum"):format(enum)) - return function(obj, _ctxt) - if enum:has_value(obj) then +do + local enum_checker = class.class("enum_checker", ITypeChecker) + function enum_checker:init(enum) + assert(is_enum(enum), ("%s is not an enum"):format(enum)) + self.enum = enum + end + function enum_checker:check(obj, _ctxt) + if self.enum:has_value(obj) then return true end - return false, ("member of %s"):format(enum) + return false, tostring(self) end + function enum_checker:__tostring() + return "enum type" + end + types.enum = wrap(enum_checker) end -function types.class(klass) - assert(class.is_class(klass), ("%s is not a class"):format(klass)) - return function(obj, _ctxt) - if class.is_an(klass, obj) then +do + local instance_of_checker = class.class("instance_of_checker", ITypeChecker) + function instance_of_checker:init(klass) + assert(class.is_class(klass), ("%s is not a class"):format(klass)) + self.class = klass + end + function instance_of_checker:check(obj, _ctxt) + if class.is_an(self.class, obj) then return true end - return false, tostring(klass) + return false, tostring(self) end + function instance_of_checker:__tostring() + return tostring(self.class) + end + types.instance_of = wrap(instance_of_checker) end -function types.implements(iface) - assert(class.is_interface(iface), ("%s is not an interface"):format(iface)) - return function(obj, _ctxt) - if class.is_an(iface, obj) then +do + local implements_checker = class.class("implements_checker", ITypeChecker) + function implements_checker:init(iface) + assert(class.is_interface(iface), ("%s is not an interface"):format(iface)) + self.iface = iface + end + function implements_checker:check(obj, _ctxt) + if class.is_an(self.iface, obj) then return true end - return false, tostring(iface) + return false, tostring(self) end + function implements_checker:__tostring() + return tostring(self.iface) + end + types.implements = wrap(implements_checker) end -function types.optional(checker) - return function(obj, ctxt) +do + local optional_checker = class.class("optional_checker", ITypeChecker) + function optional_checker:init(checker) + assert(is_type_checker(checker)) + self.checker = checker + end + function optional_checker:check(obj, ctxt) if obj == nil then return true end - local ok, err = checker(obj, ctxt) + local ok, _err = self.checker:check(obj, ctxt) if not ok then - return false, ("optional<%s>"):format(err) + return false, tostring(self) end return true end + function optional_checker:__tostring() + return ("optional<%s>"):format(self.checker) + end + types.optional = wrap(optional_checker) end -function types.keys(checker) - return function(obj, ctxt) - if not types.table(obj, ctxt) then +do + local keys_checker = class.class("keys_checker", ITypeChecker) + function keys_checker:init(checker) + assert(is_type_checker(checker)) + self.checker = checker + end + function keys_checker:check(obj, ctxt) + if not types.table:check(obj, ctxt) then return false, "table" end for key, _ in pairs(obj) do ctxt:push(key) - local ok, err = checker(key) + local ok, _err = self.checker:check(key) if not ok then - return false, err + return false, tostring(self) end ctxt:pop() end return true end + function keys_checker:__tostring() + return ("keys<%s>"):format(self.checker) + end + types.keys = wrap(keys_checker) end -function types.values(checker) - return function(obj, ctxt) - if not types.table(obj, ctxt) then +do + local values_checker = class.class("values_checker", ITypeChecker) + function values_checker:init(checker) + assert(is_type_checker(checker)) + self.checker = checker + end + function values_checker:check(obj, ctxt) + if not types.table:check(obj, ctxt) then return false, "table" end for key, val in pairs(obj) do ctxt:push_value(key, val) - local ok, err = checker(val) + local ok, _err = self.checker:check(val) if not ok then - return false, err + return false, tostring(self) end ctxt:pop() end return true end + function values_checker:__tostring() + return ("values<%s>"):format(self.checker) + end + types.values = wrap(values_checker) end -function types.map(key_checker, value_checker) - return function(obj, ctxt) - if not types.table(obj, ctxt) then +do + local map_checker = class.class("map_checker", ITypeChecker) + function map_checker:init(key_checker, value_checker) + assert(is_type_checker(key_checker)) + assert(is_type_checker(value_checker)) + self.key_checker = key_checker + self.value_checker = value_checker + end + function map_checker:check(obj, ctxt) + if not types.table:check(obj, ctxt) then return false, "table" end for key, val in pairs(obj) do ctxt:push(key) - local ok, err = key_checker(key, ctxt) + local ok, _err = self.key_checker:check(key, ctxt) if not ok then - return false, err + return false, tostring(self) end ctxt:pop() ctxt:push_value(key, val) - ok, err = value_checker(val, ctxt) + ok, _err = self.value_checker:check(val, ctxt) if not ok then - return false, err + return false, tostring(self) end ctxt:pop() end return true end + function map_checker:__tostring() + return ("map<%s, %s>"):format(self.key_checker, self.value_checker) + end + types.map = wrap(map_checker) end function types.set(value_checker) return types.map(types.boolean, value_checker) end -function types.any(...) - local checkers = { ... } - - return function(obj, ctxt) +do + local any_checker = class.class("any_checker", ITypeChecker) + function any_checker:init(...) + local checkers = { ... } for _, checker in ipairs(checkers) do + assert(is_type_checker(checker)) + end + self.checkers = checkers + end + function any_checker:check(obj, ctxt) + for _, checker in ipairs(self.checkers) do if checker(obj, ctxt) then return true end end - + return false, tostring(self) + end + function any_checker:__tostring() local s = {} - for _, checker in ipairs(checkers) do - s[#s+1] = names[checker] + for i, checker in ipairs(self.checkers) do + if i > 10 then + s[#s+1] = "..." + break + end + s[#s+1] = tostring(checker) end - return false, ("any<%s>"):format(table.concat(s, ", ")) + return ("any<%s>"):format(table.concat(", ")) end + types.any = wrap(any_checker) end -function types.all(...) - local checkers = { ... } - - return function(obj, ctxt) - for i, checker in ipairs(checkers) do +do + local all_checker = class.class("all_checker", ITypeChecker) + function all_checker:init(...) + local checkers = { ... } + for _, checker in ipairs(checkers) do + assert(is_type_checker(checker)) + end + self.checkers = checkers + end + function all_checker:check(obj, ctxt) + for _, checker in ipairs(self.checkers) do local ok, err = checker(obj, ctxt) if not ok then return false, err end end - return true end + function all_checker:__tostring() + local s = {} + for i, checker in ipairs(self.checkers) do + if i > 10 then + s[#s+1] = "..." + break + end + s[#s+1] = tostring(checker) + end + return ("all<%s>"):format(table.concat(", ")) + end + types.all = wrap(all_checker) end -function types.fields(kvs) - return function(obj, ctxt) - if not types.table(obj, ctxt) then +local function print_fields(fields) + local s = {} + local i = 0 + for key, checker in pairs(fields) do + if i > 10 then + s[#s+1] = "..." + break + end + s[#s+1] = get_name(key) .. "=" .. tostring(checker) + i = i + 1 + end + return table.concat(s, ", ") +end + +do + local fields_checker = class.class("fields_checker", ITypeChecker) + function fields_checker:init(fields) + for _, checker in pairs(fields) do + assert(is_type_checker(checker)) + end + self.fields = fields + end + function fields_checker:check(obj, ctxt) + if not types.table:check(obj, ctxt) then return false, "table" end - for key, checker in pairs(kvs) do - ctxt:push(key) - local ok, err = checker(obj[key], ctxt) + for key, checker in pairs(self.fields) do + ctxt:push(key, obj[key]) + local ok, err = checker:check(obj[key], ctxt) if not ok then return false, err end @@ -314,41 +499,65 @@ function types.fields(kvs) return true end + function fields_checker:__tostring() + return ("fields<%s>"):format(print_fields(self.fields)) + end + types.fields = wrap(fields_checker) end -function types.fields_strict(kvs) - return function(obj, ctxt) - if not types.table(obj, ctxt) then - return false +do + local fields_strict_checker = class.class("fields_strict_checker", ITypeChecker) + function fields_strict_checker:init(fields) + for _, checker in pairs(fields) do + assert(is_type_checker(checker)) + end + self.fields = fields + end + function fields_strict_checker:check(obj, ctxt) + if not types.table:check(obj, ctxt) then + return false, "table" end for key, val in pairs(obj) do - local checker = kvs[key] + local checker = self.fields[key] if not checker then - return false + return false, ("table with key \"%s\""):format(key) end - ctxt:push(key) - if not checker(val, ctxt) then - return false + ctxt:push(key, val) + local ok, err = checker(val, ctxt) + if not ok then + return false, err end ctxt:pop() end return true end + function fields_strict_checker:__tostring() + return ("fields<%s>"):format(print_fields(self.fields)) + end + types.fields_strict = wrap(fields_strict_checker) end -for key, checker in pairs(types) do - names[checker] = key -end - -function types.check(obj, checker) +function types.check(obj, checker, verbose) + assert(is_type_checker(checker)) local ctxt = make_ctxt() - local success, needed_ty = checker(obj, ctxt) + local success, needed_ty = checker:check(obj, ctxt) if not success then needed_ty = needed_ty or "" - return false, ("Typecheck failed - Value is not of type \"%s\": %s"):format(needed_ty, ctxt:make_trail(obj)) + local s + if verbose then + s = ctxt:make_trail(obj) + else + local entry = ctxt.stack[#ctxt.stack] + if entry then + s = get_name(entry.value or entry.key) + else + s = get_name(obj) + end + end + return false, ("Typecheck failed - Value is not of type \"%s\": %s"):format(needed_ty, s) end return true end From 009085d168c4c6957b687966d47dae6eef56822f Mon Sep 17 00:00:00 2001 From: Ruin0x11 Date: Thu, 9 Sep 2021 16:57:02 -0700 Subject: [PATCH 03/17] temp --- src/api/Enum.lua | 2 + src/api/feat/ITrap.lua | 25 - src/internal/data/schemas.lua | 719 +++++++++++++++++----- src/internal/data_table.lua | 86 ++- src/internal/draw/atlas.lua | 2 +- src/mod/elona/data/activity.lua | 4 +- src/mod/elona/data/activity/searching.lua | 2 +- src/mod/elona/data/effects.lua | 71 --- src/mod/elona/data/init.lua | 1 - src/mod/elona/data/item.lua | 2 +- src/mod/elona/data/item/book.lua | 6 +- src/mod/elona/data/item/container.lua | 24 +- src/mod/elona/data/item/currency.lua | 4 +- src/mod/elona/data/item/equip/arm.lua | 2 +- src/mod/elona/data/item/equip/girdle.lua | 2 +- src/mod/elona/data/item/equip/head.lua | 4 +- src/mod/elona/data/item/equip/leg.lua | 2 +- src/mod/elona/data/item/equip/melee.lua | 38 +- src/mod/elona/data/item/equip/neck.lua | 8 +- src/mod/elona/data/item/equip/ranged.lua | 16 +- src/mod/elona/data/item/equip/ring.lua | 4 +- src/mod/elona/data/item/equip/shield.lua | 4 +- src/mod/elona/data/item/fish.lua | 4 +- src/mod/elona/data/item/food.lua | 14 +- src/mod/elona/data/item/furniture.lua | 44 +- src/mod/elona/data/item/junk.lua | 4 +- src/mod/elona/data/item/potion.lua | 4 +- src/mod/elona/data/item/remains.lua | 4 +- src/mod/elona/data/item/scroll.lua | 18 +- src/mod/elona/data/item/tool.lua | 40 +- src/mod/elona/data/item/tree.lua | 9 +- src/util/types.lua | 608 +++++++++++++++--- 32 files changed, 1298 insertions(+), 479 deletions(-) delete mode 100644 src/api/feat/ITrap.lua delete mode 100644 src/mod/elona/data/effects.lua diff --git a/src/api/Enum.lua b/src/api/Enum.lua index 7801c69d6..a77d434fa 100644 --- a/src/api/Enum.lua +++ b/src/api/Enum.lua @@ -144,6 +144,7 @@ Enum.AiBehavior = Enum.new("AiBehavior", { -- >>>>>>>> shade2/init.hsp:825 #enum global fltGoblin=1 .. Enum.CharaCategory = Enum.new("CharaCategory", { + None = 0, Goblin = 1, Orc = 2, Slime = 3, @@ -172,6 +173,7 @@ Enum.CharaCategory = Enum.new("CharaCategory", { -- >>>>>>>> shade2/init.hsp:815 #enum global fltSp=1 .. Enum.FltSelect = Enum.new("FltSelect", { + None = 0, Sp = 1, Unique = 2, SpUnique = 3, diff --git a/src/api/feat/ITrap.lua b/src/api/feat/ITrap.lua deleted file mode 100644 index cf8d1d835..000000000 --- a/src/api/feat/ITrap.lua +++ /dev/null @@ -1,25 +0,0 @@ -local IFeat = require("api.feat.IFeat") -local IFactioned = require("api.IFactioned") -local Enum = require("api.Enum") - -local ITrap = class.interface("ITrap", {}, {IFeat, IFactioned}) - -function ITrap:build() - IFeat.build(self) - - IFactioned.init(self) -end - -function ITrap:refresh() - IFeat.refresh(self) - - self.is_solid = false -end - -function ITrap:on_stepped_on(obj) - if not obj:calc("is_floating") and self:relation_towards(obj) <= Enum.Relation.Enemy then - self:emit("elona_sys.on_feat_activate", obj) - end -end - -return ITrap diff --git a/src/internal/data/schemas.lua b/src/internal/data/schemas.lua index 74d331e85..64d056a40 100644 --- a/src/internal/data/schemas.lua +++ b/src/internal/data/schemas.lua @@ -2,6 +2,13 @@ local schema = require("thirdparty.schema") local data = require("internal.data") local CodeGenerator = require("api.CodeGenerator") local Enum = require("api.Enum") +local IEventEmitter = require("api.IEventEmitter") + +local ty_data_ext_field = types.fields { + name = types.string, + type = types.type, + default = types.any +} data:add_type { name = "data_ext", @@ -9,7 +16,7 @@ data:add_type { { name = "fields", template = true, - type = "table", + type = types.list(ty_data_ext_field), default = {} } } @@ -17,9 +24,7 @@ data:add_type { data:add_type { name = "event", - schema = schema.Record { - observer = schema.Optional(schema.String) - }, + fields = {}, doc = [[ Events that can be fired. ]] @@ -28,19 +33,30 @@ Events that can be fired. local IChara = require("api.chara.IChara") local IItem = require("api.item.IItem") local IFeat = require("api.feat.IFeat") -local ITrap = require("api.feat.ITrap") local IActivity = require("api.activity.IActivity") local IMef = require("api.mef.IMef") -data:add_type( - { - name = "resource", - schema = schema.Record { - type = schema.String, - value = schema.Any - } - } -) +local ty_event = types.fields { + id = types.data_id("base.event"), + name = types.string, + callback = types.callback("self", types.interface(IEventEmitter), "params", types.table, "result", types.any), +} + +local ty_color_value = types.range(types.int, 0, 255) +local ty_color = types.tuple { + ty_color_value, + ty_color_value, + ty_color_value, + types.optional(ty_color_value), +} +local ty_light = types.fields { + chip = types.data_id("base.chip"), + brightness = types.positive(types.number), + offset_y = types.number, + power = types.number, + flicker = types.positive(types.number), + always_on = types.optional(types.boolean) +} data:add_type( { @@ -48,6 +64,7 @@ data:add_type( fields = { { name = "level", + type = types.uint, default = 1, template = true, doc = [[ @@ -56,6 +73,7 @@ Relative strength of this character. }, { name = "ai_move_chance", + type = types.uint, default = 100, doc = [[ Chance this unit will take an idle action if they have no target. @@ -63,6 +81,7 @@ Chance this unit will take an idle action if they have no target. }, { name = "ai_distance", + type = types.uint, default = 1, doc = [[ Minimum distance before this unit starts moving toward their target. @@ -70,8 +89,8 @@ Minimum distance before this unit starts moving toward their target. }, { name = "portrait", + type = types.optional(types.data_id("base.portrait")), default = nil, - type = "base.portrait", doc = [[ Portrait displayed when conversing with this character. @@ -80,18 +99,13 @@ Remove this to use the character's sprite instead. }, { name = "resistances", + type = types.map(types.data_id("base.resistance"), types.int), default = {}, no_fallback = true }, - { - name = "item_type", - default = 0, - doc = [[ -The kind of item this character drops on death. -]] - }, { name = "tags", + type = types.list(types.string), default = {}, doc = [[ A list of strings used for filtering during character generation. @@ -99,6 +113,7 @@ A list of strings used for filtering during character generation. }, { name = "can_talk", + type = types.boolean, default = false, doc = [[ If true, you can talk to this character by bumping into them. @@ -106,9 +121,9 @@ If true, you can talk to this character by bumping into them. }, { name = "relation", - default = CodeGenerator.gen_literal [[ Enum.Relation.Enemy ]], + type = types.enum(Enum.Relation), + default = Enum.Relation.Enemy, template = true, - type = "integer", doc = [[ What alignment this character has. @@ -117,66 +132,67 @@ This determines if it will act hostile toward the player on first sight. }, { name = "race", + type = types.data_id("base.race"), default = "elona.slime", template = true, - type = "id:base.race", doc = [[ The race of this character. ]] }, { name = "class", + type = types.data_id("base.class"), default = "elona.predator", template = true, - type = "id:base.class", doc = [[ The class of this character. ]] }, { name = "image", + type = types.optional(types.data_id("base.chip")), default = nil, template = true, - type = "id:base.chip", doc = [[ The character's image. Can be nil to use the race's default image. ]] }, { name = "male_image", + type = types.optional(types.data_id("base.chip")), default = nil, - type = "base.chip", doc = [[ The character's male image. Can be nil to use the race's default image. ]] }, { name = "female_image", + type = types.optional(types.data_id("base.chip")), default = nil, - type = "base.chip", doc = [[ The character's female image. Can be nil to use the race's default image. ]] }, { name = "gender", + type = types.literal("female", "male"), -- TODO allow arbitrary genders default = "female", no_fallback = true, - type = "string", doc = [[ The character's gender, either "male" or "female". ]] }, - { - name = "fixlv", - default = nil - }, { name = "fltselect", - default = 0 + type = types.enum(Enum.FltSelect), + default = Enum.FltSelect.None, + doc = [[ +Determines if the character is spawned in towns, etc. +]] }, { name = "rarity", + type = types.int, default = 100000, template = true, doc = [[ @@ -187,6 +203,7 @@ Increase to make more common; set to 0 to disable random generation entirely. }, { name = "coefficient", + type = types.int, default = 400, template = true, doc = [[ @@ -200,8 +217,8 @@ low-level dungeons. }, { name = "dialog", + type = types.optional(types.data_id("elona_sys.dialog")), default = nil, - type = "elona_sys.dialog", doc = [[ Dialog tree to run upon bumping into this character. @@ -210,8 +227,8 @@ The character must have `can_talk` set to `true` for this to trigger. }, { name = "tone", + type = types.optional(types.data_id("base.tone")), default = nil, - type = "base.tone", doc = [[ Custom talk tone for this character. @@ -219,81 +236,91 @@ This is for making characters say custom text on certain events. ]] }, { + -- TODO name = "cspecialeq", + type = types.optional(types.literal(1)), default = nil }, - eqweapon1 = { + { + -- TODO + name = "eqweapon1", + type = types.optional(types.int), default = nil }, { name = "creaturepack", - default = nil + type = types.enum(Enum.CharaCategory), + default = Enum.CharaCategory.None, }, { + -- TODO remove name = "flags", + type = types.list(types.string), default = {} }, { name = "on_eat_corpse", - default = nil, - type = "function(IItem, {chara=IChara})", - doc = [[ + type = types.optional(types.callback("corpse", types.map_object("base.item"), + "params", types.fields { chara = types.map_object("base.chara") })), + doc = [[ A callback to be run when this character's corpse is eaten. ]] }, { name = "events", default = nil, - type = "table", + type = types.list(ty_event), doc = [[ List of events to bind to this character when they are spawned. ]] }, { name = "category", - default = nil, - type = "number" + type = types.enum(Enum.CharaCategory), + default = Enum.CharaCategory.None, }, { name = "color", + type = types.optional(ty_color), default = nil, - type = "{int,int,int}", doc = [[ Color to display on the character's sprite. ]] }, { + -- TODO name = "is_unique", + type = types.boolean, default = false }, - { - name = "drops", - default = nil, - type = "table", - }, { name = "ai", + type = types.data_id("base.ai_action"), default = "elona.elona_default_ai", - type = "base.ai_action", doc = [[ AI callback to run on this character's turn. ]] }, { name = "damage_reaction", + type = types.optional( + types.fields { + _id = types.data_id("base.damage_reaction"), + power = types.int + } + ), default = nil, - type = "{_id=id:base.damage_reaction,power=int}", doc = [[ A damage reaction to trigger if this character is melee attacked. ]] }, { name = "skills", + type = types.optional(types.list(types.data_id("base.skill"))), default = nil, - type = "table?", no_fallback = true, doc = [[ -Skills this character will already know on creation. +Skills this character will already know when they're created. ]] } }, @@ -442,8 +469,8 @@ data:add_type( fields = { { name = "level", + type = types.uint, default = 1, - type = "number", template = true, doc = [[ Relative strength of this item. @@ -451,32 +478,32 @@ Relative strength of this item. }, { name = "weight", + type = types.uint, default = 0, - type = "number", template = true }, { name = "value", + type = types.uint, default = 0, - type = "number", template = true }, { name = "color", + type = types.optional(ty_color), default = nil, - type = "table?" }, { name = "image", - default = "", + type = types.data_id("base.chip"), template = true, - type = "base.chip", doc = [[ The item's image. ]] }, { name = "rarity", + type = types.int, default = 0, template = true, doc = [[ @@ -487,6 +514,7 @@ Increase to make more common; set to 0 to disable random generation entirely. }, { name = "coefficient", + type = types.int, default = 0, template = true, doc = [[ @@ -500,64 +528,68 @@ dungeons. }, { name = "flags", - type = "table", + type = types.list(types.string), default = {} }, { name = "params", - type = "table", + type = types.table, default = {} }, { name = "categories", + type = types.list(types.data_id("base.item_type")), default = {}, - type = "table", template = true }, { name = "on_read", + type = types.optional(types.callback("self", types.map_object("base.item"), "chara", types.map_object("base.chara"))), default = nil, - type = "function(IItem,IChara)?" }, { name = "on_zap", + type = types.optional(types.callback("self", types.map_object("base.item"), "chara", types.map_object("base.chara"))), default = nil, - type = "function(IItem,IChara)?" }, { name = "on_eat", + type = types.optional(types.callback("self", types.map_object("base.item"), "chara", types.map_object("base.chara"))), default = nil, - type = "function(IItem,IChara)?" }, { name = "on_drink", + type = types.optional(types.callback("self", types.map_object("base.item"), "chara", types.map_object("base.chara"))), default = nil, - type = "function(IItem,IChara)?" }, { name = "fltselect", - default = nil, - type = "number?" + type = types.enum(Enum.FltSelect), + default = Enum.FltSelect.None, }, { name = "tags", + type = types.list(types.string), default = {}, template = true, doc = [[ A list of strings used for filtering during item generation. ]] }, - originalnameref2 = { + { + -- TODO + name = "originalnameref2", + type = types.optional(types.string), default = nil, - type = "string?" }, { name = "count", + type = types.optional(types.int), default = nil, - type = "number?" }, { name = "gods", + type = types.list(types.data_id("elona.god")), default = {}, doc = [[ What gods this item can be offered to. @@ -565,34 +597,34 @@ What gods this item can be offered to. }, { name = "enchantments", - default = nil, - type = "table?", - }, - { - name = "fixlv", - default = nil, - type = "string?" + type = types.list( + types.fields { + _id = types.data_id("base.enchantment"), + power = types.number, + params = types.optional(types.table) + } + ), + default = {}, }, { name = "identify_difficulty", + type = types.number, default = 0, - type = "string?" }, { name = "is_precious", - default = nil, - type = "boolean" + type = types.boolean, + default = false, }, { name = "skill", + type = types.optional(types.data_id("base.skill")), default = nil, - type = "base.skill?" }, { name = "material", - default = nil, + type = types.data_id("base.material"), template = true, - type = "id:elona.item_material", doc = [[ Material of this item. @@ -602,24 +634,25 @@ on vanilla's formula. }, { name = "effective_range", + type = types.list(types.number), default = {100, 20, 20, 20, 20, 20, 20, 20, 20, 20}, - type = "table" }, { name = "pierce_rate", + type = types.number, default = 0, - type = "number" }, { name = "events", - default = nil, - type = "table?", + type = types.list(ty_event), + default = {}, doc = [[ List of events to bind to this item when it is spawned. ]] }, { name = "is_light_source", + type = types.boolean, default = false, doc = [[ If true, lights up dungeons if in the player's inventory. @@ -627,8 +660,8 @@ If true, lights up dungeons if in the player's inventory. }, { name = "light", + type = types.optional(ty_light), default = nil, - type = "table?", doc = [[ Ambient light information. - chip (id:base.chip): chip with animation to play over tile. @@ -645,6 +678,7 @@ Ambient light information. }, { name = "spoilage_hours", + type = types.optional(types.number), default = nil, doc = [[ Hours until the item spoils. Used for items of material "elona.fresh" only. @@ -652,6 +686,7 @@ Hours until the item spoils. Used for items of material "elona.fresh" only. }, { name = "is_wishable", + type = types.boolean, default = true, doc = [[ If false, this item cannot be wished for. @@ -679,48 +714,137 @@ If false, this item cannot be wished for. data:add_type { name = "item_type", - schema = schema.Record { - no_generate = schema.Optional(schema.Boolean) + fields = { + { + name = "no_generate", + type = types.boolean, + default = false, + doc = [[ +If true, don't randomly generate items with this category in the wild. +]] + } } } data:add_type( { name = "feat", - schema = schema.Record { - name = schema.String, - image = schema.Number, - params = schema.Table, - on_instantiate = schema.Optional(schema.Function), + fields = { + { + name = "elona_id", + type = types.optional(types.uint), + }, + { + name = "params", + type = types.table, + default = {} + }, + { + name = "is_solid", + type = types.boolean, + default = true, + }, + { + name = "is_opaque", + type = types.boolean, + default = true, + }, + { + name = "image", + type = types.data_id("base.chip"), + }, + { + name = "on_refresh", + type = types.optional(types.callback("self", types.map_object("base.feat"), "params", types.table)) + }, + { + name = "on_bumped_into", + type = types.optional(types.callback("self", types.map_object("base.feat"), "params", types.table)) + }, + { + name = "on_open", + type = types.optional(types.callback("self", types.map_object("base.feat"), "params", types.table)) + }, + { + name = "on_close", + type = types.optional(types.callback("self", types.map_object("base.feat"), "params", types.table)) + }, + { + name = "on_bash", + type = types.optional(types.callback("self", types.map_object("base.feat"), "params", types.table)) + }, + { + name = "on_activate", + type = types.optional(types.callback("self", types.map_object("base.feat"), "params", types.table)) + }, + { + name = "on_ascend", + type = types.optional(types.callback("self", types.map_object("base.feat"), "params", types.table)) + }, + { + name = "on_descend", + type = types.optional(types.callback("self", types.map_object("base.feat"), "params", types.table)) + }, + { + name = "on_stepped_on", + type = types.optional(types.callback("self", types.map_object("base.feat"), "params", types.table)) + }, + { + name = "events", + type = types.list(ty_event), + default = {}, + doc = [[ +List of events to bind to this feat when it is created. +]] + }, }, - fallbacks = { - params = {} - } }, { interface = IFeat } ) -data:add_type( - { - name = "trap", - schema = schema.Record { - name = schema.String, - image = schema.Number, - params = schema.Table, - on_instantiate = schema.Optional(schema.Function), - }, - }, - { interface = ITrap } -) - data:add_type( { name = "mef", fields = { + { + name = "elona_id", + type = types.optional(types.uint), + }, + { + -- TODO + name = "params", + type = types.table, + default = {} + }, + { + name = "image", + type = types.data_id("base.chip"), + }, + { + name = "on_stepped_on", + type = types.optional(types.callback("self", types.map_object("base.mef"), "params", types.table)) + }, + { + name = "on_stepped_off", + type = types.optional(types.callback("self", types.map_object("base.mef"), "params", types.table)) + }, + { + name = "on_updated", + type = types.optional(types.callback("self", types.map_object("base.mef"), "params", types.table)) + }, + { + name = "on_removed", + type = types.optional(types.callback("self", types.map_object("base.mef"), "params", types.table)) + }, + { + name = "events", + type = types.list(ty_event), + default = {}, + doc = [[ +List of events to bind to this mef when it is created. +]] + }, }, - fallbacks = { - params = {}, - } }, { interface = IMef } ) @@ -728,16 +852,68 @@ data:add_type( data:add_type( { name = "class", - schema = schema.Record { - on_generate = schema.Optional(schema.Function), - }, + fields = { + { + name = "properties", + type = types.map(types.string, types.any), + default = {} + }, + { + name = "skills", + type = types.map(types.data_id("base.skill"), types.number), + default = {} + }, + { + name = "on_init_player", + type = types.optional(types.callback("chara", types.map_object("base.chara"))) + } + } } ) data:add_type( { name = "race", - schema = schema.Record { + fields = { + { + name = "is_extra", + type = types.boolean, + default = false + }, + { + name = "elona_id", + type = types.optional(types.uint), + }, + { + name = "properties", + type = types.map(types.string, types.any), + default = {} + }, + { + name = "male_ratio", + type = types.number, + default = 50, + }, + { + name = "height", + type = types.number, + }, + { + name = "age_min", + type = types.number, + }, + { + name = "age_max", + type = types.number, + }, + { + name = "skills", + type = types.map(types.data_id("base.skill"), types.number) + }, + { + name = "body_parts", + type = types.list(types.data_id("base.body_part")), + } }, } ) @@ -745,18 +921,122 @@ data:add_type( data:add_type( { name = "element", - schema = schema.Record { - preserves_sleep = schema.Boolean, - sound = schema.Optional(schema.String), - }, + fields = { + { + name = "elona_id", + type = types.optional(types.uint), + }, + { + name = "color", + type = types.optional(ty_color) + }, + { + name = "ui_color", + type = types.optional(ty_color) + }, + { + name = "can_resist", + type = types.optional(types.boolean) + }, + { + name = "sound", + type = types.optional(types.data_id("base.sound")) + }, + { + name = "death_anim", + type = types.optional(types.data_id("base.asset")) + }, + { + name = "death_anim_dy", + type = types.optional(types.number) + }, + { + name = "rarity", + type = types.optional(types.number) + }, + { + name = "on_modify_damage", + type = types.optional(types.callback("chara", types.map_object("base.chara"), + "damage", types.number)) + }, + { + name = "on_damage_tile", + type = types.optional(types.callback("self", types.data_entry("base.element"), + "x", types.uint, + "y", types.uint, + "source", types.map_object("base.chara"))) + }, + { + name = "on_damage", + type = types.optional(types.callback("chara", types.map_object("base.chara"), + "params", types.table)) -- TODO + }, + { + name = "on_kill", + type = types.optional(types.callback("chara", types.map_object("base.chara"), + "params", types.table)) -- TODO + }, + { + name = "calc_initial_resist_level", + type = types.optional(types.callback("chara", types.map_object("base.chara"), + "level", types.number)) + } + } } ) data:add_type{ name = "effect", fields = { + { + name = "color", + type = ty_color, + }, + { + name = "indicator", + type = types.some(types.locale_id, types.callback("chara", types.map_object("base.chara"))) + }, + { + name = "emotion_icon", + type = types.optional(types.string) -- TODO + }, + { + name = "on_turn_start", + type = types.optional(types.callback("chara", types.map_object("base.chara"))) + }, + { + name = "on_turn_end", + type = types.optional(types.callback("chara", types.map_object("base.chara"))) + }, + { + name = "stops_activity", + type = types.boolean, + default = false, + template = true, + doc = [[ +If true, this effect will stop any active activities on the applied character. +]] + }, + { + name = "related_element", + type = types.optional(types.data_id("base.element")) + }, + { + name = "calc_adjusted_power", + type = types.optional(types.callback("chara", types.map_object("base.chara"), "power", types.number)) + }, + { + name = "calc_additive_power", + type = types.optional(types.callback("chara", types.map_object("base.chara"), "power", types.number)) + }, + { + name = "on_sleep", + type = types.optional(types.some(types.literal("remove"), + types.callback("chara", types.map_object("base.chara")))) + }, { name = "auto_heal", + type = types.boolean, default = true, template = true, doc = [[ @@ -771,35 +1051,183 @@ False for sickness and choking on mochi. data:add_type( { name = "activity", - schema = { + fields = { + { + name = "elona_id", + type = types.optional(types.uint) + }, + { + name = "params", + type = types.map(types.string, types.type), + default = {} + }, + { + name = "default_turns", + type = types.some(types.uint, + types.callback({"self", types.interface(IActivity)}, types.int)), + default = 10 + }, + { + name = "animation_wait", + type = types.some(types.positive(types.number), + types.callback({"self", types.interface(IActivity)}, types.number)) + }, + { + name = "auto_turn_anim", + type = types.optional(types.some(types.data_id("base.auto_turn_anim"), + types.callback({"self", types.interface(IActivity)}, types.data_id("base.auto_turn_anim")))) + }, + { + name = "localize", + type = types.optional(types.some(types.locale_id, + types.callback({"self", types.interface(IActivity)}, types.locale_id))) + }, + { + name = "can_scroll", + type = types.boolean, + default = false + }, + { + name = "on_interrupt", + type = types.literal("ignore", "prompt", "stop"), + }, + { + name = "interrupt_on_displace", + type = types.boolean, + default = false + }, + { + name = "events", + type = types.list(ty_event), + default = {}, + doc = [[ +List of events to bind to this activity when it is created. +]] + }, }, }, { interface = IActivity } ) -data:add_type( - { - name = "map", - schema = schema.Record { - name = schema.String - }, - } -) - data:add_type { name = "body_part", - schema = schema.Record { - name = schema.String, - icon = schema.Number -- TODO: needs to be themable + fields = { + { + name = "elona_id", + type = types.optional(types.uint) + }, + { + name = "icon", + type = types.uint -- TODO: needs to be themable + } } } +local ty_image_entry = types.some( + -- "graphic/chip.png", + types.string, + + -- { + -- image = "graphic/chip.bmp", + -- count_x = 1, + -- key_color = {0, 0, 0} + -- } + types.fields_strict { + image = types.string, + count_x = types.optional(types.uint), + key_color = types.optional(ty_color) + }, + + -- { + -- height = 48, + -- source = "graphic/map0.bmp", + -- width = 48, + -- x = 0, + -- y = 0, + -- count_x = 1, + -- key_color = {0, 0, 0} + -- } + types.fields_strict { + source = types.string, + width = types.uint, + height = types.uint, + x = types.uint, + y = types.uint, + count_x = types.optional(types.uint), + key_color = types.optional(ty_color) + } +) + +-- { +-- default = "graphic/chip.bmp", +-- anim1 = { image = "graphic/chip1.bmp", count_x = 2 } +-- } +local ty_image_anims = types.map(types.string, ty_image_entry) + +local ty_image = types.some(ty_image_entry, ty_image_anims) + data:add_type { name = "map_tile", - schema = schema.Record { - image = schema.Number, - is_solid = schema.Boolean, - }, + fields = { + { + name = "elona_id", + type = types.optional(types.uint), + }, + { + name = "elona_atlas", + type = types.optional(types.uint), + }, + { + name = "image", + type = ty_image + }, + { + name = "field_type", + type = types.optional(types.data_id("elona.field_type")), + }, + { + name = "kind", + type = types.enum(Enum.TileRole), + default = Enum.TileRole.None + }, + { + name = "kind2", + type = types.enum(Enum.TileRole), + default = Enum.TileRole.None + }, + { + name = "is_solid", + type = types.boolean, + default = false, + }, + { + name = "is_opaque", + type = types.boolean, + default = false, + }, + { + name = "is_road", + type = types.boolean, + default = false, + }, + { + name = "wall", + type = types.optional(types.data_id("base.map_tile")), + }, + { + name = "wall_kind", + type = types.optional(types.literal(1, 2)), + }, + { + name = "count_x", + type = types.optional(types.uint), + }, + { + name = "disable_in_map_edit", + type = types.boolean, + default = false + }, + } } data:add_type { @@ -807,6 +1235,7 @@ data:add_type { fields = { { name = "level", + type = types.uint, default = 1, template = true, doc = [[ @@ -815,6 +1244,7 @@ Level of this enchantment. }, { name = "value", + type = types.uint, default = 100, template = true, doc = [[ @@ -823,6 +1253,7 @@ Value of this enchantment. }, { name = "level", + type = types.uint, default = 100, template = true, doc = [[ @@ -865,7 +1296,7 @@ data:add_type { fields = { { name = "level", - type = "integer", + type = "int", default = 0, template = true, doc = [[ @@ -1524,7 +1955,7 @@ data:add_type { doc = [[ Type of this config option. -One of "boolean", "string", "number", "integer" "enum", "table", "data_id" or "any". +One of "boolean", "string", "number", "int" "enum", "table", "data_id" or "any". ]] }, { diff --git a/src/internal/data_table.lua b/src/internal/data_table.lua index 962adfc00..eb09e6c6b 100644 --- a/src/internal/data_table.lua +++ b/src/internal/data_table.lua @@ -3,7 +3,6 @@ local EventTree = require ("api.EventTree") local Log = require ("api.Log") local env = require ("internal.env") local fs = require("util.fs") -local schema = require("thirdparty.schema") local data_table = class.class("data_table") @@ -157,8 +156,26 @@ local function make_fallbacks(fallbacks, fields) return result end +local ty_schema = types.fields_strict { + name = types.identifier, + fields = types.list( + types.fields_strict { + name = types.string, + template = types.optional(types.boolean), + type = types.type, + default = types.optional(types.any), + doc = types.optional(types.string), + no_fallback = types.optional(types.boolean) + } + ), + fallbacks = types.optional(types.table), + doc = types.optional(types.string) +} + +local ty_ext_table = types.map(types.some(types.interface_type, types.data_id("base.data_ext")), types.table) + function data_table:add_type(schema, params) - schema.fields = schema.fields or {} + assert(types.check(schema, ty_schema)) schema.fallbacks = schema.fallbacks or {} params = params or {} @@ -171,6 +188,38 @@ function data_table:add_type(schema, params) local mod_name, loc = env.find_calling_mod() local _type = mod_name .. "." .. schema.name + local checkers = {} + for i, field in ipairs(schema.fields) do + if type(field.name) ~= "string" then + error("Data type %s: missing field name (index %d)"):format(_type, i) + end + if not types.is_type_checker(field.type) then + error(("Data type %s: invalid type specified for field named '%s'"):format(_type, field.name)) + end + if field.default then + local ok, err = types.check(field.default, field.type) + if not ok then + error(("Data type %s: invalid default value for field '%s': '%s'"):format(_type, field.name, err)) + end + end + checkers[field.name] = field.type + end + + -- Fields available on all types + checkers._type = types.data_type_id + checkers._id = types.identifier + checkers._ext = types.optional(ty_ext_table) + checkers._ordering = types.optional(types.number) -- TODO + + schema.type = types.fields_strict(checkers) + schema.validate = function(obj, verbose) + local ok, err = types.check(obj, schema.type, verbose) + if not ok then + return false, ("Validation for data type '%s' failed: %s"):format(_type, err) + end + return true + end + if env.is_hotloading() and self.schemas[_type] then Log.debug("In-place update of type %s", _type) @@ -222,6 +271,8 @@ function data_table:add_type(schema, params) local fallbacks = make_fallbacks(schema.fallbacks, schema.fields) self.fallbacks[_type] = fallbacks + + return schema end -- TODO: metatable indexing could create a system for indexing @@ -326,26 +377,9 @@ function data_table:add(dat) end end - local errs = schema.CheckSchema(dat, _schema.schema) - local failed = false - - for _, err in ipairs(errs) do - local add = true - - if string.match(err.message, "^Superfluous value: ") then - local path = tostring(err.path) - if path == "_id" - or path == "_type" - or path == "_index_on" - then - add = false - end - end - - if add then - failed = true - -- self:error(tostring(err)) - end + local ok, err = _schema.validate(dat) + if not ok then + error(err) end -- Verify extension fields. @@ -673,6 +707,14 @@ function proxy:interface() return self.data.metatables[self._type] end +function proxy:type() + return self.data.schemas[self._type].type +end + +function proxy:validate(obj) + return self.data.schemas[self._type].validate(obj) +end + function proxy:ensure(k) local it = self[k] if it == nil then diff --git a/src/internal/draw/atlas.lua b/src/internal/draw/atlas.lua index 0d8bc7711..0325a0523 100644 --- a/src/internal/draw/atlas.lua +++ b/src/internal/draw/atlas.lua @@ -199,9 +199,9 @@ local function get_images(image) -- + creates animation "default" with frames numbered 1, 2, 3, etc. -- -- { - -- height = 48, -- source = "graphic/map0.bmp", -- width = 48, + -- height = 48, -- count_x = 1, -- x = 0, -- y = 0, diff --git a/src/mod/elona/data/activity.lua b/src/mod/elona/data/activity.lua index 085a5bea4..c6dfa5099 100644 --- a/src/mod/elona/data/activity.lua +++ b/src/mod/elona/data/activity.lua @@ -81,7 +81,7 @@ data:add { _id = "eating", elona_id = 1, - params = { food = "table", no_message = "boolean" }, + params = { food = types.map_object("base.item"), no_message = types.boolean }, default_turns = 8, animation_wait = 100, @@ -168,7 +168,7 @@ local traveling = { _id = "traveling", elona_id = 3, - params = { dest_x = "number", dest_y = "number" }, + params = { dest_x = types.uint, dest_y = types.uint }, animation_wait = 0, can_scroll = true, diff --git a/src/mod/elona/data/activity/searching.lua b/src/mod/elona/data/activity/searching.lua index 875f34266..ad1c178db 100644 --- a/src/mod/elona/data/activity/searching.lua +++ b/src/mod/elona/data/activity/searching.lua @@ -20,7 +20,7 @@ data:add { _id = "searching", elona_id = 105, - params = { feat = "table", no_more_materials = "boolean" }, + params = { feat = types.map_object("base.feat"), no_more_materials = types.boolean }, default_turns = function(self) return try_get_spot_info(self.params.feat, "activity_default_turns") or 20 diff --git a/src/mod/elona/data/effects.lua b/src/mod/elona/data/effects.lua deleted file mode 100644 index e9051abd3..000000000 --- a/src/mod/elona/data/effects.lua +++ /dev/null @@ -1,71 +0,0 @@ -local resource = {} -local function clamp_if_known(chara, new, amount) - return math.clamp(new, (amount > 0 and 1) or 0, resource["base.max_stat"]) -end - -local scale_stat = { - _type = "base.effect", - _id = "scale_stat", - - params = { stat = "number", add = "number", div = "number", neg = false }, - - on_apply = function(self, chara) - local prev = chara:get_stat(self.stat) - chara:mod_stat(self.stat, clamp_if_known(prev + math.floor(self.add + chara:calc("level") * self.mul / self.div) * (self.neg and -1 or 1), prev)) - end -} - -local four_eyes = { - _type = "elona_sys.trait", - _id = "four_eyes", - - orientation = "detrimental", - description = function(self) - local s1 = self:sub_effect_power("base.add_stat", { stat = 60 }) - local s2 = self:sub_effect_power("base.add_stat", { stat = 61 }) - return "You " .. " have 4 eyes. [PER+" .. s1 .. " CHR" .. s2 .. "]" - end, - - effects = { - {"elona_sys.scale_stat", stat = 17, add = 5, div = 3, neg = true}, - {"elona_sys.scale_stat", stat = 13, add = 5, div = 3}, - } -} - -local shield_bash = { - _type = "elona_sys.trait", - _id = "shield_bash", - - can_acquire = function(chara) - return chara.stat["168"] > 0 - end, - - effects = { - { - method = "add", - delta = { - known_abilities = { "base.shield_bash" } - } - } - } -} - -local high_resistances = { - _type = "elona_sys.trait", - _id = "high_resistances", - - orientation = "beneficial", - - effects = { - stat = { - [60] = 150, - [52] = 100, - [53] = 200, - [57] = 50, - [59] = 100, - [54] = 200, - [58] = 100, - [51] = 100, - } - } -} diff --git a/src/mod/elona/data/init.lua b/src/mod/elona/data/init.lua index b85d21887..e626dfaa1 100755 --- a/src/mod/elona/data/init.lua +++ b/src/mod/elona/data/init.lua @@ -7,7 +7,6 @@ require("mod.elona.data.race") require("mod.elona.data.chara") require("mod.elona.data.item") require("mod.elona.data.trait") -require("mod.elona.data.effects") require("mod.elona.data.feat") require("mod.elona.data.mef") require("mod.elona.data.scenario") diff --git a/src/mod/elona/data/item.lua b/src/mod/elona/data/item.lua index 780f98658..04a759573 100644 --- a/src/mod/elona/data/item.lua +++ b/src/mod/elona/data/item.lua @@ -15,7 +15,7 @@ local item = image = "elona.item_worthless_fake_gold_bar", value = 1, weight = 1, - fltselect = 1, + fltselect = Enum.FltSelect.Sp, category = 99999999, subcategory = 99999999, coefficient = 100, diff --git a/src/mod/elona/data/item/book.lua b/src/mod/elona/data/item/book.lua index 8f8050aed..be80cf7ac 100644 --- a/src/mod/elona/data/item/book.lua +++ b/src/mod/elona/data/item/book.lua @@ -28,7 +28,7 @@ data:add { return "player_turn_query" -- >>>>>>>> shade2/proc.hsp:1254 item_identify ci,knownName .. end, - fltselect = 1, + fltselect = Enum.FltSelect.Sp, category = 55000, coefficient = 100, is_wishable = false, @@ -71,7 +71,7 @@ data:add { image = "elona.item_book", value = 100, weight = 80, - fltselect = 1, + fltselect = Enum.FltSelect.Sp, category = 55000, coefficient = 100, @@ -156,7 +156,7 @@ data:add { image = "elona.item_book", value = 4000, weight = 80, - fltselect = 1, + fltselect = Enum.FltSelect.Sp, category = 55000, rarity = 50000, coefficient = 0, diff --git a/src/mod/elona/data/item/container.lua b/src/mod/elona/data/item/container.lua index c52175f36..eb167e8b2 100644 --- a/src/mod/elona/data/item/container.lua +++ b/src/mod/elona/data/item/container.lua @@ -140,7 +140,7 @@ data:add { image = "elona.item_heir_trunk", value = 380, weight = 1200, - fltselect = 1, + fltselect = Enum.FltSelect.Sp, category = 72000, coefficient = 100, @@ -171,7 +171,7 @@ data:add { image = "elona.item_wallet", value = 380, weight = 250, - fltselect = 1, + fltselect = Enum.FltSelect.Sp, category = 72000, coefficient = 100, @@ -213,7 +213,7 @@ data:add { image = "elona.item_heir_trunk", value = 380, weight = 1200, - fltselect = 1, + fltselect = Enum.FltSelect.Sp, category = 72000, coefficient = 100, categories = { @@ -496,7 +496,7 @@ data:add { image = "elona.item_new_years_gift", value = 1650, weight = 80, - fltselect = 1, + fltselect = Enum.FltSelect.Sp, category = 72000, rarity = 50000, coefficient = 100, @@ -519,7 +519,7 @@ data:add { image = "elona.item_heir_trunk", value = 4500, weight = 20000, - fltselect = 1, + fltselect = Enum.FltSelect.Sp, category = 72000, coefficient = 100, @@ -536,7 +536,7 @@ data:add { image = "elona.item_salary_chest", value = 6400, weight = 20000, - fltselect = 1, + fltselect = Enum.FltSelect.Sp, category = 72000, coefficient = 100, @@ -562,7 +562,7 @@ data:add { image = "elona.item_masters_delivery_chest", value = 380, weight = 20000, - fltselect = 1, + fltselect = Enum.FltSelect.Sp, category = 72000, coefficient = 100, @@ -596,7 +596,7 @@ data:add { image = "elona.item_shop_strongbox", value = 7200, weight = 20000, - fltselect = 1, + fltselect = Enum.FltSelect.Sp, category = 72000, coefficient = 100, @@ -625,7 +625,7 @@ data:add { value = 3800, weight = 15000, level = 30, - fltselect = 1, + fltselect = Enum.FltSelect.Sp, category = 72000, rarity = 50000, coefficient = 100, @@ -684,7 +684,7 @@ data:add { value = 14500, weight = 6500, level = 30, - fltselect = 1, + fltselect = Enum.FltSelect.Sp, category = 72000, rarity = 100000, coefficient = 100, @@ -714,7 +714,7 @@ data:add { value = 7500, weight = 2500, level = 30, - fltselect = 3, + fltselect = Enum.FltSelect.SpUnique, category = 72000, rarity = 50000, coefficient = 100, @@ -784,7 +784,7 @@ data:add { value = 1800, weight = 150000, level = 10, - fltselect = 1, + fltselect = Enum.FltSelect.Sp, category = 72000, rarity = 100000, coefficient = 100, diff --git a/src/mod/elona/data/item/currency.lua b/src/mod/elona/data/item/currency.lua index 35fc64f96..b3b97a0a3 100644 --- a/src/mod/elona/data/item/currency.lua +++ b/src/mod/elona/data/item/currency.lua @@ -168,7 +168,7 @@ data:add { image = "elona.item_token_of_friendship", value = 1, weight = 1, - fltselect = 1, + fltselect = Enum.FltSelect.Sp, category = 77000, rarity = 10000, coefficient = 100, @@ -191,7 +191,7 @@ data:add { image = "elona.item_token_of_friendship", value = 1, weight = 1, - fltselect = 1, + fltselect = Enum.FltSelect.Sp, category = 77000, rarity = 10000, coefficient = 100, diff --git a/src/mod/elona/data/item/equip/arm.lua b/src/mod/elona/data/item/equip/arm.lua index 5428528be..e41f59dab 100644 --- a/src/mod/elona/data/item/equip/arm.lua +++ b/src/mod/elona/data/item/equip/arm.lua @@ -122,7 +122,7 @@ data:add { weight = 1200, material = "elona.mithril", level = 20, - fltselect = 3, + fltselect = Enum.FltSelect.SpUnique, coefficient = 100, is_precious = true, diff --git a/src/mod/elona/data/item/equip/girdle.lua b/src/mod/elona/data/item/equip/girdle.lua index bacc09b54..bf75ee2d3 100644 --- a/src/mod/elona/data/item/equip/girdle.lua +++ b/src/mod/elona/data/item/equip/girdle.lua @@ -86,7 +86,7 @@ data:add { weight = 1250, material = "elona.mithril", level = 13, - fltselect = 3, + fltselect = Enum.FltSelect.SpUnique, coefficient = 100, is_precious = true, diff --git a/src/mod/elona/data/item/equip/head.lua b/src/mod/elona/data/item/equip/head.lua index 047ecb84f..af08f7360 100644 --- a/src/mod/elona/data/item/equip/head.lua +++ b/src/mod/elona/data/item/equip/head.lua @@ -106,7 +106,7 @@ data:add { weight = 1500, material = "elona.mithril", level = 20, - fltselect = 3, + fltselect = Enum.FltSelect.SpUnique, coefficient = 100, is_precious = true, @@ -153,7 +153,7 @@ data:add { damage_bonus = 8, material = "elona.obsidian", level = 5, - fltselect = 3, + fltselect = Enum.FltSelect.SpUnique, coefficient = 100, is_precious = true, diff --git a/src/mod/elona/data/item/equip/leg.lua b/src/mod/elona/data/item/equip/leg.lua index c1e98caba..001895269 100644 --- a/src/mod/elona/data/item/equip/leg.lua +++ b/src/mod/elona/data/item/equip/leg.lua @@ -201,7 +201,7 @@ data:add { weight = 650, material = "elona.leather", level = 15, - fltselect = 3, + fltselect = Enum.FltSelect.SpUnique, coefficient = 100, is_precious = true, diff --git a/src/mod/elona/data/item/equip/melee.lua b/src/mod/elona/data/item/equip/melee.lua index 92945f1db..a35ecbe38 100644 --- a/src/mod/elona/data/item/equip/melee.lua +++ b/src/mod/elona/data/item/equip/melee.lua @@ -45,7 +45,7 @@ data:add { weight = 6500, material = "elona.silver", level = 45, - fltselect = 3, + fltselect = Enum.FltSelect.SpUnique, coefficient = 100, is_precious = true, @@ -88,7 +88,7 @@ data:add { weight = 22500, material = "elona.iron", level = 55, - fltselect = 3, + fltselect = Enum.FltSelect.SpUnique, coefficient = 100, is_precious = true, @@ -165,7 +165,7 @@ data:add { weight = 2200, material = "elona.steel", level = 40, - fltselect = 3, + fltselect = Enum.FltSelect.SpUnique, coefficient = 100, is_precious = true, @@ -215,7 +215,7 @@ data:add { weight = 1400, material = "elona.silver", level = 30, - fltselect = 2, + fltselect = Enum.FltSelect.Unique, coefficient = 100, is_precious = true, @@ -261,7 +261,7 @@ data:add { weight = 4000, material = "elona.obsidian", level = 50, - fltselect = 3, + fltselect = Enum.FltSelect.SpUnique, coefficient = 100, is_precious = true, @@ -312,7 +312,7 @@ data:add { weight = 4200, material = "elona.obsidian", level = 30, - fltselect = 3, + fltselect = Enum.FltSelect.SpUnique, coefficient = 100, is_precious = true, @@ -386,7 +386,7 @@ data:add { weight = 2500, material = "elona.obsidian", level = 25, - fltselect = 2, + fltselect = Enum.FltSelect.Unique, coefficient = 100, is_precious = true, @@ -499,7 +499,7 @@ data:add { weight = 600, material = "elona.ether", level = 40, - fltselect = 2, + fltselect = Enum.FltSelect.Unique, coefficient = 100, is_precious = true, @@ -609,7 +609,7 @@ data:add { weight = 400, material = "elona.mica", level = 60, - fltselect = 3, + fltselect = Enum.FltSelect.SpUnique, coefficient = 100, is_precious = true, @@ -723,7 +723,7 @@ data:add { weight = 1800, material = "elona.iron", level = 30, - fltselect = 3, + fltselect = Enum.FltSelect.SpUnique, coefficient = 100, is_precious = true, @@ -805,7 +805,7 @@ data:add { weight = 6500, material = "elona.adamantium", level = 60, - fltselect = 3, + fltselect = Enum.FltSelect.SpUnique, coefficient = 100, is_precious = true, @@ -917,7 +917,7 @@ data:add { weight = 2500, material = "elona.obsidian", level = 35, - fltselect = 3, + fltselect = Enum.FltSelect.SpUnique, coefficient = 100, is_precious = true, @@ -964,7 +964,7 @@ data:add { weight = 900, material = "elona.obsidian", level = 60, - fltselect = 3, + fltselect = Enum.FltSelect.SpUnique, coefficient = 100, is_precious = true, @@ -1082,7 +1082,7 @@ data:add { weight = 2000, material = "elona.iron", level = 35, - fltselect = 3, + fltselect = Enum.FltSelect.SpUnique, coefficient = 100, is_precious = true, @@ -1130,7 +1130,7 @@ data:add { weight = 4400, material = "elona.silver", level = 60, - fltselect = 3, + fltselect = Enum.FltSelect.SpUnique, coefficient = 100, is_precious = true, @@ -1306,7 +1306,7 @@ data:add { weight = 14000, material = "elona.rubynus", level = 30, - fltselect = 3, + fltselect = Enum.FltSelect.SpUnique, coefficient = 100, is_precious = true, @@ -1353,7 +1353,7 @@ data:add { weight = 9000, material = "elona.iron", level = 35, - fltselect = 3, + fltselect = Enum.FltSelect.SpUnique, coefficient = 100, is_precious = true, @@ -1434,7 +1434,7 @@ data:add { weight = 850, material = "elona.spirit_cloth", level = 60, - fltselect = 3, + fltselect = Enum.FltSelect.SpUnique, coefficient = 100, is_precious = true, @@ -1518,7 +1518,7 @@ data:add { weight = 376500, material = "elona.ether", level = 99, - fltselect = 3, + fltselect = Enum.FltSelect.SpUnique, coefficient = 100, is_precious = true, diff --git a/src/mod/elona/data/item/equip/neck.lua b/src/mod/elona/data/item/equip/neck.lua index 4914b7a2a..aa5423192 100644 --- a/src/mod/elona/data/item/equip/neck.lua +++ b/src/mod/elona/data/item/equip/neck.lua @@ -218,7 +218,7 @@ data:add { weight = 250, material = "elona.iron", level = 15, - fltselect = 3, + fltselect = Enum.FltSelect.SpUnique, coefficient = 100, is_precious = true, @@ -255,7 +255,7 @@ data:add { weight = 400, material = "elona.coral", level = 25, - fltselect = 3, + fltselect = Enum.FltSelect.SpUnique, coefficient = 100, is_precious = true, @@ -294,7 +294,7 @@ data:add { weight = 400, material = "elona.mica", level = 25, - fltselect = 3, + fltselect = Enum.FltSelect.SpUnique, coefficient = 100, is_precious = true, @@ -333,7 +333,7 @@ data:add { weight = 150, material = "elona.mica", level = 5, - fltselect = 3, + fltselect = Enum.FltSelect.SpUnique, coefficient = 100, is_precious = true, diff --git a/src/mod/elona/data/item/equip/ranged.lua b/src/mod/elona/data/item/equip/ranged.lua index ce1b69c46..d0414c426 100644 --- a/src/mod/elona/data/item/equip/ranged.lua +++ b/src/mod/elona/data/item/equip/ranged.lua @@ -47,7 +47,7 @@ data:add { weight = 1200, material = "elona.mithril", level = 35, - fltselect = 2, + fltselect = Enum.FltSelect.Unique, coefficient = 100, is_precious = true, @@ -128,7 +128,7 @@ data:add { weight = 800, material = "elona.ether", level = 60, - fltselect = 3, + fltselect = Enum.FltSelect.SpUnique, coefficient = 100, is_precious = true, @@ -351,7 +351,7 @@ data:add { weight = 2800, material = "elona.diamond", level = 60, - fltselect = 3, + fltselect = Enum.FltSelect.SpUnique, coefficient = 100, is_precious = true, @@ -398,7 +398,7 @@ data:add { value = 25000, weight = 950, material = "elona.iron", - fltselect = 3, + fltselect = Enum.FltSelect.SpUnique, coefficient = 100, is_precious = true, @@ -484,7 +484,7 @@ data:add { weight = 8500, material = "elona.ether", level = 80, - fltselect = 3, + fltselect = Enum.FltSelect.SpUnique, rarity = 200000, coefficient = 100, @@ -639,7 +639,7 @@ data:add { weight = 7500, material = "elona.adamantium", level = 15, - fltselect = 3, + fltselect = Enum.FltSelect.SpUnique, coefficient = 100, is_precious = true, @@ -677,7 +677,7 @@ data:add { weight = 75000, material = "elona.gold", level = 25, - fltselect = 3, + fltselect = Enum.FltSelect.SpUnique, coefficient = 100, is_precious = true, @@ -758,7 +758,7 @@ data:add { weight = 250, material = "elona.silk", level = 40, - fltselect = 3, + fltselect = Enum.FltSelect.SpUnique, coefficient = 100, is_precious = true, diff --git a/src/mod/elona/data/item/equip/ring.lua b/src/mod/elona/data/item/equip/ring.lua index b4af5d845..417322dce 100644 --- a/src/mod/elona/data/item/equip/ring.lua +++ b/src/mod/elona/data/item/equip/ring.lua @@ -41,7 +41,7 @@ data:add { weight = 1200, material = "elona.mithril", level = 30, - fltselect = 3, + fltselect = Enum.FltSelect.SpUnique, coefficient = 100, is_precious = true, @@ -82,7 +82,7 @@ data:add { weight = 500, material = "elona.mithril", level = 30, - fltselect = 3, + fltselect = Enum.FltSelect.SpUnique, coefficient = 100, is_precious = true, diff --git a/src/mod/elona/data/item/equip/shield.lua b/src/mod/elona/data/item/equip/shield.lua index 2657223f1..505766ee2 100644 --- a/src/mod/elona/data/item/equip/shield.lua +++ b/src/mod/elona/data/item/equip/shield.lua @@ -203,7 +203,7 @@ data:add { weight = 2850, material = "elona.wood", level = 15, - fltselect = 3, + fltselect = Enum.FltSelect.SpUnique, coefficient = 100, skill = "elona.shield", @@ -246,7 +246,7 @@ data:add { weight = 950, material = "elona.coral", level = 15, - fltselect = 2, + fltselect = Enum.FltSelect.Unique, coefficient = 100, skill = "elona.shield", diff --git a/src/mod/elona/data/item/fish.lua b/src/mod/elona/data/item/fish.lua index 50759b34b..57d75ace6 100644 --- a/src/mod/elona/data/item/fish.lua +++ b/src/mod/elona/data/item/fish.lua @@ -316,7 +316,7 @@ data:add { weight = 1250, material = "elona.fresh", level = 15, - fltselect = 1, + fltselect = Enum.FltSelect.Sp, rarity = 300000, coefficient = 100, @@ -396,7 +396,7 @@ data:add { value = 1200, weight = 1250, level = 15, - fltselect = 1, + fltselect = Enum.FltSelect.Sp, rarity = 300000, coefficient = 100, categories = { diff --git a/src/mod/elona/data/item/food.lua b/src/mod/elona/data/item/food.lua index 5650c5a4a..55a09db01 100644 --- a/src/mod/elona/data/item/food.lua +++ b/src/mod/elona/data/item/food.lua @@ -402,7 +402,7 @@ data:add { image = "elona.item_hero_cheese", value = 100000, weight = 500, - fltselect = 3, + fltselect = Enum.FltSelect.SpUnique, coefficient = 100, is_precious = true, @@ -436,7 +436,7 @@ data:add { value = 900, weight = 500, level = 3, - fltselect = 1, + fltselect = Enum.FltSelect.Sp, rarity = 250000, coefficient = 100, @@ -471,7 +471,7 @@ data:add { image = "elona.item_rabbits_tail", value = 10000, weight = 150, - fltselect = 3, + fltselect = Enum.FltSelect.SpUnique, coefficient = 100, is_precious = true, @@ -543,7 +543,7 @@ data:add { image = "elona.item_kagami_mochi", value = 2500, weight = 800, - fltselect = 1, + fltselect = Enum.FltSelect.Sp, rarity = 400000, coefficient = 0, @@ -735,7 +735,7 @@ data:add { image = "elona.item_putitoro", value = 2000, weight = 200, - fltselect = 1, + fltselect = Enum.FltSelect.Sp, rarity = 150000, coefficient = 0, @@ -1315,7 +1315,7 @@ data:add { image = "elona.item_happy_apple", value = 100000, weight = 720, - fltselect = 3, + fltselect = Enum.FltSelect.SpUnique, coefficient = 100, is_precious = true, @@ -1349,7 +1349,7 @@ data:add { image = "elona.item_magic_fruit", value = 100000, weight = 440, - fltselect = 3, + fltselect = Enum.FltSelect.SpUnique, coefficient = 100, is_precious = true, diff --git a/src/mod/elona/data/item/furniture.lua b/src/mod/elona/data/item/furniture.lua index 345dd4ff3..5ab25b9ea 100644 --- a/src/mod/elona/data/item/furniture.lua +++ b/src/mod/elona/data/item/furniture.lua @@ -1527,7 +1527,7 @@ data:add { value = 2800, weight = 14000, on_use = function() end, - fltselect = 1, + fltselect = Enum.FltSelect.Sp, rarity = 200000, coefficient = 100, categories = { @@ -1545,7 +1545,7 @@ data:add { value = 2800, weight = 24000, on_use = function() end, - fltselect = 1, + fltselect = Enum.FltSelect.Sp, rarity = 200000, coefficient = 100, categories = { @@ -1562,7 +1562,7 @@ data:add { value = 2000, weight = 12000, on_use = function() end, - fltselect = 1, + fltselect = Enum.FltSelect.Sp, rarity = 200000, coefficient = 100, categories = { @@ -1580,7 +1580,7 @@ data:add { value = 1800, weight = 8900, on_use = function() end, - fltselect = 1, + fltselect = Enum.FltSelect.Sp, rarity = 200000, coefficient = 100, categories = { @@ -1890,7 +1890,7 @@ data:add { weight = 140000, on_use = function() end, level = 18, - fltselect = 1, + fltselect = Enum.FltSelect.Sp, rarity = 50000, coefficient = 100, categories = { @@ -1908,7 +1908,7 @@ data:add { weight = 140000, on_use = function() end, level = 18, - fltselect = 1, + fltselect = Enum.FltSelect.Sp, rarity = 50000, coefficient = 100, categories = { @@ -2604,7 +2604,7 @@ data:add { image = "elona.item_shrine_gate", value = 7500, weight = 8000, - fltselect = 1, + fltselect = Enum.FltSelect.Sp, rarity = 10000, coefficient = 100, @@ -2626,7 +2626,7 @@ data:add { value = 50, weight = 5000000, level = 15, - fltselect = 1, + fltselect = Enum.FltSelect.Sp, rarity = 400000, coefficient = 100, categories = { @@ -2910,7 +2910,7 @@ data:add { image = "elona.item_upstairs", value = 150000, weight = 7500, - fltselect = 1, + fltselect = Enum.FltSelect.Sp, rarity = 20000, coefficient = 0, categories = { @@ -2952,7 +2952,7 @@ data:add { image = "elona.item_downstairs", value = 150000, weight = 7500, - fltselect = 1, + fltselect = Enum.FltSelect.Sp, rarity = 20000, coefficient = 0, categories = { @@ -2996,7 +2996,7 @@ data:add { value = 7800, weight = 9800, level = 28, - fltselect = 1, + fltselect = Enum.FltSelect.Sp, rarity = 10000, coefficient = 100, random_color = "Furniture", @@ -3025,7 +3025,7 @@ data:add { image = "elona.item_daruma", value = 3200, weight = 720, - fltselect = 1, + fltselect = Enum.FltSelect.Sp, coefficient = 100, categories = { "elona.no_generate", @@ -3041,7 +3041,7 @@ data:add { value = 760, weight = 280, level = 25, - fltselect = 1, + fltselect = Enum.FltSelect.Sp, rarity = 5000, coefficient = 100, tags = { "fest" }, @@ -3122,7 +3122,7 @@ data:add { value = 400, weight = 150, level = 10, - fltselect = 1, + fltselect = Enum.FltSelect.Sp, rarity = 5000, coefficient = 100, tags = { "fest" }, @@ -3141,7 +3141,7 @@ data:add { value = 1650, weight = 530, level = 10, - fltselect = 1, + fltselect = Enum.FltSelect.Sp, rarity = 5000, coefficient = 100, tags = { "fest" }, @@ -3278,7 +3278,7 @@ data:add { image = "elona.item_fountain", value = 2400, weight = 600000, - fltselect = 1, + fltselect = Enum.FltSelect.Sp, coefficient = 100, categories = { @@ -3298,7 +3298,7 @@ data:add { image = "elona.item_holy_well", value = 185000, weight = 350000, - fltselect = 1, + fltselect = Enum.FltSelect.Sp, rarity = 50000, coefficient = 100, @@ -3363,7 +3363,7 @@ data:add { image = "elona.item_ceremony_altar", value = 1500, weight = 500000, - fltselect = 1, + fltselect = Enum.FltSelect.Sp, coefficient = 100, params = { altar = { god_id = "" } }, @@ -3383,7 +3383,7 @@ data:add { image = "elona.item_ceremony_altar", value = 1600, weight = 500000, - fltselect = 1, + fltselect = Enum.FltSelect.Sp, coefficient = 100, categories = { "elona.furniture_altar", @@ -3857,7 +3857,7 @@ data:add { value = 250, weight = 800, level = 5, - fltselect = 1, + fltselect = Enum.FltSelect.Sp, rarity = 25000, coefficient = 100, @@ -4035,7 +4035,7 @@ data:add { image = "elona.item_stradivarius", value = 35000, weight = 4500, - fltselect = 3, + fltselect = Enum.FltSelect.SpUnique, rarity = 400000, coefficient = 100, @@ -4070,7 +4070,7 @@ data:add { value = 35000, weight = 45000, level = 20, - fltselect = 3, + fltselect = Enum.FltSelect.SpUnique, rarity = 100000, coefficient = 100, diff --git a/src/mod/elona/data/item/junk.lua b/src/mod/elona/data/item/junk.lua index 84ea6d355..53fd6e4d1 100644 --- a/src/mod/elona/data/item/junk.lua +++ b/src/mod/elona/data/item/junk.lua @@ -372,7 +372,7 @@ data:add { image = "elona.item_bait_water_flea", value = 1000, weight = 250, - fltselect = 1, + fltselect = Enum.FltSelect.Sp, category = 64000, coefficient = 100, @@ -393,7 +393,7 @@ data:add { image = "elona.item_monster_heart", value = 25000, weight = 2500, - fltselect = 3, + fltselect = Enum.FltSelect.SpUnique, category = 64000, rarity = 800000, coefficient = 100, diff --git a/src/mod/elona/data/item/potion.lua b/src/mod/elona/data/item/potion.lua index 2c46a5aeb..22e182d3f 100644 --- a/src/mod/elona/data/item/potion.lua +++ b/src/mod/elona/data/item/potion.lua @@ -1101,7 +1101,7 @@ data:add { image = "elona.item_bottle_of_soda", value = 500, weight = 50, - fltselect = 1, + fltselect = Enum.FltSelect.Sp, category = 52000, rarity = 400000, coefficient = 0, @@ -1132,7 +1132,7 @@ data:add { image = "elona.item_blue_capsule_drug", value = 7500, weight = 100, - fltselect = 3, + fltselect = Enum.FltSelect.SpUnique, category = 52000, rarity = 5000, coefficient = 0, diff --git a/src/mod/elona/data/item/remains.lua b/src/mod/elona/data/item/remains.lua index 981ad8a53..ef033bc75 100644 --- a/src/mod/elona/data/item/remains.lua +++ b/src/mod/elona/data/item/remains.lua @@ -100,7 +100,7 @@ data:add { image = "elona.item_figurine", value = 1000, weight = 2500, - fltselect = 1, + fltselect = Enum.FltSelect.Sp, rarity = 100000, coefficient = 100, categories = { @@ -122,7 +122,7 @@ data:add { image = "elona.item_card", value = 500, weight = 200, - fltselect = 1, + fltselect = Enum.FltSelect.Sp, rarity = 100000, coefficient = 100, categories = { diff --git a/src/mod/elona/data/item/scroll.lua b/src/mod/elona/data/item/scroll.lua index 47ba187ba..9ae0dd20a 100644 --- a/src/mod/elona/data/item/scroll.lua +++ b/src/mod/elona/data/item/scroll.lua @@ -1067,7 +1067,7 @@ data:add { image = "elona.item_deed", value = 50000, weight = 500, - fltselect = 1, + fltselect = Enum.FltSelect.Sp, category = 53000, subcategory = 53100, coefficient = 100, @@ -1152,7 +1152,7 @@ data:add { value = 140000, weight = 500, on_read = deed_callback("elona.museum"), - fltselect = 1, + fltselect = Enum.FltSelect.Sp, category = 53000, subcategory = 53100, rarity = 1000, @@ -1179,7 +1179,7 @@ data:add { value = 200000, weight = 500, on_read = deed_callback("elona.shop"), - fltselect = 1, + fltselect = Enum.FltSelect.Sp, category = 53000, subcategory = 53100, rarity = 1000, @@ -1206,7 +1206,7 @@ data:add { value = 45000, weight = 500, on_read = deed_callback("elona.crop"), - fltselect = 1, + fltselect = Enum.FltSelect.Sp, category = 53000, subcategory = 53100, rarity = 1000, @@ -1231,7 +1231,7 @@ data:add { value = 10000, weight = 500, on_read = deed_callback("elona.storage_house"), - fltselect = 1, + fltselect = Enum.FltSelect.Sp, category = 53000, subcategory = 53100, rarity = 1000, @@ -1256,7 +1256,7 @@ data:add { value = 80000, weight = 500, on_read = deed_callback("elona.ranch"), - fltselect = 1, + fltselect = Enum.FltSelect.Sp, category = 53000, subcategory = 53100, rarity = 1000, @@ -1281,7 +1281,7 @@ data:add { value = 500000, weight = 500, on_read = deed_callback("elona.dungeon"), - fltselect = 1, + fltselect = Enum.FltSelect.Sp, category = 53000, subcategory = 53100, rarity = 1000, @@ -1337,7 +1337,7 @@ data:add { image = "elona.item_bill", value = 100, weight = 100, - fltselect = 1, + fltselect = Enum.FltSelect.Sp, category = 53000, rarity = 400000, coefficient = 100, @@ -1405,7 +1405,7 @@ data:add { image = "elona.item_deed", value = 15000, weight = 500, - fltselect = 3, + fltselect = Enum.FltSelect.SpUnique, category = 53000, rarity = 1000, coefficient = 100, diff --git a/src/mod/elona/data/item/tool.lua b/src/mod/elona/data/item/tool.lua index 620406776..96252b90e 100644 --- a/src/mod/elona/data/item/tool.lua +++ b/src/mod/elona/data/item/tool.lua @@ -295,7 +295,7 @@ data:add { Building.query_house_board() return "player_turn_query" end, - fltselect = 1, + fltselect = Enum.FltSelect.Sp, coefficient = 100, elona_function = 8, @@ -621,7 +621,7 @@ data:add { value = 150000, weight = 400, level = 20, - fltselect = 2, + fltselect = Enum.FltSelect.Unique, rarity = 10000, coefficient = 100, @@ -661,7 +661,7 @@ data:add { image = "elona.item_statue_of_opatos", value = 100000, weight = 15000, - fltselect = 3, + fltselect = Enum.FltSelect.SpUnique, rarity = 800000, coefficient = 100, originalnameref2 = "statue", @@ -683,7 +683,7 @@ data:add { image = "elona.item_statue_of_lulwy", value = 100000, weight = 14000, - fltselect = 3, + fltselect = Enum.FltSelect.SpUnique, rarity = 800000, coefficient = 100, originalnameref2 = "statue", @@ -738,7 +738,7 @@ data:add { value = 10000, weight = 120000, level = 10, - fltselect = 3, + fltselect = Enum.FltSelect.SpUnique, rarity = 250000, coefficient = 0, @@ -786,7 +786,7 @@ data:add { image = "elona.item_secret_treasure", value = 5000, weight = 1000, - fltselect = 3, + fltselect = Enum.FltSelect.SpUnique, rarity = 800000, coefficient = 100, @@ -809,7 +809,7 @@ data:add { image = "elona.item_gemstone", value = 50000, weight = 1200, - fltselect = 3, + fltselect = Enum.FltSelect.SpUnique, rarity = 800000, coefficient = 100, originalnameref2 = "Lulwy's gem stone", @@ -836,7 +836,7 @@ data:add { image = "elona.item_gemstone", value = 50000, weight = 1200, - fltselect = 3, + fltselect = Enum.FltSelect.SpUnique, rarity = 800000, coefficient = 100, originalnameref2 = "Jure's gem stone", @@ -863,7 +863,7 @@ data:add { image = "elona.item_gemstone", value = 50000, weight = 1200, - fltselect = 3, + fltselect = Enum.FltSelect.SpUnique, rarity = 800000, coefficient = 100, originalnameref2 = "Kumiromi's gem stone", @@ -888,7 +888,7 @@ data:add { image = "elona.item_gemstone", value = 50000, weight = 1200, - fltselect = 3, + fltselect = Enum.FltSelect.SpUnique, rarity = 800000, coefficient = 100, originalnameref2 = "gem stone", @@ -956,7 +956,7 @@ data:add { image = "elona.item_statue_of_jure", value = 100000, weight = 12000, - fltselect = 3, + fltselect = Enum.FltSelect.SpUnique, rarity = 800000, coefficient = 100, originalnameref2 = "statue", @@ -1154,7 +1154,7 @@ data:add { image = "elona.item_gemstone", value = 6800, weight = 1200, - fltselect = 1, + fltselect = Enum.FltSelect.Sp, rarity = 1000, coefficient = 100, originalnameref2 = "secret experience", @@ -1176,7 +1176,7 @@ data:add { image = "elona.item_statue_of_ehekatl", value = 100000, weight = 12000, - fltselect = 3, + fltselect = Enum.FltSelect.SpUnique, rarity = 800000, coefficient = 100, originalnameref2 = "statue", @@ -1263,7 +1263,7 @@ data:add { image = "elona.item_gemstone", value = 50000, weight = 1200, - fltselect = 1, + fltselect = Enum.FltSelect.Sp, rarity = 800000, coefficient = 100, originalnameref2 = "plank", @@ -1289,7 +1289,7 @@ data:add { image = "elona.item_gemstone", value = 50000, weight = 1200, - fltselect = 1, + fltselect = Enum.FltSelect.Sp, rarity = 800000, coefficient = 100, @@ -1314,7 +1314,7 @@ data:add { image = "elona.item_gemstone", value = 50000, weight = 1200, - fltselect = 1, + fltselect = Enum.FltSelect.Sp, rarity = 800000, coefficient = 100, @@ -1339,7 +1339,7 @@ data:add { image = "elona.item_gemstone", value = 50000, weight = 1200, - fltselect = 1, + fltselect = Enum.FltSelect.Sp, rarity = 800000, coefficient = 100, @@ -1402,7 +1402,7 @@ data:add { image = "elona.item_material_kit", value = 75000, weight = 5000, - fltselect = 3, + fltselect = Enum.FltSelect.SpUnique, rarity = 5000, coefficient = 0, @@ -1428,7 +1428,7 @@ data:add { image = "elona.item_statue_of_kumiromi", value = 100000, weight = 15000, - fltselect = 3, + fltselect = Enum.FltSelect.SpUnique, rarity = 800000, coefficient = 100, originalnameref2 = "statue", @@ -1450,7 +1450,7 @@ data:add { image = "elona.item_statue_of_mani", value = 100000, weight = 15000, - fltselect = 3, + fltselect = Enum.FltSelect.SpUnique, rarity = 800000, coefficient = 100, originalnameref2 = "statue", diff --git a/src/mod/elona/data/item/tree.lua b/src/mod/elona/data/item/tree.lua index cd53dfb5c..f1574e7ea 100644 --- a/src/mod/elona/data/item/tree.lua +++ b/src/mod/elona/data/item/tree.lua @@ -2,6 +2,7 @@ local Rand = require("api.Rand") local Gui = require("api.Gui") local Item = require("api.Item") local light = require("mod.elona.data.item.light") +local Enum = require("api.Enum") -- -- Tree @@ -46,7 +47,7 @@ data:add { image = "elona.item_tree_of_fruitless", value = 500, weight = 35000, - fltselect = 1, + fltselect = Enum.FltSelect.Sp, category = 80000, rarity = 100000, coefficient = 100, @@ -209,7 +210,7 @@ data:add { image = "elona.item_tree_of_naked", value = 500, weight = 14000, - fltselect = 8, + fltselect = Enum.FltSelect.Snow, category = 80000, rarity = 250000, coefficient = 100, @@ -227,7 +228,7 @@ data:add { image = "elona.item_tree_of_fir", value = 1800, weight = 28000, - fltselect = 8, + fltselect = Enum.FltSelect.Snow, category = 80000, rarity = 100000, coefficient = 100, @@ -246,7 +247,7 @@ data:add { value = 4800, weight = 35000, level = 30, - fltselect = 8, + fltselect = Enum.FltSelect.Snow, category = 80000, rarity = 100000, coefficient = 100, diff --git a/src/util/types.lua b/src/util/types.lua index 168da48bb..f409c6dcb 100644 --- a/src/util/types.lua +++ b/src/util/types.lua @@ -60,6 +60,36 @@ local function make_ctxt() return setmetatable(t, ctxt_mt) end +local function print_list(list) + local s = {} + for i, val in ipairs(list) do + if i > 10 then + s[#s+1] = "..." + break + end + s[#s+1] = tostring(val) + end + return table.concat(s, ", ") +end + +local function print_fields(fields) + local s = {} + local i = 0 + for key, val in pairs(fields) do + if i > 10 then + s[#s+1] = "..." + break + end + s[#s+1] = get_name(key) .. "=" .. get_name(val) + i = i + 1 + end + return table.concat(s, ", ") +end + +local function type_error(ty) + return ("Value is not of type \"%s\""):format(ty) +end + -- -- single-value checkers -- @@ -72,6 +102,18 @@ local function is_type_checker(obj) end return true end +types.is_type_checker = is_type_checker + +do + local any_checker = class.class("primitive_checker", ITypeChecker) + function any_checker:check(obj, _ctxt) + return true + end + function any_checker:__tostring() + return "any" + end + types.any = any_checker:new() +end local primitive_checker = class.class("primitive_checker", ITypeChecker) function primitive_checker:init(ty) @@ -81,7 +123,7 @@ function primitive_checker:check(obj, ctxt) if type(obj) == self.type then return true end - return false, tostring(self) + return false, type_error(self) end function primitive_checker:__tostring() return self.type @@ -113,7 +155,7 @@ do if type(obj) == "number" and not is_nan(obj) then return true end - return false, tostring(self) + return false, type_error(self) end function number_checker:__tostring() return "number" @@ -127,7 +169,7 @@ do if type(obj) == "number" and is_nan(obj) then return true end - return false, tostring(self) + return false, type_error(self) end function nan_checker:__tostring() return "nan" @@ -136,17 +178,17 @@ do end do - local integer_checker = class.class("integer_checker", ITypeChecker) - function integer_checker:check(obj, _ctxt) - if math.type(obj) == "integer" and not is_nan(obj) then + local int_checker = class.class("int_checker", ITypeChecker) + function int_checker:check(obj, _ctxt) + if math.type(obj) == "int" and not is_nan(obj) then return true end - return false, tostring(self) + return false, type_error(self) end - function integer_checker:__tostring() - return "integer" + function int_checker:__tostring() + return "int" end - types.integer = integer_checker:new() + types.int = int_checker:new() end do @@ -155,11 +197,82 @@ do if math.type(obj) == "float" and not is_nan(obj) then return true end - return false, tostring(self) + return false, type_error(self) end types.float = float_checker:new() end +do + local IDENTIFIER_REGEX = "^[a-z][_a-z0-9]*$" + + local identifier_checker = class.class("identifier_checker", ITypeChecker) + function identifier_checker:check(obj, ctxt) + if not types.string:check(obj, ctxt) then + return false, type_error(self) + end + + if not obj:match(IDENTIFIER_REGEX) then + return false, type_error(self) + end + + return true + end + function identifier_checker:__tostring() + return "identifier" + end + types.identifier = identifier_checker:new() +end + +local ID_REGEX = "^[_a-z][_a-z0-9]+%.[_a-z][_a-z0-9]+$" +do + local data_type_id_checker = class.class("data_type_id_checker", ITypeChecker) + function data_type_id_checker:check(obj, ctxt) + if not types.string:check(obj, ctxt) then + return false, type_error(self) + end + + if not obj:match(ID_REGEX) then + return false, type_error(self) + end + + return true + end + function data_type_id_checker:__tostring() + return "data_type_id" + end + types.data_type_id = data_type_id_checker:new() +end + +do + local locale_id_checker = class.class("locale_id_checker", ITypeChecker) + function locale_id_checker:check(obj, ctxt) + if not types.string:check(obj, ctxt) then + return false, type_error(self) + end + + return true + end + function locale_id_checker:__tostring() + return "locale_id" + end + types.locale_id = locale_id_checker:new() +end + +do + local type_type_checker = class.class("type_type_checker", ITypeChecker) + function type_type_checker:check(obj, _ctxt) + if is_type_checker(obj) then + return true + end + + return false, type_error(self) + end + function type_type_checker:__tostring() + return "type checker" + end + types.type = type_type_checker:new() +end + do local class_type_checker = class.class("class_type_checker", ITypeChecker) function class_type_checker:check(obj, _ctxt) @@ -167,7 +280,7 @@ do return true end - return false, tostring(self) + return false, type_error(self) end function class_type_checker:__tostring() return "class type" @@ -182,7 +295,7 @@ do return true end - return false, tostring(self) + return false, type_error(self) end function interface_type_checker:__tostring() return "interface type" @@ -202,7 +315,7 @@ do return true end - return false, tostring(self) + return false, type_error(self) end function enum_type_checker:__tostring() return "enum type" @@ -220,6 +333,137 @@ local function wrap(klass) end end +do + local gt_checker = class.class("gt_checker", ITypeChecker) + function gt_checker:init(checker, comp) + assert(is_type_checker(checker)) + self.checker = checker + self.comp = comp + end + function gt_checker:check(obj, _ctxt) + if not self.checker:check(obj) then + return false, type_error(self) + end + + if obj > self.comp then + return true + end + + return false, type_error(self) + end + function gt_checker:__tostring() + return ("%s > %s"):format(self.checker, self.comp) + end + types.gt = wrap(gt_checker) +end + +do + local lt_checker = class.class("lt_checker", ITypeChecker) + function lt_checker:init(checker, comp) + assert(is_type_checker(checker)) + self.checker = checker + self.comp = comp + end + function lt_checker:check(obj, _ctxt) + if not self.checker:check(obj) then + return false, type_error(self) + end + + if obj < self.comp then + return true + end + + return false, type_error(self) + end + function lt_checker:__tostring() + return ("%s < %s"):format(self.checker, self.comp) + end + types.lt = wrap(lt_checker) +end + +do + local gteq_checker = class.class("gteq_checker", ITypeChecker) + function gteq_checker:init(checker, comp) + assert(is_type_checker(checker)) + self.checker = checker + self.comp = comp + end + function gteq_checker:check(obj, _ctxt) + if not self.checker:check(obj) then + return false, type_error(self) + end + + if obj >= self.comp then + return true + end + + return false, type_error(self) + end + function gteq_checker:__tostring() + return ("%s >= %s"):format(self.checker, self.comp) + end + types.gteq = wrap(gteq_checker) +end + +do + local lteq_checker = class.class("lteq_checker", ITypeChecker) + function lteq_checker:init(checker, comp) + assert(is_type_checker(checker)) + self.checker = checker + self.comp = comp + end + function lteq_checker:check(obj, _ctxt) + if not self.checker:check(obj) then + return false, type_error(self) + end + + if obj <= self.comp then + return true + end + + return false, type_error(self) + end + function lteq_checker:__tostring() + return ("%s <= %s"):format(self.checker, self.comp) + end + types.lteq = wrap(lteq_checker) +end + +function types.positive(checker) + return types.gteq(checker, 0) +end + +function types.negative(checker) + return types.lt(checker, 0) +end + +types.uint = types.positive(types.integer) + +do + local range_checker = class.class("range_checker", ITypeChecker) + function range_checker:init(checker, min, max) + assert(is_type_checker(checker)) + self.checker = checker + self.min = min + self.max = max + end + function range_checker:check(obj, _ctxt) + if not self.checker:check(obj) then + return false, type_error(self) + end + + if obj < self.min or obj > self.max then + return false, type_error(self) + end + + return true + end + function range_checker:__tostring() + return ("%s in [%s, %s]"):format(self.checker, self.min, self.max) + end + types.range = wrap(range_checker) +end + do local enum_checker = class.class("enum_checker", ITypeChecker) function enum_checker:init(enum) @@ -231,7 +475,7 @@ do return true end - return false, tostring(self) + return false, type_error(self) end function enum_checker:__tostring() return "enum type" @@ -240,65 +484,96 @@ do end do - local instance_of_checker = class.class("instance_of_checker", ITypeChecker) - function instance_of_checker:init(klass) + local class_checker = class.class("class_checker", ITypeChecker) + function class_checker:init(klass) assert(class.is_class(klass), ("%s is not a class"):format(klass)) self.class = klass end - function instance_of_checker:check(obj, _ctxt) + function class_checker:check(obj, _ctxt) if class.is_an(self.class, obj) then return true end - return false, tostring(self) + return false, type_error(self) end - function instance_of_checker:__tostring() + function class_checker:__tostring() return tostring(self.class) end - types.instance_of = wrap(instance_of_checker) + types.class = wrap(class_checker) end do - local implements_checker = class.class("implements_checker", ITypeChecker) - function implements_checker:init(iface) + local interface_checker = class.class("interface_checker", ITypeChecker) + function interface_checker:init(iface) assert(class.is_interface(iface), ("%s is not an interface"):format(iface)) self.iface = iface end - function implements_checker:check(obj, _ctxt) + function interface_checker:check(obj, _ctxt) if class.is_an(self.iface, obj) then return true end - return false, tostring(self) + return false, type_error(self) end - function implements_checker:__tostring() + function interface_checker:__tostring() return tostring(self.iface) end - types.implements = wrap(implements_checker) + types.interface = wrap(interface_checker) +end + +local optional_checker = class.class("optional_checker", ITypeChecker) +function optional_checker:init(checker) + assert(is_type_checker(checker)) + self.checker = checker end +function optional_checker:check(obj, ctxt) + if obj == nil then + return true + end + + local ok, _err = self.checker:check(obj, ctxt) + if not ok then + return false, type_error(self) + end + + return true +end +function optional_checker:__tostring() + return ("optional<%s>"):format(self.checker) +end +types.optional = wrap(optional_checker) do - local optional_checker = class.class("optional_checker", ITypeChecker) - function optional_checker:init(checker) - assert(is_type_checker(checker)) - self.checker = checker + local tuple_checker = class.class("tuple_checker", ITypeChecker) + function tuple_checker:init(checkers) + for i, checker in ipairs(checkers) do + if not is_type_checker(checker) then + error(("Object for tuple index '%s' is not a type checker (%s)"):format(i, checker)) + end + end + self.checkers = checkers end - function optional_checker:check(obj, ctxt) - if obj == nil then - return true + function tuple_checker:check(obj, ctxt) + if not types.table:check(obj, ctxt) then + return false, type_error(self) end - local ok, _err = self.checker:check(obj, ctxt) - if not ok then - return false, tostring(self) + for i, checker in ipairs(self.checkers) do + local val = obj[i] + ctxt:push(i, val) + local ok, _err = checker:check(val, ctxt) + if not ok then + return false, type_error(self) + end + ctxt:pop() end return true end - function optional_checker:__tostring() - return ("optional<%s>"):format(self.checker) + function tuple_checker:__tostring() + return ("tuple<%s>"):format(print_list(self.checkers)) end - types.optional = wrap(optional_checker) + types.tuple = wrap(tuple_checker) end do @@ -309,14 +584,14 @@ do end function keys_checker:check(obj, ctxt) if not types.table:check(obj, ctxt) then - return false, "table" + return false, type_error(self) end for key, _ in pairs(obj) do ctxt:push(key) local ok, _err = self.checker:check(key) if not ok then - return false, tostring(self) + return false, type_error(self) end ctxt:pop() end @@ -337,14 +612,14 @@ do end function values_checker:check(obj, ctxt) if not types.table:check(obj, ctxt) then - return false, "table" + return false, type_error(self) end for key, val in pairs(obj) do - ctxt:push_value(key, val) + ctxt:push(key, val) local ok, _err = self.checker:check(val) if not ok then - return false, tostring(self) + return false, type_error(self) end ctxt:pop() end @@ -367,21 +642,21 @@ do end function map_checker:check(obj, ctxt) if not types.table:check(obj, ctxt) then - return false, "table" + return false, type_error(self) end for key, val in pairs(obj) do ctxt:push(key) local ok, _err = self.key_checker:check(key, ctxt) if not ok then - return false, tostring(self) + return false, type_error(self) end ctxt:pop() - ctxt:push_value(key, val) + ctxt:push(key, val) ok, _err = self.value_checker:check(val, ctxt) if not ok then - return false, tostring(self) + return false, type_error(self) end ctxt:pop() end @@ -399,23 +674,61 @@ function types.set(value_checker) end do - local any_checker = class.class("any_checker", ITypeChecker) - function any_checker:init(...) + local list_keys_checker = types.keys(types.int) + + local list_checker = class.class("list_checker", ITypeChecker) + function list_checker:init(checker) + assert(is_type_checker(checker)) + self.checker = checker + end + function list_checker:check(obj, ctxt) + if not types.table:check(obj, ctxt) then + return false, type_error(self) + end + + if #obj == 0 then + return true + end + + if not list_keys_checker:check(obj, ctxt) then + return false, type_error("table with integer keys") + end + + for i, val in ipairs(obj) do + ctxt:push(i, val) + local ok, err = self.checker:check(val, ctxt) + if not ok then + return false, err + end + ctxt:pop() + end + + return true + end + function list_checker:__tostring() + return ("list<%s>"):format(self.checker) + end + types.list = wrap(list_checker) +end + +do + local some_checker = class.class("some_checker", ITypeChecker) + function some_checker:init(...) local checkers = { ... } for _, checker in ipairs(checkers) do assert(is_type_checker(checker)) end self.checkers = checkers end - function any_checker:check(obj, ctxt) + function some_checker:check(obj, ctxt) for _, checker in ipairs(self.checkers) do - if checker(obj, ctxt) then + if checker:check(obj, ctxt) then return true end end - return false, tostring(self) + return false, type_error(self) end - function any_checker:__tostring() + function some_checker:__tostring() local s = {} for i, checker in ipairs(self.checkers) do if i > 10 then @@ -424,9 +737,9 @@ do end s[#s+1] = tostring(checker) end - return ("any<%s>"):format(table.concat(", ")) + return ("some<%s>"):format(table.concat(s, ", ")) end - types.any = wrap(any_checker) + types.some = wrap(some_checker) end do @@ -440,7 +753,7 @@ do end function all_checker:check(obj, ctxt) for _, checker in ipairs(self.checkers) do - local ok, err = checker(obj, ctxt) + local ok, err = checker:check(obj, ctxt) if not ok then return false, err end @@ -461,31 +774,19 @@ do types.all = wrap(all_checker) end -local function print_fields(fields) - local s = {} - local i = 0 - for key, checker in pairs(fields) do - if i > 10 then - s[#s+1] = "..." - break - end - s[#s+1] = get_name(key) .. "=" .. tostring(checker) - i = i + 1 - end - return table.concat(s, ", ") -end - do local fields_checker = class.class("fields_checker", ITypeChecker) function fields_checker:init(fields) - for _, checker in pairs(fields) do - assert(is_type_checker(checker)) + for key, checker in pairs(fields) do + if not is_type_checker(checker) then + error(("Object for field '%s' is not a type checker (%s)"):format(key, checker)) + end end self.fields = fields end function fields_checker:check(obj, ctxt) if not types.table:check(obj, ctxt) then - return false, "table" + return false, type_error(self) end for key, checker in pairs(self.fields) do @@ -508,44 +809,183 @@ end do local fields_strict_checker = class.class("fields_strict_checker", ITypeChecker) function fields_strict_checker:init(fields) - for _, checker in pairs(fields) do - assert(is_type_checker(checker)) + for key, checker in pairs(fields) do + if not is_type_checker(checker) then + error(("Object for field '%s' is not a type checker (%s)"):format(key, checker)) + end end self.fields = fields end function fields_strict_checker:check(obj, ctxt) if not types.table:check(obj, ctxt) then - return false, "table" + return false, type_error(self) end + local remaining = table.set(table.keys(self.fields)) for key, val in pairs(obj) do local checker = self.fields[key] if not checker then - return false, ("table with key \"%s\""):format(key) + return false, ("Table has superfluous key: \"%s\""):format(key) end ctxt:push(key, val) - local ok, err = checker(val, ctxt) + local ok, err = checker:check(val, ctxt) if not ok then return false, err end ctxt:pop() + + if remaining[key] then + remaining[key] = nil + end + end + + local missing = next(remaining) + if missing then + local checker = self.fields[missing] + if not class.is_an(optional_checker, checker) then + return false, ("Table is missing required field '%s' of type '%s'"):format(missing, checker) + end end return true end function fields_strict_checker:__tostring() - return ("fields<%s>"):format(print_fields(self.fields)) + return ("fields_strict<%s>"):format(print_fields(self.fields)) end types.fields_strict = wrap(fields_strict_checker) end +do + local literal_checker = class.class("literal_checker", ITypeChecker) + function literal_checker:init(...) + self.literals = { ... } + end + function literal_checker:check(obj, ctxt) + for _, literal in ipairs(self.literals) do + if obj == literal then + return true + end + end + return false, type_error(self) + end + function literal_checker:__tostring() + return ("literal<%s>"):format(print_list(self.literals)) + end + types.literal = wrap(literal_checker) +end + +do + local data_id_checker = class.class("data_id_checker", ITypeChecker) + function data_id_checker:init(_type) + self._type = _type + end + function data_id_checker:check(obj, ctxt) + if not types.string:check(obj, ctxt) then + return false, type_error(self) + end + + if not obj:match(ID_REGEX) then + return false, type_error(self) + end + + return true + end + function data_id_checker:__tostring() + return ("data_id<%s>"):format(self._type) + end + types.data_id = wrap(data_id_checker) +end + +do + local data_entry_checker = class.class("data_entry_checker", ITypeChecker) + function data_entry_checker:init(_type) + self._type = _type + end + function data_entry_checker:check(obj, ctxt) + if not types.table:check(obj, ctxt) then + return false, type_error(self) + end + + if obj._type ~= self._type then + return false, type_error(self) + end + + return true + end + function data_entry_checker:__tostring() + return ("data_entry<%s>"):format(self._type) + end + types.data_entry = wrap(data_entry_checker) +end + +do + local callback_checker = class.class("callback_checker", ITypeChecker) + function callback_checker:init(...) + local checkers = { ... } + local args = {} + for i=1, #checkers, 2 do + local arg_name = checkers[i] + local checker = checkers[i+1] + assert(type(arg_name) == "string", ("Callback argument name must be string, got '%s'"):format(arg_name)) + assert(is_type_checker(checker)) + args[#args+1] = {name = arg_name, checker = checker} + end + self.args = args + end + function callback_checker:check(obj, _ctxt) + if types["function"]:check(obj) then + return true + end + + return false, type_error(self) + end + function callback_checker:__tostring() + return ("function<%s>"):format(print_list(self.checkers)) + end + + function types.callback(s) + if s == nil then + return types["function"] + end + return callback_checker:new(s) + end +end + +do + local map_object_checker = class.class("map_object_checker", ITypeChecker) + function map_object_checker:init(_type) + assert(type(_type) == "string") + self._type = _type + end + function map_object_checker:check(obj, ctxt) + -- copied from MapObject.is_map_object() + if not class.is_an("api.IMapObject", obj) then + return false, ("'%s' is not a map object"):format(obj) + end + + if self._type == "any" then + return true + end + + if self._type ~= obj._type then + return false, ("Expected map object of type '%s', got '%s'"):format(self._type, obj._type) + end + + return true + end + function map_object_checker:__tostring() + return ("map_object<%s>"):format(self.iface) + end + types.map_object = wrap(map_object_checker) +end + function types.check(obj, checker, verbose) assert(is_type_checker(checker)) local ctxt = make_ctxt() - local success, needed_ty = checker:check(obj, ctxt) + local success, err = checker:check(obj, ctxt) if not success then - needed_ty = needed_ty or "" + err = err or "" local s if verbose then s = ctxt:make_trail(obj) @@ -557,7 +997,7 @@ function types.check(obj, checker, verbose) s = get_name(obj) end end - return false, ("Typecheck failed - Value is not of type \"%s\": %s"):format(needed_ty, s) + return false, ("%s: %s"):format(err, s) end return true end From 6d50dfadcc0b485223ec999523192dcb13f0b4bb Mon Sep 17 00:00:00 2001 From: Ruin0x11 Date: Thu, 9 Sep 2021 18:39:11 -0700 Subject: [PATCH 04/17] Add new rest of fields typings for base data types --- src/internal/data/config_option_type.lua | 8 +- src/internal/data/schemas.lua | 703 ++++++++++++++++------- src/internal/data_table.lua | 19 +- src/internal/draw/atlas.lua | 2 +- src/mod/elona/data/enchantment.lua | 10 +- src/mod/elona/data/skill.lua | 157 ----- src/mod/elona/data/trait.lua | 14 +- src/mod/elona_sys/init.lua | 7 - src/mod/smithing/data/chip.lua | 2 +- src/util/types.lua | 179 +++--- 10 files changed, 638 insertions(+), 463 deletions(-) diff --git a/src/internal/data/config_option_type.lua b/src/internal/data/config_option_type.lua index 4f7d396b9..dbc3ab41b 100644 --- a/src/internal/data/config_option_type.lua +++ b/src/internal/data/config_option_type.lua @@ -30,7 +30,7 @@ data:add_multi( { _id = "number", - fields = { min_value = "number", max_value = "number" }, + fields = { min_value = types.number, max_value = types.number }, widget = "api.gui.menu.config.item.ConfigItemNumberWidget", default = function(option) @@ -62,7 +62,7 @@ data:add_multi( { _id = "integer", - fields = { min_value = "integer", max_value = "integer" }, + fields = { min_value = types.int, max_value = types.int }, widget = "api.gui.menu.config.item.ConfigItemIntegerWidget", default = function(option) @@ -94,7 +94,7 @@ data:add_multi( { _id = "enum", - fields = { choices = "table" }, + fields = { choices = types.some(types.list(types.string), types.callback({}, types.list(types.string))) }, widget = "api.gui.menu.config.item.ConfigItemEnumWidget", default = function(option) @@ -125,7 +125,7 @@ data:add_multi( { _id = "string", - fields = { max_length = "integer" }, + fields = { max_length = types.uint }, widget = "api.gui.menu.config.item.ConfigItemStringWidget", default = "", diff --git a/src/internal/data/schemas.lua b/src/internal/data/schemas.lua index 64d056a40..98650c23f 100644 --- a/src/internal/data/schemas.lua +++ b/src/internal/data/schemas.lua @@ -1,8 +1,10 @@ -local schema = require("thirdparty.schema") local data = require("internal.data") local CodeGenerator = require("api.CodeGenerator") local Enum = require("api.Enum") local IEventEmitter = require("api.IEventEmitter") +local InstancedMap = require("api.InstancedMap") +local InstancedArea = require("api.InstancedArea") +local IConfigItemWidget = require("api.gui.menu.config.item.IConfigItemWidget") local ty_data_ext_field = types.fields { name = types.string, @@ -463,6 +465,12 @@ Skills this character will already know when they're created. { interface = IChara } ) +local ty_enchantment_def = types.fields { + _id = types.data_id("base.enchantment"), + power = types.number, + params = types.optional(types.table) +} + data:add_type( { name = "item", @@ -598,11 +606,7 @@ What gods this item can be offered to. { name = "enchantments", type = types.list( - types.fields { - _id = types.data_id("base.enchantment"), - power = types.number, - params = types.optional(types.table) - } + ty_enchantment_def ), default = {}, }, @@ -985,6 +989,10 @@ data:add_type( } ) +local ty_indicator_text = types.some(types.string, types.fields { text = types.string, color = ty_color }) +local ty_indicator_cb = types.callback({"chara", types.map_object("base.chara")}, ty_indicator_text) +local ty_indicator = types.some(types.locale_id, ty_indicator_cb) + data:add_type{ name = "effect", fields = { @@ -994,7 +1002,7 @@ data:add_type{ }, { name = "indicator", - type = types.some(types.locale_id, types.callback("chara", types.map_object("base.chara"))) + type = ty_indicator }, { name = "emotion_icon", @@ -1125,7 +1133,7 @@ data:add_type { local ty_image_entry = types.some( -- "graphic/chip.png", - types.string, + types.path, -- { -- image = "graphic/chip.bmp", @@ -1133,7 +1141,7 @@ local ty_image_entry = types.some( -- key_color = {0, 0, 0} -- } types.fields_strict { - image = types.string, + image = types.path, count_x = types.optional(types.uint), key_color = types.optional(ty_color) }, @@ -1148,7 +1156,7 @@ local ty_image_entry = types.some( -- key_color = {0, 0, 0} -- } types.fields_strict { - source = types.string, + source = types.path, width = types.uint, height = types.uint, x = types.uint, @@ -1252,24 +1260,81 @@ Value of this enchantment. ]] }, { - name = "level", + name = "rarity", type = types.uint, - default = 100, template = true, doc = [[ Rarity of this enchantment. Lower means more rare. ]] }, + { + name = "level", + type = types.uint, + template = true, + doc = [[ +Level of this enchantment. +]] + }, + { + name = "icon", + type = types.optional(types.uint) -- TODO: needs to be themable + }, + { + name = "color", + type = types.optional(ty_color) + }, + { + name = "params", + type = types.map(types.string, types.type), + default = {} + }, { name = "filter", + type = types.optional(types.callback({"item", types.map_object("base.item")}, types.boolean)), template = true, doc = [[ Function to filter which items this enchantment will get applied to. If nil, it can be applied to any item generated randomly. ]] }, + { + name = "on_generate", + type = types.optional(types.callback({"self", types.data_entry("base.enchantment"), "item", types.map_object("base.item"), "params", types.table}, types.boolean)), + template = true, + }, + { + name = "on_initialize", + type = types.optional(types.callback("self", types.data_entry("base.enchantment"), "item", types.map_object("base.item"), "params", types.table)), + template = true, + }, + { + name = "localize", + type = types.optional(types.callback({"power", types.number, "params", types.table, "item", types.map_object("base.item")}, types.string)), + template = true, + }, + { + name = "on_refresh", + type = types.optional(types.callback("power", types.number, "params", types.table, "item", types.map_object("base.item"), "chara", types.map_object("base.chara"))), + template = true, + }, + { + name = "on_attack_hit", + type = types.optional(types.callback("power", types.number, "enc_params", types.table, "chara", types.map_object("base.chara"), "params", types.table)), + template = true, + }, + { + name = "on_turns_passed", + type = types.optional(types.callback("power", types.number, "params", types.table, "item", types.map_object("base.item"), "chara", types.map_object("base.chara"))), + template = true, + }, + { + name = "on_eat_food", + type = types.optional(types.callback("power", types.number, "enc_params", types.table, "item", types.map_object("base.item"), "chara", types.map_object("base.chara"))), + template = true, + }, { name = "alignment", + type = types.literal("positive", "negative"), default = "positive", template = true, doc = [[ @@ -1277,12 +1342,13 @@ Determines if this enchantment is beneficial or not. One of "positive" or "negat ]] }, { - name = "power", - default = CodeGenerator.gen_literal [[ -function(power, item, wearer) - return power / 50 - end -]], + name = "adjusted_power", + type = types.optional(types.callback({"power", types.number}, types.number)), + -- default = CodeGenerator.gen_literal [[ + -- function(power, item, wearer) + -- return power / 50 + -- end + -- ]], template = true, doc = [[ How to adjust the power when applying the enchantment. @@ -1296,8 +1362,7 @@ data:add_type { fields = { { name = "level", - type = "int", - default = 0, + type = types.uint, template = true, doc = [[ Level of this ego enchantment. Typically between 0-3. @@ -1305,12 +1370,7 @@ Level of this ego enchantment. Typically between 0-3. }, { name = "filter", - type = "function", - default = CodeGenerator.gen_literal [[ -function(item) - return true -end -]], + type = types.callback("item", types.map_object("base.item")), template = true, doc = [[ A function to filter which items this ego can get applied to. @@ -1318,6 +1378,7 @@ A function to filter which items this ego can get applied to. }, { name = "enchantments", + type = types.list(ty_enchantment_def), default = {}, template = true, doc = [[ @@ -1332,12 +1393,18 @@ data:add_type { fields = {} } +local ty_target_type = types.literal("self", "nearby", "self_or_nearby", "enemy", "other", "location", "direction", "target_or_location") + data:add_type { name = "enchantment_skill", fields = { + { + name = "elona_id", + type = types.optional(types.uint) + }, { name = "skill_id", - default = "elona.short_teleport", + type = types.data_id("base.skill"), template = true, doc = [[ Skill to trigger. @@ -1345,6 +1412,7 @@ Skill to trigger. }, { name = "target_type", + type = ty_target_type, default = "self", template = true, doc = [[ @@ -1353,6 +1421,7 @@ The target of the skill. Same format as that of "base.skill". Usually either "se }, { name = "rarity", + type = types.uint, default = 100, template = true, doc = [[ @@ -1361,7 +1430,8 @@ Rarity of this enchantment skill when generating an enchantment containing it. }, { name = "categories", - default = { "elona.equip_melee" }, + type = types.list(types.data_id("base.item_type")), + default = { "elona.equip_melee", "elona.equip_ranged" }, template = true, doc = [[ Valid item categories this enchantment skill applies to. @@ -1369,10 +1439,20 @@ Valid item categories this enchantment skill applies to. }, { name = "power", + type = types.number, default = 10, template = true, doc = [[ Power of the skill when it is triggered. +]] + }, + { + name = "chance", + type = types.number, + default = 10, + template = true, + doc = [[ +Chance to trigger skill. ]] } } @@ -1383,6 +1463,7 @@ data:add_type { fields = { { name = "ammo_amount", + type = types.uint, default = 30, template = true, doc = [[ @@ -1391,6 +1472,7 @@ Controls the starting amount of ammo. }, { name = "ammo_factor", + type = types.uint, default = 70, template = true, doc = [[ @@ -1399,6 +1481,7 @@ Controls the starting amount of ammo. }, { name = "stamina_cost", + type = types.number, default = 1, template = true, doc = [[ @@ -1408,39 +1491,21 @@ Stamina cost of the ammo when fired. } } -data:add_type { - name = "stat", - schema = schema.Record { - }, -} - data:add_type { name = "skill", fields = { { name = "type", - default = "effect", + type = types.literal("stat", "stat_special", "skill", "weapon_proficiency"), + default = "skill", template = true, doc = [[ -Determines how this skill is treated in the interface. Available options: - -- "skill": Only viewable in the player's skills list in the character sheet. (default) -- "spell": Castable from the player's Spells menu. -- "action": Useable from the player's Skills menu. -]] - }, - { - name = "effect_id", - default = nil, - template = true, - doc = [[ -The related magic of this skill to trigger when its entry in the menu is selected. - -*Required* if the skill's `type` is "spell" or "action". +Determines how this skill is treated in the interface. ]] }, { name = "related_skill", + type = types.optional(types.data_id("base.skill")), default = nil, template = true, doc = [[ @@ -1449,6 +1514,7 @@ A related stat to improve when this skill is used. Affects the skill's icon in t }, { name = "cost", + type = types.uint, default = 10, template = true, doc = [[ @@ -1459,6 +1525,7 @@ Used only when the skill's `type` is "spell" or "action". }, { name = "range", + type = types.uint, default = 0, template = true, doc = [[ @@ -1472,6 +1539,7 @@ Used only when the skill's `type` is "spell" or "action". }, { name = "difficulty", + type = types.uint, default = 100, template = true, doc = [[ @@ -1482,6 +1550,7 @@ Used only when the skill's `type` is "spell" or "action". }, { name = "target_type", + type = ty_target_type, default = "self", template = true, doc = [[ @@ -1505,6 +1574,7 @@ Used only when the skill's `type` is "spell" or "action". }, { name = "ignore_missing_target", + type = types.boolean, default = false, doc = [[ If true, continue to use the skill even if a target character was not found. @@ -1517,39 +1587,91 @@ This is used by the Pickpocket skill to select an item on the ground independent data:add_type { name = "trait", - schema = schema.Record { + fields = { + { + name = "elona_id", + type = types.optional(types.uint) + }, + { + name = "level_min", + type = types.uint, + }, + { + name = "level_max", + type = types.uint, + }, + { + name = "type", + type = types.literal("feat", "mutation", "race", "ether_disease") + }, + { + name = "can_acquire", + type = types.optional(types.callback({"self", types.data_entry("base.trait"), "chara", types.map_object("base.chara")}, types.boolean)) + }, + { + name = "on_modify_level", + type = types.optional(types.callback("cur_level", types.int, "chara", types.map_object("base.chara"), "prev_level", types.int)) + }, + { + name = "on_refresh", + type = types.optional(types.callback("self", types.data_entry("base.trait"), "chara", types.map_object("base.chara"))) + }, + { + name = "on_turn_begin", + type = types.optional(types.callback({"self", types.data_entry("base.trait"), "chara", types.map_object("base.chara")}, types.any)) + }, + { + name = "locale_params", + type = types.optional(types.callback({"self", types.data_entry("base.trait"), "chara", types.map_object("base.chara")}, types.any)) + }, }, } data:add_type { name = "sound", - schema = schema.Record { - file = schema.String - }, + fields = { + { + name = "elona_id", + type = types.optional(types.uint) + }, + { + name = "file", + type = types.path + } + } } data:add_type { name = "music", - schema = schema.Record { - file = schema.String - }, + fields = { + { + name = "elona_id", + type = types.optional(types.uint) + }, + { + name = "file", + type = types.path + } + } } data:add_type { name = "ui_indicator", - schema = schema.Record { - indicator = schema.Function - }, + fields = { + { + name = "indicator", + type = ty_indicator_cb + } + } } data:add_type { name = "scenario", fields = { { - name = "on_game_begin", - default = nil, + name = "on_game_start", + type = types.callback("self", types.data_entry("base.scenario"), "player", types.map_object("base.chara")), template = true, - type = "function(self,IChara)", doc = [[ Function called on game begin. Is passed the created player. ]] @@ -1562,16 +1684,79 @@ data:add_type { fields = { { name = "overrides", - default = {}, + type = types.map(types.data_type_id, types.table), template = true, } } } +local ty_region = types.tuple(types.uint, types.uint, types.uint, types.uint) + data:add_type { name = "asset", - schema = schema.Record { - }, + fields = { + { + name = "type", + type = types.literal("asset", "font", "color"), + default = "asset" + }, + + -- asset + { + name = "image", + type = types.optional(types.path) + }, + { + name = "source", + type = types.optional(types.path) + }, + { + name = "x", + type = types.optional(types.uint) + }, + { + name = "y", + type = types.optional(types.uint) + }, + { + name = "width", + type = types.optional(types.uint) + }, + { + name = "height", + type = types.optional(types.uint) + }, + { + name = "count_x", + type = types.optional(types.uint) + }, + { + name = "count_y", + type = types.optional(types.uint) + }, + { + name = "regions", + type = types.optional(types.some(types.values(ty_region), + types.callback({"width", types.number, "height", types.number}, + types.values(ty_region)))) + }, + { + name = "key_color", + type = types.optional(types.some(types.literal("none"), ty_color)) + }, + + -- font + { + name = "size", + type = types.optional(types.uint) + }, + + -- color + { + name = "color", + type = types.optional(ty_color) + } + } } data:add_type { @@ -1579,9 +1764,8 @@ data:add_type { fields = { { name = "image", - default = "mod//graphic/image.png", + type = ty_image, template = true, - type = "string|{source=string,x=int,y=int,width=int,height=int,count_x=int?,count_y=int?,key_color={int,int,int}?}", doc = [[ The image to use for this chip. @@ -1596,8 +1780,19 @@ It can either be a string referencing an image file, or a table with these conte - key_color: if `source` is a BMP, controls the color to convert to transparency. Defaults to {0, 0, 0}. ]] }, + { + name = "shadow", + type = types.uint, + default = 0 + }, + { + name = "stack_height", + type = types.int, + default = 0 + }, { name = "y_offset", + type = types.int, default = 0, template = true, doc = [[ @@ -1607,180 +1802,184 @@ Y offset of the sprite in pixels. } } -data:add_type { - name = "asset", - schema = schema.Record { - target = schema.String, - } -} - data:add_type { name = "ai_action", fields = { { name = "act", - default = CodeGenerator.gen_literal [[ -function(chara, params) - return true - end]], + type = types.callback({"chara", types.map_object("base.chara"), "params", types.table}, types.boolean), template = true, - type = "function(IChara,table)", doc = [[ - Runs arbitrary AI actions. Is passed the character and extra parameters, differing depending on the action. +Runs arbitrary AI actions. Is passed the character and extra parameters, differing depending on the action. - Returns true if the character acted, false if not. +Returns true if the character acted, false if not. ]] } } } -data:add_type { - name = "talk", - schema = schema.Record { - messages = schema.Table - } -} - data:add_type { name = "talk_event", - schema = schema.Record { - params = schema.Table + fields = { + { + name = "elona_txt_id", + type = types.optional(types.string) + } } } data:add_type { name = "portrait", - schema = schema.Record { - image = schema.String - } -} - -data:add_type { - name = "config_menu", - schema = schema.Record { - options = schema.Table, - on_generate = schema.Optional(schema.Function), + fields = { + { + name = "elona_id", + type = types.optional(types.uint) + }, + { + name = "image", + type = ty_image + } } } data:add_type { name = "keybind", - schema = schema.Record { - default = schema.String + fields = { + { + name = "default", + type = types.string + }, + { + name = "default_alternate", + type = types.optional(types.list(types.string)) + } } } data:add_type { name = "pcc_part", - schema = schema.Record { - kind = schema.String, - image = schema.String + fields = { + { + name = "kind", + type = types.literal("belt", "body", "boots", "chest", "cloth", "etc", "eye", "glove", "hair", "hairbk", "leg", "mantle", "mantlebk", "pants", "ride", "ridebk", "subhair") + }, + { + name = "image", + type = types.path + }, + { + name = "key_color", + type = types.optional(ty_color) + } } } +local ty_chara_filter = types.fields { + quality = types.enum(Enum.Quality), + level = types.uint, + initial_level = types.uint, + id = types.data_id("base.chara"), + fltselect = types.enum(Enum.FltSelect), + category = types.enum(Enum.CharaCategory), + create_params = types.table, + tag_filters = types.list(types.string), + race_filter = types.data_id("base.race"), + ownerless = types.boolean, +} + data:add_type { - name = "map_template", - schema = schema.Record { - map = schema.String, - copy = schema.Optional(schema.Table), - areas = schema.Optional(schema.Table), - on_generate = schema.Optional(schema.Function), - }, + name = "map_archetype", fields = { { - name = "copy", - default = {}, + name = "starting_pos", + type = types.optional(types.callback("map", types.class(InstancedMap), + "chara", types.map_object("base.chara"), + "prev_map", types.optional(types.class(InstancedMap)), + "feat", types.optional(types.map_object("base.feat")))), template = true, - type = "table", doc = [[ -List of fields to copy to the map when it is instantiated. +Callback run when this map is restocked, refreshing things like shop inventories. ]] }, { - name = "areas", - default = nil, - template = false, - type = "table", + name = "on_generate_map", + type = types.optional(types.callback({"area", types.class(InstancedArea)}, types.class(InstancedMap))), + template = true, doc = [[ -List of map entrances to other maps contained in this map. +Callback run when this map is to be generated. Must return the final map. ]] }, - } -} + { + name = "on_map_renew_minor", + type = types.optional(types.callback("map", types.class(InstancedMap), "params", types.table)), + template = true, + doc = [[ +Callback run when this map is restocked, refreshing things like shop inventories. +]] + }, + { + name = "on_map_renew_major", + type = types.optional(types.callback("map", types.class(InstancedMap), "params", types.table)), + template = true, + doc = [[ +Callback run when this map is renewed, in order to regenerate its geometry. +]] + }, + { + name = "on_map_renew_geometry", + type = types.optional(types.callback("map", types.class(InstancedMap), "params", types.table)), + template = true, + doc = [[ +Callback run when this map's geometry is recreated from scratch. -data:add_type { - name = "map_archetype", - fields = { +Used for restoring towns to their pristine condition after destroying their terrain. +]] + }, { - name = "on_spawn_monster", - default = CodeGenerator.gen_literal [[ -function(map) - end]], + name = "on_map_loaded_events", + type = types.optional(types.callback("map", types.class(InstancedMap), "params", types.table)), template = true, - type = "function(InstancedMap)", doc = [[ -Callback run when a monster is spawned in the map. +Callback run when this map is about to be entered. ]] }, { - name = "on_map_restock", - default = CodeGenerator.gen_literal [[ -function(map) - end]], + name = "on_map_entered", + type = types.optional(types.callback("map", types.class(InstancedMap), "params", types.table)), template = true, - type = "function(InstancedMap)", doc = [[ -Callback run when this map is restocked, refreshing things like shop inventories. +Callback run when this map is being entered (after on_map_loaded_events). ]] }, { - name = "on_map_renew", - default = CodeGenerator.gen_literal [[ -function(map) - end]], + name = "on_map_pass_turn", + type = types.optional(types.callback({"map", types.class(InstancedMap), "params", types.table, "result", types.string}, types.string)), template = true, - type = "function(InstancedMap)", doc = [[ -Callback run when this map is renewed, in order to regenerate its geometry. +Callback run when a turn is passed in this map. ]] }, { - name = "on_generate_map", - default = CodeGenerator.gen_literal [[ -function(area, floor) - return InstancedMap(20, 20) -end -]], + name = "properties", + type = types.map(types.string, types.any), template = true, - type = "function(InstancedArea, int)?", doc = [[ -How this map should be generated for the first time. - -This is to be used for generating areas from `base.area_archetype` so you don't -have to create a new instance of `base.area_archetype` every single time for its -`on_generate_floor` callback if all you want is an area containing a single map. -If you don't list this map archetype in the `floors` property of any area -archetype, then this function can be omitted. +Properties to copy to this map after it is generated. Does not override any values already set in the `on_generate` callback. ]] }, { - name = "properties", - default = CodeGenerator.gen_literal [[ -{ - is_indoor = true, - level = 10 -}]], + name = "chara_filter", + type = types.optional(types.callback({"map", types.class(InstancedMap)}, ty_chara_filter)), template = true, - type = "table", doc = [[ Properties to copy to this map after it is generated. Does not override any values already set in the `on_generate` callback. ]] }, { - name = "_events", + name = "events", + type = types.list(ty_event), default = {}, template = false, - type = "table", doc = [[ Additional events to bind to this map when it is loaded. ]] @@ -1793,13 +1992,8 @@ data:add_type { fields = { { name = "on_generate_floor", - default = CodeGenerator.gen_literal [[ - function(area, floor) - return InstancedMap:new(25, 25) -end -]], + type = types.optional(types.callback({"area", types.class(InstancedArea), "floor", types.int}, types.class(InstancedMap))), template = true, - type = "function(InstancedArea, int)", doc = [[ Map generator for this area. Determines how maps in this area should be created when they're initially generated. Takes an area and a floor number and returns a @@ -1816,27 +2010,35 @@ set `is_temporary` to `true` on the generated map. }, { name = "image", + type = types.data_id("base.chip"), default = "elona.feat_area_village", template = true, - type = "id:base.chip", doc = [[ Image this area will have when created with Area.create_entrance(). ]] }, { name = "deepest_floor", + type = types.optional(types.int), default = nil, template = false, - type = "int?", doc = [[ Deepest floor of this area. Used with generating dungeons. ]] }, { name = "parent_area", + type = types.optional( + types.fields_strict { + _id = types.data_id("base.area_archetype"), + on_floor = types.uint, + x = types.uint, + y = types.uint, + starting_floor = types.uint + } + ), default = nil, template = true, - type = "{_id=id:base.unique_area,on_floor=uint,x=uint,y=uint,starting_floor=uint}", doc = [[ Parent area that this area is contained in. If present, an entrance leading to this area on floor `starting_floor` will be created when the given parent area's @@ -1871,12 +2073,8 @@ data:add_type { fields = { { name = "on_damage", - default = CodeGenerator.gen_literal [[ - function(chara, power, params) -end -]], + type = types.callback("chara", types.map_object("base.chara", "power", types.number, "params", types.params)), template = true, - type = "function(IChara, int, table)", doc = [[ Behavior to trigger when this character is melee attacked. ]] @@ -1889,8 +2087,8 @@ data:add_type { fields = { { name = "language_code", + type = types.string, template = true, - default = "", doc = [[ The language code for this language. @@ -1905,8 +2103,23 @@ base. } } +local ty_dialog_choice_entry = types.tuple(types.string, types.some(types.locale_id, types.literal("MORE", "BYE"))) +local ty_dialog_choice_cb = types.callback({"speaker", types.map_object("base.chara"), "state", types.table}, types.list(ty_dialog_choice_entry)) +local ty_dialog_choice = types.some(ty_dialog_choice_entry, ty_dialog_choice_cb) + data:add_type { name = "role", + fields = { + { + name = "elona_id", + type = types.optional(types.uint) + }, + { + name = "dialog_choices", + type = types.list(ty_dialog_choice), + default = {} + } + } } data:add_type { @@ -1914,31 +2127,34 @@ data:add_type { fields = { { name = "validate", + type = types.callback({"option", types.data_entry("base.config_option"), "value", types.any}, {types.boolean, types.optional(types.string)}), template = true, - default = CodeGenerator.gen_literal [[ - function(value, option) - return true -end -]], doc = [[ -Used to validate if a value for this option is valid. +Used to validate if a value for this config option type is valid. ]] }, { name = "widget", + type = types.some(types.require_path, types.callback({"proto", types.data_entry("base.config_option")}, types.interface(IConfigItemWidget))), template = true, - type = "string", doc = [[ -Require path of the widget used to display this config option. +Require path of the widget used to display this config option type. It must implement IConfigItemWidget. ]] }, { name = "fields", - type = "table", + type = types.map(types.string, types.type), + doc = [[ +Extra fields for configuring this config option type. +]] + }, + { + name = "default", + type = types.some(types.serializable, types.callback({"option", types.data_entry("base.config_option")}, types.serializable)), doc = [[ -Extra fields for configuring this config option. +Default value of this config option type. ]] } } @@ -1949,19 +2165,19 @@ data:add_type { fields = { { name = "type", + type = types.some(types.literal("boolean", "string", "number", "int", "enum", "table", "data_id", "any"), types.data_id("base.config_option_type")), template = true, - default = "boolean", no_fallback = true, doc = [[ Type of this config option. -One of "boolean", "string", "number", "int" "enum", "table", "data_id" or "any". +One of "boolean", "string", "number", "int", "enum", "table", "data_id" or "any". ]] }, { name = "default", + type = types.any, template = true, - default = true, no_fallback = true, doc = [[ Default value of this config option. @@ -1969,7 +2185,7 @@ Default value of this config option. }, { name = "choices", - default = CodeGenerator.gen_literal "{}", + type = types.some(types.list(types.string)), types.callback({}, types.list(types.string)), no_fallback = true, doc = [[ Only used if the type is "enum". @@ -1979,12 +2195,36 @@ The list of enum variants of this config option. }, { name = "data_type", - default = "base.chara", + type = types.data_type_id, no_fallback = true, doc = [[ Only used if the type is "data_id". The data type of the ID in this config option. +]] + }, + { + name = "on_changed", + type = types.callback("value", types.any, "is_startup", types.boolean), + no_fallback = true, + doc = [[ +Callback run immediately after this option is changed in the settings menu. + +"is_startup" is true if the option was set from the intial config load at startup. +]] + } + }, + validation = "permissive" +} + +data:add_type { + name = "config_menu", + fields = { + { + name = "items", + type = types.list(types.data_id("base.config_option")), + doc = [[ +List of config options in this config menu. ]] } } @@ -1993,25 +2233,84 @@ The data type of the ID in this config option. data:add_type { name = "auto_turn_anim", fields = { + { + name = "sound", + type = types.data_id("base.sound") + }, + { + name = "on_start_callback", + type = types.optional(types.callback()) + }, + { + name = "callback", + type = types.callback({"x", types.number, "y", types.number, "t", types.table}, types.callback()) + }, + { + name = "callback", + type = types.callback({"x", types.number, "y", types.number, "t", types.table}) + } } } +local ty_equip_spec = types.map(types.string, types.fields { category = types.data_id("base.item_type"), quality = types.enum(Enum.Quality)}) +local ty_drop = types.fields { + _id = types.data_id("base.item"), + amount = types.uint, + on_create = types.callback("item", types.map_object("base.item"), "chara", types.map_object("base.chara"), "attacker", types.optional(types.map_object("base.chara"))) +} + data:add_type { name = "equipment_type", - fields = {} + fields = { + { + name = "elona_id", + type = types.optional(types.uint) + }, + { + name = "on_initialize_equipment", + type = types.callback("chara", types.map_object("base.chara"), "equip_spec", ty_equip_spec, "gen_chance", types.uint) + }, + { + name = "on_drop_loot", + type = types.optional(types.callback("chara", types.map_object("base.chara"), "attacker", types.optional(types.map_object("base.chara")), "drops", types.list(ty_drop))) + } + } } data:add_type { name = "loot_type", - fields = {} + fields = { + { + name = "elona_id", + type = types.optional(types.uint) + }, + { + name = "on_drop_loot", + type = types.callback("chara", types.map_object("base.chara"), "attacker", types.optional(types.map_object("base.chara")), "drops", types.list(ty_drop)) + } + } } data:add_type { name = "trait_indicator", - fields = {} + fields = { + { + name = "applies_to", + type = types.callback("chara", types.map_object("base.chara")) + }, + { + name = "make_indicator", + type = types.callback({"chara", types.map_object("base.chara")}, types.fields_strict { desc = types.string, color = types.optional(ty_color) }), + } + } } data:add_type { name = "journal_page", - fields = {} + fields = { + { + name = "render", + type = types.callback({}, types.string) + } + } } diff --git a/src/internal/data_table.lua b/src/internal/data_table.lua index eb09e6c6b..fd9d95879 100644 --- a/src/internal/data_table.lua +++ b/src/internal/data_table.lua @@ -169,7 +169,8 @@ local ty_schema = types.fields_strict { } ), fallbacks = types.optional(types.table), - doc = types.optional(types.string) + doc = types.optional(types.string), + validation = types.optional(types.literal("strict", "permissive")) } local ty_ext_table = types.map(types.some(types.interface_type, types.data_id("base.data_ext")), types.table) @@ -211,7 +212,11 @@ function data_table:add_type(schema, params) checkers._ext = types.optional(ty_ext_table) checkers._ordering = types.optional(types.number) -- TODO - schema.type = types.fields_strict(checkers) + if schema.validation == "permissive" then + schema.type = types.fields(checkers) + else + schema.type = types.fields_strict(checkers) + end schema.validate = function(obj, verbose) local ok, err = types.check(obj, schema.type, verbose) if not ok then @@ -271,15 +276,6 @@ function data_table:add_type(schema, params) local fallbacks = make_fallbacks(schema.fallbacks, schema.fields) self.fallbacks[_type] = fallbacks - - return schema -end - --- TODO: metatable indexing could create a system for indexing --- sandboxed properties partitioned by each mod. For example the --- underlying table would contain { base = {...}, mod = {...} } and --- indexing obj.field might actually self.index obj.base.field. -function data_table:extend_type(type_id, delta) end -- Apply data edits. @@ -377,6 +373,7 @@ function data_table:add(dat) end end + -- TODO only validate after all data has been added (handles data entry field dependencies) local ok, err = _schema.validate(dat) if not ok then error(err) diff --git a/src/internal/draw/atlas.lua b/src/internal/draw/atlas.lua index 0325a0523..73893d0e0 100644 --- a/src/internal/draw/atlas.lua +++ b/src/internal/draw/atlas.lua @@ -202,9 +202,9 @@ local function get_images(image) -- source = "graphic/map0.bmp", -- width = 48, -- height = 48, - -- count_x = 1, -- x = 0, -- y = 0, + -- count_x = 1, -- key_color = {0, 0, 0} -- } -- diff --git a/src/mod/elona/data/enchantment.lua b/src/mod/elona/data/enchantment.lua index 27033d3c0..133692a63 100644 --- a/src/mod/elona/data/enchantment.lua +++ b/src/mod/elona/data/enchantment.lua @@ -40,7 +40,7 @@ data:add { icon = 2, color = { 0, 0, 100 }, - params = { skill_id = "id:base.skill" }, + params = { skill_id = types.data_id("base.skill") }, on_generate = function(self, item, params) -- >>>>>>>> shade2/item_data.hsp:555 if enc=encModAttb{ .. self.params.skill_id = Skill.random_attribute() @@ -122,7 +122,7 @@ data:add { icon = 3, color = { 80, 100, 0 }, - params = { element_id = "id:base.element" }, + params = { element_id = types.data_id("base.element") }, on_generate = function(self, item, params) -- >>>>>>>> shade2/item_data.hsp:560 if enc=encModRes{ .. self.params.element_id = Skill.random_resistance_by_rarity() @@ -183,7 +183,7 @@ data:add { icon = 1, color = { 0, 100, 0 }, - params = { skill_id = "id:base.skill" }, + params = { skill_id = types.data_id("base.skill") }, on_generate = function(self, item, params) -- >>>>>>>> shade2/item_data.hsp:565 if enc=encModSkill{ .. self.params.skill_id = Skill.random_skill() @@ -251,7 +251,7 @@ data:add { icon = 8, color = { 0, 100, 100 }, - params = { skill_id = "id:base.skill" }, + params = { skill_id = types.data_id("base.skill") }, on_generate = function(self, item, params) -- >>>>>>>> shade2/item_data.hsp:570 if enc=encSustain{ .. self.params.skill_id = Skill.random_attribute() @@ -311,7 +311,7 @@ data:add { rarity = 300, filter = filter_categories { "elona.equip_melee", "elona.equip_ranged" }, - params = { element_id = "id:base.element" }, + params = { element_id = types.data_id("base.element") }, on_generate = function(self, item, params) -- >>>>>>>> shade2/item_data.hsp:574 if enc=encEleDmg{ .. self.params.element_id = Skill.random_resistance_by_rarity() diff --git a/src/mod/elona/data/skill.lua b/src/mod/elona/data/skill.lua index 0a8957a0d..55a599903 100644 --- a/src/mod/elona/data/skill.lua +++ b/src/mod/elona/data/skill.lua @@ -3,7 +3,6 @@ local skill = { _id = "stat_life", type = "stat_special", elona_id = 2, - ability_type = 0, cost = 0, range = 0, @@ -15,7 +14,6 @@ local skill = { _id = "stat_mana", type = "stat_special", elona_id = 3, - ability_type = 0, cost = 0, range = 0, @@ -27,7 +25,6 @@ local skill = { _id = "stat_strength", type = "stat", elona_id = 10, - ability_type = 0, cost = 0, range = 0, }, @@ -35,7 +32,6 @@ local skill = { _id = "stat_constitution", type = "stat", elona_id = 11, - ability_type = 0, cost = 0, range = 0, }, @@ -43,7 +39,6 @@ local skill = { _id = "stat_dexterity", type = "stat", elona_id = 12, - ability_type = 0, cost = 0, range = 0, }, @@ -51,7 +46,6 @@ local skill = { _id = "stat_perception", type = "stat", elona_id = 13, - ability_type = 0, cost = 0, range = 0, }, @@ -59,7 +53,6 @@ local skill = { _id = "stat_learning", type = "stat", elona_id = 14, - ability_type = 0, cost = 0, range = 0, }, @@ -67,7 +60,6 @@ local skill = { _id = "stat_will", type = "stat", elona_id = 15, - ability_type = 0, cost = 0, range = 0, }, @@ -75,7 +67,6 @@ local skill = { _id = "stat_magic", type = "stat", elona_id = 16, - ability_type = 0, cost = 0, range = 0, }, @@ -83,7 +74,6 @@ local skill = { _id = "stat_charisma", type = "stat", elona_id = 17, - ability_type = 0, cost = 0, range = 0, }, @@ -91,7 +81,6 @@ local skill = { _id = "stat_speed", type = "stat", elona_id = 18, - ability_type = 0, cost = 0, range = 0, @@ -105,7 +94,6 @@ local skill = { _id = "stat_luck", type = "stat", elona_id = 19, - ability_type = 0, cost = 0, range = 0, @@ -118,7 +106,6 @@ local skill = { type = "weapon_proficiency", elona_id = 100, related_skill = "elona.stat_strength", - ability_type = 0, cost = 0, range = 0, @@ -129,7 +116,6 @@ local skill = { type = "weapon_proficiency", elona_id = 101, related_skill = "elona.stat_dexterity", - ability_type = 0, cost = 0, range = 0, @@ -140,7 +126,6 @@ local skill = { type = "weapon_proficiency", elona_id = 102, related_skill = "elona.stat_strength", - ability_type = 0, cost = 0, range = 0, @@ -151,7 +136,6 @@ local skill = { type = "weapon_proficiency", elona_id = 103, related_skill = "elona.stat_constitution", - ability_type = 0, cost = 0, range = 0, }, @@ -160,7 +144,6 @@ local skill = { type = "weapon_proficiency", elona_id = 104, related_skill = "elona.stat_constitution", - ability_type = 0, cost = 0, range = 0, @@ -171,7 +154,6 @@ local skill = { type = "weapon_proficiency", elona_id = 105, related_skill = "elona.stat_constitution", - ability_type = 0, cost = 0, range = 0, }, @@ -180,7 +162,6 @@ local skill = { type = "weapon_proficiency", elona_id = 106, related_skill = "elona.stat_strength", - ability_type = 0, cost = 0, range = 0, @@ -216,7 +197,6 @@ local skill = { type = "weapon_proficiency", elona_id = 107, related_skill = "elona.stat_strength", - ability_type = 0, cost = 0, range = 0, @@ -227,7 +207,6 @@ local skill = { type = "weapon_proficiency", elona_id = 108, related_skill = "elona.stat_dexterity", - ability_type = 0, cost = 0, range = 0, @@ -239,7 +218,6 @@ local skill = { type = "weapon_proficiency", elona_id = 109, related_skill = "elona.stat_dexterity", - ability_type = 0, cost = 0, range = 0, @@ -250,7 +228,6 @@ local skill = { type = "weapon_proficiency", elona_id = 110, related_skill = "elona.stat_perception", - ability_type = 0, cost = 0, range = 0, @@ -261,7 +238,6 @@ local skill = { type = "weapon_proficiency", elona_id = 111, related_skill = "elona.stat_dexterity", - ability_type = 0, cost = 0, range = 0, @@ -272,7 +248,6 @@ local skill = { type = "skill", elona_id = 168, related_skill = "elona.stat_constitution", - ability_type = 0, cost = 0, range = 0, }, @@ -281,7 +256,6 @@ local skill = { type = "skill", elona_id = 173, related_skill = "elona.stat_dexterity", - ability_type = 0, cost = 0, range = 0, @@ -292,7 +266,6 @@ local skill = { type = "skill", elona_id = 166, related_skill = "elona.stat_dexterity", - ability_type = 0, cost = 0, range = 0, }, @@ -301,103 +274,6 @@ local skill = { type = "skill", elona_id = 167, related_skill = "elona.stat_strength", - ability_type = 0, - cost = 0, - range = 0, - }, - { - _id = "element_fire", - type = "resistance", - elona_id = 50, - ability_type = 0, - cost = 0, - range = 1, - }, - { - _id = "element_cold", - type = "resistance", - elona_id = 51, - ability_type = 0, - cost = 0, - range = 1, - }, - { - _id = "element_lightning", - type = "resistance", - elona_id = 52, - ability_type = 0, - cost = 0, - range = 1, - }, - { - _id = "element_darkness", - type = "resistance", - elona_id = 53, - ability_type = 0, - cost = 0, - range = 2, - }, - { - _id = "element_mind", - type = "resistance", - elona_id = 54, - ability_type = 0, - cost = 0, - range = 2, - }, - { - _id = "element_nether", - type = "resistance", - elona_id = 56, - ability_type = 0, - cost = 0, - range = 4, - }, - { - _id = "element_poison", - type = "resistance", - elona_id = 55, - ability_type = 0, - cost = 0, - range = 3, - }, - { - _id = "element_sound", - type = "resistance", - elona_id = 57, - ability_type = 0, - cost = 0, - range = 3, - }, - { - _id = "element_nerve", - type = "resistance", - elona_id = 58, - ability_type = 0, - cost = 0, - range = 3, - }, - { - _id = "element_chaos", - type = "resistance", - elona_id = 59, - ability_type = 0, - cost = 0, - range = 4, - }, - { - _id = "element_magic", - type = "resistance", - elona_id = 60, - ability_type = 0, - cost = 0, - range = 5, - }, - { - _id = "element_cut", - type = "resistance", - elona_id = 61, - ability_type = 0, cost = 0, range = 0, }, @@ -406,7 +282,6 @@ local skill = { type = "skill", elona_id = 153, related_skill = "elona.stat_strength", - ability_type = 0, cost = 0, range = 0, }, @@ -415,7 +290,6 @@ local skill = { type = "skill", elona_id = 152, related_skill = "elona.stat_strength", - ability_type = 0, cost = 0, range = 0, }, @@ -424,7 +298,6 @@ local skill = { type = "skill", elona_id = 189, related_skill = "elona.stat_perception", - ability_type = 0, cost = 0, range = 0, }, @@ -433,7 +306,6 @@ local skill = { type = "skill", elona_id = 154, related_skill = "elona.stat_constitution", - ability_type = 0, cost = 0, range = 0, }, @@ -442,7 +314,6 @@ local skill = { type = "skill", elona_id = 163, related_skill = "elona.stat_constitution", - ability_type = 0, cost = 0, range = 0, }, @@ -451,7 +322,6 @@ local skill = { type = "skill", elona_id = 176, related_skill = "elona.stat_constitution", - ability_type = 0, cost = 0, range = 0, }, @@ -460,7 +330,6 @@ local skill = { type = "skill", elona_id = 169, related_skill = "elona.stat_constitution", - ability_type = 0, cost = 0, range = 0, }, @@ -469,7 +338,6 @@ local skill = { type = "skill", elona_id = 170, related_skill = "elona.stat_constitution", - ability_type = 0, cost = 0, range = 0, }, @@ -478,7 +346,6 @@ local skill = { type = "skill", elona_id = 171, related_skill = "elona.stat_dexterity", - ability_type = 0, cost = 0, range = 0, }, @@ -487,7 +354,6 @@ local skill = { type = "skill", elona_id = 158, related_skill = "elona.stat_dexterity", - ability_type = 0, cost = 0, range = 0, }, @@ -496,7 +362,6 @@ local skill = { type = "skill", elona_id = 175, related_skill = "elona.stat_dexterity", - ability_type = 0, cost = 0, range = 0, }, @@ -505,7 +370,6 @@ local skill = { type = "skill", elona_id = 177, related_skill = "elona.stat_dexterity", - ability_type = 0, cost = 0, range = 0, }, @@ -514,7 +378,6 @@ local skill = { type = "skill", elona_id = 179, related_skill = "elona.stat_dexterity", - ability_type = 0, cost = 0, range = 0, }, @@ -523,7 +386,6 @@ local skill = { type = "skill", elona_id = 157, related_skill = "elona.stat_perception", - ability_type = 0, cost = 0, range = 0, }, @@ -532,7 +394,6 @@ local skill = { type = "skill", elona_id = 159, related_skill = "elona.stat_perception", - ability_type = 0, cost = 0, range = 0, }, @@ -541,7 +402,6 @@ local skill = { type = "skill", elona_id = 162, related_skill = "elona.stat_perception", - ability_type = 0, cost = 0, range = 0, }, @@ -550,7 +410,6 @@ local skill = { type = "skill", elona_id = 186, related_skill = "elona.stat_perception", - ability_type = 0, cost = 0, range = 0, }, @@ -559,7 +418,6 @@ local skill = { type = "skill", elona_id = 187, related_skill = "elona.stat_perception", - ability_type = 0, cost = 0, range = 0, }, @@ -568,7 +426,6 @@ local skill = { type = "skill", elona_id = 161, related_skill = "elona.stat_learning", - ability_type = 0, cost = 0, range = 0, }, @@ -577,7 +434,6 @@ local skill = { type = "skill", elona_id = 150, related_skill = "elona.stat_learning", - ability_type = 0, cost = 0, range = 0, }, @@ -586,7 +442,6 @@ local skill = { type = "skill", elona_id = 165, related_skill = "elona.stat_learning", - ability_type = 0, cost = 0, range = 0, }, @@ -595,7 +450,6 @@ local skill = { type = "skill", elona_id = 178, related_skill = "elona.stat_learning", - ability_type = 0, cost = 0, range = 0, }, @@ -604,7 +458,6 @@ local skill = { type = "skill", elona_id = 180, related_skill = "elona.stat_learning", - ability_type = 0, cost = 0, range = 0, }, @@ -613,7 +466,6 @@ local skill = { type = "skill", elona_id = 151, related_skill = "elona.stat_learning", - ability_type = 0, cost = 0, range = 0, }, @@ -622,7 +474,6 @@ local skill = { type = "skill", elona_id = 155, related_skill = "elona.stat_magic", - ability_type = 0, cost = 0, range = 0, }, @@ -631,7 +482,6 @@ local skill = { type = "skill", elona_id = 174, related_skill = "elona.stat_magic", - ability_type = 0, cost = 0, range = 0, }, @@ -640,7 +490,6 @@ local skill = { type = "skill", elona_id = 172, related_skill = "elona.stat_magic", - ability_type = 0, cost = 0, range = 0, }, @@ -649,7 +498,6 @@ local skill = { type = "skill", elona_id = 188, related_skill = "elona.stat_magic", - ability_type = 0, cost = 0, range = 0, }, @@ -658,7 +506,6 @@ local skill = { type = "skill", elona_id = 164, related_skill = "elona.stat_will", - ability_type = 0, cost = 0, range = 0, }, @@ -667,7 +514,6 @@ local skill = { type = "skill", elona_id = 181, related_skill = "elona.stat_will", - ability_type = 0, cost = 0, range = 0, }, @@ -676,7 +522,6 @@ local skill = { type = "skill", elona_id = 182, related_skill = "elona.stat_will", - ability_type = 0, cost = 0, range = 0, }, @@ -685,7 +530,6 @@ local skill = { type = "skill", elona_id = 156, related_skill = "elona.stat_charisma", - ability_type = 0, cost = 0, range = 0, }, @@ -694,7 +538,6 @@ local skill = { type = "skill", elona_id = 160, related_skill = "elona.stat_charisma", - ability_type = 0, cost = 0, range = 0, }, diff --git a/src/mod/elona/data/trait.lua b/src/mod/elona/data/trait.lua index a94e288ec..9f8cc9017 100644 --- a/src/mod/elona/data/trait.lua +++ b/src/mod/elona/data/trait.lua @@ -192,7 +192,7 @@ local trait = { level_max = 1, type = "feat", - can_learn = function(self, chara) + can_acquire = function(self, chara) return chara:has_skill("elona.shield") end, @@ -216,7 +216,7 @@ local trait = { level_max = 2, type = "feat", - can_learn = function(self, chara) + can_acquire = function(self, chara) return chara:has_skill("elona.dual_wield") end, @@ -256,7 +256,7 @@ local trait = { level_max = 2, type = "feat", - can_learn = function(self, chara) + can_acquire = function(self, chara) return chara:has_skill("elona.negotiation") end, @@ -320,7 +320,7 @@ local trait = { level_max = 2, type = "feat", - can_learn = function(self, chara) + can_acquire = function(self, chara) return chara:has_skill("elona.detection") end, @@ -336,7 +336,7 @@ local trait = { level_max = 2, type = "feat", - can_learn = function(self, chara) + can_acquire = function(self, chara) if self.level == 1 then return chara.level >= 5 end @@ -355,7 +355,7 @@ local trait = { level_max = 3, type = "feat", - can_learn = function(self, chara) + can_acquire = function(self, chara) if self.level == 1 then return chara.level >= 5 end @@ -386,7 +386,7 @@ local trait = { level_max = 3, type = "feat", - can_learn = function(self, chara) + can_acquire = function(self, chara) return chara:has_skill("elona.evasion") end, diff --git a/src/mod/elona_sys/init.lua b/src/mod/elona_sys/init.lua index e5d6b64d5..8c20ba9a0 100644 --- a/src/mod/elona_sys/init.lua +++ b/src/mod/elona_sys/init.lua @@ -1,12 +1,6 @@ local CodeGenerator = require("api.CodeGenerator") local function add_elona_id(_type) - data:extend_type( - _type, - { - elona_id = schema.Number, - } - ) data:add_index(_type, "elona_id") end @@ -63,7 +57,6 @@ add_elona_id("base.element") add_elona_id("base.sound") add_elona_id("base.music") add_elona_id("base.body_part") -add_elona_id("base.map_template") add_elona_id("base.portrait") diff --git a/src/mod/smithing/data/chip.lua b/src/mod/smithing/data/chip.lua index 407f678bd..8a9d63ed4 100644 --- a/src/mod/smithing/data/chip.lua +++ b/src/mod/smithing/data/chip.lua @@ -1,4 +1,4 @@ -data:add { +d,ata:add { _type = "base.chip", _id = "blacksmith_hammer", diff --git a/src/util/types.lua b/src/util/types.lua index f409c6dcb..30afe7e83 100644 --- a/src/util/types.lua +++ b/src/util/types.lua @@ -25,20 +25,20 @@ local INSPECT_OPTIONS = { newline = " ", indent = "", max_length = 16, } -local function get_name(obj) - if type(obj) == "string" then - return smart_quote(obj) - elseif type(obj) == "table" then - if class.is_class_instance(obj) then - return tostring(obj) +local function get_name(obj, ctxt) + if type(obj, ctxt) == "string" then + return smart_quote(obj, ctxt) + elseif type(obj, ctxt) == "table" then + if class.is_class_instance(obj, ctxt) then + return tostring(obj, ctxt) end return inspect(obj, INSPECT_OPTIONS) end - return tostring(obj) + return tostring(obj, ctxt) end -function ctxt_mt:make_trail(obj) +function ctxt_mt:make_trail(obj, ctxt) local seen = {obj = true} local s = { get_name(obj, seen) } for _, entry in ipairs(self.stack) do @@ -86,8 +86,12 @@ local function print_fields(fields) return table.concat(s, ", ") end -local function type_error(ty) - return ("Value is not of type \"%s\""):format(ty) +local function type_error(ty, inner) + local s = ("Value is not of type \"%s\""):format(ty) + if inner then + s = s .. "(" .. inner .. ")" + end + return s end -- @@ -96,9 +100,9 @@ end local ITypeChecker = class.interface("ITypeChecker", { check = "function" }) -local function is_type_checker(obj) +local function is_type_checker(obj, ctxt) if not class.is_an(ITypeChecker, obj) then - return false, ("%s is not a type checker"):format(obj) + return false, ("%s is not a type checker"):format(obj, ctxt) end return true end @@ -120,7 +124,7 @@ function primitive_checker:init(ty) self.type = ty end function primitive_checker:check(obj, ctxt) - if type(obj) == self.type then + if type(obj, ctxt) == self.type then return true end return false, type_error(self) @@ -143,7 +147,7 @@ for _, ty in ipairs(primitives) do types[ty] = primitive_checker:new(ty) end -local function is_nan(obj) +local function is_nan(obj, ctxt) -- According to IEEE 754, a nan value is considered not equal to any value, -- including itself. return obj ~= obj @@ -180,7 +184,7 @@ end do local int_checker = class.class("int_checker", ITypeChecker) function int_checker:check(obj, _ctxt) - if math.type(obj) == "int" and not is_nan(obj) then + if math.type(obj) == "integer" and not is_nan(obj) then return true end return false, type_error(self) @@ -243,6 +247,21 @@ do types.data_type_id = data_type_id_checker:new() end +do + local path_checker = class.class("path_checker", ITypeChecker) + function path_checker:check(obj, ctxt) + if not types.string:check(obj, ctxt) then + return false, type_error(self) + end + + return true + end + function path_checker:__tostring() + return "path" + end + types.path = path_checker:new() +end + do local locale_id_checker = class.class("locale_id_checker", ITypeChecker) function locale_id_checker:check(obj, ctxt) @@ -258,6 +277,21 @@ do types.locale_id = locale_id_checker:new() end +do + local require_path_checker = class.class("require_path_checker", ITypeChecker) + function require_path_checker:check(obj, ctxt) + if not types.string:check(obj, ctxt) then + return false, type_error(self) + end + + return true + end + function require_path_checker:__tostring() + return "require_path" + end + types.require_path = require_path_checker:new() +end + do local type_type_checker = class.class("type_type_checker", ITypeChecker) function type_type_checker:check(obj, _ctxt) @@ -340,9 +374,10 @@ do self.checker = checker self.comp = comp end - function gt_checker:check(obj, _ctxt) - if not self.checker:check(obj) then - return false, type_error(self) + function gt_checker:check(obj, ctxt) + local ok, err = self.checker:check(obj, ctxt) + if not ok then + return false, type_error(self, err) end if obj > self.comp then @@ -364,9 +399,10 @@ do self.checker = checker self.comp = comp end - function lt_checker:check(obj, _ctxt) - if not self.checker:check(obj) then - return false, type_error(self) + function lt_checker:check(obj, ctxt) + local ok, err = self.checker:check(obj, ctxt) + if not ok then + return false, type_error(self, err) end if obj < self.comp then @@ -388,9 +424,10 @@ do self.checker = checker self.comp = comp end - function gteq_checker:check(obj, _ctxt) - if not self.checker:check(obj) then - return false, type_error(self) + function gteq_checker:check(obj, ctxt) + local ok, err = self.checker:check(obj, ctxt) + if not ok then + return false, type_error(self, err) end if obj >= self.comp then @@ -412,9 +449,10 @@ do self.checker = checker self.comp = comp end - function lteq_checker:check(obj, _ctxt) - if not self.checker:check(obj) then - return false, type_error(self) + function lteq_checker:check(obj, ctxt) + local ok, err = self.checker:check(obj, ctxt) + if not ok then + return false, type_error(self, err) end if obj <= self.comp then @@ -437,7 +475,7 @@ function types.negative(checker) return types.lt(checker, 0) end -types.uint = types.positive(types.integer) +types.uint = types.positive(types.int) do local range_checker = class.class("range_checker", ITypeChecker) @@ -447,16 +485,17 @@ do self.min = min self.max = max end - function range_checker:check(obj, _ctxt) - if not self.checker:check(obj) then - return false, type_error(self) + function range_checker:check(obj, ctxt) + local ok, err = self.checker:check(obj, ctxt) + if not ok then + return false, type_error(self, err) end - if obj < self.min or obj > self.max then - return false, type_error(self) + if obj >= self.min and obj <= self.max then + return true end - return true + return false, type_error(self) end function range_checker:__tostring() return ("%s in [%s, %s]"):format(self.checker, self.min, self.max) @@ -531,9 +570,9 @@ function optional_checker:check(obj, ctxt) return true end - local ok, _err = self.checker:check(obj, ctxt) + local ok, err = self.checker:check(obj, ctxt) if not ok then - return false, type_error(self) + return false, type_error(self, err) end return true @@ -561,9 +600,9 @@ do for i, checker in ipairs(self.checkers) do local val = obj[i] ctxt:push(i, val) - local ok, _err = checker:check(val, ctxt) + local ok, err = checker:check(val, ctxt) if not ok then - return false, type_error(self) + return false, type_error(self, err) end ctxt:pop() end @@ -587,11 +626,11 @@ do return false, type_error(self) end - for key, _ in pairs(obj) do + for key, _ in pairs(obj, ctxt) do ctxt:push(key) - local ok, _err = self.checker:check(key) + local ok, err = self.checker:check(key) if not ok then - return false, type_error(self) + return false, type_error(self, err) end ctxt:pop() end @@ -615,11 +654,11 @@ do return false, type_error(self) end - for key, val in pairs(obj) do + for key, val in pairs(obj, ctxt) do ctxt:push(key, val) - local ok, _err = self.checker:check(val) + local ok, err = self.checker:check(val) if not ok then - return false, type_error(self) + return false, type_error(self, err) end ctxt:pop() end @@ -645,18 +684,18 @@ do return false, type_error(self) end - for key, val in pairs(obj) do + for key, val in pairs(obj, ctxt) do ctxt:push(key) - local ok, _err = self.key_checker:check(key, ctxt) + local ok, err = self.key_checker:check(key, ctxt) if not ok then - return false, type_error(self) + return false, type_error(self, err) end ctxt:pop() ctxt:push(key, val) - ok, _err = self.value_checker:check(val, ctxt) + ok, err = self.value_checker:check(val, ctxt) if not ok then - return false, type_error(self) + return false, type_error(self, err) end ctxt:pop() end @@ -674,7 +713,7 @@ function types.set(value_checker) end do - local list_keys_checker = types.keys(types.int) + local list_keys_checker = types.keys(types.uint) local list_checker = class.class("list_checker", ITypeChecker) function list_checker:init(checker) @@ -690,13 +729,14 @@ do return true end - if not list_keys_checker:check(obj, ctxt) then - return false, type_error("table with integer keys") + local ok, err = list_keys_checker:check(obj, ctxt) + if not ok then + return false, type_error(("table with integer keys (%s)"):format(err)) end - for i, val in ipairs(obj) do + for i, val in ipairs(obj, ctxt) do ctxt:push(i, val) - local ok, err = self.checker:check(val, ctxt) + ok, err = self.checker:check(val, ctxt) if not ok then return false, err end @@ -742,6 +782,8 @@ do types.some = wrap(some_checker) end +types.serializable = types.some(types["nil"], types.boolean, types.number, types.string, types.table) + do local all_checker = class.class("all_checker", ITypeChecker) function all_checker:init(...) @@ -822,7 +864,7 @@ do end local remaining = table.set(table.keys(self.fields)) - for key, val in pairs(obj) do + for key, val in pairs(obj, ctxt) do local checker = self.fields[key] if not checker then return false, ("Table has superfluous key: \"%s\""):format(key) @@ -924,17 +966,18 @@ do function callback_checker:init(...) local checkers = { ... } local args = {} - for i=1, #checkers, 2 do - local arg_name = checkers[i] - local checker = checkers[i+1] - assert(type(arg_name) == "string", ("Callback argument name must be string, got '%s'"):format(arg_name)) - assert(is_type_checker(checker)) - args[#args+1] = {name = arg_name, checker = checker} - end + -- TODO retvals + -- for i=1, #checkers, 2 do + -- local arg_name = checkers[i] + -- local checker = checkers[i+1] + -- assert(type(arg_name) == "string", ("Callback argument name must be string, got '%s'"):format(arg_name)) + -- assert(is_type_checker(checker)) + -- args[#args+1] = {name = arg_name, checker = checker} + -- end self.args = args end function callback_checker:check(obj, _ctxt) - if types["function"]:check(obj) then + if types["function"]:check(obj, ctxt) then return true end @@ -961,7 +1004,7 @@ do function map_object_checker:check(obj, ctxt) -- copied from MapObject.is_map_object() if not class.is_an("api.IMapObject", obj) then - return false, ("'%s' is not a map object"):format(obj) + return false, ("'%s' is not a map object"):format(obj, ctxt) end if self._type == "any" then @@ -988,13 +1031,13 @@ function types.check(obj, checker, verbose) err = err or "" local s if verbose then - s = ctxt:make_trail(obj) + s = ctxt:make_trail(obj, ctxt) else local entry = ctxt.stack[#ctxt.stack] if entry then s = get_name(entry.value or entry.key) else - s = get_name(obj) + s = get_name(obj, ctxt) end end return false, ("%s: %s"):format(err, s) @@ -1003,13 +1046,13 @@ function types.check(obj, checker, verbose) end function types.wrap(checker) - return function(obj) + return function(obj, ctxt) return types.check(obj, checker) end end function types.wrap_strict(checker) - return function(obj) + return function(obj, ctxt) return assert(types.check(obj, checker)) end end From 08ef660b3c1b0d7bccddbaed3d25260580b9988f Mon Sep 17 00:00:00 2001 From: Ruin0x11 Date: Thu, 9 Sep 2021 21:08:59 -0700 Subject: [PATCH 05/17] Add types for all data types --- src/api/gui/menu/InventoryContext.lua | 16 +- src/api/gui/menu/InventoryMenu.lua | 6 +- src/internal/data/schemas.lua | 101 ++- src/internal/data/talk.lua | 32 - src/internal/data/theme.lua | 22 - src/internal/data_table.lua | 27 +- src/internal/env.lua | 1 - .../autopickup/data/autopickup/predicate.lua | 8 +- src/mod/autopickup/data/autopickup/target.lua | 8 +- src/mod/base/data/doc.lua | 113 --- src/mod/base/data/init.lua | 1 - src/mod/elona/api/God.lua | 16 +- src/mod/elona/api/HomeMap.lua | 172 ----- src/mod/elona/api/aspect/ItemBookAspect.lua | 2 +- src/mod/elona/data/bait.lua | 17 +- src/mod/elona/data/book.lua | 16 +- src/mod/elona/data/building.lua | 13 +- src/mod/elona/data/encounter.lua | 20 +- src/mod/elona/data/ex_help.lua | 9 +- src/mod/elona/data/field.lua | 34 +- src/mod/elona/data/fish.lua | 32 +- src/mod/elona/data/god.lua | 6 +- src/mod/elona/data/guild.lua | 8 +- src/mod/elona/data/home.lua | 202 +++++- src/mod/elona/data/inventory_proto.lua | 2 +- src/mod/elona/data/item.lua | 1 + src/mod/elona/data/item/fish.lua | 1 + src/mod/elona/data/item/remains.lua | 1 + src/mod/elona/data/item_material.lua | 306 +++++---- src/mod/elona/data/material.lua | 8 +- src/mod/elona/data/material_spot.lua | 38 +- src/mod/elona/data/nefia.lua | 14 +- src/mod/elona/data/plant.lua | 16 +- src/mod/elona/data/production_recipe.lua | 8 +- src/mod/elona/data/quest/collect.lua | 6 +- src/mod/elona/data/quest/deliver.lua | 10 +- src/mod/elona/data/quest/escort.lua | 6 +- src/mod/elona/data/random_event.lua | 15 +- src/mod/elona/data/shop_inventory.lua | 45 +- src/mod/elona/data/weather.lua | 46 +- src/mod/elona/data/wish_handler.lua | 8 +- src/mod/elona/init/god.lua | 67 +- src/mod/elona_sys/api/Magic.lua | 7 - src/mod/elona_sys/bindable_event/init.lua | 39 -- src/mod/elona_sys/dialog/init.lua | 10 +- src/mod/elona_sys/events.lua | 6 + src/mod/elona_sys/god/init.lua | 0 src/mod/elona_sys/init.lua | 421 ++++++++---- src/mod/elona_sys/map_tileset/init.lua | 17 +- src/mod/ffhp/api/ItemEx.lua | 2 +- src/mod/ffhp/data/item_ex_mapping.lua | 9 +- src/mod/map_editor/data/map_editor/plugin.lua | 9 +- .../data/simple_indicators/indicator.lua | 8 +- src/mod/smithing/data/chip.lua | 2 +- src/mod/sokoban/data/sokoban/board.lua | 3 +- src/mod/titles/data/titles/title.lua | 21 +- src/mod/tools/api/Mx.lua | 125 ---- src/mod/tools/exec/interactive.lua | 140 ---- src/mod/tools/init.lua | 17 - src/mod/visual_ai/data/visual_ai/block.lua | 57 +- src/repl_startup.lua | 1 - src/thirdparty/schema.lua | 644 ------------------ src/util/types.lua | 56 +- 63 files changed, 1275 insertions(+), 1799 deletions(-) delete mode 100644 src/mod/base/data/doc.lua delete mode 100644 src/mod/elona_sys/bindable_event/init.lua delete mode 100644 src/mod/elona_sys/god/init.lua delete mode 100644 src/mod/tools/api/Mx.lua delete mode 100644 src/mod/tools/exec/interactive.lua delete mode 100644 src/thirdparty/schema.lua diff --git a/src/api/gui/menu/InventoryContext.lua b/src/api/gui/menu/InventoryContext.lua index 91ffba38b..f0dfd7930 100644 --- a/src/api/gui/menu/InventoryContext.lua +++ b/src/api/gui/menu/InventoryContext.lua @@ -99,9 +99,9 @@ local sources = { return name .. " (Ground)" end, params = { - ground_x = { type = "number", optional = true }, - ground_y = { type = "number", optional = true }, - chara = { type = "IChara", optional = true }, + ground_x = types.optional(types.uint), + ground_y = types.optional(types.uint), + chara = types.map_object("base.chara") } }, { @@ -203,14 +203,8 @@ function InventoryContext:init(proto, params, ctxt_params) if self.proto.params then for name, required_type in pairs(self.proto.params) do local val = passed_params[name] - local optional = false - if type(required_type) == "table" then - optional = required_type.optional - required_type = assert(required_type.type) - end - - local ok = type(val) == required_type + local ok = types.check(val, required_type) if not ok then ok = type(val) == "table" @@ -218,7 +212,7 @@ function InventoryContext:init(proto, params, ctxt_params) and val:is_a(required_type) end - if not ok and not (optional and val == nil) then + if not ok then error(string.format("Inventory context expects parameter %s (%s) to be passed.", name, required_type)) end diff --git a/src/api/gui/menu/InventoryMenu.lua b/src/api/gui/menu/InventoryMenu.lua index 322bf9e49..e7e877ad3 100644 --- a/src/api/gui/menu/InventoryMenu.lua +++ b/src/api/gui/menu/InventoryMenu.lua @@ -450,11 +450,11 @@ function InventoryMenu:update_filtering(play_sound) self.play_sound = true end - if self.ctxt.proto.show_weight_text then + if self.ctxt.proto.hide_weight_text then + self.total_weight_text = "" + else local weight_text = I18N.get("ui.inv.window.total_weight", self.total_weight, self.max_weight, self.cargo_weight) self.total_weight_text = ("%d items (%s)"):format(self.pages:len(), weight_text) - else - self.total_weight_text = "" end end diff --git a/src/internal/data/schemas.lua b/src/internal/data/schemas.lua index 98650c23f..a56c31bc6 100644 --- a/src/internal/data/schemas.lua +++ b/src/internal/data/schemas.lua @@ -44,13 +44,6 @@ local ty_event = types.fields { callback = types.callback("self", types.interface(IEventEmitter), "params", types.table, "result", types.any), } -local ty_color_value = types.range(types.int, 0, 255) -local ty_color = types.tuple { - ty_color_value, - ty_color_value, - ty_color_value, - types.optional(ty_color_value), -} local ty_light = types.fields { chip = types.data_id("base.chip"), brightness = types.positive(types.number), @@ -283,7 +276,7 @@ List of events to bind to this character when they are spawned. }, { name = "color", - type = types.optional(ty_color), + type = types.optional(types.color), default = nil, doc = [[ Color to display on the character's sprite. @@ -498,7 +491,7 @@ Relative strength of this item. }, { name = "color", - type = types.optional(ty_color), + type = types.optional(types.color), default = nil, }, { @@ -736,6 +729,7 @@ data:add_type( fields = { { name = "elona_id", + indexed = true, type = types.optional(types.uint), }, { @@ -812,6 +806,7 @@ data:add_type( fields = { { name = "elona_id", + indexed = true, type = types.optional(types.uint), }, { @@ -886,6 +881,7 @@ data:add_type( }, { name = "elona_id", + indexed = true, type = types.optional(types.uint), }, { @@ -928,15 +924,16 @@ data:add_type( fields = { { name = "elona_id", + indexed = true, type = types.optional(types.uint), }, { name = "color", - type = types.optional(ty_color) + type = types.optional(types.color) }, { name = "ui_color", - type = types.optional(ty_color) + type = types.optional(types.color) }, { name = "can_resist", @@ -989,7 +986,7 @@ data:add_type( } ) -local ty_indicator_text = types.some(types.string, types.fields { text = types.string, color = ty_color }) +local ty_indicator_text = types.some(types.string, types.fields { text = types.string, color = types.color }) local ty_indicator_cb = types.callback({"chara", types.map_object("base.chara")}, ty_indicator_text) local ty_indicator = types.some(types.locale_id, ty_indicator_cb) @@ -998,7 +995,7 @@ data:add_type{ fields = { { name = "color", - type = ty_color, + type = types.color, }, { name = "indicator", @@ -1122,6 +1119,7 @@ data:add_type { fields = { { name = "elona_id", + indexed = true, type = types.optional(types.uint) }, { @@ -1143,7 +1141,7 @@ local ty_image_entry = types.some( types.fields_strict { image = types.path, count_x = types.optional(types.uint), - key_color = types.optional(ty_color) + key_color = types.optional(types.color) }, -- { @@ -1162,7 +1160,7 @@ local ty_image_entry = types.some( x = types.uint, y = types.uint, count_x = types.optional(types.uint), - key_color = types.optional(ty_color) + key_color = types.optional(types.color) } ) @@ -1281,7 +1279,7 @@ Level of this enchantment. }, { name = "color", - type = types.optional(ty_color) + type = types.optional(types.color) }, { name = "params", @@ -1400,6 +1398,7 @@ data:add_type { fields = { { name = "elona_id", + indexed = true, type = types.optional(types.uint) }, { @@ -1514,7 +1513,7 @@ A related stat to improve when this skill is used. Affects the skill's icon in t }, { name = "cost", - type = types.uint, + type = types.number, default = 10, template = true, doc = [[ @@ -1581,6 +1580,11 @@ If true, continue to use the skill even if a target character was not found. This is used by the Pickpocket skill to select an item on the ground independent of a target character. ]] + }, + { + name = "ai_check_ranged_if_self", + type = types.boolean, + default = false } } } @@ -1590,6 +1594,7 @@ data:add_type { fields = { { name = "elona_id", + indexed = true, type = types.optional(types.uint) }, { @@ -1632,6 +1637,7 @@ data:add_type { fields = { { name = "elona_id", + indexed = true, type = types.optional(types.uint) }, { @@ -1646,6 +1652,7 @@ data:add_type { fields = { { name = "elona_id", + indexed = true, type = types.optional(types.uint) }, { @@ -1690,6 +1697,23 @@ data:add_type { } } +data:add_type { + name = "theme_transform", + + fields = { + { + name = "applies_to", + type = types.data_type_id, + template = true + }, + { + name = "transform", + type = types.callback({"old", types.table, "new", types.table}, types.table), + template = true, + } + } +} + local ty_region = types.tuple(types.uint, types.uint, types.uint, types.uint) data:add_type { @@ -1742,7 +1766,7 @@ data:add_type { }, { name = "key_color", - type = types.optional(types.some(types.literal("none"), ty_color)) + type = types.optional(types.some(types.literal("none"), types.color)) }, -- font @@ -1754,7 +1778,7 @@ data:add_type { -- color { name = "color", - type = types.optional(ty_color) + type = types.optional(types.color) } } } @@ -1782,17 +1806,17 @@ It can either be a string referencing an image file, or a table with these conte }, { name = "shadow", - type = types.uint, + type = types.optional(types.uint), default = 0 }, { name = "stack_height", - type = types.int, + type = types.optional(types.int), default = 0 }, { name = "y_offset", - type = types.int, + type = types.optional(types.int), default = 0, template = true, doc = [[ @@ -1828,11 +1852,35 @@ data:add_type { } } +data:add_type { + name = "tone", + + fields = { + { + name = "show_in_menu", + type = types.boolean, + default = false, + }, + { + name = "texts", + template = true, + type = types.map(types.string, + types.map(types.data_id("base.talk_event"), + types.list(types.some(types.string, + types.callback("t", types.table, + "env", types.table, + "args", types.table, + "chara", types.map_object("base.map_object")))))) + }, + } +} + data:add_type { name = "portrait", fields = { { name = "elona_id", + indexed = true, type = types.optional(types.uint) }, { @@ -1869,7 +1917,7 @@ data:add_type { }, { name = "key_color", - type = types.optional(ty_color) + type = types.optional(types.color) } } } @@ -2112,6 +2160,7 @@ data:add_type { fields = { { name = "elona_id", + indexed = true, type = types.optional(types.uint) }, { @@ -2185,7 +2234,7 @@ Default value of this config option. }, { name = "choices", - type = types.some(types.list(types.string)), types.callback({}, types.list(types.string)), + type = types.some(types.list(types.string), types.callback({}, types.list(types.string))), no_fallback = true, doc = [[ Only used if the type is "enum". @@ -2264,6 +2313,7 @@ data:add_type { fields = { { name = "elona_id", + indexed = true, type = types.optional(types.uint) }, { @@ -2282,6 +2332,7 @@ data:add_type { fields = { { name = "elona_id", + indexed = true, type = types.optional(types.uint) }, { @@ -2300,7 +2351,7 @@ data:add_type { }, { name = "make_indicator", - type = types.callback({"chara", types.map_object("base.chara")}, types.fields_strict { desc = types.string, color = types.optional(ty_color) }), + type = types.callback({"chara", types.map_object("base.chara")}, types.fields_strict { desc = types.string, color = types.optional(types.color) }), } } } diff --git a/src/internal/data/talk.lua b/src/internal/data/talk.lua index 05eb69927..fb780e566 100644 --- a/src/internal/data/talk.lua +++ b/src/internal/data/talk.lua @@ -1,37 +1,5 @@ local data = require("internal.data") -data:add_type { - name = "talk_event", - - fields = { - { - name = "elona_txt_id", - type = "string?" - }, - { - name = "variant_txt_ids", - type = "table?" - } - } -} - -data:add_type { - name = "tone", - - fields = { - { - name = "show_in_menu", - default = nil, - type = "boolean?" - }, - { - name = "texts", - template = true, - type = "table" - }, - } -} - data:add { _type = "base.talk_event", _id = "calm", diff --git a/src/internal/data/theme.lua b/src/internal/data/theme.lua index 17f366cc9..cb1647572 100644 --- a/src/internal/data/theme.lua +++ b/src/internal/data/theme.lua @@ -8,28 +8,6 @@ data:add { overrides = {} } -data:add_type { - name = "theme_transform", - - fields = { - { - name = "applies_to", - type = "string", - template = true - }, - { - name = "transform", - type = "function", - template = true, - default = CodeGenerator.gen_literal [[ -function(old, new) - return table.merge(old, {}) -end -]] - } - } -} - data:add { _type = "base.theme_transform", _id = "chip", diff --git a/src/internal/data_table.lua b/src/internal/data_table.lua index fd9d95879..deec20f27 100644 --- a/src/internal/data_table.lua +++ b/src/internal/data_table.lua @@ -118,7 +118,7 @@ local function remove_index_field(self, dat, _type, field) end end -function data_table:add_index(_type, field) +function data_table:_add_index(_type, field) if not self.schemas[_type] then return end @@ -165,7 +165,8 @@ local ty_schema = types.fields_strict { type = types.type, default = types.optional(types.any), doc = types.optional(types.string), - no_fallback = types.optional(types.boolean) + no_fallback = types.optional(types.boolean), + indexed = types.optional(types.boolean) } ), fallbacks = types.optional(types.table), @@ -220,7 +221,7 @@ function data_table:add_type(schema, params) schema.validate = function(obj, verbose) local ok, err = types.check(obj, schema.type, verbose) if not ok then - return false, ("Validation for data type '%s' failed: %s"):format(_type, err) + return false, ("Validation for data entry '%s:%s.%s' failed: %s"):format(_type, mod_name, obj._id or "", err) end return true end @@ -366,6 +367,13 @@ function data_table:add(dat) return nil end + -- TODO only validate after all data has been added (handles data entry field dependencies) + -- TODO add fallback field types + local ok, err = _schema.validate(dat) + if not ok then + -- print("Error: " .. err) + end + local fallbacks = self.fallbacks[_type] for field, fallback in pairs(fallbacks) do if dat[field] == nil then @@ -373,12 +381,6 @@ function data_table:add(dat) end end - -- TODO only validate after all data has been added (handles data entry field dependencies) - local ok, err = _schema.validate(dat) - if not ok then - error(err) - end - -- Verify extension fields. if dat._ext then -- Convert extensions in list part to blank-parameter ones in map part @@ -457,8 +459,11 @@ function data_table:add(dat) -- TODO fallbacks and prototype_fallbacks should be separate self.inner[_type][full_id] = dat - for field, _ in pairs(_schema.indexes) do - add_index_field(self, dat, _type, field) + for _, field in ipairs(_schema.fields) do + if field.indexed then + _schema.indexes[field] = true + add_index_field(self, dat, _type, field.name) + end end dat._id = full_id diff --git a/src/internal/env.lua b/src/internal/env.lua index 66e1c46c8..a161dfd43 100644 --- a/src/internal/env.lua +++ b/src/internal/env.lua @@ -708,7 +708,6 @@ function env.generate_sandbox(mod_name, is_strict) sandbox["dofile"] = function(path) return env.load_sandboxed_chunk(path, mod_name) end sandbox["data"] = require("internal.data") sandbox["config"] = require("internal.config") - sandbox["schema"] = require("thirdparty.schema") sandbox["pause"] = function(...) return _G.pause(...) end sandbox["_G"] = sandbox diff --git a/src/mod/autopickup/data/autopickup/predicate.lua b/src/mod/autopickup/data/autopickup/predicate.lua index 28dfb5d55..21fd94486 100644 --- a/src/mod/autopickup/data/autopickup/predicate.lua +++ b/src/mod/autopickup/data/autopickup/predicate.lua @@ -3,7 +3,13 @@ local IItemFood = require("mod.elona.api.aspect.IItemFood") local IItemFromChara = require("mod.elona.api.aspect.IItemFromChara") data:add_type { - name = "predicate" + name = "predicate", + fields = { + { + name = "match", + type = types.callback({"item", types.map_object("base.item")}, types.boolean) + } + } } data:add { diff --git a/src/mod/autopickup/data/autopickup/target.lua b/src/mod/autopickup/data/autopickup/target.lua index ee34f5270..efff01bee 100644 --- a/src/mod/autopickup/data/autopickup/target.lua +++ b/src/mod/autopickup/data/autopickup/target.lua @@ -1,7 +1,13 @@ local ElonaItem = require("mod.elona.api.ElonaItem") data:add_type { - name = "target" + name = "target", + fields = { + { + name = "match", + type = types.callback({"item", types.map_object("base.item")}, types.boolean) + } + } } data:add { diff --git a/src/mod/base/data/doc.lua b/src/mod/base/data/doc.lua deleted file mode 100644 index 2a7a9cac6..000000000 --- a/src/mod/base/data/doc.lua +++ /dev/null @@ -1,113 +0,0 @@ --- freeform documentation that doesn't really go anywhere else, just --- for the ability to have it readily available at the REPL - -data:add_type { - name = "doc", - schema = schema.Record{} -} - -data:add { - _type = "base.doc", - _id = "lua_manual_patterns", - _doc = [[ -### Patterns - -#### Character Class: - -A *character class* is used to represent a set of characters. The -following combinations are allowed in describing a character class: - -- ***x*:** (where *x* is not one of the *magic characters* - `^$()%.[]*+-?`) represents the character *x* itself. -- **`.`:** (a dot) represents all characters. -- **`%a`:** represents all letters. -- **`%c`:** represents all control characters. -- **`%d`:** represents all digits. -- **`%l`:** represents all lowercase letters. -- **`%p`:** represents all punctuation characters. -- **`%s`:** represents all space characters. -- **`%u`:** represents all uppercase letters. -- **`%w`:** represents all alphanumeric characters. -- **`%x`:** represents all hexadecimal digits. -- **`%z`:** represents the character with representation 0. -- **`%x`:** (where *x* is any non-alphanumeric character) represents - the character *x*. This is the standard way to escape the magic - characters. Any punctuation character (even the non magic) can be - preceded by a \'`%`\' when used to represent itself in a pattern. -- **`[set]`:** represents the class which is the union of all - characters in *set*. A range of characters can be specified by - separating the end characters of the range with a \'`-`\'. All - classes `%`*x* described above can also be used as components in - *set*. All other characters in *set* represent themselves. For - example, `[%w_]` (or `[_%w]`) represents all alphanumeric characters - plus the underscore, `[0-7]` represents the octal digits, and - `[0-7%l%-]` represents the octal digits plus the lowercase letters - plus the \'`-`\' character. - - The interaction between ranges and classes is not defined. - Therefore, patterns like `[%a-z]` or `[a-%%]` have no meaning. - -- **`[^set]`:** represents the complement of *set*, where *set* is - interpreted as above. - -For all classes represented by single letters (`%a`, `%c`, etc.), the -corresponding uppercase letter represents the complement of the class. -For instance, `%S` represents all non-space characters. - -The definitions of letter, space, and other character groups depend on -the current locale. In particular, the class `[a-z]` may not be -equivalent to `%l`. - -#### Pattern Item: - -A *pattern item* can be - -- a single character class, which matches any single character in the - class; -- a single character class followed by \'`*`\', which matches 0 or - more repetitions of characters in the class. These repetition items - will always match the longest possible sequence; -- a single character class followed by \'`+`\', which matches 1 or - more repetitions of characters in the class. These repetition items - will always match the longest possible sequence; -- a single character class followed by \'`-`\', which also matches 0 - or more repetitions of characters in the class. Unlike \'`*`\', - these repetition items will always match the *shortest* possible - sequence; -- a single character class followed by \'`?`\', which matches 0 or 1 - occurrence of a character in the class; -- `%n`, for *n* between 1 and 9; such item matches a substring equal - to the *n*-th captured string (see below); -- `%bxy`, where *x* and *y* are two distinct characters; such item - matches strings that start with *x*, end with *y*, and where the *x* - and *y* are *balanced*. This means that, if one reads the string - from left to right, counting *+1* for an *x* and *-1* for a *y*, the - ending *y* is the first *y* where the count reaches 0. For instance, - the item `%b()` matches expressions with balanced parentheses. - -#### Pattern: - -A *pattern* is a sequence of pattern items. A \'`^`\' at the beginning -of a pattern anchors the match at the beginning of the subject string. A -\'`$`\' at the end of a pattern anchors the match at the end of the -subject string. At other positions, \'`^`\' and \'`$`\' have no special -meaning and represent themselves. - -#### Captures: - -A pattern can contain sub-patterns enclosed in parentheses; they -describe *captures*. When a match succeeds, the substrings of the -subject string that match captures are stored (*captured*) for future -use. Captures are numbered according to their left parentheses. For -instance, in the pattern `"(a*(.)%w(%s*))"`, the part of the string -matching `"a*(.)%w(%s*)"` is stored as the first capture (and therefore -has number 1); the character matching \"`.`\" is captured with number 2, -and the part matching \"`%s*`\" has number 3. - -As a special case, the empty capture `()` captures the current string -position (a number). For instance, if we apply the pattern `"()aa()"` on -the string `"flaaap"`, there will be two captures: 3 and 5. - -A pattern cannot contain embedded zeros. Use `%z` instead. -]] -} diff --git a/src/mod/base/data/init.lua b/src/mod/base/data/init.lua index e04122220..afdc097c9 100644 --- a/src/mod/base/data/init.lua +++ b/src/mod/base/data/init.lua @@ -1,5 +1,4 @@ require("mod.base.data.language") -require("mod.base.data.doc") require("mod.base.data.keybind") require("mod.base.data.asset") require("mod.base.data.auto_turn_anim") diff --git a/src/mod/elona/api/God.lua b/src/mod/elona/api/God.lua index f3b134cd1..d2a80f739 100644 --- a/src/mod/elona/api/God.lua +++ b/src/mod/elona/api/God.lua @@ -122,16 +122,20 @@ function God.can_offer_item_to(god_id, item) return false end -function God.make_skill_blessing(skill, coefficient, add) - -- data["base.skill"]:ensure(skill) TODO - return function(chara) - if chara:has_skill(skill) then - local amount = math.clamp((chara.piety or 0) / coefficient, 1, add + chara:skill_level("elona.faith") / 10) - chara:mod_skill_level(skill, amount, "add") +local function mkblessing(cb) + return function(skill, coefficient, add) + return function(chara) + if chara:has_skill(skill) then + local amount = math.clamp((chara.piety or 0) / coefficient, 1, add + chara:skill_level("elona.faith") / 10) + chara[cb](chara, skill, amount, "add") + end end end end +God.make_skill_blessing = mkblessing("mod_skill_level") +God.make_resist_blessing = mkblessing("mod_resist_level") + function God.switch_religion_with_penalty(chara, new_god) -- >>>>>>>> shade2/god.hsp:238 gosub *screen_drawStatus ... Gui.update_screen() diff --git a/src/mod/elona/api/HomeMap.lua b/src/mod/elona/api/HomeMap.lua index af4d5d930..d13a55413 100755 --- a/src/mod/elona/api/HomeMap.lua +++ b/src/mod/elona/api/HomeMap.lua @@ -1,181 +1,9 @@ -local Chara = require("api.Chara") -local Item = require("api.Item") local InstancedMap = require("api.InstancedMap") local Elona122Map = require("mod.elona_sys.map_loader.Elona122Map") -local Sidequest = require("mod.elona_sys.sidequest.api.Sidequest") -local I18N = require("api.I18N") local Log = require("api.Log") local HomeMap = {} -local function value(level) - -- >>>>>>>> shade2/item.hsp:647 iValue(ci)=5000+4500*iParam1(ci)*iParam1(ci)*iPa .. - return 5000 + 4500 * level * level * level + level * 20000 - -- <<<<<<<< shade2/item.hsp:647 iValue(ci)=5000+4500*iParam1(ci)*iParam1(ci)*iPa .. -end - -data:add { - _type = "elona.home", - _id = "cave", - - map = "home0", - value = value(0), - image = "elona.feat_area_your_dungeon", - home_scale = 0, - - properties = { - item_on_floor_limit = 100, - home_rank_points = 1000 - }, - - on_generate = function(map) - -- >>>>>>>> shade2/map.hsp:877 if gHomeLevel=0{ .. - if Sidequest.is_active_main_quest("elona.main_quest") - and Sidequest.progress("elona.main_quest") == 0 - then - local chara = Chara.create("elona.larnneire", 18, 10, {}, map) - chara:add_role("elona.special") - - chara = Chara.create("elona.lomias", 16, 11, {}, map) - chara:add_role("elona.special") - - local item = Item.create("elona.heir_trunk", 6, 10, {}, map) - item.count = 3 - - item = Item.create("elona.salary_chest", 15, 19, {}, map) - item.count = 4 - - item = Item.create("elona.freezer", 9, 8, {}, map) - item.count = 4 - - item = Item.create("elona.book", 18, 19, {}, map) - item.params = { book_id = "elona.beginners_guide" } - end - -- <<<<<<<< shade2/map.hsp:884 flt:item_create -1,idBook,18,19:iBookId(ci)=1 .. - end -} - -data:add { - _type = "elona.home", - _id = "shack", - - map = "home1", - value = value(1), - image = "elona.feat_area_town", - home_scale = 1, - - -- >>>>>>>> shade2/map_user.hsp:7 if gHomeLevel=1{ .. - properties = { - item_on_floor_limit = 150, - home_rank_points = 3000 - }, - -- <<<<<<<< shade2/map_user.hsp:10 } .. -} - -data:add { - _type = "elona.home", - _id = "cozy_house", - - map = "home2", - value = value(2), - home_scale = 2, - - -- >>>>>>>> shade2/map_user.hsp:11 if gHomeLevel=2{ .. - properties = { - item_on_floor_limit = 200, - home_rank_points = 5000 - }, - -- <<<<<<<< shade2/map_user.hsp:14 } .. -} - -data:add { - _type = "elona.home", - _id = "estate", - - map = "home3", - value = value(3), - home_scale = 3, - - -- >>>>>>>> shade2/map_user.hsp:15 if gHomeLevel=3{ .. - properties = { - item_on_floor_limit = 300, - home_rank_points = 7000 - }, - -- <<<<<<<< shade2/map_user.hsp:18 } .. -} - -data:add { - _type = "elona.home", - _id = "cyber_house", - - map = "home4", - value = value(4), - image = "elona.feat_area_tent", - home_scale = 4, - - -- >>>>>>>> shade2/map_user.hsp:19 if gHomeLevel=4{ .. - properties = { - item_on_floor_limit = 350, - home_rank_points = 8000, - tileset = "elona.sf" - }, - -- <<<<<<<< shade2/map_user.hsp:23 } .. -} - -data:add { - _type = "elona.home", - _id = "small_castle", - - map = "home5", - -- >>>>>>>> shade2/item.hsp:648 if iParam1(ci)=5:iValue(ci)*=2 .. - value = value(5) * 2, - -- <<<<<<<< shade2/item.hsp:648 if iParam1(ci)=5:iValue(ci)*=2 .. - image = "elona.feat_area_castle", - home_scale = 5, - - -- >>>>>>>> shade2/map_user.hsp:24 if gHomeLevel=5{ .. - properties = { - item_on_floor_limit = 100, - home_rank_points = 1000 - }, - -- <<<<<<<< shade2/map_user.hsp:27 } .. - - on_generate = function(map) - -- >>>>>>>> shade2/map.hsp:901 if gHomeLevel=5{ .. - local chara - - chara = Chara.create("elona.shopkeeper", 31, 20, {}, map) - chara:add_role("elona.shopkeeper", { inventory_id = "elona.general_vendor" }) - chara.shop_rank = 10 - chara.name = I18N.get("chara.job.general_vendor", chara.name) - - chara = Chara.create("elona.shopkeeper", 9, 20, {}, map) - chara:add_role("elona.shopkeeper", { inventory_id = "elona.blacksmith" }) - chara.shop_rank = 12 - chara.name = I18N.get("chara.job.blacksmith", chara.name) - - chara = Chara.create("elona.shopkeeper", 4, 20, {}, map) - chara:add_role("elona.shopkeeper", {inventory_id="elona.goods_vendor"}) - chara.shop_rank = 10 - chara.name = I18N.get("chara.job.goods_vendor", chara.name) - - chara = Chara.create("elona.wizard", 4, 11, {}, map) - chara:add_role("elona.identifier") - - chara = Chara.create("elona.bartender", 30, 11, {}, map) - chara:add_role("elona.bartender") - - chara = Chara.create("elona.healer", 30, 4, nil, map) - chara:add_role("elona.healer") - - chara = Chara.create("elona.wizard", 4, 4, nil, map) - chara:add_role("elona.shopkeeper", { inventory_id = "elona.magic_vendor" }) - chara.shop_rank = 11 - chara.name = I18N.get("chara.job.magic_vendor", chara.name) - -- <<<<<<<< shade2/map.hsp:909 } .. - end -} - function HomeMap.generate(home_id, opts) opts = opts or {} diff --git a/src/mod/elona/api/aspect/ItemBookAspect.lua b/src/mod/elona/api/aspect/ItemBookAspect.lua index a73891710..445e2c5ec 100644 --- a/src/mod/elona/api/aspect/ItemBookAspect.lua +++ b/src/mod/elona/api/aspect/ItemBookAspect.lua @@ -9,7 +9,7 @@ function ItemBookAspect:init(item, params) self.book_id = params.book_id else local cands = data["elona.book"]:iter() - :filter(function(book) return book.is_randomly_generated end) + :filter(function(book) return not book.no_generate end) :extract("_id") :to_list() self.book_id = Rand.choice(cands) diff --git a/src/mod/elona/data/bait.lua b/src/mod/elona/data/bait.lua index 2e9968f73..aec84d7ca 100644 --- a/src/mod/elona/data/bait.lua +++ b/src/mod/elona/data/bait.lua @@ -1,5 +1,20 @@ data:add_type { - name = "bait" + name = "bait", + + fields = { + { + name = "image", + type = types.data_id("base.chip") + }, + { + name = "rank", + type = types.uint, + }, + { + name = "value", + type = types.uint + } + } } local function value(rank) diff --git a/src/mod/elona/data/book.lua b/src/mod/elona/data/book.lua index 81db9397b..eb5729c4b 100644 --- a/src/mod/elona/data/book.lua +++ b/src/mod/elona/data/book.lua @@ -2,8 +2,14 @@ data:add_type { name = "book", fields = { { - name = "is_randomly_generated", - default = true, + name = "elona_id", + indexed = true, + type = types.optional(types.uint), + }, + { + name = "no_generate", + type = types.boolean, + default = false, template = true } } @@ -11,8 +17,8 @@ data:add_type { data:add_multi("elona.book", { { _id = "my_diary", elona_id = 0 }, - { _id = "beginners_guide", elona_id = 1, is_randomly_generated = false }, - { _id = "its_a_bug", elona_id = 2, is_randomly_generated = false }, + { _id = "beginners_guide", elona_id = 1, no_generate = false }, + { _id = "its_a_bug", elona_id = 2, no_generate = false }, { _id = "dont_read_this", elona_id = 3 }, { _id = "museum_guide", elona_id = 4 }, { _id = "crimberry_addict", elona_id = 5 }, @@ -23,7 +29,7 @@ data:add_multi("elona.book", { { _id = "water", elona_id = 10 }, { _id = "breeders_guide", elona_id = 11 }, { _id = "strange_diary", elona_id = 12 }, - { _id = "pyramid_invitation", elona_id = 13, is_randomly_generated = false }, + { _id = "pyramid_invitation", elona_id = 13, no_generate = false }, { _id = "card_game_manual", elona_id = 14 }, { _id = "dungeon_guide", elona_id = 15 }, }) diff --git a/src/mod/elona/data/building.lua b/src/mod/elona/data/building.lua index a4ce55a98..33742e7df 100644 --- a/src/mod/elona/data/building.lua +++ b/src/mod/elona/data/building.lua @@ -1,5 +1,16 @@ data:add_type { - name = "building" + name = "building", + fields = { + { + name = "area_archetype_id", + type = types.data_id("base.area_archetype"), + template = true + }, + { + name = "tax_cost", + type = types.int + } + } } data:add { diff --git a/src/mod/elona/data/encounter.lua b/src/mod/elona/data/encounter.lua index 1bfebd18b..d4fa34a64 100644 --- a/src/mod/elona/data/encounter.lua +++ b/src/mod/elona/data/encounter.lua @@ -1,14 +1,11 @@ -local CodeGenerator = require("api.CodeGenerator") +local InstancedMap = require("api.InstancedMap") data:add_type { name = "encounter", fields = { { name = "encounter_level", - default = CodeGenerator.gen_literal [[ -function(outer_map, outer_x, outer_y) - return 10 -end]], + type = types.callback({"outer_map", types.class(InstancedMap), "outer_x", types.uint, "outer_y", types.uint}, types.number), template = true, doc = [[ Controls the level of the encounter. @@ -16,11 +13,7 @@ Controls the level of the encounter. }, { name = "before_encounter_start", - default = CodeGenerator.gen_literal [[ -function(level, outer_map, outer_x, outer_y) - Gui.mes("Ambush!") - Input.query_more() -end]], + type = types.callback({"level", types.uint, "outer_map", types.class(InstancedMap), "outer_x", types.uint, "outer_y", types.uint}, types.number), template = true, doc = [[ This is run before the player is transported to the encounter map. @@ -28,12 +21,7 @@ This is run before the player is transported to the encounter map. }, { name = "on_map_entered", - default = CodeGenerator.gen_literal [[ -function(map, level, outer_map, outer_x, outer_y) - for i = 1, 10 do - Chara.create("elona.putit", nil, nil, nil, map) - end -end]], + type = types.callback({"map", types.class(InstancedMap), "level", types.uint, "outer_map", types.class(InstancedMap), "outer_x", types.uint, "outer_y", types.uint}, types.number), template = true, doc = [[ Generates the encounter. This function receives map that the encounter will take diff --git a/src/mod/elona/data/ex_help.lua b/src/mod/elona/data/ex_help.lua index 2d2ff4130..3285a6b7a 100644 --- a/src/mod/elona/data/ex_help.lua +++ b/src/mod/elona/data/ex_help.lua @@ -1,5 +1,12 @@ data:add_type { - name = "ex_help" + name = "ex_help", + fields = { + { + name = "elona_id", + indexed = true, + type = types.optional(types.uint) + } + } } local helps = { diff --git a/src/mod/elona/data/field.lua b/src/mod/elona/data/field.lua index 79fea21b7..3fe6dfd66 100644 --- a/src/mod/elona/data/field.lua +++ b/src/mod/elona/data/field.lua @@ -1,21 +1,33 @@ local Rand = require("api.Rand") local Itemgen = require("mod.elona.api.Itemgen") -local schema = require("thirdparty.schema") local I18N = require("api.I18N") +local InstancedMap = require("api.InstancedMap") data:add_type { name = "field_type", - schema = schema.Record { - generate = schema.Function, - }, -} - -data:extend_type( - "base.map_tile", - { - field_type = schema.Optional(schema.String), + fields = { + { + name = "default_tile", + type = types.data_id("base.map_tile") + }, + { + name = "fog", + type = types.data_id("base.map_tile") + }, + { + name = "tiles", + type = types.list(types.fields_strict { id = types.data_id("base.map_tile"), density = types.number }) + }, + { + name = "generate", + type = types.optional(types.callback("self", types.data_entry("elona.field_type"), "map", types.class(InstancedMap))) + }, + { + name = "material_spot_type", + type = types.optional(types.data_id("elona.material_spot")) + } } -) +} local function create_junk_items(map) local stood_map_tile = true diff --git a/src/mod/elona/data/fish.lua b/src/mod/elona/data/fish.lua index 3fbb6b012..cd8808f1b 100644 --- a/src/mod/elona/data/fish.lua +++ b/src/mod/elona/data/fish.lua @@ -1,6 +1,36 @@ -- >>>>>>>> shade2/item_data.hsp:1243 #define global maxFish 100 ... data:add_type { - name = "fish" + name = "fish", + fields = { + { + name = "level", + type = types.uint, + }, + { + name = "rarity", + type = types.uint, + }, + { + name = "power", + type = types.uint, + }, + { + name = "speed", + type = types.uint, + }, + { + name = "weight", + type = types.uint, + }, + { + name = "value", + type = types.uint, + }, + { + name = "item_id", + type = types.data_id("base.item"), + }, + } } local fish = { diff --git a/src/mod/elona/data/god.lua b/src/mod/elona/data/god.lua index a54c3147a..41805420a 100644 --- a/src/mod/elona/data/god.lua +++ b/src/mod/elona/data/god.lua @@ -81,9 +81,9 @@ local god = { blessings = { God.make_skill_blessing("elona.stat_magic", 300, 18), God.make_skill_blessing("elona.meditation", 350, 15), - God.make_skill_blessing("elona.element_fire", 50, 200), - God.make_skill_blessing("elona.element_cold", 50, 200), - God.make_skill_blessing("elona.element_lightning", 50, 200), + God.make_resist_blessing("elona.fire", 50, 200), + God.make_resist_blessing("elona.cold", 50, 200), + God.make_resist_blessing("elona.lightning", 50, 200), }, offerings = { { type = "category", id = "elona.equip_melee_staff" }, diff --git a/src/mod/elona/data/guild.lua b/src/mod/elona/data/guild.lua index 54d759817..292d5126b 100644 --- a/src/mod/elona/data/guild.lua +++ b/src/mod/elona/data/guild.lua @@ -7,7 +7,13 @@ local function order(elona_id) end data:add_type { - name = "guild" + name = "guild", + fields = { + { + name = "guest_trainer_skills", + type = types.list(types.data_id("base.skill")) + } + } } -- diff --git a/src/mod/elona/data/home.lua b/src/mod/elona/data/home.lua index 030a3dbcd..6b8549e12 100644 --- a/src/mod/elona/data/home.lua +++ b/src/mod/elona/data/home.lua @@ -1,7 +1,203 @@ +local Chara = require("api.Chara") +local Item = require("api.Item") +local Sidequest = require("mod.elona_sys.sidequest.api.Sidequest") +local I18N = require("api.I18N") +local InstancedMap = require("api.InstancedMap") + data:add_type { name = "home", - schema = schema.Record { - map = schema.Optional(schema.String), - on_generate = schema.Optional(schema.Function), + fields = { + { + name = "map", + type = types.string + }, + { + name = "map", + type = types.data_id("base.chip") + }, + { + name = "value", + type = types.number + }, + { + name = "home_scale", + type = types.uint + }, + { + name = "properties", + type = types.map(types.string, types.any) + }, + { + name = "on_generate", + type = types.optional(types.callback("map", types.class(InstancedMap))) + } } } + +local function value(level) + -- >>>>>>>> shade2/item.hsp:647 iValue(ci)=5000+4500*iParam1(ci)*iParam1(ci)*iPa .. + return 5000 + 4500 * level * level * level + level * 20000 + -- <<<<<<<< shade2/item.hsp:647 iValue(ci)=5000+4500*iParam1(ci)*iParam1(ci)*iPa .. +end + +data:add { + _type = "elona.home", + _id = "cave", + + map = "home0", + value = value(0), + image = "elona.feat_area_your_dungeon", + home_scale = 0, + + properties = { + item_on_floor_limit = 100, + home_rank_points = 1000 + }, + + on_generate = function(map) + -- >>>>>>>> shade2/map.hsp:877 if gHomeLevel=0{ .. + if Sidequest.is_active_main_quest("elona.main_quest") + and Sidequest.progress("elona.main_quest") == 0 + then + local chara = Chara.create("elona.larnneire", 18, 10, {}, map) + chara:add_role("elona.special") + + chara = Chara.create("elona.lomias", 16, 11, {}, map) + chara:add_role("elona.special") + + local item = Item.create("elona.heir_trunk", 6, 10, {}, map) + item.count = 3 + + item = Item.create("elona.salary_chest", 15, 19, {}, map) + item.count = 4 + + item = Item.create("elona.freezer", 9, 8, {}, map) + item.count = 4 + + item = Item.create("elona.book", 18, 19, {}, map) + item.params = { book_id = "elona.beginners_guide" } + end + -- <<<<<<<< shade2/map.hsp:884 flt:item_create -1,idBook,18,19:iBookId(ci)=1 .. + end +} + +data:add { + _type = "elona.home", + _id = "shack", + + map = "home1", + value = value(1), + image = "elona.feat_area_town", + home_scale = 1, + + -- >>>>>>>> shade2/map_user.hsp:7 if gHomeLevel=1{ .. + properties = { + item_on_floor_limit = 150, + home_rank_points = 3000 + }, + -- <<<<<<<< shade2/map_user.hsp:10 } .. +} + +data:add { + _type = "elona.home", + _id = "cozy_house", + + map = "home2", + value = value(2), + home_scale = 2, + + -- >>>>>>>> shade2/map_user.hsp:11 if gHomeLevel=2{ .. + properties = { + item_on_floor_limit = 200, + home_rank_points = 5000 + }, + -- <<<<<<<< shade2/map_user.hsp:14 } .. +} + +data:add { + _type = "elona.home", + _id = "estate", + + map = "home3", + value = value(3), + home_scale = 3, + + -- >>>>>>>> shade2/map_user.hsp:15 if gHomeLevel=3{ .. + properties = { + item_on_floor_limit = 300, + home_rank_points = 7000 + }, + -- <<<<<<<< shade2/map_user.hsp:18 } .. +} + +data:add { + _type = "elona.home", + _id = "cyber_house", + + map = "home4", + value = value(4), + image = "elona.feat_area_tent", + home_scale = 4, + + -- >>>>>>>> shade2/map_user.hsp:19 if gHomeLevel=4{ .. + properties = { + item_on_floor_limit = 350, + home_rank_points = 8000, + tileset = "elona.sf" + }, + -- <<<<<<<< shade2/map_user.hsp:23 } .. +} + +data:add { + _type = "elona.home", + _id = "small_castle", + + map = "home5", + -- >>>>>>>> shade2/item.hsp:648 if iParam1(ci)=5:iValue(ci)*=2 .. + value = value(5) * 2, + -- <<<<<<<< shade2/item.hsp:648 if iParam1(ci)=5:iValue(ci)*=2 .. + image = "elona.feat_area_castle", + home_scale = 5, + + -- >>>>>>>> shade2/map_user.hsp:24 if gHomeLevel=5{ .. + properties = { + item_on_floor_limit = 100, + home_rank_points = 1000 + }, + -- <<<<<<<< shade2/map_user.hsp:27 } .. + + on_generate = function(map) + -- >>>>>>>> shade2/map.hsp:901 if gHomeLevel=5{ .. + local chara + + chara = Chara.create("elona.shopkeeper", 31, 20, {}, map) + chara:add_role("elona.shopkeeper", { inventory_id = "elona.general_vendor" }) + chara.shop_rank = 10 + chara.name = I18N.get("chara.job.general_vendor", chara.name) + + chara = Chara.create("elona.shopkeeper", 9, 20, {}, map) + chara:add_role("elona.shopkeeper", { inventory_id = "elona.blacksmith" }) + chara.shop_rank = 12 + chara.name = I18N.get("chara.job.blacksmith", chara.name) + + chara = Chara.create("elona.shopkeeper", 4, 20, {}, map) + chara:add_role("elona.shopkeeper", {inventory_id="elona.goods_vendor"}) + chara.shop_rank = 10 + chara.name = I18N.get("chara.job.goods_vendor", chara.name) + + chara = Chara.create("elona.wizard", 4, 11, {}, map) + chara:add_role("elona.identifier") + + chara = Chara.create("elona.bartender", 30, 11, {}, map) + chara:add_role("elona.bartender") + + chara = Chara.create("elona.healer", 30, 4, nil, map) + chara:add_role("elona.healer") + + chara = Chara.create("elona.wizard", 4, 4, nil, map) + chara:add_role("elona.shopkeeper", { inventory_id = "elona.magic_vendor" }) + chara.shop_rank = 11 + chara.name = I18N.get("chara.job.magic_vendor", chara.name) + -- <<<<<<<< shade2/map.hsp:909 } .. + end +} diff --git a/src/mod/elona/data/inventory_proto.lua b/src/mod/elona/data/inventory_proto.lua index f76b8ec26..79f80dcec 100755 --- a/src/mod/elona/data/inventory_proto.lua +++ b/src/mod/elona/data/inventory_proto.lua @@ -1510,7 +1510,7 @@ local inv_take = { default_amount = 1, -- <<<<<<<< shade2/command.hsp:3943 if iId(ci)=idGold:in=iNum(ci):else:in=1 .. -- >>>>>>>> shade2/command.hsp:3565 if invCtrl=25:s="" ... - show_weight_text = false, + hide_weight_text = true, -- <<<<<<<< shade2/command.hsp:3565 if invCtrl=25:s="" .. -- >>>>>>>> shade2/command.hsp:3568 if invCtrl=25{ ... show_target_equip = true, diff --git a/src/mod/elona/data/item.lua b/src/mod/elona/data/item.lua index 04a759573..273e4230b 100644 --- a/src/mod/elona/data/item.lua +++ b/src/mod/elona/data/item.lua @@ -1,3 +1,4 @@ +local Enum = require("api.Enum") local light = require("mod.elona.data.item.light") -- TODO: Some fields should not be stored on the prototype as diff --git a/src/mod/elona/data/item/fish.lua b/src/mod/elona/data/item/fish.lua index 57d75ace6..1b5cdc0ab 100644 --- a/src/mod/elona/data/item/fish.lua +++ b/src/mod/elona/data/item/fish.lua @@ -1,3 +1,4 @@ +local Enum = require("api.Enum") local IItemFood = require("mod.elona.api.aspect.IItemFood") -- diff --git a/src/mod/elona/data/item/remains.lua b/src/mod/elona/data/item/remains.lua index ef033bc75..2064f6519 100644 --- a/src/mod/elona/data/item/remains.lua +++ b/src/mod/elona/data/item/remains.lua @@ -1,6 +1,7 @@ -- -- Remains -- +local Enum = require("api.Enum") local IItemFromChara = require("mod.elona.api.aspect.IItemFromChara") local IItemMuseumValued = require("mod.elona.api.aspect.IItemMuseumValued") local ItemMuseumValuedFigureAspect = require("mod.elona.api.aspect.ItemMuseumValuedFigureAspect") diff --git a/src/mod/elona/data/item_material.lua b/src/mod/elona/data/item_material.lua index e34472216..b5ed39589 100644 --- a/src/mod/elona/data/item_material.lua +++ b/src/mod/elona/data/item_material.lua @@ -1,63 +1,75 @@ data:add_type { name = "item_material", fields = { + { + name = "elona_id", + indexed = true, + type = types.optional(types.uint), + }, { name = "weight", + type = types.uint, default = 10, template = true }, { name = "value", + type = types.uint, default = 10, template = true }, { name = "hit_bonus", + type = types.int, default = 10, template = true }, { name = "damage_bonus", + type = types.int, default = 10, template = true }, { name = "dv", + type = types.int, default = 10, template = true }, { name = "pv", + type = types.int, default = 10, template = true }, { name = "dice_y", + type = types.uint, default = 100, template = true }, { name = "color", - type = "{int,int,int}", + type = types.color, default = { 255, 255, 255 }, template = true }, { name = "no_furniture", - default = nil + type = types.boolean, + default = false } }, } -data:add_index("elona.item_material", "elona_id") data:add { _type="elona.item_material", _id="sand", elona_id=0, - a="砂", - b="子供のおもちゃの", - c="sand", - d="toy", + -- a="砂", + -- b="子供のおもちゃの", + -- c="sand", + -- d="toy", weight=10, value=80, hit_bonus=-5, @@ -72,10 +84,10 @@ data:add { _type="elona.item_material", _id="leather", elona_id=1, - a="革", - b="全てを包む", - c="leather", - d="mysterious", + -- a="革", + -- b="全てを包む", + -- c="leather", + -- d="mysterious", weight=100, value=150, hit_bonus=12, @@ -90,10 +102,10 @@ data:add { _type="elona.item_material", _id="silk", elona_id=2, - a="シルク", - b="美しき", - c="silk", - d="beautiful", + -- a="シルク", + -- b="美しき", + -- c="silk", + -- d="beautiful", weight=40, value=190, hit_bonus=9, @@ -114,10 +126,10 @@ data:add { _type="elona.item_material", _id="cloth", elona_id=3, - a="布", - b="艶やかなる", - c="cloth", - d="charming", + -- a="布", + -- b="艶やかなる", + -- c="cloth", + -- d="charming", weight=20, value=30, hit_bonus=6, @@ -134,10 +146,10 @@ data:add { _type="elona.item_material", _id="scale", elona_id=4, - a="鱗", - b="逆鱗に触れし", - c="scale", - d="wrath", + -- a="鱗", + -- b="逆鱗に触れし", + -- c="scale", + -- d="wrath", weight=180, value=250, hit_bonus=14, @@ -156,10 +168,10 @@ data:add { _type="elona.item_material", _id="glass", elona_id=5, - a="硝子", - b="透き通る", - c="glass", - d="transparent", + -- a="硝子", + -- b="透き通る", + -- c="glass", + -- d="transparent", weight=180, value=150, hit_bonus=19, @@ -182,10 +194,10 @@ data:add { _type="elona.item_material", _id="mithril", elona_id=7, - a="ミスリル", - b="古なる", - c="mithril", - d="ancient", + -- a="ミスリル", + -- b="古なる", + -- c="mithril", + -- d="ancient", weight=240, value=750, hit_bonus=20, @@ -209,10 +221,10 @@ data:add { _type="elona.item_material", _id="ether", elona_id=8, - a="エーテル", - b="永遠なる", - c="ether", - d="eternal", + -- a="エーテル", + -- b="永遠なる", + -- c="ether", + -- d="eternal", weight=80, value=1200, hit_bonus=8, @@ -244,10 +256,10 @@ data:add { _type="elona.item_material", _id="steel", elona_id=9, - a="スティール", - b="由緒ある", - c="steel", - d="historic", + -- a="スティール", + -- b="由緒ある", + -- c="steel", + -- d="historic", weight=270, value=280, hit_bonus=12, @@ -266,10 +278,10 @@ data:add { _type="elona.item_material", _id="iron", elona_id=10, - a="鉄", - b="鉄塊と呼ばれる", - c="metal", - d="mass", + -- a="鉄", + -- b="鉄塊と呼ばれる", + -- c="metal", + -- d="mass", weight=280, value=190, hit_bonus=8, @@ -292,10 +304,10 @@ data:add { _type="elona.item_material", _id="crystal", elona_id=11, - a="水晶", - b="異光を放つ", - c="crystal", - d="rainbow", + -- a="水晶", + -- b="異光を放つ", + -- c="crystal", + -- d="rainbow", weight=200, value=800, hit_bonus=19, @@ -314,10 +326,10 @@ data:add { _type="elona.item_material", _id="bronze", elona_id=12, - a="ブロンズ", - b="気高き", - c="bronze", - d="noble", + -- a="ブロンズ", + -- b="気高き", + -- c="bronze", + -- d="noble", weight=200, value=70, hit_bonus=2, @@ -336,10 +348,10 @@ data:add { _type="elona.item_material", _id="diamond", elona_id=13, - a="ダイヤ", - b="うつろいなき", - c="diamond", - d="ever lasting", + -- a="ダイヤ", + -- b="うつろいなき", + -- c="diamond", + -- d="ever lasting", weight=330, value=1100, hit_bonus=19, @@ -358,10 +370,10 @@ data:add { _type="elona.item_material", _id="spirit_cloth", elona_id=14, - a="霊布", - b="この世ならざる", - c="spirit cloth", - d="amazing", + -- a="霊布", + -- b="この世ならざる", + -- c="spirit cloth", + -- d="amazing", weight=40, value=750, hit_bonus=3, @@ -384,10 +396,10 @@ data:add { _type="elona.item_material", _id="rubynus", elona_id=15, - a="ルビナス", - b="赤く染まった", - c="rubynus", - d="crimson", + -- a="ルビナス", + -- b="赤く染まった", + -- c="rubynus", + -- d="crimson", weight=250, value=1000, hit_bonus=38, @@ -411,10 +423,10 @@ data:add { _type="elona.item_material", _id="paper", elona_id=16, - a="紙", - b="ふざけた", - c="paper", - d="silly", + -- a="紙", + -- b="ふざけた", + -- c="paper", + -- d="silly", weight=10, value=20, hit_bonus=15, @@ -436,10 +448,10 @@ data:add { _type="elona.item_material", _id="dawn_cloth", elona_id=17, - a="宵晒", - b="宵闇を纏いし", - c="dawn cloth", - d="dawn", + -- a="宵晒", + -- b="宵闇を纏いし", + -- c="dawn cloth", + -- d="dawn", weight=45, value=850, hit_bonus=10, @@ -458,10 +470,10 @@ data:add { _type="elona.item_material", _id="bone", elona_id=18, - a="ボーン", - b="不死なる", - c="bone", - d="immortal", + -- a="ボーン", + -- b="不死なる", + -- c="bone", + -- d="immortal", weight=120, value=300, hit_bonus=10, @@ -484,10 +496,10 @@ data:add { _type="elona.item_material", _id="chain", elona_id=19, - a="鉄鎖", - b="連鎖せし", - c="chain", - d="spiral", + -- a="鉄鎖", + -- b="連鎖せし", + -- c="chain", + -- d="spiral", weight=200, value=300, hit_bonus=11, @@ -510,10 +522,10 @@ data:add { _type="elona.item_material", _id="obsidian", elona_id=20, - a="オブシディアン", - b="神殺しの", - c="obsidian", - d="godbane", + -- a="オブシディアン", + -- b="神殺しの", + -- c="obsidian", + -- d="godbane", weight=160, value=350, hit_bonus=16, @@ -532,10 +544,10 @@ data:add { _type="elona.item_material", _id="mica", elona_id=21, - a="ミカ", - b="儚き", - c="mica", - d="ephemeral", + -- a="ミカ", + -- b="儚き", + -- c="mica", + -- d="ephemeral", weight=40, value=150, hit_bonus=10, @@ -556,10 +568,10 @@ data:add { _type="elona.item_material", _id="pearl", elona_id=22, - a="真珠", - b="闇を照らす", - c="perl", - d="shining", + -- a="真珠", + -- b="闇を照らす", + -- c="perl", + -- d="shining", weight=240, value=400, hit_bonus=18, @@ -579,10 +591,10 @@ data:add { _type="elona.item_material", _id="emerald", elona_id=23, - a="エメラルド", - b="奇跡を呼ぶ", - c="emerald", - d="miracle", + -- a="エメラルド", + -- b="奇跡を呼ぶ", + -- c="emerald", + -- d="miracle", weight=240, value=1050, hit_bonus=22, @@ -601,10 +613,10 @@ data:add { _type="elona.item_material", _id="dragon_scale", elona_id=24, - a="竜鱗", - b="竜を統べし", - c="dragon scale", - d="dragonbane", + -- a="竜鱗", + -- b="竜を統べし", + -- c="dragon scale", + -- d="dragonbane", weight=220, value=800, hit_bonus=25, @@ -629,10 +641,10 @@ data:add { _type="elona.item_material", _id="silver", elona_id=25, - a="シルバー", - b="闇を砕く", - c="silver", - d="dreadbane", + -- a="シルバー", + -- b="闇を砕く", + -- c="silver", + -- d="dreadbane", weight=230, value=250, hit_bonus=10, @@ -655,10 +667,10 @@ data:add { _type="elona.item_material", _id="platinum", elona_id=26, - a="白銀", - b="光を纏いし", - c="platinum", - d="brilliant", + -- a="白銀", + -- b="光を纏いし", + -- c="platinum", + -- d="brilliant", weight=260, value=350, hit_bonus=16, @@ -681,10 +693,10 @@ data:add { _type="elona.item_material", _id="zylon", elona_id=27, - a="ザイロン", - b="異国からもたらされし", - c="zylon", - d="foreign", + -- a="ザイロン", + -- b="異国からもたらされし", + -- c="zylon", + -- d="foreign", weight=50, value=500, hit_bonus=5, @@ -703,10 +715,10 @@ data:add { _type="elona.item_material", _id="griffon_scale", elona_id=28, - a="翼鳥鱗", - b="翼を折られし", - c="griffon scale", - d="fallen", + -- a="翼鳥鱗", + -- b="翼を折られし", + -- c="griffon scale", + -- d="fallen", weight=70, value=1000, hit_bonus=16, @@ -725,10 +737,10 @@ data:add { _type="elona.item_material", _id="titanium", elona_id=29, - a="チタン", - b="色褪せぬ", - c="titanium", - d="fadeless", + -- a="チタン", + -- b="色褪せぬ", + -- c="titanium", + -- d="fadeless", weight=200, value=750, hit_bonus=21, @@ -751,10 +763,10 @@ data:add { _type="elona.item_material", _id="chrome", elona_id=30, - a="クロム", - b="真実を暴く", - c="chrome", - d="pure", + -- a="クロム", + -- b="真実を暴く", + -- c="chrome", + -- d="pure", weight=320, value=500, hit_bonus=15, @@ -769,10 +781,10 @@ data:add { _type="elona.item_material", _id="adamantium", elona_id=31, - a="アダマンタイト", - b="大地を揺るがす", - c="adamantium", - d="earth", + -- a="アダマンタイト", + -- b="大地を揺るがす", + -- c="adamantium", + -- d="earth", weight=360, value=1150, hit_bonus=11, @@ -798,10 +810,10 @@ data:add { _type="elona.item_material", _id="gold", elona_id=32, - a="ゴールデン", - b="黄金に輝く", - c="gold", - d="golden", + -- a="ゴールデン", + -- b="黄金に輝く", + -- c="gold", + -- d="golden", weight=300, value=800, hit_bonus=13, @@ -824,10 +836,10 @@ data:add { _type="elona.item_material", _id="coral", elona_id=33, - a="珊瑚", - b="海からもたらされし", - c="coral", - d="ocean", + -- a="珊瑚", + -- b="海からもたらされし", + -- c="coral", + -- d="ocean", weight=180, value=240, hit_bonus=7, @@ -847,10 +859,10 @@ data:add { _type="elona.item_material", _id="lead", elona_id=34, - a="鉛", - b="重き", - c="iron", - d="heavy", + -- a="鉛", + -- b="重き", + -- c="iron", + -- d="heavy", weight=300, value=50, hit_bonus=3, @@ -871,10 +883,10 @@ data:add { _type="elona.item_material", _id="fresh", elona_id=35, - a="生もの", - b="食用", - c="raw", - d="candy", + -- a="生もの", + -- b="食用", + -- c="raw", + -- d="candy", weight=100, value=50, hit_bonus=-5, @@ -889,10 +901,10 @@ data:add { _type="elona.item_material", _id="wood", elona_id=43, - a="木", - b="古き", - c="wood", - d="old", + -- a="木", + -- b="古き", + -- c="wood", + -- d="old", weight=150, value=50, hit_bonus=-5, diff --git a/src/mod/elona/data/material.lua b/src/mod/elona/data/material.lua index 96e573963..43886c2d4 100644 --- a/src/mod/elona/data/material.lua +++ b/src/mod/elona/data/material.lua @@ -1,24 +1,30 @@ data:add_type { name = "material", fields = { + { + name = "elona_id", + type = types.optional(types.uint), + }, { name = "level", + type = types.uint, default = 1, template = true }, { name = "rarity", + type = types.uint, default = 1, template = true }, { name = "image", + type = types.data_id("base.chip"), default = "elona.item_garbage", template = true } } } -data:add_index("elona.material", "elona_id") local materials = { -- global diff --git a/src/mod/elona/data/material_spot.lua b/src/mod/elona/data/material_spot.lua index 8d1daf530..b96c7e7c1 100644 --- a/src/mod/elona/data/material_spot.lua +++ b/src/mod/elona/data/material_spot.lua @@ -8,14 +8,22 @@ data:add_type { name = "material_spot", fields = { { - name = "on_finish", - type = "locale_key", + name = "on_search", + type = types.optional(types.callback({"chara", types.map_object("base.chara"), + "feat", types.map_object("base.feat"), + "level", types.uint, + "choices", types.list(types.data_id("elona.material"))}, + types.data_id("elona.material"))), + default = nil, + }, + { + name = "get_verb", + type = types.locale_id, default = nil, }, { name = "materials", - type = "table", - default = {}, + type = types.list(types.data_id("elona.material")), template = true } } @@ -101,65 +109,65 @@ data:add_type { fields = { { name = "auto_turn_anim", - type = "id:base.auto_turn_anim", + type = types.data_id("base.auto_turn_anim"), default = "base.searching", template = true }, { name = "activity_name", - type = "locale_key", + type = types.locale_id, default = "activity._.elona.searching.verb", template = true }, { name = "activity_animation_wait", - type = "number", + type = types.uint, default = 15, template = true }, { name = "activity_default_turns", - type = "integer", + type = types.uint, default = 20, template = true }, { name = "image", - type = "id:base.chip?", + type = types.optional(types.data_id("base.chip")), default = nil, template = true }, { name = "material_spot_type", - type = "id:elona.material_spot?", + type = types.optional(types.data_id("elona.material_spot?")), default = nil, template = true }, { name = "on_stepped_on_text", - type = "locale_key", + type = types.locale_id, default = "action.move.feature.material.spot", template = true }, { name = "on_start_gather_text", - type = "locale_key", + type = types.locale_id, default = "activity.dig_spot.start.other", template = true }, { name = "on_start_gather_sound", - type = "id:base.sound?", + type = types.optional(types.data_id("base.sound")), default = nil, }, { name = "on_gather_sound_text", - type = "locale_key?", + type = types.optional(types.locale_id), default = nil, }, { name = "on_gather_no_more_text", - type = "locale_key", + type = types.locale_id, default = "activity.material.searching.no_more", template = true }, diff --git a/src/mod/elona/data/nefia.lua b/src/mod/elona/data/nefia.lua index a4c38e618..e84efad64 100644 --- a/src/mod/elona/data/nefia.lua +++ b/src/mod/elona/data/nefia.lua @@ -7,9 +7,21 @@ local MapEntrance = require("mod.elona_sys.api.MapEntrance") local Dungeon = require("mod.elona.api.Dungeon") local Feat = require("api.Feat") local IFeat = require("api.feat.IFeat") +local InstancedArea = require("api.InstancedArea") +local InstancedMap = require("api.InstancedMap") data:add_type { - name = "nefia" + name = "nefia", + fields = { + { + name = "image", + type = types.data_id("base.chip") + }, + { + name = "on_generate_floor", + type = types.callback({"area", types.class(InstancedArea), "floor", types.uint}, types.class(InstancedMap)) + }, + } } data:add { diff --git a/src/mod/elona/data/plant.lua b/src/mod/elona/data/plant.lua index 6708f55cc..e5efc4461 100644 --- a/src/mod/elona/data/plant.lua +++ b/src/mod/elona/data/plant.lua @@ -5,7 +5,21 @@ local Enum = require("api.Enum") local Gardening = require("mod.elona.api.Gardening") data:add_type { - name = "plant" + name = "plant", + fields = { + { + name = "growth_difficulty", + type = types.number + }, + { + name = "regrowth_difficulty", + type = types.number, + }, + { + name = "on_harvest", + type = types.callback("plant", types.map_object("base.feat", "params", types.table)), + } + } } data:add { diff --git a/src/mod/elona/data/production_recipe.lua b/src/mod/elona/data/production_recipe.lua index 5656a30a6..0ff08bf09 100644 --- a/src/mod/elona/data/production_recipe.lua +++ b/src/mod/elona/data/production_recipe.lua @@ -3,23 +3,23 @@ data:add_type { fields = { { name = "item_id", - type = "id:base.item", + type = types.data_id("base.item"), template = true, }, { name = "skill_used", - type = "id:base.skill", + type = types.data_id("base.skill"), template = true, }, { name = "required_skill_level", - type = "integer", + type = types.uint, default = 1, template = true, }, { name = "materials", - type = "table", + type = types.list(types.fields_strict { _id = types.data_id("elona.material"), amount = types.uint }), template = true, }, } diff --git a/src/mod/elona/data/quest/collect.lua b/src/mod/elona/data/quest/collect.lua index 41386621e..b088d9f18 100644 --- a/src/mod/elona/data/quest/collect.lua +++ b/src/mod/elona/data/quest/collect.lua @@ -26,9 +26,9 @@ local collect = { chance = 14, params = { - target_chara_uid = "number", - target_name = "string", - target_item_id = "string" + target_chara_uid = types.uint, + target_name = types.string, + target_item_id = types.data_id("base.item") }, difficulty = function() diff --git a/src/mod/elona/data/quest/deliver.lua b/src/mod/elona/data/quest/deliver.lua index b68d678ae..ec3810923 100644 --- a/src/mod/elona/data/quest/deliver.lua +++ b/src/mod/elona/data/quest/deliver.lua @@ -29,11 +29,11 @@ local deliver = { chance = 6, params = { - target_map_uid = "number", - target_chara_uid = "number", - target_name = "string", - item_category = "string", - item_id = "string", + target_map_uid = types.uint, + target_chara_uid = types.uint, + target_name = types.string, + item_category = types.data_id("base.item_type"), + item_id = types.data_id("base.item"), }, difficulty = 0, diff --git a/src/mod/elona/data/quest/escort.lua b/src/mod/elona/data/quest/escort.lua index b9f282da2..a1909ad02 100644 --- a/src/mod/elona/data/quest/escort.lua +++ b/src/mod/elona/data/quest/escort.lua @@ -55,7 +55,11 @@ local escort = { min_fame = 0, chance = 11, - params = { escort_type = "string", destination_map_uid = "number", encounters_seen = "number" }, + params = { + escort_type = types.literal("protect", "poison", "deadline"), + destination_map_uid = types.uint, + encounters_seen = types.uint + }, difficulty = 0, diff --git a/src/mod/elona/data/random_event.lua b/src/mod/elona/data/random_event.lua index 87746378c..4c357da59 100644 --- a/src/mod/elona/data/random_event.lua +++ b/src/mod/elona/data/random_event.lua @@ -14,40 +14,35 @@ local DeferredEvent = require("mod.elona_sys.api.DeferredEvent") local DeferredEvents = require("mod.elona.api.DeferredEvents") local Calc = require("mod.elona.api.Calc") local Enum = require("api.Enum") -local CodeGenerator = require("api.CodeGenerator") data:add_type { name = "random_event", fields = { { name = "image", - type = "id:base.asset", + type = types.data_id("base.asset"), template = true, }, { name = "on_event_triggered", - type = "function", - default = CodeGenerator.gen_literal [[ -function() -end -]], + type = types.callback(), template = true }, { name = "choice_count", - type = "integer", + type = types.uint, default = 1, template = true, }, { name = "choices", - type = "table?", + type = types.optional(types.list(types.callback())), default = nil, template = true, }, { name = "luck_threshold", - type = "integer?", + type = types.optional(types.uint), default = nil, }, } diff --git a/src/mod/elona/data/shop_inventory.lua b/src/mod/elona/data/shop_inventory.lua index 965cdc878..0928b3c26 100755 --- a/src/mod/elona/data/shop_inventory.lua +++ b/src/mod/elona/data/shop_inventory.lua @@ -1,8 +1,5 @@ local Rand = require("api.Rand") -local Item = require("api.Item") -local World = require("api.World") local Filters = require("mod.elona.api.Filters") -local schema = require("thirdparty.schema") local Enum = require("api.Enum") local ItemMemory = require("mod.elona_sys.api.ItemMemory") local Chara = require("api.Chara") @@ -89,14 +86,46 @@ Available properties: shopkeeper: character who is the shopkeeper. ]] --- NOTE: "id" must be the same as a character role, and between --- [1000,1999]. (2003 is special-cased.) +local ty_item_categories = types.some(types.data_id("base.item_type"), types.list(types.data_id("base.item_type"))) + +local ty_shop_inv_rule = types.fields { + one_in = types.uint, + all_but_one_in = types.uint, + categories = ty_item_categories, + id = types.some(types.data_id("base.item"), types.literal("Skip")), + choices = types.list(types.fields { categories = types.some(types.data_id("base.item_type"), types.list(types.data_id("base.item_type"))) }), + predicate = types.callback({"args", types.table}, types.boolean), + on_generate = types.callback({}, types.table), -- TODO recursive types +} + data:add_type( { name = "shop_inventory", - schema = schema.Record { - type = schema.String, - value = schema.Any + fields = { + { + name = "elona_id", + type = types.uint, + }, + { + name = "rules", + type = types.some(types.list(ty_shop_inv_rule), types.callback({}, types.list(ty_shop_inv_rule))) + }, + { + name = "item_number", + type = types.optional(types.callback({"shopkeeper", types.map_object("base.chara"), "items_to_create", types.uint, "rules", types.list(ty_shop_inv_rule)}, types.uint)) + }, + { + name = "item_base_value", + type = types.optional(types.callback({"args", types.table}, types.uint)) + }, + { + name = "on_generate_item", + type = types.optional(types.callback("args", types.table)) + }, + { + name = "restock_interval", + type = types.positive(types.number) + }, } } ) diff --git a/src/mod/elona/data/weather.lua b/src/mod/elona/data/weather.lua index 489cc7748..c348b9337 100644 --- a/src/mod/elona/data/weather.lua +++ b/src/mod/elona/data/weather.lua @@ -19,34 +19,44 @@ data:add_type { fields = { { name = "travel_speed_modifier", - default = CodeGenerator.gen_literal [[ -function(turns) - return turns * 3 / 2 -end -]], + type = types.callback({"turns", types.number}, types.number), template = true }, { name = "on_travel", - default = CodeGenerator.gen_literal [[ -function(chara, turns) - if Rand.one_in(4) then - return turns + 10 - end - - return turns -end -]], + type = types.callback({"chara", types.map_object("base.chara"), "turns", types.number}, types.number), + template = true + }, + { + name = "on_weather_change", + type = types.callback({}, types.data_id("elona.weather")), template = true }, { name = "draw_callback", - default = CodeGenerator.gen_literal [[ -function() -end -]], + type = types.callback(), template = true }, + { + name = "outdoor_shadow", + type = types.callback({"shadow", types.color}, types.color), + template = true + }, + { + name = "on_turn_start", + type = types.callback("chara", types.map_object("base.chara")), + template = true + }, + { + name = "is_bad_weather", + type = types.boolean, + template = true, + default = false + }, + { + name = "ambient_sound", + type = types.optional(types.data_id("base.sound")), + }, } } diff --git a/src/mod/elona/data/wish_handler.lua b/src/mod/elona/data/wish_handler.lua index 4e827b323..86ca1a2dc 100644 --- a/src/mod/elona/data/wish_handler.lua +++ b/src/mod/elona/data/wish_handler.lua @@ -21,12 +21,7 @@ data:add_type { fields = { { name = "on_wish", - type = "function(string, IChara)", - default = CodeGenerator.gen_literal [[ -function(wish, chara) - return false - end -]], + type = types.callback({"wish", types.string, "chara", types.map_object("base.chara")}, types.boolean), template = true, doc = [[ Code to run on wish. `wish` contains the wish text. `chara` contains the wishing character. @@ -34,6 +29,7 @@ Code to run on wish. `wish` contains the wish text. `chara` contains the wishing }, { name = "ordering", + type = types.int, default = 0, template = true, doc = [[ diff --git a/src/mod/elona/init/god.lua b/src/mod/elona/init/god.lua index 48d25fb46..d0cab280d 100644 --- a/src/mod/elona/init/god.lua +++ b/src/mod/elona/init/god.lua @@ -1,17 +1,72 @@ local Event = require("api.Event") -local Rand = require("api.Rand") -local schema = require("thirdparty.schema") local God = require("mod.elona.api.God") +local ty_god_item = types.fields { + id = types.data_id("base.item"), + no_stack = types.boolean, + only_once = types.boolean, + properties = types.table +} + +local ty_god_offering = types.some( + types.fields_strict { + type = types.literal("category"), + id = types.data_id("base.item_type") + }, + types.fields_strict { + type = types.literal("item"), + id = types.data_id("base.item") + } +) + data:add_type { name = "god", - schema = schema.Record { - elona_id = schema.Number + fields = { + { + name = "elona_id", + indexed = true, + type = types.optional(types.uint) + }, + { + name = "is_primary_god", + type = types.boolean + }, + { + name = "summon", + type = types.optional(types.data_id("base.chara")) + }, + { + name = "servant", + type = types.data_id("base.chara") + }, + { + name = "items", + type = types.list(ty_god_item) + }, + { + name = "artifact", + type = types.data_id("base.item") + }, + { + name = "blessings", + type = types.list(types.callback("chara", types.map_object("base.chara"))) + }, + { + name = "offerings", + type = types.list(ty_god_offering), + default = {} + }, + { + name = "on_join_faith", + type = types.optional(types.callback("chara", types.map_object("base.chara"))) + }, + { + name = "on_leave_faith", + type = types.optional(types.callback("chara", types.map_object("base.chara"))) + } } } -data:add_index("elona.god", "elona_id") - local function set_god(chara) local has_dialog = chara.can_talk or chara.dialog diff --git a/src/mod/elona_sys/api/Magic.lua b/src/mod/elona_sys/api/Magic.lua index 97699c9cc..4b98ddf1d 100755 --- a/src/mod/elona_sys/api/Magic.lua +++ b/src/mod/elona_sys/api/Magic.lua @@ -369,13 +369,6 @@ function Magic.cast(id, params) return result.did_something, result.turn_result end -local function on_cast_magic(_, params, result) - local did_something, turn_result = params.magic:cast(params.magic_params) - result.did_something = did_something - result.turn_result = turn_result -end -Event.register("elona_sys.on_cast_magic", "Cast magic", on_cast_magic, { priority = 100000 }) - function Magic.skills_for_magic(magic_id) if magic_id == nil then return nil diff --git a/src/mod/elona_sys/bindable_event/init.lua b/src/mod/elona_sys/bindable_event/init.lua deleted file mode 100644 index b282a9e72..000000000 --- a/src/mod/elona_sys/bindable_event/init.lua +++ /dev/null @@ -1,39 +0,0 @@ -local Event = require("api.Event") -local CodeGenerator = require("api.CodeGenerator") - -data:add_type { - name = "bindable_event", - fields = { - { - name = "event_id", - default = "", - template = true - }, - { - name = "description", - default = "", - template = true - }, - { - name = "callback", - default = CodeGenerator.gen_literal [[ - function(receiver, params, result) - end - ]], - template = true - }, - } -} - -Event.register("base.on_object_instantiated", "Bind events in bindable_events table", - function(receiver, params, result) - if receiver.bindable_events then - for _, bindable_event in ipairs(receiver.bindable_events) do - local entry = data["elona_sys.bindable_event"]:ensure(bindable_event) - receiver:connect_self(entry.event_id, - entry.description, - entry.callback, - { priority = entry.priority or 200000}) - end - end - end) \ No newline at end of file diff --git a/src/mod/elona_sys/dialog/init.lua b/src/mod/elona_sys/dialog/init.lua index da1cbf597..a2b5a4d7e 100644 --- a/src/mod/elona_sys/dialog/init.lua +++ b/src/mod/elona_sys/dialog/init.lua @@ -1,10 +1,10 @@ data:add_type { name = "dialog", - schema = schema.Record { - name = schema.String, - image = schema.Number, - max_hp = schema.Number, - on_death = schema.Optional(schema.Function), + fields = { + { + name = "nodes", + type = types.map(types.identifier, types.any) -- TODO + } } } diff --git a/src/mod/elona_sys/events.lua b/src/mod/elona_sys/events.lua index 980d14dff..18f33fffb 100644 --- a/src/mod/elona_sys/events.lua +++ b/src/mod/elona_sys/events.lua @@ -634,6 +634,12 @@ local function proc_confusion_message(chara) end Event.register("base.before_chara_moved", "Proc confusion message", proc_confusion_message, { priority = 200000 }) +local function on_cast_magic(_, params, result) + local did_something, turn_result = params.magic:cast(params.magic_params) + result.did_something = did_something + result.turn_result = turn_result +end +Event.register("elona_sys.on_cast_magic", "Cast magic", on_cast_magic, { priority = 100000 }) require("mod.elona_sys.event.instantiate_feat") require("mod.elona_sys.event.instantiate_item") diff --git a/src/mod/elona_sys/god/init.lua b/src/mod/elona_sys/god/init.lua deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/mod/elona_sys/init.lua b/src/mod/elona_sys/init.lua index 8c20ba9a0..76f466296 100644 --- a/src/mod/elona_sys/init.lua +++ b/src/mod/elona_sys/init.lua @@ -1,91 +1,133 @@ -local CodeGenerator = require("api.CodeGenerator") - -local function add_elona_id(_type) - data:add_index(_type, "elona_id") -end - -data:extend_type( - "base.chara", - { - impress = schema.Number, - attract = schema.Number, - on_gold_amount = schema.Function, - } -) - -data:extend_type( - "base.item", - { - elona_id = schema.Number, - } -) - -data:extend_type( - "base.skill", - { - elona_id = schema.Number, - } -) - -data:extend_type( - "base.trait", - { - elona_id = schema.Number, - } -) - -data:extend_type( - "base.scenario", - { - restrictions = schema.Table, - } -) - -data:extend_type( - "base.feat", - { - elona_id = schema.Optional(schema.Number), - } -) - -add_elona_id("base.chara") -add_elona_id("base.item") -add_elona_id("base.skill") -add_elona_id("base.element") -add_elona_id("base.feat") -add_elona_id("base.element") -add_elona_id("base.sound") -add_elona_id("base.music") -add_elona_id("base.body_part") -add_elona_id("base.portrait") +local InventoryContext = require("api.gui.menu.InventoryContext") +local InventoryWrapper = require("api.gui.menu.InventoryWrapper") +local ty_quest = types.table -- TODO data:add_type { name = "quest", - schema = schema.Record { - }, + fields = { + { + name = "client_chara_type", + type = types.uint, + }, + { + name = "reward", + type = types.data_id("elona_sys.quest_reward") + }, + { + name = "reward_fix", + type = types.uint, + }, + { + name = "min_fame", + type = types.uint + }, + { + name = "chance", + type = types.uint + }, + { + name = "params", + type = types.map(types.string, types.type) + }, + { + name = "difficulty", + type = types.some(types.number, types.callback({}, types.number)) + }, + { + name = "expiration_hours", + type = types.callback({}, types.number) + }, + { + name = "deadline_days", + type = types.optional(types.callback({}, types.number)) + }, + { + name = "generate", + type = types.callback({"quest", ty_quest, "client", types.map_object("base.chara")}, types.boolean) + }, + { + name = "on_accept", + type = types.callback({"quest", ty_quest}, {types.boolean, types.optional(types.locale_id)}) + }, + { + name = "on_failure", + type = types.callback({"quest", ty_quest}) + }, + { + name = "on_complete", + type = types.callback({}, types.locale_id) + }, + { + name = "prevents_return", + type = types.boolean, + default = false + } + } } data:add_type { name = "quest_reward", - schema = schema.Record { - }, + fields = { + { + name = "elona_id", + indexed = true, + type = types.optional(types.uint) + }, + { + name = "generate", + type = types.callback({"quest_reward", types.table, "quest", ty_quest}) + } + } } data:add_type { name = "sidequest", - schema = schema.Record { - }, + fields = { + { + name = "elona_id", + indexed = true, + type = types.optional(types.uint) + }, + { + name = "is_main_quest", + type = types.boolean, + default = false + }, + { + name = "progress", + type = types.map(types.int, types.locale_id) + } + } +} + +local ty_dice = types.fields_strict { + x = types.number, + y = types.number, + bonus = types.number +} + +local ty_magic_params = types.fields_strict { + source = types.optional(types.map_object("any")), + target = types.optional(types.map_object("base.chara")), + item = types.optional(types.map_object("base.item")), + x = types.optional(types.uint), + y = types.optional(types.uint) } data:add_type { name = "magic", fields = { + { + name = "elona_id", + indexed = true, + type = types.optional(types.uint) + }, { name = "params", + type = types.list(types.literal("source", "target", "item", "x", "y")), default = { "source" }, template = true, - type = "table", doc = [[ The parameters this magic accepts. @@ -94,7 +136,11 @@ doc = [[ }, { name = "dice", - default = CodeGenerator.gen_literal [[ + type = types.optional(types.callback({"self", types.data_entry("elona_sys.magic"), "params", types.table}, ty_dice)), + doc = [[ +The dice indicating the relative strength of this magic. Has this format: + +```lua function(self, params) local level = params.source:skill_level("my_mod.some_magic") return { @@ -103,67 +149,66 @@ function(self, params) bonus = 50, } end -]], - type = "function(elona_sys.magic, table)", - doc = [[ -The dice indicating the relative strength of this magic. Has this format: +``` ]] }, { name = "cast", - default = CodeGenerator.gen_literal [[ -function(self, params) - local source = params.source - local target = params.target - local map = params.source:current_map() - - return true -end]], + type = types.callback({"self", types.data_entry("elona_sys.magic"), "params", ty_magic_params}, {types.boolean, types.optional(types.fields { obvious = types.boolean })}), template = true, - type = "function(elona_sys.magic, table)", -doc = [[ - Runs arbitrary AI actions. Is passed the character and extra parameters, differing depending on the action. - - Returns true if the character acted, false if not. + doc = [[ +Function run when the magic is cast. ]] }, + { + name = "related_skill", + type = types.data_id("base.skill") + }, + { + name = "cost", + type = types.number + }, + { + name = "range", + type = types.uint + }, + { + name = "type", + type = types.literal("skill", "action", "effect") + } }, } -add_elona_id("elona_sys.magic") data:add_type { name = "buff", fields = { { name = "type", + type = types.literal("blessing", "hex", "food"), default = "blessing", template = true, - type = "table", doc = [[ -The type of this buff. Available options: - -- blessing -- hex -- food +The type of this buff. ]] }, { - name = "apply", - default = CodeGenerator.gen_literal [[ -function(self, params) - local source = params.source - local target = params.target - local map = params.source:current_map() - - return true -end]], + name = "on_refresh", + type = types.callback({"self", types.data_entry("base.buff"), "chara", types.map_object("base.chara")}, types.boolean), template = true, - type = "function(elona_sys.magic, table)?", doc = [[ Run the logic for this buff, if any. This can be omitted if the effect is implemented in event handlers, like for Silence. ]] }, + { + name = "params", + type = types.callback({"self", types.data_entry("base.buff"), "params", types.table}, types.fields_strict { duration = types.number, power = types.number }) + }, + { + -- TODO needs to be themable + name = "image", + type = types.uint + } }, } @@ -172,24 +217,40 @@ data:add_type { fields = { { name = "wait", + type = types.number, default = 50, template = true, - type = "number", doc = [[ How much time to wait when running this animation, in milliseconds. ]] }, { name = "frames", + type = types.optional(types.int), default = nil, - type = "integer?", doc = [[ How many frames this animation holds. Omit to default to the asset's `count_x` property. +]] + }, + { + name = "wait", + type = types.optional(types.number), + default = 3.5, + doc = [[ +How much time to wait between frames. +]] + }, + { + name = "rotation", + type = types.optional(types.number), + default = 0, + doc = [[ +How much time to wait between frames. ]] }, { name = "asset", - type = "id:base.asset", + type = types.data_id("base.asset"), template = true, doc = [[ The asset that holds this animation's frames. It should have a `count_x` property. @@ -197,7 +258,7 @@ The asset that holds this animation's frames. It should have a `count_x` propert }, { name = "sound", - type = "id:base.sound?", + type = types.optional(types.data_id("base.sound")), template = true, doc = [[ A sound to play for this animation, if any. @@ -206,16 +267,115 @@ A sound to play for this animation, if any. } } +local ty_ctxt_source = types.fields_strict { + name = types.string, + getter = types.callback({"ctxt", types.class(InventoryContext)}, types.iterator(types.map_object("base.item"))), + order = types.uint, + get_item_name = types.optional(types.callback({"self", types.table, "name", types.string, "item", types.map_object("base.item"), "menu", types.table}, types.string)), + on_draw = types.optional(types.callback("self", types.table, "x", types.number, "y", types.number, "item", types.map_object("base.item"), "menu", types.table)), + params = types.map(types.string, types.type) +} + +local ty_ctxt_item = types.fields_strict { + item = types.map_object("base.item"), + source = ty_ctxt_source +} + +local ty_key_hint = types.fields_strict { action = types.locale_id, keys = types.some(types.string, types.list(types.string)) } + data:add_type { name = "inventory_proto", fields = { { - name = "show_weight_text", - default = true, + name = "elona_id", + type = types.optional(types.uint) + }, + { + name = "elona_sub_id", + type = types.optional(types.uint) + }, + { + name = "sources", + type = types.list(types.literal("chara", "equipment", "target", "container", "shop", "target_equipment", "ground")) + }, + { + name = "shortcuts", + type = types.boolean, + default = false + }, + { + name = "icon", + type = types.optional(types.uint), + }, + { + name = "query_amount", + type = types.boolean, + default = false + }, + { + name = "show_money", + type = types.boolean, + default = false, + }, + { + name = "window_title", + type = types.locale_id + }, + { + name = "query_text", + type = types.locale_id + }, + { + name = "window_detail_header", + type = types.locale_id + }, + { + name = "keybinds", + type = types.optional(types.callback({"ctxt", types.class(InventoryContext)}, types.map(types.string, types.callback("wrapper", types.class(InventoryWrapper))))) + }, + { + name = "key_hints", + type = types.optional(types.callback({"ctxt", types.class(InventoryContext)}, types.list(ty_key_hint))) + }, + { + name = "get_item_detail_text", + type = types.optional(types.callback({"name", types.string, "item", types.map_object("base.item")}, types.string)) + }, + { + name = "sort", + type = types.optional(types.callback({"ctxt", types.class(InventoryContext), "a", ty_ctxt_item, "b", ty_ctxt_item}, types.boolean)) + }, + { + name = "filter", + type = types.optional(types.callback({"ctxt", types.class(InventoryContext), "item", types.map_object("base.item")}, types.boolean)) + }, + { + name = "after_filter", + type = types.optional(types.callback({"ctxt", types.class(InventoryContext), "filtered", types.list(ty_ctxt_item)}, types.optional(types.string))) + }, + { + name = "can_select", + type = types.optional(types.callback({"ctxt", types.class(InventoryContext), "item", types.map_object("base.item")}, types.boolean)) + }, + { + name = "on_select", + type = types.optional(types.callback({"ctxt", types.class(InventoryContext), "item", types.map_object("base.item")}, types.string)) + }, + { + name = "on_shortcut", + type = types.optional(types.callback({"ctxt", types.class(InventoryContext), "item", types.map_object("base.item")}, {types.optional(types.string), types.optional(types.string)})) + }, + { + name = "on_menu_exit", + type = types.optional(types.callback({"ctxt", types.class(InventoryContext)}, types.string)) + }, + { + name = "hide_weight_text", + type = types.boolean, + default = false, template = true, - type = "boolean", doc = [[ -If true, show weight text at the bottom of the inventory menu. Defaults to true. +If true, hide weight text at the bottom of the inventory menu. Defaults to false. ]] }, } @@ -223,14 +383,48 @@ If true, show weight text at the bottom of the inventory menu. Defaults to true. data:add_type { name = "inventory_group", - schema = schema.Record { - protos = schema.Table + fields = { + { + name = "protos", + type = types.list(types.data_id("base.inventory_proto")) + } } } +local ty_scene_entry = types.some( + types.fields_strict { + [1] = types.literal("wait", "fade", "fadein") + }, + types.fields_strict { + [1] = types.literal("pic"), + [2] = types.data_id("base.asset"), + }, + types.fields_strict { + [1] = types.literal("mc"), + [2] = types.data_id("base.music"), + }, + types.fields_strict { + [1] = types.literal("txt"), + [2] = types.string + }, + types.fields_strict { + [1] = types.literal("chat"), + [2] = types.uint, + [3] = types.string + }, + types.fields_strict { + [1] = types.literal("actor"), + [2] = types.fields_strict { name = types.string, portrait = types.data_id("base.portrait") } + } +) + data:add_type { name = "scene", - schema = schema.Record { + fields = { + { + name = "content", + type = types.map(types.string, types.list(ty_scene_entry)) + } } } @@ -240,7 +434,6 @@ require("mod.elona_sys.data.event") require("mod.elona_sys.map_tileset.init") require("mod.elona_sys.dialog.init") require("mod.elona_sys.deferred_event.init") -require("mod.elona_sys.bindable_event.init") require("mod.elona_sys.events") diff --git a/src/mod/elona_sys/map_tileset/init.lua b/src/mod/elona_sys/map_tileset/init.lua index 121c7acfd..fc368b751 100644 --- a/src/mod/elona_sys/map_tileset/init.lua +++ b/src/mod/elona_sys/map_tileset/init.lua @@ -1,7 +1,18 @@ data:add_type { name = "map_tileset", - schema = schema.Record { - elona_id = schema.Number + fields = { + { + name = "elona_id", + indexed = true, + type = types.optional(types.uint) + }, + { + name = "tiles", + type = types.map(types.data_id("base.map_tile"), types.some(types.data_id("base.map_tile"), types.callback({}, types.data_id("base.map_tile")))) + }, + { + name = "fog", + type = types.data_id("base.map_tile") + } } } -data:add_index("elona_sys.map_tileset", "elona_id") diff --git a/src/mod/ffhp/api/ItemEx.lua b/src/mod/ffhp/api/ItemEx.lua index 1cff83314..afff3babb 100644 --- a/src/mod/ffhp/api/ItemEx.lua +++ b/src/mod/ffhp/api/ItemEx.lua @@ -143,7 +143,7 @@ function ItemEx.parse_item_ex_csv(csv_file, base_path, mod_id) local shadow = tonumber(row[6]) local color = tonumber(row[7]) local use_directional_chips = tonumber(row[8]) - if use_directional_chips == "1" then + if use_directional_chips == 1 then use_directional_chips = true chip_path = Fs.join(base_path, "graphic", "item", ("itemEx2_%03d.bmp"):format(chip_id)) end diff --git a/src/mod/ffhp/data/item_ex_mapping.lua b/src/mod/ffhp/data/item_ex_mapping.lua index 171969f83..143e47e4c 100644 --- a/src/mod/ffhp/data/item_ex_mapping.lua +++ b/src/mod/ffhp/data/item_ex_mapping.lua @@ -5,23 +5,22 @@ data:add_type { fields = { { name = "item_id", + type = types.data_id("base.item"), template = true, - default = "", - type = "id:base.item" }, { name = "chip_id", + type = types.optional(types.data_id("base.chip")), template = true, - type = "id:base.chip?" }, { name = "color", + type = types.optional(types.color), template = true, - type = "color?|string?" }, { name = "chip_variants", - type = "table?" + type = types.optional(types.list(types.data_id("base.chip"))), } } } diff --git a/src/mod/map_editor/data/map_editor/plugin.lua b/src/mod/map_editor/data/map_editor/plugin.lua index a91007cc7..7dda7fe27 100644 --- a/src/mod/map_editor/data/map_editor/plugin.lua +++ b/src/mod/map_editor/data/map_editor/plugin.lua @@ -2,9 +2,16 @@ local MapEditor122Plugin = require("mod.map_editor.api.plugin.MapEditor122Plugin local MapEditorLayoutPlugin = require("mod.map_editor.api.plugin.MapEditorLayoutPlugin") local MapEditorNefiaPlugin = require("mod.map_editor.api.plugin.MapEditorNefiaPlugin") local MapEditorWfcPlugin = require("mod.map_editor.api.plugin.MapEditorWfcPlugin") +local IMapEditorPlugin = require("mod.map_editor.api.IMapEditorPlugin") data:add_type { - name = "plugin" + name = "plugin", + fields = { + { + name = "impl", + type = types.class_type_implementing(IMapEditorPlugin) + } + } } data:add { diff --git a/src/mod/simple_indicators/data/simple_indicators/indicator.lua b/src/mod/simple_indicators/data/simple_indicators/indicator.lua index b1933421e..428d778e7 100644 --- a/src/mod/simple_indicators/data/simple_indicators/indicator.lua +++ b/src/mod/simple_indicators/data/simple_indicators/indicator.lua @@ -1,5 +1,11 @@ data:add_type { - name = "indicator" + name = "indicator", + fields = { + { + name = "render", + type = types.callback({"player", types.map_object("base.chara")}, types.string) + } + } } data:add { diff --git a/src/mod/smithing/data/chip.lua b/src/mod/smithing/data/chip.lua index 8a9d63ed4..407f678bd 100644 --- a/src/mod/smithing/data/chip.lua +++ b/src/mod/smithing/data/chip.lua @@ -1,4 +1,4 @@ -d,ata:add { +data:add { _type = "base.chip", _id = "blacksmith_hammer", diff --git a/src/mod/sokoban/data/sokoban/board.lua b/src/mod/sokoban/data/sokoban/board.lua index f4117a3df..e5d31551e 100644 --- a/src/mod/sokoban/data/sokoban/board.lua +++ b/src/mod/sokoban/data/sokoban/board.lua @@ -3,8 +3,7 @@ data:add_type { fields = { { name = "layout", - type = "string", - default = "", + type = types.string, template = true } } diff --git a/src/mod/titles/data/titles/title.lua b/src/mod/titles/data/titles/title.lua index c3ec16dc0..17749ec0e 100644 --- a/src/mod/titles/data/titles/title.lua +++ b/src/mod/titles/data/titles/title.lua @@ -1,3 +1,22 @@ data:add_type { - name = "title" + name = "title", + fields = { + { + -- TODO standardize + name = "elona_variant_ids", + type = types.map(types.identifier, types.uint), + }, + { + name = "localize_info", + type = types.callback({"info", types.table}, types.table) + }, + { + name = "check_earned", + type = types.callback({"chara", types.map_object("base.chara")}, types.boolean) + }, + { + name = "on_refresh", + type = types.callback("chara", types.map_object("base.chara"), "effect_on", types.boolean) + } + } } diff --git a/src/mod/tools/api/Mx.lua b/src/mod/tools/api/Mx.lua deleted file mode 100644 index 4b7b4e292..000000000 --- a/src/mod/tools/api/Mx.lua +++ /dev/null @@ -1,125 +0,0 @@ -local Gui = require("api.Gui") -local Input = require("api.Input") -local FuzzyFinderPrompt = require("mod.tools.api.FuzzyFinderPrompt") - -local Mx = {} - -local match_opts = { - max_gap = 5, - ignore_spaces = true -} - -function Mx.completing_read(cands, opts) - opts = opts or {} - opts.match_opts = opts.match_opts or match_opts - opts.prompt_length = 30 - - return FuzzyFinderPrompt:new(cands, opts):query() -end - -function Mx.read_type(ty, entry) - if type(entry) == "table" and entry.prompt then - Gui.mes(entry.prompt) - end - - if data:has_type(ty) then - local cands = data[ty]:iter():extract("_id"):to_list() - return Mx.completing_read(cands) - elseif ty == "number" then - return Input.query_number(entry.max or nil, entry.initial_amount or nil) - elseif ty == "string" then - return Input.query_text(entry.length or 20, true, false) - elseif ty == "choice" then - assert(entry.candidates, "argument must have 'candidates' field") - return Mx.completing_read(entry.candidates, { get_name = entry.get_name } ) - else - error(("unknown argument type '%s'"):format(ty)) - end -end - -local function get_single_arg(entry, arg) - if type(entry) == "function" then - return entry(arg) - elseif type(entry) ~= "table" then - return entry - end - - local ty = assert(entry.type, "spec entry must have 'type' field") - return Mx.read_type(ty, entry) -end - -function Mx.get_args(spec, arg) - local args = {} - local canceled - - if type(spec) == "function" then - args, canceled = spec(arg) - if canceled then - return nil, canceled - end - assert(type(args) == "table" and args[1]) - else - for i, entry in ipairs(spec) do - local arg, canceled = get_single_arg(entry, arg) - if canceled then - return nil, canceled - end - args[i] = arg - end - end - - return args, nil -end - -function Mx.start(arg) - local cands = data["tools.interactive_fn"]:iter():extract("_id"):to_list() - - local id, canceled = Mx.completing_read(cands) - - if canceled then - return nil, canceled - end - - if id == nil then - return "player_turn_query" - end - - local entry = data["tools.interactive_fn"]:ensure(id) - local args, canceled = Mx.get_args(entry.spec, arg) - if canceled then - return nil, canceled - end - - entry.func(table.unpack(args)) - - return "player_turn_query" -end - -function Mx.make_interactive(name, tbl, func, spec) - if type(tbl) == "function" then - spec = func - func = "func" - tbl = { func = tbl } - end - - assert(tbl[func], ("Function '%s' not found in table"):format(func)) - local func = function(...) return tbl[func](...) end - - if data["tools.interactive_fn"][name] then - data:replace { - _type = "tools.interactive_fn", - _id = name, - func = func, - spec = spec or {} - } - else - data:add { - _type = "tools.interactive_fn", - _id = name, - func = func, - spec = spec or {} - } - end -end - -return Mx diff --git a/src/mod/tools/exec/interactive.lua b/src/mod/tools/exec/interactive.lua deleted file mode 100644 index e64cccebd..000000000 --- a/src/mod/tools/exec/interactive.lua +++ /dev/null @@ -1,140 +0,0 @@ -local Mx = require("mod.tools.api.Mx") - -local PicViewer = require("mod.tools.api.PicViewer") -local function cands() - local keys = data["base.asset"]:iter():extract("_id") - return Mx.completing_read(keys) -end -Mx.make_interactive("pic_viewer_start", PicViewer, "start", {cands}) - - -local Input = require("api.Input") -Mx.make_interactive("input_reload_keybinds", Input, "reload_keybinds") - - -local Tools = require("mod.tools.api.Tools") -Mx.make_interactive("goto_down_stairs", Tools, "goto_down_stairs") -Mx.make_interactive("goto_up_stairs", Tools, "goto_up_stairs") - - -local Chara = require("api.Chara") -local chara_create = function(id, x, y, amount) - local map = Chara.player():current_map() - for i=1, amount or 1 do - Chara.create(id, x, y, {}, map) - end -end -Mx.make_interactive("chara_create", chara_create, - { - { type="base.chara" }, - function() return Chara.player().x end, - function() return Chara.player().y end, - function(arg) - if arg then - return Mx.read_type("number", { max=100, initial_amount=5 }) - end - end - } -) - - -local Item = require("api.Item") -Mx.make_interactive("item_create", Item, "create", - { - { type="base.item" }, - function() return Chara.player().x end, - function() return Chara.player().y end, - function() - return { - amount = Mx.read_type("number", { max=1000, initial_amount=1 }) - } - end - }) - -local Watcher = require("mod.tools.api.Watcher") -local Map = require("api.Map") -Mx.make_interactive("start_watching", Watcher, "start_watching_object", - function() - local get_name = function(obj) - return ("%d (%s) [%s]"):format(obj.uid, obj.name or obj._id, obj._type) - end - local objects = Map.current():iter() - local object, canceled = Mx.read_type("choice", {candidates=objects, get_name=get_name}) - if canceled then - return nil, canceled - end - - return { - ("%d (%s)"):format(object.uid, object.name or object._id), - object, - config.tools.default_watches - } - end) - -Mx.make_interactive("stop_watching", Watcher, "stop_watching_object", - { - function() - local conv = function(name, watch) - return name - end - local cands = fun.iter(Watcher.get_widget().watches):map(conv) - - return Mx.read_type("choice", {candidates=cands}) - end - }) - -Mx.make_interactive("start_watching_index", Watcher, "start_watching_index", - { - function() - local widget = Watcher.get_widget() - local conv = function(name, watch) - return name - end - local cands = fun.iter(widget.watches):map(conv) - - return Mx.read_type("choice", {candidates=cands}) - end, - { type = "string" } - }) - -Mx.make_interactive("stop_watching_index", Watcher, "stop_watching_index", - function() - local widget = Watcher.get_widget() - local conv = function(name, watch) - return name - end - local cands = fun.iter(widget.watches):map(conv) - - local name, canceled = Mx.read_type("choice", {candidates=cands}) - if canceled then - return nil, canceled - end - - cands = widget.watches[name].indices - local index, canceled = Mx.read_type("choice", {candidates=cands}) - if canceled then - return nil, canceled - end - - return {name, index} - end) - -Mx.make_interactive("watcher_clear", Watcher, "clear") - -Mx.make_interactive("restart_scenario", Tools, "restart_scenario") - -Mx.make_interactive("chara_sheet", Tools, "chara_sheet") - --- --- Keybinds --- - -local Gui = require("api.Gui") -Gui.bind_keys { - ["tools.m_x"] = function() - Mx.start() - end, - ["tools.prefix_m_x"] = function() - Mx.start(true) - end, -} diff --git a/src/mod/tools/init.lua b/src/mod/tools/init.lua index 58efeae75..c89706250 100644 --- a/src/mod/tools/init.lua +++ b/src/mod/tools/init.lua @@ -1,26 +1,9 @@ local Gui = require("api.Gui") local Debug = require("mod.tools.api.debug.Debug") -data:add_type { - name = "interactive_fn", - fields = { - { - name = "func", - type = "function", - template = true - }, - { - name = "spec", - type = "table", - template = true - } - } -} - require("mod.tools.data.init") require("mod.tools.exec.config") -require("mod.tools.exec.interactive") require("mod.tools.exec.widgets") local function toggle_widget(id) diff --git a/src/mod/visual_ai/data/visual_ai/block.lua b/src/mod/visual_ai/data/visual_ai/block.lua index 30696b0a1..8df230291 100644 --- a/src/mod/visual_ai/data/visual_ai/block.lua +++ b/src/mod/visual_ai/data/visual_ai/block.lua @@ -1,60 +1,79 @@ +local ty_pos = types.fields { x = types.uint, y = types.uint } +local ty_visual_ai_var = types.table -- TODO + data:add_type { name = "block", fields = { { name = "icon", - type = "id:base.asset", + type = types.data_id("base.asset"), template = true }, { name = "type", - type = "string", - default = "action", + type = types.literal("target", "action", "condition", "special"), template = true }, { name = "vars", - type = "table", + type = types.map(types.identifier, ty_visual_ai_var), default = {}, template = true }, { name = "color", - type = "string|table|nil", + type = types.optional(types.color), default = nil, template = true }, { name = "target_source", - type = "string", + type = types.optional(types.literal("character", "items_on_self", "items_on_ground")) }, { name = "target_filter", - type = "function", + type = types.optional(types.callback({"self", types.table, + "chara", types.map_object("base.chara"), + "candidate", types.map_object("base.chara")}, + types.boolean)) }, { name = "target_order", - type = "function", - }, - { - name = "ordering", - type = "number", - default = 10000, - template = true + type = types.optional(types.callback({"self", types.table, + "chara", types.map_object("base.chara"), + "candidate_a", types.map_object("base.chara"), + "candidate_b", types.map_object("base.chara")}, + types.boolean)) }, { name = "is_terminal", - type = "boolean", - default = true + type = types.optional(types.boolean), }, { name = "format_name", - type = "function" + type = types.optional(types.callback({"proto", types.data_entry("visual_ai.block"), "vars", types.table}, types.string)) }, { name = "applies_to", - type = "string", - default = "any", + type = types.optional(types.literal("any", "map_object", "position")), + template = true + }, + { + name = "action", + type = types.optional(types.callback({"self", types.table, + "chara", types.map_object("base.chara"), + "target", types.some(types.map_object("any"), ty_pos), + "ty", types.literal("map_object", "position")}, + types.string)), + template = true + }, + { + name = "action", + type = types.optional(types.callback({"self", types.table, + "chara", types.map_object("base.chara"), + "target", types.some(types.map_object("any"), ty_pos), + "ty", types.literal("map_object", "position")}, + types.boolean)), template = true } } diff --git a/src/repl_startup.lua b/src/repl_startup.lua index f8f9f1009..e53339fb5 100644 --- a/src/repl_startup.lua +++ b/src/repl_startup.lua @@ -12,7 +12,6 @@ Magic = require("mod.elona_sys.api.Magic") Effect = require("mod.elona.api.Effect") Quest = require("mod.elona_sys.api.Quest") Scene = require("mod.elona_sys.scene.api.Scene") -Mx = require("mod.tools.api.Mx") ElonaCommand = require("mod.elona.api.ElonaCommand") PicViewer = require("mod.tools.api.PicViewer") Skill = require("mod.elona_sys.api.Skill") diff --git a/src/thirdparty/schema.lua b/src/thirdparty/schema.lua deleted file mode 100644 index 35bdb8d91..000000000 --- a/src/thirdparty/schema.lua +++ /dev/null @@ -1,644 +0,0 @@ ---[[ -The MIT License (MIT) - -Copyright (c) 2014 Sebastian Schoener - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -]] - -local schema = {} - --- Checks an object against a schema. -function schema.CheckSchema(obj, schem, path) - if path == nil then - path = schema.Path.new() - path:setBase(obj) - end - if type(schem) == "function" then - return schem(obj, path) - else -- attempt to simply compare the values - if schem == obj then - return nil - end - return schema.Error("Invalid value: "..path.." should be "..tostring(schem), path) - end -end - -function schema.FormatOutput(output) - local format = schema.List() - for k,v in ipairs(output) do - format:append(v:format()) - end - return table.concat(format, "\n") -end - -------------------------------------------------------------------------------- --- Infrastructure -------------------------------------------------------------------------------- - --- Path class. Represents paths to values in a table (the path's *base*). -local Path = {} -function Path.new(...) - local arg = {...} - local self = setmetatable({}, Path) - self.p = {} - for k,v in ipairs(arg) do - self.p[k] = v - end - return self -end - --- Sets the base of the path, i.e. the table to which the path is relative. --- Note that this is the actual *table*, not the table's name. -function Path:setBase(base) - self.base = base -end - --- Gets the base of the path. -function Path:getBase() - return self.base -end - --- Returns the target of the path or 'nil' if the path is invalid. -function Path:target() - if self.base == nil then - error("Path:target() called on a path without a base!") - end - local current = self.base - for k,v in ipairs(self.p) do - current = current[v] - if current == nil then - return nil - end - end - return current -end - --- Pushes an entry to the end of the path. -function Path:push(obj) - self.p[#self.p + 1] = obj - return self -end - --- Pops an entry from the end of the path. -function Path:pop() - local tmp = self.p[#self.p] - self.p[#self.p] = nil - return tmp -end - --- Returns the topmost entry of the end of the path. -function Path:top() - return self.p[#self.p] -end - --- Returns the length of the path. -function Path:length() - return #self.p -end - --- Returns the element at the specified index. -function Path:get(index) - return self.p[index] -end - --- Copies the path. -function Path:copy() - local cp = Path.new() - cp.base = self.base - for k,v in ipairs(self.p) do - cp.p[k] = v - end - return cp -end - -Path.__index = Path -Path.__tostring = function(tbl) - if #tbl.p == 0 then - return '' - end - return table.concat(tbl.p,".") -end -Path.__concat = function(lhs, rhs) - if type(lhs) == "table" then - return tostring(lhs)..rhs - elseif type(rhs) == "table" then - return lhs..tostring(rhs) - end -end -Path.__len = function(self) - return #self.p -end - -setmetatable(Path, { - __call = function (cls, ...) - return Path.new(...) - end -}) -schema.Path = Path - --- List class -local List = {} -function List.new(...) - local self = setmetatable({}, List) - local arg = {...} - for k,v in ipairs(arg) do - self[k] = v - end - return self -end - -function List:add(obj) - self[#self+1] = obj - return self -end - -function List:append(list) - for k,v in ipairs(list) do - self[#self+k] = v - end - return self -end - -List.__index = List -List.__tostring = function(self) - local tmp = {} - for k,v in ipairs(self) do - tmp[k] = tostring(v) - end - return table.concat(tmp, "\n") -end -setmetatable(List, { - __call = function(cls, ...) - return List.new(...) - end -}) -schema.List = List - --- Error class. Describes mismatches that occured during the schema-checking. -local Error = {} -function Error.new(msg, path, suberrors) - local self = setmetatable({}, Error) - self.message = msg - self.path = path:copy() - self.suberrors = suberrors - return self -end - --- Returns a list of strings which represent the error (with indenttation for --- suberrors). -function Error:format() - local output = List.new(self.message) - if self.suberrors ~= nil then - for k,sub in pairs(self.suberrors) do - local subout = sub:format() - for k1,msg in pairs(subout) do - output = output:add(" "..msg) - end - end - end - return output -end - -Error.__tostring = function(self) - return table.concat(self:format(), "\n") -end -Error.__index = Error -setmetatable(Error, { - __call = function(cls, ...) - return List(Error.new(...)) - end -}) -schema.Error = Error - -------------------------------------------------------------------------------- --- Schema Building Blocks --- A schema is a function taking the object to be checked and the path to the --- current value in the environment. --- It returns either 'true' if the schema accepted the object or an Error --- object which describes why it was rejected. --- The schemata below are just some basic building blocks. Expand them to your --- liking. -------------------------------------------------------------------------------- - --- Always accepts. -function schema.Any(obj, path) - return nil -end - --- Always fails. -function schema.Nothing(obj, path) - return schema.Error("Failure: '"..path.."' will always fail.", path) -end - --- Checks a value against a specific type. -local function TypeSchema(obj, path, typeId) - if type(obj) ~= typeId then - return schema.Error("Type mismatch: '"..path.."' should be "..typeId..", is "..type(obj), path) - else - return nil - end -end - -function schema.Boolean (obj, path) return TypeSchema(obj, path, "boolean") end -function schema.Function(obj, path) return TypeSchema(obj, path, "function") end -function schema.Nil (obj, path) return TypeSchema(obj, path, "nil") end -function schema.Number (obj, path) return TypeSchema(obj, path, "number") end -function schema.String (obj, path) return TypeSchema(obj, path, "string") end -function schema.Table (obj, path) return TypeSchema(obj, path, "table") end -function schema.UserData(obj, path) return TypeSchema(obj, path, "userdata") end - --- Checks that some value is a string matching a given pattern. -function schema.Pattern(pattern) - local userPattern = pattern - if not pattern:match("^^") then - pattern = "^" .. pattern - end - if not pattern:match("$$") then - pattern = pattern .. "$" - end - local function CheckPattern(obj, path) - local err = schema.String(obj, path) - if err then - return err - end - if string.match(obj, pattern) then - return nil - else - return schema.Error("Invalid value: '"..path.."' must match pattern '"..userPattern.."'", path) - end - end - return CheckPattern -end - --- Checks that some number is an integer. -function schema.Integer(obj, path) - local err = schema.Number(obj, path) - if err then - return err - end - if math.floor(obj) == obj then - return nil - end - return schema.Error("Invalid value: '"..path.."' must be an integral number", path) -end - --- Checks that some number is >= 0. -function schema.NonNegativeNumber(obj, path) - local err = schema.Number(obj, path) - if err then - return err - end - if obj >= 0 then - return nil - end - return schema.Error("Invalid value: '"..path.."' must be >= 0", path) -end - --- Checks that some number is > 0. -function schema.PositiveNumber(obj, path) - local err = schema.Number(obj, path) - if err then - return err - end - if obj > 0 then - return nil - end - return schema.Error("Invalid value: '"..path.."' must be > 0", path) -end - --- Checks that some value is a number from the interval [lower, upper]. -function schema.NumberFrom(lower, upper) - local function CheckNumberFrom(obj, path) - local err = schema.Number(obj, path) - if err then - return err - end - if lower <= obj and upper >= obj then - return nil - else - return schema.Error("Invalid value: '"..path.."' must be between "..lower.." and "..upper, path) - end - end - return CheckNumberFrom -end - --- Takes schemata and accepts their disjunction. -function schema.OneOf(...) - local arg = {...} - local function CheckOneOf(obj, path) - for k,v in ipairs(arg) do - local err = schema.CheckSchema(obj, v, path) - if not err then return nil end - end - return schema.Error("No suitable alternative: No schema matches '"..path.."'", path) - end - return CheckOneOf -end - --- Takes a schema and returns an optional schema. -function schema.Optional(s) - return schema.OneOf(s, schema.Nil) -end - --- Takes schemata and accepts their conjuction. -function schema.AllOf(...) - local arg = {...} - local function CheckAllOf(obj, path) - local errmsg = nil - for k,v in ipairs(arg) do - local err = schema.CheckSchema(obj, v, path) - if err then - if errmsg == nil then - errmsg = err - else - errmsg = errmsg:append(err) - end - end - end - return errmsg - end - return CheckAllOf -end - --- Builds a record type schema, i.e. a table with a fixed set of keys (strings) --- with corresponding values. Use as in --- Record({ --- name = schema, --- name2 = schema2 --- }) -function schema.Record(recordschema, additionalValues) - if additionalValues == nil then - additionalValues = false - end - local function CheckRecord(obj, path) - if type(obj) ~= "table" then - return schema.Error("Type mismatch: '"..path.."' should be a record (table), is "..type(obj), path) - end - - local errmsg = nil - local function AddError(msg) - if errmsg == nil then - errmsg = msg - else - errmsg = errmsg:append(msg) - end - end - - for k,v in pairs(recordschema) do - path:push(k) - local err = schema.CheckSchema(obj[k], v, path) - if err then - AddError(err) - end - path:pop() - end - - for k, v in pairs(obj) do - path:push(k) - if type(k) ~= "string" then - AddError(schema.Error("Invalid key: '"..path.."' must be of type 'string'", path)) - end - if recordschema[k] == nil and not additionalValues then - AddError(schema.Error("Superfluous value: '"..path.."' does not appear in the record schema", path)) - end - path:pop() - end - return errmsg - end - return CheckRecord -end - -function schema.MixedTable(t_schema, additional_values) - local function CheckMixedTable(obj, path) - local obj_t = type(obj) - if obj_t ~= "table" then - local msg = ("Type mismatch: '%s' should be a table, is %s"):format(path, obj_t) - return schema.Error(msg, path) - end - - local errmsg = nil - local function AddError(msg) - if errmsg == nil then - errmsg = msg - else - errmsg = errmsg:append(msg) - end - end - - local checked_keys = {} - for k, v in pairs(t_schema) do - path:push(k) - local err = schema.CheckSchema(obj[k], v, path) - if err then - AddError(err) - end - checked_keys[k] = true - path:pop() - end - - for k, v in pairs(obj) do - if not checked_keys[k] then - path:push(k) - local k_type = type(k) - if k_type ~= "string" and k_type ~= "number" then - local msg = ("Invalid key: '%s' must be of type 'string' or 'number'"):format(k_type) - AddError(schema.Error(msg, path)) - end - - local t_schema_v = t_schema[k] - if t_schema_v then - local err = schema.CheckSchema(v, t_schema_v, path) - if err then - AddError(err) - end - else - if not additional_values then - local msg = ("Superfluous value: '%s' does not appear in the table schema") - :format(path) - AddError(schema.Error(msg, path)) - end - end - path:pop() - end - end - return errmsg - end - return CheckMixedTable -end - --- Builds a map type schema, i.e. a table with an arbitraty number of --- entries where both all keys (and all vaules) fit a common schema. -function schema.Map(keyschema, valschema) - local function CheckMap(obj, path) - if type(obj) ~= "table" then - return schema.Error("Type mismatch: '"..path.."' should be a map (table), is "..type(obj), path) - end - - local errmsg = nil - local function AddError(msg) - if errmsg == nil then - errmsg = msg - else - errmsg = errmsg:append(msg) - end - end - - -- aggregate error message - for k, v in pairs(obj) do - path:push(k) - local keyErr = schema.CheckSchema(k, keyschema, path) - if keyErr then - AddError(schema.Error("Invalid map key", path, keyErr)) - end - - local valErr = schema.CheckSchema(v, valschema, path) - if valErr then - AddError(valErr) - end - path:pop() - end - return errmsg - end - return CheckMap -end - --- Builds a collection type schema, i.e. a table with an arbitrary number of --- entries where we only care about the type of the values. -function schema.Collection(valschema) - return schema.Map(schema.Any, valschema) -end - --- Builds a tuple type schema, i.e. a table with a fixed number of entries, --- each indexed by a number and with a fixed type. -function schema.Tuple(...) - local arg = {...} - - local function CheckTuple(obj, path) - if type(obj) ~= "table" then - return schema.Error("Type mismatch: '"..path.."' should be a map (tuple), is "..type(obj), path) - end - - if #obj ~= #arg then - return schema.Error("Invalid length: '"..path.." should have exactly "..#arg.." elements", path) - end - - local errmsg = nil - local function AddError(msg) - if errmsg == nil then - errmsg = msg - else - errmsg = errmsg:append(msg) - end - end - - local min = 1 - local max = #arg - for k, v in pairs(obj) do - path:push(k) - local err = schema.Integer(k, path) - if not err then - err = schema.CheckSchema(v, arg[k], path) - if err then - AddError(err) - end - else - AddError(schema.Error("Invalid tuple key", path, err)) - end - path:pop() - end - return errmsg - end - return CheckTuple -end - --- Builds a conditional type schema, i.e. a schema that depends on the value of --- another value. The dependence must be *local*, i.e. defined in the same --- table. Use as in --- Case("name", {"Peter", schema1}, {"Mary", schema2}, {OneOf(...), schema3}) --- This will check the field "name" against every schema in the first component --- and will return the second component of the first match. -function schema.Case(relativePath, ...) - if type(relativePath) ~= "table" then - relativePath = schema.Path("..", relativePath) - end - local cases = {...} - for k,v in ipairs(cases) do - if type(v) ~= "table" then - error("Cases expects inputs of the form {conditionSchema, schema}; argument "..v.." is invalid") - end - end - - local function CheckCase(obj, path) - local condPath = path:copy() - for k=0, #relativePath do - local s = relativePath:get(k) - if s == ".." then - condPath:pop() - else - condPath:push(s) - end - end - - local errmsg = nil - local function AddError(msg) - if errmsg == nil then - errmsg = msg - else - errmsg = errmsg:append(msg) - end - end - - local anyCond = false - local condObj = condPath:target() - for k,v in ipairs(cases) do - local condSchema = v[1] - local valSchema = v[2] - local condErr = schema.CheckSchema(condObj, condSchema, condPath) - if not condErr then - anyCond = true - local err = schema.CheckSchema(obj, valSchema, path) - if err then - AddError(schema.Error("Case failed: Condition "..k.." of '"..path.."' holds but the consequence does not", path, err)) - end - end - end - - if not anyCond then - AddError(schema.Error("Case failed: No condition on '"..path.."' holds")) - end - - return errmsg - end - return CheckCase -end - -function schema.Test(fn, msg) - local function CheckTest(obj, path) - local pok, ok = pcall(fn, obj) - if pok and ok then - return nil - else - return schema.Error("Invalid value: '"..path..(msg and "': "..msg or ""), path) - end - end - return CheckTest -end - -return schema diff --git a/src/util/types.lua b/src/util/types.lua index 30afe7e83..7b3511eb4 100644 --- a/src/util/types.lua +++ b/src/util/types.lua @@ -22,7 +22,7 @@ local function smart_quote(str) end local INSPECT_OPTIONS = { - newline = " ", indent = "", max_length = 16, + newline = " ", indent = "", max_length = 32, } local function get_name(obj, ctxt) @@ -560,6 +560,48 @@ do types.interface = wrap(interface_checker) end +do + local class_type_implementing_checker = class.class("class_type_implementing_checker", ITypeChecker) + function class_type_implementing_checker:init(iface) + assert(class.is_interface(iface), ("%s is not a interface"):format(iface)) + self.iface = iface + end + function class_type_implementing_checker:check(obj, _ctxt) + if not class.is_class(obj) then + return false, type_error(self) + end + + if class.uses_interface(self.iface, obj) then + return true + end + + return false, type_error(self) + end + function class_type_implementing_checker:__tostring() + return (""):format(self.iface) + end + types.class_type_implementing = wrap(class_type_implementing_checker) +end + +do + local iterator_checker = class.class("iterator_checker", ITypeChecker) + function iterator_checker:init(ty) + self.type = ty + end + function iterator_checker:check(obj, ctxt) + if type(obj) == "table" and tostring(obj) == "" then + -- TODO account for type of inner object + return true + end + + return false, type_error(self) + end + function iterator_checker:__tostring() + return ("iterator<%s>"):format(self.ty) + end + types.iterator = wrap(iterator_checker) +end + local optional_checker = class.class("optional_checker", ITypeChecker) function optional_checker:init(checker) assert(is_type_checker(checker)) @@ -917,6 +959,14 @@ do types.literal = wrap(literal_checker) end +local ty_color_value = types.range(types.int, 0, 255) +types.color = types.tuple { + ty_color_value, + ty_color_value, + ty_color_value, + types.optional(ty_color_value), +} + do local data_id_checker = class.class("data_id_checker", ITypeChecker) function data_id_checker:init(_type) @@ -976,7 +1026,7 @@ do -- end self.args = args end - function callback_checker:check(obj, _ctxt) + function callback_checker:check(obj, ctxt) if types["function"]:check(obj, ctxt) then return true end @@ -984,7 +1034,7 @@ do return false, type_error(self) end function callback_checker:__tostring() - return ("function<%s>"):format(print_list(self.checkers)) + return ("function<%s>"):format(print_list(self.args)) end function types.callback(s) From 203e584b21516610985f5106ee890ccb2922d81e Mon Sep 17 00:00:00 2001 From: Ruin0x11 Date: Thu, 9 Sep 2021 22:11:54 -0700 Subject: [PATCH 06/17] Start fixing validation errors --- src/api/gui/hud/UiStatusEffects.lua | 4 - src/api/gui/menu/SkillsMenu.lua | 2 +- src/api/gui/menu/SpellsMenu.lua | 3 - src/api/item/InstancedEnchantment.lua | 4 +- src/game/startup.lua | 1 + src/internal/data/schemas.lua | 32 ++++-- src/internal/data_table.lua | 103 +++++++++++------- src/mod/elona/api/God.lua | 10 +- src/mod/elona/data/chip.lua | 4 +- src/mod/elona/data/random_event.lua | 5 + .../test_map/item_enchantments.lua | 7 +- src/util/types.lua | 26 +++-- 12 files changed, 124 insertions(+), 77 deletions(-) diff --git a/src/api/gui/hud/UiStatusEffects.lua b/src/api/gui/hud/UiStatusEffects.lua index 59c9046db..81fbb4152 100644 --- a/src/api/gui/hud/UiStatusEffects.lua +++ b/src/api/gui/hud/UiStatusEffects.lua @@ -17,13 +17,11 @@ end local function make_status_indicators(_, params, result) local chara = params.chara - -- TODO ordering for _, v in data["base.ui_indicator"]:iter() do if v.indicator then local raw = v.indicator(chara) if type(raw) == "table" then raw.text = I18N.get_optional(raw.text) or raw.text - raw.ordering = v.ordering result[#result+1] = raw end end @@ -50,12 +48,10 @@ function UiStatusEffects:set_data(player) for _, ind in ipairs(raw) do if type(ind) == "table" then - ind.ordering = ind.ordering or 100000 self.indicators[#self.indicators + 1] = ind end end - table.sort(raw, function(a, b) return a.ordering < b.ordering end) if self.t then self:calc_max_width() end diff --git a/src/api/gui/menu/SkillsMenu.lua b/src/api/gui/menu/SkillsMenu.lua index 170180ee1..13ca1df49 100644 --- a/src/api/gui/menu/SkillsMenu.lua +++ b/src/api/gui/menu/SkillsMenu.lua @@ -62,7 +62,7 @@ function SkillsMenu.generate_list(chara) list[#list+1] = { _id = entry._id, - ordering = (entry.elona_id or 0) * 100, + ordering = entry._ordering, name = name, cost = ("%d Sp"):format(cost), description = utf8.wide_sub(Skill.get_description(entry._id, chara), 0, 34), diff --git a/src/api/gui/menu/SpellsMenu.lua b/src/api/gui/menu/SpellsMenu.lua index 591753e2b..546ffae4b 100644 --- a/src/api/gui/menu/SpellsMenu.lua +++ b/src/api/gui/menu/SpellsMenu.lua @@ -58,7 +58,6 @@ function SpellsMenu.generate_list(chara) list[#list+1] = { _id = entry._id, - ordering = (entry.elona_id or 0) * 100, name = name, cost_stock = ("%d (%d)"):format(Skill.calc_spell_mp_cost(entry._id, chara), chara:spell_stock(entry._id)), lv_chance = ("%d/%d%%"):format(chara:skill_level(entry._id), Skill.calc_spell_success_chance(entry._id, chara)), @@ -68,8 +67,6 @@ function SpellsMenu.generate_list(chara) end end - table.sort(list, function(a, b) return a.ordering < b.ordering end) - return list end diff --git a/src/api/item/InstancedEnchantment.lua b/src/api/item/InstancedEnchantment.lua index ff00eeaa9..2743094d2 100644 --- a/src/api/item/InstancedEnchantment.lua +++ b/src/api/item/InstancedEnchantment.lua @@ -80,8 +80,8 @@ end function InstancedEnchantment:__lt(other) -- >>>>>>>> shade2/item_data.hsp:496 #deffunc sortEnc int id ... - local my_ordering = self.ordering or (self.proto.elona_id and self.proto.elona_id * 10000) or 0 - local their_ordering = other.ordering or (other.proto.elona_id and other.proto.elona_id * 10000) or 0 + local my_ordering = self.proto._ordering + local their_ordering = other.proto._ordering return my_ordering < their_ordering -- <<<<<<<< shade2/item_data.hsp:513 #global .. end diff --git a/src/game/startup.lua b/src/game/startup.lua index 3cf5f5089..e68352fe2 100644 --- a/src/game/startup.lua +++ b/src/game/startup.lua @@ -114,6 +114,7 @@ function startup.run(mods) mod.load_mods(mods) data:run_all_edits() + data:sort_all() -- data is finalized at this point. diff --git a/src/internal/data/schemas.lua b/src/internal/data/schemas.lua index a56c31bc6..90cdb3810 100644 --- a/src/internal/data/schemas.lua +++ b/src/internal/data/schemas.lua @@ -1160,6 +1160,7 @@ local ty_image_entry = types.some( x = types.uint, y = types.uint, count_x = types.optional(types.uint), + count_y = types.optional(types.uint), key_color = types.optional(types.color) } ) @@ -1599,11 +1600,11 @@ data:add_type { }, { name = "level_min", - type = types.uint, + type = types.int, }, { name = "level_max", - type = types.uint, + type = types.int, }, { name = "type", @@ -1786,6 +1787,14 @@ data:add_type { data:add_type { name = "chip", fields = { + { + name = "elona_id", + type = types.optional(types.uint), + }, + { + name = "elona_atlas", + type = types.optional(types.uint), + }, { name = "image", type = ty_image, @@ -1804,11 +1813,20 @@ It can either be a string referencing an image file, or a table with these conte - key_color: if `source` is a BMP, controls the color to convert to transparency. Defaults to {0, 0, 0}. ]] }, + { + name = "group", + type = types.string, + }, { name = "shadow", type = types.optional(types.uint), default = 0 }, + { + name = "is_tall", + type = types.boolean, + default = false + }, { name = "stack_height", type = types.optional(types.int), @@ -2214,13 +2232,13 @@ data:add_type { fields = { { name = "type", - type = types.some(types.literal("boolean", "string", "number", "int", "enum", "table", "data_id", "any"), types.data_id("base.config_option_type")), + type = types.some(types.literal("boolean", "string", "number", "integer", "enum", "table", "data_id", "any"), types.data_id("base.config_option_type")), template = true, no_fallback = true, doc = [[ Type of this config option. -One of "boolean", "string", "number", "int", "enum", "table", "data_id" or "any". +One of "boolean", "string", "number", "integer", "enum", "table", "data_id" or "any". ]] }, { @@ -2234,7 +2252,7 @@ Default value of this config option. }, { name = "choices", - type = types.some(types.list(types.string), types.callback({}, types.list(types.string))), + type = types.optional(types.some(types.list(types.string), types.callback({}, types.list(types.string)))), no_fallback = true, doc = [[ Only used if the type is "enum". @@ -2244,7 +2262,7 @@ The list of enum variants of this config option. }, { name = "data_type", - type = types.data_type_id, + type = types.optional(types.data_type_id), no_fallback = true, doc = [[ Only used if the type is "data_id". @@ -2254,7 +2272,7 @@ The data type of the ID in this config option. }, { name = "on_changed", - type = types.callback("value", types.any, "is_startup", types.boolean), + type = types.optional(types.callback("value", types.any, "is_startup", types.boolean)), no_fallback = true, doc = [[ Callback run immediately after this option is changed in the settings menu. diff --git a/src/internal/data_table.lua b/src/internal/data_table.lua index deec20f27..6567eb06b 100644 --- a/src/internal/data_table.lua +++ b/src/internal/data_table.lua @@ -3,6 +3,7 @@ local EventTree = require ("api.EventTree") local Log = require ("api.Log") local env = require ("internal.env") local fs = require("util.fs") +local Stopwatch = require("api.Stopwatch") local data_table = class.class("data_table") @@ -45,12 +46,12 @@ function data_table:init() rawset(self, "fallbacks", {}) rawset(self, "inner", {}) + rawset(self, "inner_sorted", {}) rawset(self, "index", {}) rawset(self, "schemas", {}) rawset(self, "metatables", {}) rawset(self, "generates", {}) rawset(self, "ext", {}) - rawset(self, "strict", false) rawset(self, "global_edits", {}) rawset(self, "single_edits", {}) @@ -179,6 +180,8 @@ local ty_ext_table = types.map(types.some(types.interface_type, types.data_id("b function data_table:add_type(schema, params) assert(types.check(schema, ty_schema)) schema.fallbacks = schema.fallbacks or {} + schema.max_ordering = 100000 + schema.needs_resort = true params = params or {} @@ -209,9 +212,9 @@ function data_table:add_type(schema, params) -- Fields available on all types checkers._type = types.data_type_id - checkers._id = types.identifier + checkers._id = types.data_type_id checkers._ext = types.optional(ty_ext_table) - checkers._ordering = types.optional(types.number) -- TODO + checkers._ordering = types.optional(types.number) if schema.validation == "permissive" then schema.type = types.fields(checkers) @@ -221,7 +224,7 @@ function data_table:add_type(schema, params) schema.validate = function(obj, verbose) local ok, err = types.check(obj, schema.type, verbose) if not ok then - return false, ("Validation for data entry '%s:%s.%s' failed: %s"):format(_type, mod_name, obj._id or "", err) + return false, ("Validation for data entry '%s:%s' failed: %s"):format(_type, obj._id or "", err) end return true end @@ -268,6 +271,7 @@ function data_table:add_type(schema, params) end self.inner[_type] = {} + self.inner_sorted[_type] = {} self.index[_type] = {} self.schemas[_type] = schema self.metatables[_type] = metatable @@ -301,24 +305,44 @@ function data_table:run_edits_for(_type, _id) self[_type][_id] = self.global_edits[_type](self[_type][_id]) end -local function update_docs(dat, _schema, loc, is_hotloading) - if (dat._doc or _schema.on_document) then - if loc then - dat._defined_in = { - relative = fs.normalize(loc.short_src), - line = loc.lastlinedefined - } - else - dat._defined_in = { - relative = ".", - line = 0 - } - end - local the_doc = dat._doc - if _schema.on_document then - the_doc =_schema.on_document(dat) +function data_table:validate_all(verbose) + local errors = {} + for _, _type, proxy in self:iter() do + for _id, entry in proxy:iter() do + local ok, err = proxy:validate(entry, verbose) + if not ok then + errors[#errors+1] = { _type = _type, _id = _id, error = err } + end end end + return errors +end + +local function sort_data_entries(a, b) + return a._ordering < b._ordering +end + +function data_table:sort_all() + local errors = {} + local inner = self.inner + local sw = Stopwatch:new("info") + for _type, _ in pairs(inner) do + self:sort_type(_type) + end + sw:p("data:sort_all()") + return errors +end + +function data_table:sort_type(_type) + local src = self.inner[_type] + local dst = {} + assert(src, "Unknown type") + for _, entry in pairs(src) do + table.insert(dst, entry) + end + table.sort(dst, sort_data_entries) + self.inner_sorted[_type] = dst + self.schemas[_type].needs_resort = false end function data_table:replace(dat) @@ -367,13 +391,6 @@ function data_table:add(dat) return nil end - -- TODO only validate after all data has been added (handles data entry field dependencies) - -- TODO add fallback field types - local ok, err = _schema.validate(dat) - if not ok then - -- print("Error: " .. err) - end - local fallbacks = self.fallbacks[_type] for field, fallback in pairs(fallbacks) do if dat[field] == nil then @@ -419,8 +436,6 @@ function data_table:add(dat) end end - if self.strict and failed then return nil end - local full_id = mod_name .. "." .. _id Log.trace("Adding data entry %s:%s", _type, full_id) @@ -433,6 +448,8 @@ function data_table:add(dat) local Event = require("api.Event") Event.trigger("base.before_hotload_prototype", {old=self.inner[_type][full_id], new=dat}) + dat._ordering = self.inner[_type][full_id]._ordering + table.replace_with(self.inner[_type][full_id], dat) self:run_edits_for(_type, full_id) @@ -447,8 +464,6 @@ function data_table:add(dat) Event.trigger("base.on_hotload_prototype", {entry=dat}) - update_docs(dat, _schema, loc, true) - return dat else self:error(("ID is already taken on type '%s': '%s'"):format(_type, full_id)) @@ -456,6 +471,17 @@ function data_table:add(dat) end end + if dat._ordering then + if type(dat._ordering) ~= "number" then + self:error(("_ordering field must be number, got %s (%s)"):format(dat._ordering, full_id)) + return nil + end + _schema.max_ordering = math.max(_schema.max_ordering, dat._ordering) + else + _schema.max_ordering = _schema.max_ordering + 1000 + dat._ordering = _schema.max_ordering + end + -- TODO fallbacks and prototype_fallbacks should be separate self.inner[_type][full_id] = dat @@ -472,7 +498,7 @@ function data_table:add(dat) self.ext[full_id] = make_ext_fallback(dat) end - update_docs(dat, _schema, loc) + _schema.needs_resort = true return dat end @@ -675,10 +701,6 @@ function proxy:__index(k) return self.data.schemas[self._type]._defined_in end - if k == "on_document" then - return self.data.schemas[self._type].on_document - end - if k == "doc" then return self.data.schemas[self._type].doc end @@ -713,8 +735,8 @@ function proxy:type() return self.data.schemas[self._type].type end -function proxy:validate(obj) - return self.data.schemas[self._type].validate(obj) +function proxy:validate(obj, verbose) + return self.data.schemas[self._type].validate(obj, verbose) end function proxy:ensure(k) @@ -751,7 +773,10 @@ local function iter(state, prev_index) end function proxy:iter() - local inner_iter, inner_state, inner_index = pairs(self.data.inner[self._type]) + if self.data.schemas[self._type].needs_resort then + self.data:sort_type(self._type) + end + local inner_iter, inner_state, inner_index = ipairs(self.data.inner_sorted[self._type]) return fun.wrap(iter, {iter=inner_iter,state=inner_state}, inner_index) end diff --git a/src/mod/elona/api/God.lua b/src/mod/elona/api/God.lua index d2a80f739..3098850c1 100644 --- a/src/mod/elona/api/God.lua +++ b/src/mod/elona/api/God.lua @@ -125,16 +125,16 @@ end local function mkblessing(cb) return function(skill, coefficient, add) return function(chara) - if chara:has_skill(skill) then - local amount = math.clamp((chara.piety or 0) / coefficient, 1, add + chara:skill_level("elona.faith") / 10) - chara[cb](chara, skill, amount, "add") + if chara["has_" .. cb](chara, skill) then + local amount = math.clamp((chara.piety or 0) / coefficient, 1, add + chara[cb .. "_level"](chara, "elona.faith") / 10) + chara["mod_" .. cb .. "_level"](chara, skill, amount, "add") end end end end -God.make_skill_blessing = mkblessing("mod_skill_level") -God.make_resist_blessing = mkblessing("mod_resist_level") +God.make_skill_blessing = mkblessing("skill") +God.make_resist_blessing = mkblessing("resist") function God.switch_religion_with_penalty(chara, new_god) -- >>>>>>>> shade2/god.hsp:238 gosub *screen_drawStatus ... diff --git a/src/mod/elona/data/chip.lua b/src/mod/elona/data/chip.lua index bea8dc250..d491418e0 100644 --- a/src/mod/elona/data/chip.lua +++ b/src/mod/elona/data/chip.lua @@ -1397,7 +1397,6 @@ local function make_chip_group(chips, group, source) local x = (chip.elona_id % 33) * 48 local y = math.floor(chip.elona_id / 33) * 48 - chip.count_x = chip.count_x or 1 chip._id = group .. "_" .. chip._id chip._type = "base.chip" @@ -1408,10 +1407,11 @@ local function make_chip_group(chips, group, source) y = y, width = width, height = height, - count_x = chip.count_x, + count_x = chip.count_x or 1, count_y = 1 } + chip.count_x = nil chip.group = group data:add(chip) diff --git a/src/mod/elona/data/random_event.lua b/src/mod/elona/data/random_event.lua index 4c357da59..c7364a306 100644 --- a/src/mod/elona/data/random_event.lua +++ b/src/mod/elona/data/random_event.lua @@ -18,6 +18,11 @@ local Enum = require("api.Enum") data:add_type { name = "random_event", fields = { + { + name = "elona_id", + type = types.optional(types.uint), + indexed = true, + }, { name = "image", type = types.data_id("base.asset"), diff --git a/src/mod/test_room/data/map_archetype/test_map/item_enchantments.lua b/src/mod/test_room/data/map_archetype/test_map/item_enchantments.lua index 413bd7187..abef7c56b 100644 --- a/src/mod/test_room/data/map_archetype/test_map/item_enchantments.lua +++ b/src/mod/test_room/data/map_archetype/test_map/item_enchantments.lua @@ -11,7 +11,7 @@ local item_enchantments = { local function items_in_category(cat) local filter = function(i) - if i.enchantments ~= nil then + if #i.enchantments > 0 then return false end for _, c in ipairs(i.categories or {}) do @@ -66,6 +66,9 @@ local function make_enchantments(x, y, map) ids[cat] = items_in_category(cat) end local _id = Rand.choice(ids[cat]) + if _id == nil then + error("No items in category " .. cat) + end for i= -1, 1, 2 do local power = 150 * i local item = assert(Item.create(_id, ix, iy, {}, map)) @@ -108,7 +111,7 @@ end local function make_fixed_enchantments(x, y, map) local filter = function(i) - return i.enchantments ~= nil + return #i.enchantments > 0 end local ix = x diff --git a/src/util/types.lua b/src/util/types.lua index 7b3511eb4..45d7731d6 100644 --- a/src/util/types.lua +++ b/src/util/types.lua @@ -25,22 +25,21 @@ local INSPECT_OPTIONS = { newline = " ", indent = "", max_length = 32, } -local function get_name(obj, ctxt) - if type(obj, ctxt) == "string" then - return smart_quote(obj, ctxt) - elseif type(obj, ctxt) == "table" then - if class.is_class_instance(obj, ctxt) then - return tostring(obj, ctxt) +local function get_name(obj) + if type(obj) == "string" then + return smart_quote(obj) + elseif type(obj) == "table" then + if class.is_class_instance(obj) then + return tostring(obj) end return inspect(obj, INSPECT_OPTIONS) end - return tostring(obj, ctxt) + return tostring(obj) end -function ctxt_mt:make_trail(obj, ctxt) - local seen = {obj = true} - local s = { get_name(obj, seen) } +function ctxt_mt:make_trail(obj) + local s = { get_name(obj) } for _, entry in ipairs(self.stack) do s[#s+1] = "[" s[#s+1] = get_name(entry.key) @@ -1081,11 +1080,14 @@ function types.check(obj, checker, verbose) err = err or "" local s if verbose then - s = ctxt:make_trail(obj, ctxt) + s = ctxt:make_trail(obj) else local entry = ctxt.stack[#ctxt.stack] if entry then - s = get_name(entry.value or entry.key) + s = get_name(entry.key) + if entry.value then + s = s .. " (" .. get_name(entry.value) .. ")" + end else s = get_name(obj, ctxt) end From 5b6bd85db8175b5c98ce54807631fc5d7c40e5d8 Mon Sep 17 00:00:00 2001 From: Ruin0x11 Date: Thu, 9 Sep 2021 22:52:55 -0700 Subject: [PATCH 07/17] Upgrade certain params tables to use typecheckers --- src/api/Activity.lua | 44 ++++++++++--- src/api/Feat.lua | 21 ++++-- src/internal/data/schemas.lua | 12 +++- src/internal/data_table.lua | 14 ++-- src/mod/elona/api/Gardening.lua | 42 ++++++------ src/mod/elona/api/God.lua | 2 +- src/mod/elona/data/activity.lua | 25 ++++--- src/mod/elona/data/activity/fishing.lua | 2 +- src/mod/elona/data/feat.lua | 87 +++++++++++-------------- src/mod/elona/data/inventory_proto.lua | 14 ++-- 10 files changed, 150 insertions(+), 113 deletions(-) diff --git a/src/api/Activity.lua b/src/api/Activity.lua index a965a054c..0b4a8925d 100644 --- a/src/api/Activity.lua +++ b/src/api/Activity.lua @@ -3,20 +3,46 @@ local data = require("internal.data") local Activity = {} +local function copy_params(activity, params) + local proto = data["base.activity"]:ensure(activity._id) + local found = table.set{} + + for property, entry in pairs(proto.params or {}) do + local value = params[property] + local error_msg = "Invalid parameter passed for activity with ID '%d': " + local checker + if types.is_type_checker(entry) then + checker = entry + else + checker = entry.type + if value == nil then + value = entry.default + error_msg = "Invalid default parameter for activity with ID '%d': " + end + end + local ok, err = types.check(value, checker) + if not ok then + error((error_msg):format(activity._id), err) + end + activity.params[property] = value + end + + if table.count(found) ~= table.count(params) then + for k, v in pairs(params) do + if not proto.params[k] then + error(("Activity '%s' does not accept parameter '%s'"):format(activity._id, k)) + end + end + end +end + function Activity.create(id, params) local obj = Object.generate_from("base.activity", id) Object.finalize(obj) obj.params = {} - local activity = data["base.activity"]:ensure(id) - for property, ty in pairs(activity.params or {}) do - local value = params[property] - -- everything is implicitly optional for now, until we get a better - -- typechecker - if value ~= nil and type(value) ~= ty then - error(("Activity '%s' requires parameter '%s' of type %s, got '%s'"):format(id, property, ty, value)) - end - obj.params[property] = value + if params then + copy_params(obj, params) end return obj diff --git a/src/api/Feat.lua b/src/api/Feat.lua index b31b28a3b..7bedb3bec 100644 --- a/src/api/Feat.lua +++ b/src/api/Feat.lua @@ -58,13 +58,22 @@ end local function copy_params(feat, params) local proto = data["base.feat"]:ensure(feat._id) local found = table.set{} - for property, ty in pairs(proto.params or {}) do + for property, entry in pairs(proto.params or {}) do local value = params[property] - -- everything is implicitly optional for now, until we get a better - -- typechecker - if value ~= nil and type(value) ~= ty then - error(("Feat '%s' requires parameter '%s' of type %s, got '%s'"):format(feat._id, property, ty, value)) - found[property] = true + local error_msg = "Invalid parameter passed for feat with ID '%d': " + local checker + if types.is_type_checker(entry) then + checker = entry + else + checker = entry.type + if value == nil then + value = entry.default + error_msg = "Invalid default parameter for feat with ID '%d': " + end + end + local ok, err = types.check(value, checker) + if not ok then + error((error_msg):format(feat._id), err) end feat.params[property] = value end diff --git a/src/internal/data/schemas.lua b/src/internal/data/schemas.lua index 90cdb3810..5f9565750 100644 --- a/src/internal/data/schemas.lua +++ b/src/internal/data/schemas.lua @@ -57,6 +57,11 @@ data:add_type( { name = "chara", fields = { + { + name = "elona_id", + type = types.optional(types.uint), + indexed = true, + }, { name = "level", type = types.uint, @@ -468,6 +473,11 @@ data:add_type( { name = "item", fields = { + { + name = "elona_id", + type = types.optional(types.uint), + indexed = true, + }, { name = "level", type = types.uint, @@ -734,7 +744,7 @@ data:add_type( }, { name = "params", - type = types.table, + type = types.map(types.string, types.fields { type = types.type, default = types.optional(types.any) }), default = {} }, { diff --git a/src/internal/data_table.lua b/src/internal/data_table.lua index 6567eb06b..306609d98 100644 --- a/src/internal/data_table.lua +++ b/src/internal/data_table.lua @@ -182,6 +182,7 @@ function data_table:add_type(schema, params) schema.fallbacks = schema.fallbacks or {} schema.max_ordering = 100000 schema.needs_resort = true + schema.indexes = {} params = params or {} @@ -208,6 +209,10 @@ function data_table:add_type(schema, params) end end checkers[field.name] = field.type + + if field.indexed then + schema.indexes[field.name] = true + end end -- Fields available on all types @@ -251,8 +256,6 @@ function data_table:add_type(schema, params) return end - schema.indexes = {} - local metatable = params.interface or {} metatable._type = _type @@ -485,11 +488,8 @@ function data_table:add(dat) -- TODO fallbacks and prototype_fallbacks should be separate self.inner[_type][full_id] = dat - for _, field in ipairs(_schema.fields) do - if field.indexed then - _schema.indexes[field] = true - add_index_field(self, dat, _type, field.name) - end + for field, _ in pairs(_schema.indexes) do + add_index_field(self, dat, _type, field) end dat._id = full_id diff --git a/src/mod/elona/api/Gardening.lua b/src/mod/elona/api/Gardening.lua index 69c1cdff6..22ac6b18a 100644 --- a/src/mod/elona/api/Gardening.lua +++ b/src/mod/elona/api/Gardening.lua @@ -43,7 +43,7 @@ function Gardening.plant_seed(seed, chara, x, y) data["elona.plant"]:ensure(plant_id) local plant = assert(Feat.create("elona.plant", x, y, { force = true }, map)) - plant.plant_id = plant_id + plant.params.plant_id = plant_id Gardening.recalc_plant_growth_time(plant, chara, is_crop_tile) local mes @@ -72,7 +72,7 @@ function Gardening.grow_plants(map, chara, days_passed) for _, feat in Feat.iter(map):filter(is_plant) do for _ = 1, days_passed do - if feat.plant_growth_stage >= 2 then + if feat.params.plant_growth_stage >= 2 then break end local is_crop_tile = map:tile(feat.x, feat.y).role == Enum.TileRole.Crop @@ -84,14 +84,14 @@ end function Gardening.grow_plant(plant, chara, is_crop_tile) -- >>>>>>>> elona122/shade2/action.hsp:2294 *item_seedGrowth .. - plant.plant_time_to_growth_days = plant.plant_time_to_growth_days - 1 - if plant.plant_time_to_growth_days % 50 == 0 then - if plant.plant_time_to_growth_days >= 50 then + plant.params.plant_time_to_growth_days = plant.params.plant_time_to_growth_days - 1 + if plant.params.plant_time_to_growth_days % 50 == 0 then + if plant.params.plant_time_to_growth_days >= 50 then -- >= 50 means wilted - plant.plant_growth_stage = 3 - plant.image = "elona.feat_plant_" .. plant.plant_growth_stage + plant.params.plant_growth_stage = 3 + plant.image = "elona.feat_plant_" .. plant.params.plant_growth_stage else - plant.plant_growth_stage = math.min(plant.plant_growth_stage + 1, 3) + plant.params.plant_growth_stage = math.min(plant.params.plant_growth_stage + 1, 3) Gardening.recalc_plant_growth_time(plant, chara, is_crop_tile) end end @@ -99,21 +99,21 @@ function Gardening.grow_plant(plant, chara, is_crop_tile) end function Gardening.recalc_plant_growth_time(plant, chara, is_crop_tile) - plant.plant_growth_stage = plant.plant_growth_stage or 0 - plant.image = "elona.feat_plant_" .. plant.plant_growth_stage + plant.params.plant_growth_stage = plant.params.plant_growth_stage or 0 + plant.image = "elona.feat_plant_" .. plant.params.plant_growth_stage local time_to_growth = Gardening.calc_plant_time_to_growth_days(plant, chara, is_crop_tile) - plant.plant_time_to_growth_days = time_to_growth + plant.params.plant_time_to_growth_days = time_to_growth end function Gardening.calc_gardening_difficulty(plant, chara, is_crop_tile) - local plant_data = data["elona.plant"]:ensure(plant.plant_id) + local plant_data = data["elona.plant"]:ensure(plant.params.plant_id) local difficulty = plant_data.growth_difficulty or 10 if not is_crop_tile then difficulty = difficulty * 3 / 2 end - if plant.plant_growth_stage == 0 and not Weather.is_raining() then + if plant.params.plant_growth_stage == 0 and not Weather.is_raining() then difficulty = difficulty * 2 end @@ -135,14 +135,14 @@ end function Gardening.calc_regrowth_difficulty(plant, chara, is_crop_tile) -- >>>>>>>> shade2/action.hsp:2316 p=15 ... - local plant_data = data["elona.plant"]:ensure(plant.plant_id) + local plant_data = data["elona.plant"]:ensure(plant.params.plant_id) local difficulty = plant_data.regrowth_difficulty or 15 if not is_crop_tile then difficulty = difficulty * 2 end - if plant.plant_growth_stage == 0 and not Weather.is_raining() then + if plant.params.plant_growth_stage == 0 and not Weather.is_raining() then difficulty = difficulty * 4 / 3 end @@ -159,9 +159,9 @@ function Gardening.regrow_plant(plant, chara, is_crop_tile) local map = assert(chara:current_map()) local new_plant = assert(Feat.create("elona.plant", plant.x, plant.y, { force = true }, map)) - new_plant.plant_id = plant.plant_id - new_plant.plant_growth_stage = 0 - new_plant.plant_time_to_growth_days = 0 + new_plant.params.plant_id = plant.params.plant_id + new_plant.params.plant_growth_stage = 0 + new_plant.params.plant_time_to_growth_days = 0 Gardening.recalc_plant_growth_time(new_plant, chara, is_crop_tile) Gui.mes_c("action.plant.new_plant_grows", "Green") plant:remove_ownership() @@ -172,11 +172,11 @@ end function Gardening.get_plant(plant, chara) -- >>>>>>>> elona122/shade2/command.hsp:3198 if feat>>>>>>> shade2/proc.hsp:467 cActionPeriod(cc)=10+limit(iWeight(ci)/(1+sSTR( ... local item = params.item @@ -1345,7 +1350,7 @@ data:add { _id = "training", elona_id = 104, - params = { skill_id = "string", item = "table" }, + params = { skill_id = types.data_id("base.skill"), item = types.map_object("base.item") }, -- >>>>>>>> shade2/proc.hsp:478 cActionPeriod(cc)=50 ... default_turns = 50, @@ -1499,7 +1504,7 @@ data:add { _id = "pickpocket", elona_id = 105, - params = { item = "table" }, + params = { item = types.map_object("base.item") }, default_turns = function(self, params) -- >>>>>>>> shade2/proc.hsp:443:DONE cActionPeriod(cc)=2+limit(iWeight(ci)/500,0,50) .. return 2 + math.clamp(self.params.item:calc("weight") / 500, 0, 50) diff --git a/src/mod/elona/data/activity/fishing.lua b/src/mod/elona/data/activity/fishing.lua index 7c6de7ac4..6d9e38437 100644 --- a/src/mod/elona/data/activity/fishing.lua +++ b/src/mod/elona/data/activity/fishing.lua @@ -140,7 +140,7 @@ data:add { _id = "fishing", elona_id = 7, - params = { x = "number", y = "number", fishing_pole = "table", no_animation = "boolean" }, + params = { x = types.uint, y = types.uint, fishing_pole = types.map_object("base.item"), no_animation = types.optional(types.boolean) }, default_turns = 100, animation_wait = 40, diff --git a/src/mod/elona/data/feat.lua b/src/mod/elona/data/feat.lua index 5665f200d..6af4835c8 100644 --- a/src/mod/elona/data/feat.lua +++ b/src/mod/elona/data/feat.lua @@ -28,36 +28,32 @@ data:add { is_solid = true, is_opaque = true, params = { - opened = "boolean", - open_sound = "string", - close_sound = "string", - opened_tile = "string", - closed_tile = "string", - difficulty = "number" + opened = { type = types.boolean, default = false }, + open_sound = { type = types.optional(types.data_id("base.sound")), default = "base.door1" }, + close_sound = { type = types.optional(types.data_id("base.sound")), default = "base.door1" }, + locked_sound = { type = types.optional(types.data_id("base.sound")), default = "base.locked1" }, + opened_tile = { type = types.optional(types.data_id("base.chip")), default = "elona.feat_door_wooden_open" }, + closed_tile = { type = types.optional(types.data_id("base.chip")), default = "elona.feat_door_wooden_closed" }, + difficulty = { type = types.number, default = 0 } }, - open_sound = "base.door1", - close_sound = nil, - locked_sound = "base.locked1", - closed_tile = "elona.feat_door_wooden_closed", - opened_tile = "elona.feat_door_wooden_open", on_refresh = function(self) - self.opened = not not self.opened + self.params.opened = not not self.params.opened - self:reset("can_open", not self.opened, "set") - self:reset("can_close", self.opened, "set") - self:reset("is_solid", not self.opened, "set") - self:reset("is_opaque", not self.opened, "set") + self.can_open = not self.params.opened + self.can_close = self.params.opened + self.is_solid = not self.params.opened + self.is_opaque = not self.params.opened - if self.opened then - self:reset("image", self.opened_tile) + if self.params.opened then + self.image = self.params.opened_tile else - self:reset("image", self.closed_tile) + self.image = self.params.closed_tile end end, on_bumped_into = function(self, params) self.proto.on_open(self, params) end, on_open = function(self, params) - if self.opened then + if self.params.opened then return "turn_end" end @@ -65,26 +61,26 @@ data:add { -- TODO move to aspect if SkillCheck.try_to_open_door(chara, self) then - if self.difficulty and self.difficulty > 0 then + if self.params.difficulty > 0 then -- >>>>>>>> shade2/calculation.hsp:99 skillExp rsOpenLock,r1,100 ... Skill.gain_skill_exp(chara, "elona.lock_picking", 100) -- <<<<<<<< shade2/calculation.hsp:99 skillExp rsOpenLock,r1,100 .. end - self.difficulty = 0 - self.opened = true + self.params.difficulty = 0 + self.params.opened = true self.is_solid = false self.is_opaque = false if chara:is_in_fov() then Gui.mes("action.open.door.succeed", chara) end - if self.open_sound then - Gui.play_sound(self.open_sound, self.x, self.y) + if self.params.open_sound then + Gui.play_sound(self.params.open_sound, self.x, self.y) end else Gui.mes_duplicate() - if self.locked_sound then - Gui.play_sound(self.locked_sound, self.x, self.y) + if self.params.locked_sound then + Gui.play_sound(self.params.locked_sound, self.x, self.y) end if chara:is_in_fov() then Gui.mes("action.open.door.fail", chara) @@ -100,7 +96,7 @@ data:add { return "turn_end" end, on_close = function(self, params) - self.opened = false + self.params.opened = false self.is_solid = true self.is_opaque = true @@ -114,14 +110,14 @@ data:add { end, on_bash = function(self, params) -- >>>>>>>> elona122/shade2/action.hsp:443 if feat(1)=objDoorClosed{ .. - if self.opened then + if self.params.opened then return nil end local basher = params.chara Gui.play_sound("base.bash1") - local difficulty = self.difficulty * 3 + 30 + local difficulty = self.params.difficulty * 3 + 30 local is_jail = self:current_map()._archetype == "elona.jail" if is_jail then @@ -132,8 +128,8 @@ data:add { if Rand.rnd(difficulty) < str and Rand.one_in(2) then Gui.mes("action.bash.door.destroyed") - if self.difficulty > str then - Skill.gain_skill_exp("elona.stat_strength", (self.difficulty - str) * 15) + if self.params.difficulty > str then + Skill.gain_skill_exp("elona.stat_strength", (self.params.difficulty - str) * 15) end self:remove_ownership() return "turn_end" @@ -159,8 +155,8 @@ data:add { end end if Rand.one_in(3) then - if self.difficulty > 0 then - self.difficulty = self.difficulty - 1 + if self.params.difficulty > 0 then + self.params.difficulty = self.params.difficulty - 1 Gui.mes_visible("action.bash.door.cracked", basher) end end @@ -169,14 +165,7 @@ data:add { return "turn_end" -- <<<<<<<< elona122/shade2/action.hsp:464 } .. - end, - events = { - { - id = "base.on_object_finalized", - name = "Set difficulty.", - callback = function(self) self.difficulty = self.difficulty or 5 end - } - } + end } @@ -189,8 +178,6 @@ data:add { is_solid = true, is_opaque = false, - params = {}, - on_bash = function(self, params) local map = self:current_map() local basher = params.chara @@ -412,16 +399,16 @@ data:add { is_opaque = false, params = { - plant_id = "string", - plant_growth_stage = "number", - plant_time_to_growth_days = "number" + plant_id = { type = types.data_id("elona.plant"), default = "elona.vegetable" }, + plant_growth_stage = { type = types.uint, default = 0 }, + plant_time_to_growth_days = { type = types.number, default = 0 }, }, on_stepped_on = function(self, params) -- >>>>>>>> shade2/action.hsp:768 if feat(1)=objPlant{ ... - local name = I18N.get("plant." .. self.plant_id .. ".plant_name") + local name = I18N.get("plant." .. self.params.plant_id .. ".plant_name") - local stage = self.plant_growth_stage + local stage = self.params.plant_growth_stage if stage == 0 then Gui.mes("action.move.feature.seed.growth.seed", name) elseif stage == 1 then @@ -439,7 +426,7 @@ data:add { id = "elona.on_harvest_plant", name = "Harvest plant.", callback = function(self, params) - data["elona.plant"]:ensure(self.plant_id).on_harvest(self, params) + data["elona.plant"]:ensure(self.params.plant_id).on_harvest(self, params) end } } diff --git a/src/mod/elona/data/inventory_proto.lua b/src/mod/elona/data/inventory_proto.lua index 79f80dcec..99bb19510 100755 --- a/src/mod/elona/data/inventory_proto.lua +++ b/src/mod/elona/data/inventory_proto.lua @@ -95,7 +95,7 @@ local inv_drop = { _id = "inv_drop", elona_id = 2, - params = { is_multi_drop = { type = "boolean", optional = true } }, + params = { is_multi_drop = types.optional(types.boolean) }, keybinds = function(ctxt) return { @@ -243,7 +243,7 @@ local inv_equip = { _id = "inv_equip", elona_id = 6, - params = { body_part_id = "string" }, + params = { body_part_id = types.data_id("base.body_part") }, sources = { "chara" }, icon = nil, window_title = "ui.inventory_command.equip", @@ -335,7 +335,7 @@ local inv_give = { elona_id = 10, sources = { "chara" }, - params = { is_giving_to_ally = "boolean" }, + params = { is_giving_to_ally = types.optional(types.boolean) }, icon = 17, show_money = false, query_amount = false, @@ -694,7 +694,7 @@ local inv_dip = { elona_id = 18, sources = { "chara", "ground", "equipment" }, - params = { dip_item = "table" }, + params = { dip_item = types.map_object("base.item") }, icon = nil, query_amount = false, window_title = "ui.inventory_command.dip", @@ -742,7 +742,7 @@ local inv_present = { elona_id = 20, sources = { "chara" }, - params = { trade_item = "table" }, + params = { trade_item = types.map_object("base.item") }, window_title = "ui.inventory_command.present", query_text = function(ctxt) @@ -922,7 +922,7 @@ local inv_take_food_container = { elona_sub_id = 3, sources = { "container" }, - params = { container_item = "table" }, + params = { container_item = types.map_object("base.item") }, icon = 17, show_money = false, query_amount = false, @@ -1013,7 +1013,7 @@ local inv_put_food_container = { elona_sub_id = 3, sources = { "chara" }, - params = { container_item = "table" }, + params = { container_item = types.map_object("base.item") }, icon = 17, show_money = false, query_amount = false, From d7c2481bca0518b77258e9f1e318e9e68ae9903e Mon Sep 17 00:00:00 2001 From: Ruin0x11 Date: Thu, 9 Sep 2021 23:00:28 -0700 Subject: [PATCH 08/17] [smithing] Update activities/inventory protos for typechecking --- src/mod/smithing/data/activity.lua | 21 ++++++++++++++++++--- src/mod/smithing/data/inventory_proto.lua | 6 +++--- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/mod/smithing/data/activity.lua b/src/mod/smithing/data/activity.lua index 70cfe7582..951ac37d8 100644 --- a/src/mod/smithing/data/activity.lua +++ b/src/mod/smithing/data/activity.lua @@ -48,7 +48,14 @@ data:add { _type = "base.activity", _id = "create_equipment", - params = { hammer = "table", extend = "number", categories = "table", target_item = "table", material_item = "table", infinite = "boolean" }, + params = { + hammer = types.map_object("base.item"), + extend = types.number, + categories = types.list(types.data_id("base.item_type")), + target_item = types.map_object("base.item"), + material_item = types.map_object("base.item"), + infinite = types.optional(types.boolean) + }, default_turns = SmithingFormula.calc_hammer_activity_turns, animation_wait = 20, @@ -134,7 +141,11 @@ data:add { _type = "base.activity", _id = "repair_furniture", - params = { hammer = "table", target_item = "table", material_item = "table" }, + params = { + hammer = types.map_object("base.item"), + target_item = types.map_object("base.item"), + material_item = types.map_object("base.item") + }, default_turns = SmithingFormula.calc_hammer_activity_turns, animation_wait = 20, @@ -172,7 +183,11 @@ data:add { _type = "base.activity", _id = "repair_equipment", - params = { hammer = "table", target_item = "table", power = "number" }, + params = { + hammer = types.map_object("base.item"), + target_item = types.map_object("base.item"), + power = types.number + }, default_turns = SmithingFormula.calc_hammer_activity_turns, animation_wait = 20, diff --git a/src/mod/smithing/data/inventory_proto.lua b/src/mod/smithing/data/inventory_proto.lua index 984d0711e..88fb848ed 100644 --- a/src/mod/smithing/data/inventory_proto.lua +++ b/src/mod/smithing/data/inventory_proto.lua @@ -8,7 +8,7 @@ data:add { elona_sub_id = 0, sources = { "chara", "equipment", "ground" }, - params = { hammer = "table" }, + params = { hammer = types.map_object("base.item") }, icon = nil, show_money = false, query_amount = false, @@ -28,7 +28,7 @@ data:add { elona_sub_id = 1, sources = { "chara", "equipment", "ground" }, - params = { hammer = "table", selected_items = "table" }, + params = { hammer = types.map_object("base.item"), selected_items = types.list(types.map_object("base.item")) }, icon = nil, show_money = false, query_amount = false, @@ -48,7 +48,7 @@ data:add { elona_sub_id = 3, sources = { "chara", "equipment", "ground" }, - params = { hammer = "table", selected_items = "table" }, + params = { hammer = types.map_object("base.item"), selected_items = types.list(types.map_object("base.item")) }, icon = nil, show_money = false, query_amount = false, From 0888769d6990761a9b55d98912e2355b27721166 Mon Sep 17 00:00:00 2001 From: Ruin0x11 Date: Fri, 10 Sep 2021 00:21:23 -0700 Subject: [PATCH 09/17] Fix base.item validation errors; remove ordering fields --- src/api/Object.lua | 3 + src/api/chara/IChara.lua | 3 - src/api/gui/menu/ChooseNpcMenu.lua | 5 +- src/api/gui/menu/FeatsMenu.lua | 8 +- src/api/gui/menu/InventoryContext.lua | 2 +- src/api/gui/menu/SkillStatusMenu.lua | 12 +- src/api/gui/menu/SkillsMenu.lua | 3 - .../gui/menu/chara_make/SelectRaceMenu.lua | 2 - src/api/gui/menu/inv/ResistanceLayout.lua | 5 - src/api/item/IItem.lua | 3 - src/internal/data/schemas.lua | 224 +++++++++++++++--- src/internal/data_table.lua | 31 +-- src/mod/autodig/data/ui_indicator.lua | 1 - src/mod/autoplant/data/ui_indicator.lua | 1 - src/mod/base/init.lua | 2 +- .../api/decoder/CustomItemDecoder.lua | 2 +- src/mod/elona/api/Rank.lua | 5 +- src/mod/elona/data/class.lua | 24 +- src/mod/elona/data/element.lua | 28 +-- src/mod/elona/data/field.lua | 3 +- src/mod/elona/data/guild.lua | 12 +- src/mod/elona/data/home.lua | 2 +- src/mod/elona/data/inventory_proto.lua | 2 +- src/mod/elona/data/item.lua | 2 - src/mod/elona/data/item/book.lua | 9 +- src/mod/elona/data/item/cargo.lua | 1 - src/mod/elona/data/item/container.lua | 25 +- src/mod/elona/data/item/currency.lua | 8 - src/mod/elona/data/item/equip/head.lua | 2 +- src/mod/elona/data/item/equip/neck.lua | 12 +- src/mod/elona/data/item/fish.lua | 11 - src/mod/elona/data/item/food.lua | 4 - src/mod/elona/data/item/furniture.lua | 1 - src/mod/elona/data/item/junk.lua | 31 --- src/mod/elona/data/item/ore.lua | 25 -- src/mod/elona/data/item/potion.lua | 62 ----- src/mod/elona/data/item/rod.lua | 27 --- src/mod/elona/data/item/scroll.lua | 62 +---- src/mod/elona/data/item/spellbook.lua | 59 ----- src/mod/elona/data/item/tool.lua | 34 +-- src/mod/elona/data/item/tree.lua | 11 - src/mod/elona/data/item_type.lua | 160 ++++++------- src/mod/elona/data/journal_page.lua | 12 +- src/mod/elona/data/material_spot.lua | 2 +- src/mod/elona/data/quest/collect.lua | 2 +- src/mod/elona/data/quest/conquer.lua | 4 +- src/mod/elona/data/quest/cook.lua | 6 +- src/mod/elona/data/quest/deliver.lua | 2 +- src/mod/elona/data/quest/escort.lua | 2 +- src/mod/elona/data/quest/harvest.lua | 4 +- src/mod/elona/data/quest/hunt.lua | 2 +- src/mod/elona/data/quest/huntex.lua | 4 +- src/mod/elona/data/quest/party.lua | 4 +- src/mod/elona/data/quest/supply.lua | 4 +- src/mod/elona/data/quest_reward.lua | 2 +- src/mod/elona/data/race.lua | 154 ++++++------ src/mod/elona/data/rank.lua | 22 -- src/mod/elona/data/sidequest.lua | 42 ++-- src/mod/elona/data/trait_indicator.lua | 10 - src/mod/elona_sys/api/Command.lua | 6 +- src/mod/elona_sys/api/Compat.lua | 2 +- src/mod/elona_sys/api/Quest.lua | 13 +- src/mod/elona_sys/dialog/init.lua | 2 +- src/mod/elona_sys/init.lua | 10 +- src/mod/elona_sys/sidequest/api/Sidequest.lua | 2 +- src/mod/noafindskitten/data/quest.lua | 1 - src/mod/omake_overhaul/data/titles/title.lua | 7 - .../api/gui/UiSimpleIndicatorsWidget.lua | 3 - .../data/simple_indicators/indicator.lua | 2 - .../data/simple_indicators/indicator.lua | 4 - src/mod/sokoban/data/quest.lua | 1 - src/mod/sokoban/data/sokoban/board.lua | 2 +- src/mod/titles/api/gui/TitlesMenu.lua | 5 +- src/mod/tools/api/Tools.lua | 14 -- .../visual_ai/api/gui/VisualAIBlockList.lua | 3 - src/mod/visual_ai/data/visual_ai/block.lua | 4 +- .../visual_ai/data/visual_ai/block/action.lua | 20 -- .../data/visual_ai/block/condition.lua | 10 - .../data/visual_ai/block/special.lua | 5 - .../visual_ai/data/visual_ai/block/target.lua | 34 --- src/util/types.lua | 17 +- 81 files changed, 527 insertions(+), 847 deletions(-) diff --git a/src/api/Object.lua b/src/api/Object.lua index 369ffce7c..557199b58 100644 --- a/src/api/Object.lua +++ b/src/api/Object.lua @@ -91,6 +91,9 @@ function Object.generate(proto) local obj = object.deserialize(proto) assert(obj.proto) + local fallbacks = data.fallbacks[obj._type] + obj:mod_base_with(table.deepcopy(fallbacks), "merge") + return obj end diff --git a/src/api/chara/IChara.lua b/src/api/chara/IChara.lua index 427a17b6a..0c0756437 100644 --- a/src/api/chara/IChara.lua +++ b/src/api/chara/IChara.lua @@ -109,9 +109,6 @@ end --- Finishes initializing this character. All characters must run this --- function sometime after running pre_build() before being used. function IChara:build() - local fallbacks = data.fallbacks["base.chara"] - self:mod_base_with(table.deepcopy(fallbacks), "merge") - self.state = "Alive" self.target = nil diff --git a/src/api/gui/menu/ChooseNpcMenu.lua b/src/api/gui/menu/ChooseNpcMenu.lua index 8e0a59ba0..f882fa7f9 100644 --- a/src/api/gui/menu/ChooseNpcMenu.lua +++ b/src/api/gui/menu/ChooseNpcMenu.lua @@ -61,6 +61,8 @@ function ChooseNpcMenu.generate_list(charas, topic) return true end + local sort = function(a, b) return a.ordering > b.ordering end + local list = fun.iter(charas):filter(filter_) :map(function(chara) local gender = I18N.capitalize(I18N.get("ui.sex3." .. chara:calc("gender"))) @@ -83,10 +85,9 @@ function ChooseNpcMenu.generate_list(charas, topic) ordering = chara:calc("level") } end) + :into_sorted(sort) :to_list() - table.insertion_sort(list, function(a, b) return a.ordering > b.ordering end) - return list end diff --git a/src/api/gui/menu/FeatsMenu.lua b/src/api/gui/menu/FeatsMenu.lua index 80ce83348..9737e9f4a 100644 --- a/src/api/gui/menu/FeatsMenu.lua +++ b/src/api/gui/menu/FeatsMenu.lua @@ -142,12 +142,10 @@ end function FeatsMenu.generate_list(chara) local list = {} - local sort = function(a, b) return (a.ordering or a.elona_id or 0) < (b.ordering or b.elona_id or 0) end - if chara.feats_acquirable > 0 then list[#list+1] = { type = "header", text = I18N.get("trait.window.available_feats") } - for _, trait in data["base.trait"]:iter():filter(function(t) return t.type == "feat" end):into_sorted(sort) do + for _, trait in data["base.trait"]:iter():filter(function(t) return t.type == "feat" end) do local level = chara:trait_level(trait._id) if can_acquire_trait(trait, level, chara) then local delta = 1 @@ -160,7 +158,7 @@ function FeatsMenu.generate_list(chara) list[#list+1] = { type = "header", text = I18N.get("trait.window.feats_and_traits") } - for _, trait in data["base.trait"]:iter():into_sorted(sort) do + for _, trait in data["base.trait"]:iter() do local level = chara:trait_level(trait._id) if level ~= 0 then local color = trait_color(level) @@ -169,7 +167,7 @@ function FeatsMenu.generate_list(chara) end end - for _, trait_ind in data["base.trait_indicator"]:iter():into_sorted(sort) do + for _, trait_ind in data["base.trait_indicator"]:iter() do if trait_ind.applies_to(chara) then local indicator = trait_ind.make_indicator(chara) list[#list+1] = { diff --git a/src/api/gui/menu/InventoryContext.lua b/src/api/gui/menu/InventoryContext.lua index f0dfd7930..b2a405b94 100644 --- a/src/api/gui/menu/InventoryContext.lua +++ b/src/api/gui/menu/InventoryContext.lua @@ -252,7 +252,7 @@ end -- >>>>>>>> shade2/command.hsp:3431 list(0,listMax)=cnt,refType*1000+iId(cnt) ... local function category_order(item) local order = function(cat) - return data["base.item_type"]:ensure(cat).ordering or 0 + return data["base.item_type"]:ensure(cat)._ordering or 0 end local major = item:major_categories() diff --git a/src/api/gui/menu/SkillStatusMenu.lua b/src/api/gui/menu/SkillStatusMenu.lua index 8374830ff..b00bcd85b 100644 --- a/src/api/gui/menu/SkillStatusMenu.lua +++ b/src/api/gui/menu/SkillStatusMenu.lua @@ -287,7 +287,7 @@ function SkillStatusMenu.build_list(chara, mode, trainer_skills) local has_skill = function(skill_entry) return chara:has_skill(skill_entry._id) end -- >>>>>>>> shade2/command.hsp:2382 list(0,listMax)=-1,20000:listn(0,listMax)=lang("◆ .. - list[#list+1] = { name = I18N.get("ui.chara_sheet.category.skill"), kind = "header", ordering = 100000 } + list[#list+1] = { name = I18N.get("ui.chara_sheet.category.skill"), kind = "header", ordering = 1000000 } local skill_iter @@ -307,11 +307,11 @@ function SkillStatusMenu.build_list(chara, mode, trainer_skills) kind = "skill", icon = Ui.skill_icon(skill_entry.related_skill), right_align = right_align, - ordering = (skill_entry.elona_id or 0) + 110000 + ordering = skill_entry._ordering + 1100000 } end - list[#list+1] = { name = I18N.get("ui.chara_sheet.category.weapon_proficiency"), kind = "header", ordering = 200000 } + list[#list+1] = { name = I18N.get("ui.chara_sheet.category.weapon_proficiency"), kind = "header", ordering = 2000000 } for _, skill_entry in Skill.iter_weapon_proficiencies() do local add = true @@ -334,13 +334,13 @@ function SkillStatusMenu.build_list(chara, mode, trainer_skills) detail = skill_detail(skill_entry._id), icon = Ui.skill_icon(skill_entry.related_skill), right_align = right_align, - ordering = (skill_entry.elona_id or 0) + 210000 + ordering = skill_entry._ordering + 2100000 } end end if mode == "player_status" or mode == "informer" then - list[#list+1] = { name = I18N.get("ui.chara_sheet.category.resistance"), kind = "header", ordering = 300000 } + list[#list+1] = { name = I18N.get("ui.chara_sheet.category.resistance"), kind = "header", ordering = 3000000 } for _, element_entry in Skill.iter_resistances() do if chara:has_resist(element_entry._id) then list[#list+1] = { @@ -352,7 +352,7 @@ function SkillStatusMenu.build_list(chara, mode, trainer_skills) detail = resist_detail(element_entry._id), icon = 11, right_align = right_align, - ordering = (element_entry.elona_id or 0) + 310000 + ordering = element_entry._ordering or 0 + 3100000 } end end diff --git a/src/api/gui/menu/SkillsMenu.lua b/src/api/gui/menu/SkillsMenu.lua index 13ca1df49..2cb3960e3 100644 --- a/src/api/gui/menu/SkillsMenu.lua +++ b/src/api/gui/menu/SkillsMenu.lua @@ -62,7 +62,6 @@ function SkillsMenu.generate_list(chara) list[#list+1] = { _id = entry._id, - ordering = entry._ordering, name = name, cost = ("%d Sp"):format(cost), description = utf8.wide_sub(Skill.get_description(entry._id, chara), 0, 34), @@ -71,8 +70,6 @@ function SkillsMenu.generate_list(chara) end end - table.sort(list, function(a, b) return a.ordering < b.ordering end) - return list end diff --git a/src/api/gui/menu/chara_make/SelectRaceMenu.lua b/src/api/gui/menu/chara_make/SelectRaceMenu.lua index 0d70a5f9d..d2cfc61d5 100644 --- a/src/api/gui/menu/chara_make/SelectRaceMenu.lua +++ b/src/api/gui/menu/chara_make/SelectRaceMenu.lua @@ -52,8 +52,6 @@ function SelectRaceMenu:init(charamake_data) races = races:to_list() - table.sort(races, function(a, b) return a.proto.ordering < b.proto.ordering end) - self.pages = UiList:new_paged(races, 16) table.merge(self.pages, UiListExt()) self.bg = Ui.random_cm_bg() diff --git a/src/api/gui/menu/inv/ResistanceLayout.lua b/src/api/gui/menu/inv/ResistanceLayout.lua index 6865d6882..897e626ad 100644 --- a/src/api/gui/menu/inv/ResistanceLayout.lua +++ b/src/api/gui/menu/inv/ResistanceLayout.lua @@ -21,14 +21,9 @@ function ResistanceLayout.make_list() } end - local sort = function(a, b) - return (a.ordering or 0) < (b.ordering or 0) - end - return data["base.element"]:iter() :filter(filter) :map(map) - :into_sorted(sort) :to_list() end diff --git a/src/api/item/IItem.lua b/src/api/item/IItem.lua index 815840667..b9da3ce7d 100644 --- a/src/api/item/IItem.lua +++ b/src/api/item/IItem.lua @@ -39,9 +39,6 @@ function IItem:normal_build(params) self.name = self._id self.image = self.image or self.proto.image - local fallbacks = data.fallbacks["base.item"] - self:mod_base_with(table.deepcopy(fallbacks), "merge") - IObject.normal_build(self, params) end diff --git a/src/internal/data/schemas.lua b/src/internal/data/schemas.lua index 5f9565750..525b605d4 100644 --- a/src/internal/data/schemas.lua +++ b/src/internal/data/schemas.lua @@ -45,14 +45,36 @@ local ty_event = types.fields { } local ty_light = types.fields { - chip = types.data_id("base.chip"), - brightness = types.positive(types.number), + chip = types.string, + bright = types.positive(types.number), offset_y = types.number, power = types.number, flicker = types.positive(types.number), always_on = types.optional(types.boolean) } +local ty_chara_filter = types.fields { + quality = types.enum(Enum.Quality), + level = types.uint, + initial_level = types.uint, + id = types.data_id("base.chara"), + fltselect = types.enum(Enum.FltSelect), + category = types.enum(Enum.CharaCategory), + create_params = types.table, + tag_filters = types.list(types.string), + race_filter = types.data_id("base.race"), + ownerless = types.boolean, +} + +local ty_item_filter = types.fields { + quality = types.enum(Enum.Quality), + level = types.uint, + id = types.data_id("base.chara"), + categories = types.some(types.data_id("base.item_type"), types.list(types.data_id("base.item_type"))), + create_params = types.table, + ownerless = types.boolean, +} + data:add_type( { name = "chara", @@ -478,6 +500,10 @@ data:add_type( type = types.optional(types.uint), indexed = true, }, + { + name = "custom_author", + type = types.optional(types.string), + }, { name = "level", type = types.uint, @@ -504,6 +530,16 @@ Relative strength of this item. type = types.optional(types.color), default = nil, }, + { + name = "random_color", + type = types.optional(types.literal("Random", "Furniture")), + default = nil, + }, + { + name = "container_params", + type = types.optional(types.fields { type = types.literal("local"), max_capacity = types.optional(types.uint), combine_weight = types.optional(types.boolean) }), + default = nil, + }, { name = "image", type = types.data_id("base.chip"), @@ -547,11 +583,38 @@ dungeons. type = types.table, default = {} }, + { + name = "quality", + type = types.optional(types.enum(Enum.Quality)), + }, + { + name = "medal_value", + type = types.uint, + default = 0 + }, { name = "categories", - type = types.list(types.data_id("base.item_type")), - default = {}, - template = true + type = types.fields({ no_implicit = types.optional(types.boolean) }, types.data_id("base.item_type")), + default = { "elona.equip_melee", "elona.equip_ranged" }, + template = true, + doc = [[ +Valid item categories this enchantment skill applies to. +]] + }, + { + name = "on_generate", + type = types.optional(types.callback("self", types.map_object("base.item"))), + default = nil, + }, + { + name = "on_init_params", + type = types.optional(types.callback("self", types.map_object("base.item"))), + default = nil, + }, + { + name = "before_wish", + type = types.optional(types.callback({"self", types.map_object("base.item"), "params", types.table}, ty_item_filter)), + default = nil, }, { name = "on_read", @@ -573,6 +636,31 @@ dungeons. type = types.optional(types.callback("self", types.map_object("base.item"), "chara", types.map_object("base.chara"))), default = nil, }, + { + name = "on_open", + type = types.optional(types.callback("self", types.map_object("base.item"), "chara", types.map_object("base.chara"))), + default = nil, + }, + { + name = "on_throw", + type = types.optional(types.callback("self", types.map_object("base.item"), "chara", types.map_object("base.chara"))), + default = nil, + }, + { + name = "on_use", + type = types.optional(types.callback("self", types.map_object("base.item"), "chara", types.map_object("base.chara"))), + default = nil, + }, + { + name = "on_ascend", + type = types.optional(types.callback("self", types.map_object("base.item"), "chara", types.map_object("base.chara"))), + default = nil, + }, + { + name = "on_descend", + type = types.optional(types.callback("self", types.map_object("base.item"), "chara", types.map_object("base.chara"))), + default = nil, + }, { name = "fltselect", type = types.enum(Enum.FltSelect), @@ -587,6 +675,12 @@ dungeons. A list of strings used for filtering during item generation. ]] }, + { + -- TODO + name = "knownnameref", + type = types.optional(types.string), + default = nil, + }, { -- TODO name = "originalnameref2", @@ -623,6 +717,31 @@ What gods this item can be offered to. type = types.boolean, default = false, }, + { + name = "is_handmade", + type = types.boolean, + default = false, + }, + { + name = "is_showroom_only", + type = types.boolean, + default = false, + }, + { + name = "has_random_name", + type = types.boolean, + default = false, + }, + { + -- TODO remove + name = "elona_function", + type = types.optional(types.uint), + }, + { + -- TODO remove + name = "elona_type", + type = types.optional(types.string), + }, { name = "skill", type = types.optional(types.data_id("base.skill")), @@ -691,6 +810,16 @@ Ambient light information. Hours until the item spoils. Used for items of material "elona.fresh" only. ]] }, + { + name = "cooldown_hours", + type = types.optional(types.uint), + default = nil + }, + { + name = "ambient_sounds", + type = types.optional(types.list(types.data_id("base.sound"))), + default = nil + }, { name = "is_wishable", type = types.boolean, @@ -698,7 +827,37 @@ Hours until the item spoils. Used for items of material "elona.fresh" only. doc = [[ If false, this item cannot be wished for. ]] - } + }, + { + name = "cannot_use_flight_on", + type = types.optional(types.boolean), + default = nil + }, + { + name = "prevent_sell_in_own_shop", + type = types.optional(types.boolean), + default = nil + }, + { + name = "always_drop", + type = types.optional(types.boolean), + default = nil + }, + { + name = "always_stack", + type = types.boolean, + default = false, + }, + { + name = "prevent_dip", + type = types.optional(types.boolean), + default = nil + }, + { + name = "can_read_in_world_map", + type = types.optional(types.boolean), + default = nil + }, }, fallbacks = { amount = 1, @@ -712,8 +871,6 @@ If false, this item cannot be wished for. x_offset = nil, y_offset = nil, - - can_use_flight_on = nil -- elona.cooler_box } }, { interface = IItem } @@ -1227,6 +1384,11 @@ data:add_type { type = types.boolean, default = false, }, + { + name = "show_name", + type = types.boolean, + default = false, + }, { name = "wall", type = types.optional(types.data_id("base.map_tile")), @@ -1235,6 +1397,20 @@ data:add_type { name = "wall_kind", type = types.optional(types.literal(1, 2)), }, + { + name = "mining_difficulty", + type = types.uint, + default = 0, + }, + { + name = "mining_difficulty_coefficient", + type = types.uint, + default = 30, + }, + { + name = "anime_frame", + type = types.optional(types.uint), + }, { name = "count_x", type = types.optional(types.uint), @@ -1274,14 +1450,6 @@ Value of this enchantment. template = true, doc = [[ Rarity of this enchantment. Lower means more rare. -]] - }, - { - name = "level", - type = types.uint, - template = true, - doc = [[ -Level of this enchantment. ]] }, { @@ -1884,6 +2052,10 @@ data:add_type { name = "tone", fields = { + { + name = "author", + type = types.optional(types.string), + }, { name = "show_in_menu", type = types.boolean, @@ -1928,6 +2100,11 @@ data:add_type { { name = "default_alternate", type = types.optional(types.list(types.string)) + }, + { + name = "uses_shift_delay", + type = types.boolean, + default = false } } } @@ -1950,19 +2127,6 @@ data:add_type { } } -local ty_chara_filter = types.fields { - quality = types.enum(Enum.Quality), - level = types.uint, - initial_level = types.uint, - id = types.data_id("base.chara"), - fltselect = types.enum(Enum.FltSelect), - category = types.enum(Enum.CharaCategory), - create_params = types.table, - tag_filters = types.list(types.string), - race_filter = types.data_id("base.race"), - ownerless = types.boolean, -} - data:add_type { name = "map_archetype", fields = { @@ -2323,7 +2487,7 @@ data:add_type { type = types.callback({"x", types.number, "y", types.number, "t", types.table}, types.callback()) }, { - name = "callback", + name = "draw", type = types.callback({"x", types.number, "y", types.number, "t", types.table}) } } diff --git a/src/internal/data_table.lua b/src/internal/data_table.lua index 306609d98..936dc4f1a 100644 --- a/src/internal/data_table.lua +++ b/src/internal/data_table.lua @@ -43,6 +43,7 @@ end function data_table:init() rawset(self, "errors", {}) + rawset(self, "defaults", {}) rawset(self, "fallbacks", {}) rawset(self, "inner", {}) @@ -136,8 +137,8 @@ function data_table:_add_index(_type, field) end end -local function make_fallbacks(fallbacks, fields) - local result = table.deepcopy(fallbacks) +local function make_defaults(fields) + local result = {} for _, field in ipairs(fields) do local default = field.default if not field.no_fallback then @@ -146,8 +147,6 @@ local function make_fallbacks(fallbacks, fields) if mt then if mt.__codegen_type == "block_string" then default = field.default[1] - elseif mt.__codegen_type == "literal" then - default = fallbacks[field.name] end end end @@ -195,10 +194,14 @@ function data_table:add_type(schema, params) local _type = mod_name .. "." .. schema.name local checkers = {} + local seen = table.set {} for i, field in ipairs(schema.fields) do if type(field.name) ~= "string" then error("Data type %s: missing field name (index %d)"):format(_type, i) end + if seen[field.name] then + error(("Data type %s: duplicate field name '%s' (index %d)"):format(_type, field.name, i)) + end if not types.is_type_checker(field.type) then error(("Data type %s: invalid type specified for field named '%s'"):format(_type, field.name)) end @@ -209,6 +212,7 @@ function data_table:add_type(schema, params) end end checkers[field.name] = field.type + seen[field.name] = true if field.indexed then schema.indexes[field.name] = true @@ -251,8 +255,9 @@ function data_table:add_type(schema, params) end table.replace_with(self.schemas[_type], schema) - local fallbacks = make_fallbacks(schema.fallbacks, schema.fields) - self.fallbacks[_type] = fallbacks + local defaults = make_defaults(schema.fields) + self.defaults[_type] = defaults + self.fallbacks[_type] = table.merge(table.deepcopy(schema.fallbacks, defaults)) return end @@ -282,8 +287,9 @@ function data_table:add_type(schema, params) self.global_edits[_type] = EventTree:new() - local fallbacks = make_fallbacks(schema.fallbacks, schema.fields) - self.fallbacks[_type] = fallbacks + local defaults = make_defaults(schema.fields) + self.defaults[_type] = defaults + self.fallbacks[_type] = table.merge(table.deepcopy(schema.fallbacks, defaults)) end -- Apply data edits. @@ -366,7 +372,7 @@ end local function make_ext_fallback(dat) local fields = dat.fields or {} - local ext = make_fallbacks({}, fields) + local ext = make_defaults(fields) return ext end @@ -394,12 +400,7 @@ function data_table:add(dat) return nil end - local fallbacks = self.fallbacks[_type] - for field, fallback in pairs(fallbacks) do - if dat[field] == nil then - dat[field] = fallback - end - end + dat = table.merge_missing(dat, self.defaults[_type]) -- Verify extension fields. if dat._ext then diff --git a/src/mod/autodig/data/ui_indicator.lua b/src/mod/autodig/data/ui_indicator.lua index ef13abf4e..0db275b77 100644 --- a/src/mod/autodig/data/ui_indicator.lua +++ b/src/mod/autodig/data/ui_indicator.lua @@ -14,6 +14,5 @@ data:add { _type = "base.ui_indicator", _id = "autodig", - ordering = 1000000, indicator = indicator_autodig } diff --git a/src/mod/autoplant/data/ui_indicator.lua b/src/mod/autoplant/data/ui_indicator.lua index 0c37a8599..1eae671d9 100644 --- a/src/mod/autoplant/data/ui_indicator.lua +++ b/src/mod/autoplant/data/ui_indicator.lua @@ -14,6 +14,5 @@ data:add { _type = "base.ui_indicator", _id = "autoplant", - ordering = 1000000, indicator = indicator_autoplant } diff --git a/src/mod/base/init.lua b/src/mod/base/init.lua index 6fd29fd7f..b59f57104 100644 --- a/src/mod/base/init.lua +++ b/src/mod/base/init.lua @@ -96,7 +96,7 @@ data["base.effect"]:edit("register status effect indicator", return raw end end, - ordering = dat.ordering + _ordering = dat._ordering } end return dat diff --git a/src/mod/cdata_tools/api/decoder/CustomItemDecoder.lua b/src/mod/cdata_tools/api/decoder/CustomItemDecoder.lua index 0a346ad2b..3371e09a4 100644 --- a/src/mod/cdata_tools/api/decoder/CustomItemDecoder.lua +++ b/src/mod/cdata_tools/api/decoder/CustomItemDecoder.lua @@ -126,7 +126,7 @@ local function make_item_locale_data(item_data, locale, mod_id, item_id) end local function find_item_type(elona_item_type) - local filter = function(t) return t.ordering == elona_item_type end + local filter = function(t) return t._ordering == elona_item_type end local ty = data["base.item_type"]:iter():filter(filter):nth(1) if ty == nil then error("Could not find Elona item type " .. elona_item_type) diff --git a/src/mod/elona/api/Rank.lua b/src/mod/elona/api/Rank.lua index e9e066dd0..e896f399c 100644 --- a/src/mod/elona/api/Rank.lua +++ b/src/mod/elona/api/Rank.lua @@ -13,14 +13,11 @@ local function maybe_init_rank(rank_id) end function Rank.iter() - local sort = function(a, b) - return (a.ordering or 0) < (b.ordering or 0) - end local map = function(rank) return rank, maybe_init_rank(rank._id) end - return data["elona.rank"]:iter():into_sorted(sort):map(map) + return data["elona.rank"]:iter():map(map) end function Rank.get(rank_id) diff --git a/src/mod/elona/data/class.lua b/src/mod/elona/data/class.lua index 5022e438e..dfbd692f7 100644 --- a/src/mod/elona/data/class.lua +++ b/src/mod/elona/data/class.lua @@ -3,7 +3,7 @@ local Item = require("api.Item") local class = { { _id = "warrior", - ordering = 10010, + _ordering = 10010, properties = { equipment_type = "elona.warrior" @@ -36,7 +36,7 @@ local class = { }, { _id = "thief", - ordering = 10020, + _ordering = 10020, properties = { equipment_type = "elona.thief" @@ -66,7 +66,7 @@ local class = { }, { _id = "wizard", - ordering = 10030, + _ordering = 10030, properties = { equipment_type = "elona.mage" @@ -100,7 +100,7 @@ local class = { }, { _id = "farmer", - ordering = 10040, + _ordering = 10040, properties = { equipment_type = "elona.warrior" @@ -133,7 +133,7 @@ local class = { }, { _id = "predator", - ordering = 20010, + _ordering = 20010, is_extra = true, properties = { @@ -155,7 +155,7 @@ local class = { }, { _id = "archer", - ordering = 10050, + _ordering = 10050, properties = { equipment_type = "elona.archer" @@ -185,7 +185,7 @@ local class = { }, { _id = "warmage", - ordering = 10060, + _ordering = 10060, properties = { equipment_type = "elona.war_mage" @@ -219,7 +219,7 @@ local class = { }, { _id = "tourist", - ordering = 10070, + _ordering = 10070, properties = { equipment_type = nil @@ -241,7 +241,7 @@ local class = { }, { _id = "pianist", - ordering = 10080, + _ordering = 10080, properties = { equipment_type = "elona.archer" @@ -273,7 +273,7 @@ local class = { }, { _id = "gunner", - ordering = 20020, + _ordering = 20020, is_extra = true, properties = { @@ -299,7 +299,7 @@ local class = { }, { _id = "priest", - ordering = 10090, + _ordering = 10090, properties = { equipment_type = "elona.priest" @@ -333,7 +333,7 @@ local class = { }, { _id = "claymore", - ordering = 10100, + _ordering = 10100, properties = { equipment_type = "elona.claymore" diff --git a/src/mod/elona/data/element.lua b/src/mod/elona/data/element.lua index 58e43368c..363518b19 100644 --- a/src/mod/elona/data/element.lua +++ b/src/mod/elona/data/element.lua @@ -16,7 +16,7 @@ local element = { { _id = "fire", elona_id = 50, - ordering = order(50), + _ordering = order(50), color = { 255, 155, 155 }, ui_color = { 150, 0, 0 }, can_resist = true, @@ -60,7 +60,7 @@ local element = { { _id = "cold", elona_id = 51, - ordering = order(51), + _ordering = order(51), color = { 255, 255, 255 }, ui_color = { 0, 0, 150 }, can_resist = true, @@ -83,7 +83,7 @@ local element = { { _id = "lightning", elona_id = 52, - ordering = order(52), + _ordering = order(52), color = { 255, 255, 175 }, ui_color = { 150, 150, 0 }, can_resist = true, @@ -116,7 +116,7 @@ local element = { { _id = "darkness", elona_id = 53, - ordering = order(53), + _ordering = order(53), color = { 175, 175, 255 }, ui_color = { 100, 80, 80 }, can_resist = true, @@ -134,7 +134,7 @@ local element = { { _id = "mind", elona_id = 54, - ordering = order(54), + _ordering = order(54), color = { 255, 195, 185 }, ui_color = { 150, 100, 50 }, can_resist = true, @@ -153,7 +153,7 @@ local element = { { _id = "poison", elona_id = 55, - ordering = order(55), + _ordering = order(55), color = { 175, 255, 175 }, ui_color = { 0, 150, 0 }, can_resist = true, @@ -171,7 +171,7 @@ local element = { { _id = "nether", elona_id = 56, - ordering = order(56), + _ordering = order(56), color = { 155, 154, 153 }, ui_color = { 150, 50, 0 }, can_resist = true, @@ -206,7 +206,7 @@ local element = { { _id = "sound", elona_id = 57, - ordering = order(57), + _ordering = order(57), color = { 235, 215, 155 }, ui_color = { 50, 100, 150 }, can_resist = true, @@ -224,7 +224,7 @@ local element = { { _id = "nerve", elona_id = 58, - ordering = order(59), + _ordering = order(59), color = { 155, 205, 205 }, ui_color = { 100, 150, 50 }, can_resist = true, @@ -243,7 +243,7 @@ local element = { { _id = "chaos", elona_id = 59, - ordering = order(59), + _ordering = order(59), color = { 185, 155, 215 }, ui_color = { 150, 0, 150 }, can_resist = true, @@ -280,7 +280,7 @@ local element = { { _id = "magic", elona_id = 60, - ordering = order(60), + _ordering = order(60), ui_color = { 150, 100, 100 }, can_resist = true, rarity = 5, @@ -297,7 +297,7 @@ local element = { { _id = "cut", elona_id = 61, - ordering = order(61), + _ordering = order(61), on_damage = function(chara, params) -- >>>>>>>> shade2/chara_func.hsp:1555 if ele=rsResCut : dmgCon tc,conBleed,rnd(eleP+ .. @@ -309,7 +309,7 @@ local element = { { _id = "ether", elona_id = 62, - ordering = order(62), + _ordering = order(62), on_damage = function(chara) print("ether") @@ -319,7 +319,7 @@ local element = { _id = "acid", color = { 175, 255, 175 }, elona_id = 63, - ordering = order(63), + _ordering = order(63), sound = "base.atk_poison", death_anim = "base.anim_elem_poison", diff --git a/src/mod/elona/data/field.lua b/src/mod/elona/data/field.lua index 3fe6dfd66..890b0d2da 100644 --- a/src/mod/elona/data/field.lua +++ b/src/mod/elona/data/field.lua @@ -16,7 +16,8 @@ data:add_type { }, { name = "tiles", - type = types.list(types.fields_strict { id = types.data_id("base.map_tile"), density = types.number }) + type = types.list(types.fields_strict { id = types.data_id("base.map_tile"), density = types.number }), + default = {} }, { name = "generate", diff --git a/src/mod/elona/data/guild.lua b/src/mod/elona/data/guild.lua index 292d5126b..5c4621a25 100644 --- a/src/mod/elona/data/guild.lua +++ b/src/mod/elona/data/guild.lua @@ -38,7 +38,7 @@ do _type = "elona_sys.sidequest", _id = "guild_mage_joining", elona_id = 216, - ordering = order(216), + _ordering = order(216), progress = { [1] = function() @@ -52,7 +52,7 @@ do _type = "elona_sys.sidequest", _id = "guild_mage_quota", elona_id = 219, - ordering = order(219), + _ordering = order(219), progress = { [1] = function() @@ -86,7 +86,7 @@ do _type = "elona_sys.sidequest", _id = "guild_fighter_joining", elona_id = 217, - ordering = order(217), + _ordering = order(217), progress = { [1] = function() @@ -102,7 +102,7 @@ do _type = "elona_sys.sidequest", _id = "guild_fighter_quota", elona_id = 220, - ordering = order(220), + _ordering = order(220), progress = { [1] = function() @@ -138,7 +138,7 @@ do _type = "elona_sys.sidequest", _id = "guild_thief_joining", elona_id = 218, - ordering = order(218), + _ordering = order(218), progress = { [1] = "sidequest._.elona.guild_thief_joining.progress._0", @@ -150,7 +150,7 @@ do _type = "elona_sys.sidequest", _id = "guild_thief_quota", elona_id = 221, - ordering = order(221), + _ordering = order(221), progress = { [1] = function() diff --git a/src/mod/elona/data/home.lua b/src/mod/elona/data/home.lua index 6b8549e12..dabbae714 100644 --- a/src/mod/elona/data/home.lua +++ b/src/mod/elona/data/home.lua @@ -12,7 +12,7 @@ data:add_type { type = types.string }, { - name = "map", + name = "image", type = types.data_id("base.chip") }, { diff --git a/src/mod/elona/data/inventory_proto.lua b/src/mod/elona/data/inventory_proto.lua index 99bb19510..264889221 100755 --- a/src/mod/elona/data/inventory_proto.lua +++ b/src/mod/elona/data/inventory_proto.lua @@ -1464,7 +1464,7 @@ local inv_equipment_flight = { filter = function(ctxt, item) -- >>>>>>>> shade2/command.hsp:3404 if invCtrl(1)=6: if (iWeight(cnt)<=0)or(iId(cnt) .. - return item.weight > 1 and item:calc("can_use_flight_on") ~= false + return item.weight > 1 and not item:calc("cannot_use_flight_on") ~= false -- <<<<<<<< shade2/command.hsp:3404 if invCtrl(1)=6: if (iWeight(cnt)<=0)or(iId(cnt) .. end, diff --git a/src/mod/elona/data/item.lua b/src/mod/elona/data/item.lua index 273e4230b..e198cf28d 100644 --- a/src/mod/elona/data/item.lua +++ b/src/mod/elona/data/item.lua @@ -17,8 +17,6 @@ local item = value = 1, weight = 1, fltselect = Enum.FltSelect.Sp, - category = 99999999, - subcategory = 99999999, coefficient = 100, categories = { "elona.bug", diff --git a/src/mod/elona/data/item/book.lua b/src/mod/elona/data/item/book.lua index be80cf7ac..02ed38f5b 100644 --- a/src/mod/elona/data/item/book.lua +++ b/src/mod/elona/data/item/book.lua @@ -29,7 +29,6 @@ data:add { -- >>>>>>>> shade2/proc.hsp:1254 item_identify ci,knownName .. end, fltselect = Enum.FltSelect.Sp, - category = 55000, coefficient = 100, is_wishable = false, @@ -47,7 +46,6 @@ data:add { image = "elona.item_book", value = 500, weight = 80, - category = 55000, rarity = 2000000, coefficient = 100, @@ -72,10 +70,9 @@ data:add { value = 100, weight = 80, fltselect = Enum.FltSelect.Sp, - category = 55000, coefficient = 100, - param1 = 2, + -- param1 = 2, elona_type = "normal_book", categories = { "elona.book", @@ -90,7 +87,6 @@ data:add { image = "elona.item_textbook", value = 4800, weight = 80, - category = 55000, rarity = 50000, coefficient = 100, @@ -112,7 +108,6 @@ data:add { image = "elona.item_book", value = 4000, weight = 80, - category = 55000, rarity = 50000, coefficient = 0, @@ -141,7 +136,6 @@ data:add { -- menucycle = 1, -- show_city_chart(), end, - category = 55000, rarity = 20000, coefficient = 0, categories = { @@ -157,7 +151,6 @@ data:add { value = 4000, weight = 80, fltselect = Enum.FltSelect.Sp, - category = 55000, rarity = 50000, coefficient = 0, originalnameref2 = "book", diff --git a/src/mod/elona/data/item/cargo.lua b/src/mod/elona/data/item/cargo.lua index 10a8c4274..7a36f4cc2 100644 --- a/src/mod/elona/data/item/cargo.lua +++ b/src/mod/elona/data/item/cargo.lua @@ -240,7 +240,6 @@ data:add { elona_id = 597, image = "elona.item_christmas_tree", value = 3500, - is_cargo = true, coefficient = 100, categories = { diff --git a/src/mod/elona/data/item/container.lua b/src/mod/elona/data/item/container.lua index eb167e8b2..57775e5de 100644 --- a/src/mod/elona/data/item/container.lua +++ b/src/mod/elona/data/item/container.lua @@ -58,7 +58,6 @@ data:add { image = "elona.item_small_gamble_chest", value = 3000, weight = 3000, - category = 72000, rarity = 100000, coefficient = 100, random_color = "Furniture", @@ -90,7 +89,6 @@ data:add { image = "elona.item_small_gamble_chest", value = 1200, weight = 300000, - category = 72000, rarity = 500000, coefficient = 100, random_color = "Furniture", @@ -112,7 +110,6 @@ data:add { image = "elona.item_shop_strongbox", value = 1000, weight = 300000, - category = 72000, rarity = 500000, coefficient = 100, random_color = "Furniture", @@ -141,7 +138,6 @@ data:add { value = 380, weight = 1200, fltselect = Enum.FltSelect.Sp, - category = 72000, coefficient = 100, categories = { @@ -172,7 +168,6 @@ data:add { value = 380, weight = 250, fltselect = Enum.FltSelect.Sp, - category = 72000, coefficient = 100, on_init_params = function(self) @@ -214,7 +209,6 @@ data:add { value = 380, weight = 1200, fltselect = Enum.FltSelect.Sp, - category = 72000, coefficient = 100, categories = { "elona.container", @@ -222,9 +216,6 @@ data:add { }, is_wishable = false, - on_init_params = function(self) - end, - container_params = { type = "local" }, @@ -252,7 +243,6 @@ data:add { image = "elona.item_material_box", value = 500, weight = 1200, - category = 72000, coefficient = 100, categories = { "elona.container" @@ -266,7 +256,6 @@ data:add { image = "elona.item_rare_treasure_ball", value = 4000, weight = 500, - category = 72000, rarity = 100000, coefficient = 100, @@ -300,7 +289,6 @@ data:add { image = "elona.item_rare_treasure_ball", value = 12000, weight = 500, - category = 72000, rarity = 25000, coefficient = 100, tags = { "spshop" }, @@ -336,7 +324,6 @@ data:add { image = "elona.item_small_gamble_chest", value = 1200, weight = 3400, - category = 72000, rarity = 50000, coefficient = 100, @@ -497,7 +484,6 @@ data:add { value = 1650, weight = 80, fltselect = Enum.FltSelect.Sp, - category = 72000, rarity = 50000, coefficient = 100, categories = { @@ -520,7 +506,6 @@ data:add { value = 4500, weight = 20000, fltselect = Enum.FltSelect.Sp, - category = 72000, coefficient = 100, categories = { @@ -537,7 +522,6 @@ data:add { value = 6400, weight = 20000, fltselect = Enum.FltSelect.Sp, - category = 72000, coefficient = 100, on_open = function(self, params) @@ -563,7 +547,6 @@ data:add { value = 380, weight = 20000, fltselect = Enum.FltSelect.Sp, - category = 72000, coefficient = 100, is_precious = true, @@ -597,7 +580,6 @@ data:add { value = 7200, weight = 20000, fltselect = Enum.FltSelect.Sp, - category = 72000, coefficient = 100, prevent_sell_in_own_shop = true, @@ -626,7 +608,6 @@ data:add { weight = 15000, level = 30, fltselect = Enum.FltSelect.Sp, - category = 72000, rarity = 50000, coefficient = 100, @@ -685,7 +666,6 @@ data:add { weight = 6500, level = 30, fltselect = Enum.FltSelect.Sp, - category = 72000, rarity = 100000, coefficient = 100, @@ -715,7 +695,6 @@ data:add { weight = 2500, level = 30, fltselect = Enum.FltSelect.SpUnique, - category = 72000, rarity = 50000, coefficient = 100, @@ -734,7 +713,7 @@ data:add { is_precious = true, quality = Enum.Quality.Unique, - can_use_flight_on = false, + cannot_use_flight_on = true, categories = { "elona.container", @@ -785,7 +764,6 @@ data:add { weight = 150000, level = 10, fltselect = Enum.FltSelect.Sp, - category = 72000, rarity = 100000, coefficient = 100, @@ -826,7 +804,6 @@ data:add { image = "elona.item_recipe_holder", value = 2500, weight = 550, - category = 72000, rarity = 100000, coefficient = 0, categories = { diff --git a/src/mod/elona/data/item/currency.lua b/src/mod/elona/data/item/currency.lua index b3b97a0a3..1d67f7b92 100644 --- a/src/mod/elona/data/item/currency.lua +++ b/src/mod/elona/data/item/currency.lua @@ -43,7 +43,6 @@ data:add { image = "elona.item_gold_piece", value = 1, weight = 0, - category = 68000, coefficient = 100, prevent_sell_in_own_shop = true, @@ -103,7 +102,6 @@ data:add { image = "elona.item_platinum_coin", value = 1, weight = 1, - category = 69000, coefficient = 100, tags = { "noshop" }, always_drop = true, @@ -146,7 +144,6 @@ data:add { image = "elona.item_small_medal", value = 1, weight = 1, - category = 77000, rarity = 10000, coefficient = 100, @@ -154,7 +151,6 @@ data:add { always_stack = true, tags = { "noshop" }, - rftags = { "ore" }, categories = { "elona.tag_noshop", "elona.ore" @@ -169,14 +165,12 @@ data:add { value = 1, weight = 1, fltselect = Enum.FltSelect.Sp, - category = 77000, rarity = 10000, coefficient = 100, is_precious = true, tags = { "noshop" }, - rftags = { "ore" }, categories = { "elona.tag_noshop", "elona.no_generate", @@ -192,7 +186,6 @@ data:add { value = 1, weight = 1, fltselect = Enum.FltSelect.Sp, - category = 77000, rarity = 10000, coefficient = 100, originalnameref2 = "token", @@ -200,7 +193,6 @@ data:add { is_precious = true, tags = { "noshop" }, - rftags = { "ore" }, categories = { "elona.tag_noshop", "elona.no_generate", diff --git a/src/mod/elona/data/item/equip/head.lua b/src/mod/elona/data/item/equip/head.lua index af08f7360..0c73195d1 100644 --- a/src/mod/elona/data/item/equip/head.lua +++ b/src/mod/elona/data/item/equip/head.lua @@ -150,7 +150,6 @@ data:add { image = "elona.item_knight_helm", value = 15000, weight = 2400, - damage_bonus = 8, material = "elona.obsidian", level = 5, fltselect = Enum.FltSelect.SpUnique, @@ -183,6 +182,7 @@ data:add { equip_slots = { "elona.head" }, dv = 2, pv = 7, + damage_bonus = 8, } } } diff --git a/src/mod/elona/data/item/equip/neck.lua b/src/mod/elona/data/item/equip/neck.lua index aa5423192..966ad2328 100644 --- a/src/mod/elona/data/item/equip/neck.lua +++ b/src/mod/elona/data/item/equip/neck.lua @@ -41,7 +41,7 @@ data:add { material = "elona.metal", level = 30, coefficient = 100, - has_random_name = "ring", + has_random_name = true, categories = { "elona.equip_neck_armor", "elona.equip_neck" @@ -65,7 +65,7 @@ data:add { material = "elona.soft", level = 30, coefficient = 100, - has_random_name = "ring", + has_random_name = true, categories = { "elona.equip_neck_armor", "elona.equip_neck" @@ -89,7 +89,7 @@ data:add { material = "elona.metal", level = 10, coefficient = 100, - has_random_name = "ring", + has_random_name = true, categories = { "elona.equip_neck_armor", "elona.equip_neck" @@ -113,7 +113,7 @@ data:add { material = "elona.soft", level = 10, coefficient = 100, - has_random_name = "ring", + has_random_name = true, tags = { "fest" }, categories = { "elona.equip_neck_armor", @@ -139,7 +139,7 @@ data:add { material = "elona.metal", level = 5, coefficient = 100, - has_random_name = "ring", + has_random_name = true, categories = { "elona.equip_neck_armor", "elona.equip_neck" @@ -162,7 +162,7 @@ data:add { material = "elona.metal", rarity = 800000, coefficient = 100, - has_random_name = "ring", + has_random_name = true, categories = { "elona.equip_neck_armor", "elona.equip_neck" diff --git a/src/mod/elona/data/item/fish.lua b/src/mod/elona/data/item/fish.lua index 1b5cdc0ab..405dffde1 100644 --- a/src/mod/elona/data/item/fish.lua +++ b/src/mod/elona/data/item/fish.lua @@ -43,7 +43,6 @@ data:add { coefficient = 100, tags = { "fish" }, - rftags = { "fish" }, categories = { "elona.tag_fish", "elona.food", @@ -71,7 +70,6 @@ data:add { coefficient = 100, tags = { "fish" }, - rftags = { "fish" }, categories = { "elona.tag_fish", "elona.food", @@ -99,7 +97,6 @@ data:add { coefficient = 100, tags = { "fish" }, - rftags = { "fish" }, categories = { "elona.tag_fish", "elona.food", @@ -127,7 +124,6 @@ data:add { coefficient = 100, tags = { "fish" }, - rftags = { "fish" }, categories = { "elona.tag_fish", "elona.food", @@ -154,7 +150,6 @@ data:add { coefficient = 100, tags = { "fish" }, - rftags = { "fish" }, categories = { "elona.tag_fish", "elona.food", @@ -181,7 +176,6 @@ data:add { coefficient = 100, tags = { "fish" }, - rftags = { "fish" }, categories = { "elona.tag_fish", "elona.food", @@ -209,7 +203,6 @@ data:add { coefficient = 100, tags = { "fish" }, - rftags = { "fish" }, categories = { "elona.tag_fish", "elona.food", @@ -237,7 +230,6 @@ data:add { coefficient = 100, tags = { "fish" }, - rftags = { "fish" }, categories = { "elona.tag_fish", "elona.food", @@ -265,7 +257,6 @@ data:add { coefficient = 100, tags = { "fish" }, - rftags = { "fish" }, categories = { "elona.tag_fish", "elona.food", @@ -293,7 +284,6 @@ data:add { coefficient = 100, tags = { "fish" }, - rftags = { "fish" }, categories = { "elona.tag_fish", "elona.food", @@ -321,7 +311,6 @@ data:add { rarity = 300000, coefficient = 100, - rftags = { "fish" }, categories = { "elona.no_generate", diff --git a/src/mod/elona/data/item/food.lua b/src/mod/elona/data/item/food.lua index 55a09db01..c84436b30 100644 --- a/src/mod/elona/data/item/food.lua +++ b/src/mod/elona/data/item/food.lua @@ -668,8 +668,6 @@ data:add { coefficient = 0, originalnameref2 = "bottle", - rftags = { "flavor" }, - categories = { "elona.food" }, @@ -692,8 +690,6 @@ data:add { coefficient = 0, originalnameref2 = "sack", - rftags = { "flavor" }, - categories = { "elona.food" }, diff --git a/src/mod/elona/data/item/furniture.lua b/src/mod/elona/data/item/furniture.lua index 5ab25b9ea..60364bab6 100644 --- a/src/mod/elona/data/item/furniture.lua +++ b/src/mod/elona/data/item/furniture.lua @@ -1309,7 +1309,6 @@ data:add { value = 380, weight = 180, coefficient = 100, - can_read_multiple_times = true, categories = { "elona.furniture" } diff --git a/src/mod/elona/data/item/junk.lua b/src/mod/elona/data/item/junk.lua index 53fd6e4d1..85eb7a6c6 100644 --- a/src/mod/elona/data/item/junk.lua +++ b/src/mod/elona/data/item/junk.lua @@ -17,7 +17,6 @@ data:add { image = "elona.item_bonfire", value = 170, weight = 3200, - category = 64000, coefficient = 100, categories = { "elona.junk" @@ -32,7 +31,6 @@ data:add { image = "elona.item_flag", value = 130, weight = 1400, - category = 64000, coefficient = 100, categories = { "elona.junk" @@ -46,7 +44,6 @@ data:add { image = "elona.item_skeleton", value = 10, weight = 80, - category = 64000, coefficient = 100, categories = { "elona.junk" @@ -60,7 +57,6 @@ data:add { image = "elona.item_tombstone", value = 10, weight = 12000, - category = 64000, coefficient = 100, categories = { "elona.junk" @@ -74,7 +70,6 @@ data:add { image = "elona.item_basket", value = 40, weight = 80, - category = 64000, coefficient = 100, tags = { "fest" }, random_color = "Furniture", @@ -91,7 +86,6 @@ data:add { image = "elona.item_empty_bowl", value = 25, weight = 90, - category = 64000, coefficient = 100, random_color = "Furniture", categories = { @@ -106,7 +100,6 @@ data:add { image = "elona.item_bowl", value = 30, weight = 80, - category = 64000, coefficient = 100, random_color = "Furniture", categories = { @@ -121,7 +114,6 @@ data:add { image = "elona.item_straw", value = 7, weight = 70, - category = 64000, coefficient = 100, categories = { "elona.junk" @@ -135,7 +127,6 @@ data:add { image = "elona.item_fire_wood", value = 10, weight = 1500, - category = 64000, coefficient = 100, random_color = "Furniture", categories = { @@ -150,7 +141,6 @@ data:add { image = "elona.item_scarecrow", value = 10, weight = 4800, - category = 64000, coefficient = 100, random_color = "Furniture", categories = { @@ -165,7 +155,6 @@ data:add { image = "elona.item_broom", value = 100, weight = 800, - category = 64000, coefficient = 100, categories = { "elona.junk" @@ -179,7 +168,6 @@ data:add { image = "elona.item_large_bouquet", value = 240, weight = 1400, - category = 64000, coefficient = 100, categories = { "elona.junk" @@ -193,7 +181,6 @@ data:add { image = "elona.item_stump", value = 250, weight = 3500, - category = 64000, coefficient = 100, _ext = { @@ -212,7 +199,6 @@ data:add { image = "elona.item_shit", value = 25, weight = 80, - category = 64000, rarity = 250000, coefficient = 100, params = { chara_id = nil }, @@ -228,7 +214,6 @@ data:add { image = "elona.item_snow_scarecrow", value = 10, weight = 4800, - category = 64000, coefficient = 100, random_color = "Furniture", categories = { @@ -247,8 +232,6 @@ data:add { image = "elona.item_broken_vase", value = 6, weight = 800, - category = 64000, - subcategory = 64000, coefficient = 100, categories = { "elona.junk", @@ -263,8 +246,6 @@ data:add { image = "elona.item_broken_sword", value = 10, weight = 1050, - category = 64000, - subcategory = 64000, coefficient = 100, categories = { "elona.junk", @@ -279,8 +260,6 @@ data:add { image = "elona.item_bone_fragment", value = 10, weight = 80, - category = 64000, - subcategory = 64000, coefficient = 100, categories = { "elona.junk", @@ -295,8 +274,6 @@ data:add { image = "elona.item_ore_piece", value = 180, weight = 12000, - category = 64000, - subcategory = 64000, coefficient = 100, random_color = "Furniture", @@ -314,8 +291,6 @@ data:add { image = "elona.item_animal_bone", value = 8, weight = 40, - category = 64000, - subcategory = 64000, coefficient = 100, categories = { "elona.junk", @@ -334,8 +309,6 @@ data:add { image = "elona.item_washing", value = 140, weight = 250, - category = 64000, - subcategory = 64100, coefficient = 100, categories = { "elona.junk_town", @@ -350,8 +323,6 @@ data:add { image = "elona.item_whisky", value = 10, weight = 220, - category = 64000, - subcategory = 64100, coefficient = 100, originalnameref2 = "lot", random_color = "Furniture", @@ -373,7 +344,6 @@ data:add { value = 1000, weight = 250, fltselect = Enum.FltSelect.Sp, - category = 64000, coefficient = 100, _ext = { @@ -394,7 +364,6 @@ data:add { value = 25000, weight = 2500, fltselect = Enum.FltSelect.SpUnique, - category = 64000, rarity = 800000, coefficient = 100, diff --git a/src/mod/elona/data/item/ore.lua b/src/mod/elona/data/item/ore.lua index bfb8b8919..6fecfb972 100644 --- a/src/mod/elona/data/item/ore.lua +++ b/src/mod/elona/data/item/ore.lua @@ -11,10 +11,8 @@ data:add { image = "elona.item_crystal", value = 450, weight = 1600, - category = 77000, coefficient = 100, - rftags = { "ore" }, color = { 255, 255, 175 }, categories = { "elona.ore", @@ -29,10 +27,8 @@ data:add { image = "elona.item_crystal", value = 470, weight = 900, - category = 77000, coefficient = 100, - rftags = { "ore" }, color = { 255, 155, 155 }, categories = { "elona.ore", @@ -47,10 +43,8 @@ data:add { image = "elona.item_crystal", value = 450, weight = 1200, - category = 77000, coefficient = 100, - rftags = { "ore" }, color = { 255, 215, 175 }, categories = { "elona.ore", @@ -66,11 +60,9 @@ data:add { image = "elona.item_worthless_fake_gold_bar", value = 2000, weight = 1100, - category = 77000, rarity = 500000, coefficient = 100, - rftags = { "ore" }, categories = { "elona.ore", @@ -87,9 +79,7 @@ data:add { image = "elona.item_worthless_fake_gold_bar", value = 1, weight = 1, - category = 77000, coefficient = 100, - rftags = { "ore" }, categories = { "elona.ore" } @@ -106,13 +96,10 @@ data:add { image = "elona.item_raw_ore", value = 1400, weight = 240, - category = 77000, - subcategory = 77001, rarity = 500000, coefficient = 100, originalnameref2 = "raw ore", - rftags = { "ore" }, color = { 255, 155, 155 }, categories = { "elona.ore_valuable", @@ -129,12 +116,9 @@ data:add { image = "elona.item_raw_ore", value = 720, weight = 70, - category = 77000, - subcategory = 77001, coefficient = 100, originalnameref2 = "raw ore", - rftags = { "ore" }, categories = { "elona.ore_valuable", @@ -150,13 +134,10 @@ data:add { image = "elona.item_raw_ore_of_diamond", value = 2450, weight = 380, - category = 77000, - subcategory = 77001, rarity = 400000, coefficient = 100, originalnameref2 = "raw ore", - rftags = { "ore" }, color = { 175, 255, 175 }, categories = { "elona.ore_valuable", @@ -173,13 +154,10 @@ data:add { image = "elona.item_raw_ore_of_diamond", value = 4200, weight = 320, - category = 77000, - subcategory = 77001, rarity = 250000, coefficient = 100, originalnameref2 = "raw ore", - rftags = { "ore" }, color = { 175, 175, 255 }, categories = { "elona.ore_valuable", @@ -196,11 +174,8 @@ data:add { image = "elona.item_junk_stone", value = 10, weight = 450, - category = 77000, - subcategory = 64000, coefficient = 100, - rftags = { "ore" }, categories = { "elona.junk_in_field", diff --git a/src/mod/elona/data/item/potion.lua b/src/mod/elona/data/item/potion.lua index 22e182d3f..0d4710046 100644 --- a/src/mod/elona/data/item/potion.lua +++ b/src/mod/elona/data/item/potion.lua @@ -20,7 +20,6 @@ data:add { image = "elona.item_potion", value = 100, weight = 120, - category = 52000, coefficient = 100, originalnameref2 = "bottle", @@ -45,7 +44,6 @@ data:add { image = "elona.item_potion", value = 20, weight = 120, - category = 52000, coefficient = 100, originalnameref2 = "potion", has_random_name = true, @@ -75,7 +73,6 @@ data:add { image = "elona.item_potion", value = 30, weight = 120, - category = 52000, coefficient = 100, originalnameref2 = "potion", has_random_name = true, @@ -105,7 +102,6 @@ data:add { image = "elona.item_potion", value = 40, weight = 120, - category = 52000, coefficient = 100, originalnameref2 = "potion", has_random_name = true, @@ -135,7 +131,6 @@ data:add { image = "elona.item_potion", value = 120, weight = 120, - category = 52000, coefficient = 100, has_random_name = true, @@ -164,7 +159,6 @@ data:add { image = "elona.item_potion", value = 120, weight = 120, - category = 52000, coefficient = 100, has_random_name = true, @@ -194,7 +188,6 @@ data:add { value = 50000, weight = 120, level = 10, - category = 52000, rarity = 80000, coefficient = 0, originalnameref2 = "potion", @@ -225,7 +218,6 @@ data:add { image = "elona.item_potion", value = 150, weight = 120, - category = 52000, coefficient = 100, originalnameref2 = "potion", has_random_name = true, @@ -252,7 +244,6 @@ data:add { image = "elona.item_potion", value = 40, weight = 120, - category = 52000, coefficient = 100, originalnameref2 = "potion", has_random_name = true, @@ -283,7 +274,6 @@ data:add { value = 800, weight = 120, level = 9, - category = 52000, coefficient = 100, originalnameref2 = "potion", has_random_name = true, @@ -311,7 +301,6 @@ data:add { value = 700, weight = 120, level = 8, - category = 52000, coefficient = 100, originalnameref2 = "potion", has_random_name = true, @@ -338,7 +327,6 @@ data:add { image = "elona.item_potion", value = 850, weight = 120, - category = 52000, rarity = 700000, coefficient = 100, originalnameref2 = "potion", @@ -366,7 +354,6 @@ data:add { image = "elona.item_potion", value = 30, weight = 120, - category = 52000, coefficient = 100, originalnameref2 = "potion", has_random_name = true, @@ -396,7 +383,6 @@ data:add { image = "elona.item_potion", value = 450, weight = 120, - category = 52000, coefficient = 100, originalnameref2 = "potion", has_random_name = true, @@ -423,7 +409,6 @@ data:add { image = "elona.item_potion", value = 30, weight = 120, - category = 52000, coefficient = 100, originalnameref2 = "potion", has_random_name = true, @@ -452,7 +437,6 @@ data:add { image = "elona.item_molotov", value = 800, weight = 50, - category = 52000, coefficient = 0, originalnameref2 = "bottle", @@ -480,7 +464,6 @@ data:add { image = "elona.item_potion", value = 150, weight = 120, - category = 52000, coefficient = 0, originalnameref2 = "potion", has_random_name = true, @@ -511,7 +494,6 @@ data:add { value = 5000, weight = 120, level = 8, - category = 52000, rarity = 200000, coefficient = 0, originalnameref2 = "potion", @@ -543,7 +525,6 @@ data:add { value = 4000, weight = 120, level = 10, - category = 52000, rarity = 400000, coefficient = 0, originalnameref2 = "potion", @@ -570,7 +551,6 @@ data:add { image = "elona.item_potion", value = 280, weight = 50, - category = 52000, rarity = 400000, coefficient = 0, originalnameref2 = "bottle", @@ -632,7 +612,6 @@ data:add { image = "elona.item_potion", value = 500, weight = 120, - category = 52000, rarity = 2000000, coefficient = 100, originalnameref2 = "bottle", @@ -666,7 +645,6 @@ data:add { image = "elona.item_potion", value = 100000, weight = 120, - category = 52000, rarity = 30000, coefficient = 0, originalnameref2 = "potion", @@ -708,7 +686,6 @@ data:add { image = "elona.item_potion", value = 1900, weight = 120, - category = 52000, rarity = 300000, coefficient = 100, has_random_name = true, @@ -737,7 +714,6 @@ data:add { image = "elona.item_bottle_of_milk", value = 1000, weight = 300, - category = 52000, rarity = 300000, coefficient = 100, originalnameref2 = "bottle", @@ -767,7 +743,6 @@ data:add { value = 400, weight = 50, level = 10, - category = 52000, coefficient = 0, has_random_name = true, @@ -795,7 +770,6 @@ data:add { image = "elona.item_handful_of_snow", value = 10, weight = 50, - category = 52000, rarity = 100000, coefficient = 100, originalnameref2 = "handful", @@ -869,7 +843,6 @@ data:add { value = 4500, weight = 50, level = 5, - category = 52000, rarity = 150000, coefficient = 0, @@ -920,7 +893,6 @@ data:add { value = 50000, weight = 120, level = 15, - category = 52000, rarity = 10000, coefficient = 100, originalnameref2 = "bottle", @@ -953,7 +925,6 @@ data:add { image = "elona.item_handful_of_snow", value = 10, weight = 50, - category = 52000, rarity = 100000, coefficient = 100, originalnameref2 = "potion", @@ -978,7 +949,6 @@ data:add { image = "elona.item_vomit", value = 400, weight = 100, - category = 52000, rarity = 10000, coefficient = 0, @@ -1003,7 +973,6 @@ data:add { image = "elona.item_potion", value = 4500, weight = 120, - category = 52000, rarity = 4000, coefficient = 100, originalnameref2 = "potion", @@ -1044,7 +1013,6 @@ data:add { image = "elona.item_potion", value = 12000, weight = 120, - category = 52000, rarity = 5000, coefficient = 0, originalnameref2 = "potion", @@ -1072,7 +1040,6 @@ data:add { image = "elona.item_potion", value = 1500, weight = 120, - category = 52000, rarity = 300000, coefficient = 100, has_random_name = true, @@ -1102,7 +1069,6 @@ data:add { value = 500, weight = 50, fltselect = Enum.FltSelect.Sp, - category = 52000, rarity = 400000, coefficient = 0, originalnameref2 = "bottle", @@ -1133,7 +1099,6 @@ data:add { value = 7500, weight = 100, fltselect = Enum.FltSelect.SpUnique, - category = 52000, rarity = 5000, coefficient = 0, @@ -1165,8 +1130,6 @@ data:add { image = "elona.item_potion", value = 150, weight = 120, - category = 52000, - subcategory = 52001, coefficient = 100, originalnameref2 = "potion", has_random_name = true, @@ -1195,8 +1158,6 @@ data:add { value = 300, weight = 120, level = 4, - category = 52000, - subcategory = 52001, coefficient = 100, originalnameref2 = "potion", has_random_name = true, @@ -1225,8 +1186,6 @@ data:add { value = 1280, weight = 120, level = 8, - category = 52000, - subcategory = 52001, coefficient = 50, originalnameref2 = "potion", has_random_name = true, @@ -1255,8 +1214,6 @@ data:add { value = 3000, weight = 120, level = 15, - category = 52000, - subcategory = 52001, rarity = 700000, coefficient = 50, originalnameref2 = "potion", @@ -1286,8 +1243,6 @@ data:add { value = 5000, weight = 120, level = 25, - category = 52000, - subcategory = 52001, rarity = 600000, coefficient = 0, originalnameref2 = "potion", @@ -1317,8 +1272,6 @@ data:add { value = 7500, weight = 120, level = 35, - category = 52000, - subcategory = 52001, rarity = 500000, coefficient = 0, originalnameref2 = "potion", @@ -1348,8 +1301,6 @@ data:add { value = 10000, weight = 120, level = 45, - category = 52000, - subcategory = 52001, rarity = 250000, coefficient = 0, originalnameref2 = "potion", @@ -1379,8 +1330,6 @@ data:add { value = 15000, weight = 120, level = 45, - category = 52000, - subcategory = 52001, rarity = 150000, coefficient = 0, originalnameref2 = "potion", @@ -1409,8 +1358,6 @@ data:add { image = "elona.item_potion", value = 280, weight = 120, - category = 52000, - subcategory = 52001, coefficient = 0, originalnameref2 = "potion", has_random_name = true, @@ -1438,8 +1385,6 @@ data:add { image = "elona.item_potion", value = 280, weight = 120, - category = 52000, - subcategory = 52001, coefficient = 0, originalnameref2 = "potion", has_random_name = true, @@ -1470,8 +1415,6 @@ data:add { image = "elona.item_potion", value = 280, weight = 50, - category = 52000, - subcategory = 52002, coefficient = 0, originalnameref2 = "bottle", @@ -1496,8 +1439,6 @@ data:add { image = "elona.item_bottle_of_whisky", value = 180, weight = 50, - category = 52000, - subcategory = 52002, coefficient = 100, originalnameref2 = "bottle", @@ -1522,8 +1463,6 @@ data:add { image = "elona.item_molotov", value = 280, weight = 50, - category = 52000, - subcategory = 52002, coefficient = 0, originalnameref2 = "bottle", @@ -1552,7 +1491,6 @@ data:add { image = "elona.item_empty_bottle", value = 100, weight = 120, - category = 52000, rarity = 800000, coefficient = 100, diff --git a/src/mod/elona/data/item/rod.lua b/src/mod/elona/data/item/rod.lua index eed12e935..6dd9f70f9 100644 --- a/src/mod/elona/data/item/rod.lua +++ b/src/mod/elona/data/item/rod.lua @@ -15,7 +15,6 @@ data:add { value = 1080, weight = 800, level = 4, - category = 56000, coefficient = 0, originalnameref2 = "rod", has_random_name = true, @@ -45,7 +44,6 @@ data:add { image = "elona.item_rod", value = 840, weight = 800, - category = 56000, coefficient = 0, originalnameref2 = "rod", has_random_name = true, @@ -76,7 +74,6 @@ data:add { value = 650, weight = 800, level = 3, - category = 56000, coefficient = 0, originalnameref2 = "rod", has_random_name = true, @@ -107,7 +104,6 @@ data:add { value = 800, weight = 800, level = 2, - category = 56000, coefficient = 0, originalnameref2 = "rod", has_random_name = true, @@ -137,7 +133,6 @@ data:add { image = "elona.item_rod", value = 700, weight = 800, - category = 56000, coefficient = 0, originalnameref2 = "rod", has_random_name = true, @@ -168,7 +163,6 @@ data:add { value = 1460, weight = 800, level = 8, - category = 56000, coefficient = 0, originalnameref2 = "rod", has_random_name = true, @@ -199,7 +193,6 @@ data:add { value = 1600, weight = 800, level = 8, - category = 56000, coefficient = 0, originalnameref2 = "rod", has_random_name = true, @@ -230,7 +223,6 @@ data:add { value = 4800, weight = 800, level = 15, - category = 56000, rarity = 250000, coefficient = 0, originalnameref2 = "rod", @@ -262,7 +254,6 @@ data:add { value = 1900, weight = 800, level = 8, - category = 56000, coefficient = 0, originalnameref2 = "rod", has_random_name = true, @@ -293,7 +284,6 @@ data:add { value = 1500, weight = 800, level = 3, - category = 56000, coefficient = 0, originalnameref2 = "rod", has_random_name = true, @@ -324,7 +314,6 @@ data:add { value = 3250, weight = 800, level = 4, - category = 56000, coefficient = 0, originalnameref2 = "rod", has_random_name = true, @@ -355,7 +344,6 @@ data:add { value = 2600, weight = 800, level = 10, - category = 56000, rarity = 800000, coefficient = 0, originalnameref2 = "rod", @@ -387,7 +375,6 @@ data:add { value = 300000, weight = 800, level = 10, - category = 56000, rarity = 20000, coefficient = 0, originalnameref2 = "rod", @@ -422,7 +409,6 @@ data:add { value = 1080, weight = 800, level = 4, - category = 56000, coefficient = 0, originalnameref2 = "rod", has_random_name = true, @@ -453,7 +439,6 @@ data:add { value = 4200, weight = 800, level = 8, - category = 56000, coefficient = 0, originalnameref2 = "rod", has_random_name = true, @@ -484,7 +469,6 @@ data:add { value = 3600, weight = 800, level = 7, - category = 56000, rarity = 400000, coefficient = 0, originalnameref2 = "rod", @@ -516,7 +500,6 @@ data:add { value = 4100, weight = 800, level = 11, - category = 56000, rarity = 200000, coefficient = 0, originalnameref2 = "rod", @@ -548,7 +531,6 @@ data:add { value = 3800, weight = 800, level = 12, - category = 56000, rarity = 500000, coefficient = 0, originalnameref2 = "rod", @@ -580,7 +562,6 @@ data:add { value = 16000, weight = 800, level = 5, - category = 56000, rarity = 100000, coefficient = 0, originalnameref2 = "rod", @@ -616,7 +597,6 @@ data:add { value = 3500, weight = 800, level = 3, - category = 56000, rarity = 700000, coefficient = 0, originalnameref2 = "rod", @@ -648,7 +628,6 @@ data:add { value = 4500, weight = 800, level = 5, - category = 56000, rarity = 700000, coefficient = 0, originalnameref2 = "rod", @@ -680,7 +659,6 @@ data:add { value = 6000, weight = 800, level = 7, - category = 56000, rarity = 450000, coefficient = 0, originalnameref2 = "rod", @@ -712,7 +690,6 @@ data:add { value = 4000, weight = 800, level = 5, - category = 56000, rarity = 800000, coefficient = 0, originalnameref2 = "rod", @@ -744,7 +721,6 @@ data:add { value = 5600, weight = 800, level = 3, - category = 56000, rarity = 800000, coefficient = 0, originalnameref2 = "rod", @@ -776,7 +752,6 @@ data:add { value = 4400, weight = 800, level = 8, - category = 56000, rarity = 800000, coefficient = 0, originalnameref2 = "rod", @@ -808,7 +783,6 @@ data:add { value = 3800, weight = 800, level = 4, - category = 56000, rarity = 700000, coefficient = 0, originalnameref2 = "rod", @@ -839,7 +813,6 @@ data:add { image = "elona.item_rod", value = 2000, weight = 800, - category = 56000, rarity = 500000, coefficient = 0, originalnameref2 = "rod", diff --git a/src/mod/elona/data/item/scroll.lua b/src/mod/elona/data/item/scroll.lua index 9ae0dd20a..c1ddd215c 100644 --- a/src/mod/elona/data/item/scroll.lua +++ b/src/mod/elona/data/item/scroll.lua @@ -21,7 +21,6 @@ data:add { on_read = function(self, params) return ElonaMagic.read_scroll(self, {{ _id = "elona.identify", power = 100 }}, params) end, - category = 53000, coefficient = 0, originalnameref2 = "scroll", has_random_name = true, @@ -44,7 +43,6 @@ data:add { on_read = function(self, params) return ElonaMagic.read_scroll(self, {{ _id = "elona.oracle", power = 100 }}, params) end, - category = 53000, coefficient = 0, originalnameref2 = "scroll", has_random_name = true, @@ -67,7 +65,6 @@ data:add { on_read = function(self, params) return ElonaMagic.read_scroll(self, {{ _id = "elona.teleport", power = 100 }}, params) end, - category = 53000, coefficient = 0, originalnameref2 = "scroll", has_random_name = true, @@ -92,7 +89,6 @@ data:add { on_read = function(self, params) return ElonaMagic.read_scroll(self, {{ _id = "elona.buff_incognito", power = 300 }}, params) end, - category = 53000, rarity = 70000, coefficient = 0, originalnameref2 = "scroll", @@ -116,7 +112,6 @@ data:add { on_read = function(self, params) return ElonaMagic.read_scroll(self, {{ _id = "elona.uncurse", power = 100 }}, params) end, - category = 53000, coefficient = 0, originalnameref2 = "scroll", has_random_name = true, @@ -139,7 +134,6 @@ data:add { on_read = function(self, params) return ElonaMagic.read_scroll(self, {{ _id = "elona.return", power = 100 }}, params) end, - category = 53000, rarity = 300000, coefficient = 0, originalnameref2 = "scroll", @@ -163,7 +157,6 @@ data:add { on_read = function(self, params) return ElonaMagic.read_scroll(self, {{ _id = "elona.magic_map", power = 500 }}, params) end, - category = 53000, coefficient = 0, originalnameref2 = "scroll", has_random_name = true, @@ -187,7 +180,6 @@ data:add { return ElonaMagic.read_scroll(self, {{ _id = "elona.effect_gain_skill", power = 100 }}, params) end, level = 15, - category = 53000, rarity = 25000, coefficient = 0, originalnameref2 = "scroll", @@ -228,7 +220,6 @@ data:add { return ElonaMagic.read_scroll(self, {{ _id = "elona.effect_gain_knowledge", power = 100 }}, params) end, level = 5, - category = 53000, rarity = 500000, coefficient = 0, originalnameref2 = "scroll", @@ -252,7 +243,6 @@ data:add { on_read = function(self, params) return ElonaMagic.read_scroll(self, {{ _id = "elona.teleport", power = 100 }}, params) end, - category = 53000, coefficient = 0, originalnameref2 = "scroll", has_random_name = true, @@ -277,7 +267,6 @@ data:add { on_read = function(self, params) return ElonaMagic.read_scroll(self, {{ _id = "elona.effect_curse", power = 100 }}, params) end, - category = 53000, coefficient = 0, originalnameref2 = "scroll", has_random_name = true, @@ -304,7 +293,6 @@ data:add { return ElonaMagic.read_scroll(self, {{ _id = "elona.identify", power = 2000 }}, params) end, level = 10, - category = 53000, rarity = 300000, coefficient = 0, originalnameref2 = "scroll", @@ -329,7 +317,6 @@ data:add { return ElonaMagic.read_scroll(self, {{ _id = "elona.uncurse", power = 2500 }}, params) end, level = 12, - category = 53000, rarity = 300000, coefficient = 0, originalnameref2 = "scroll", @@ -354,7 +341,6 @@ data:add { return ElonaMagic.read_scroll(self, {{ _id = "elona.buff_holy_veil", power = 250 }}, params) end, level = 3, - category = 53000, rarity = 400000, coefficient = 0, originalnameref2 = "scroll", @@ -378,7 +364,6 @@ data:add { on_read = function(self, params) return ElonaMagic.read_scroll(self, {{ _id = "elona.holy_light", power = 300 }}, params) end, - category = 53000, rarity = 800000, coefficient = 0, originalnameref2 = "scroll", @@ -403,7 +388,6 @@ data:add { return ElonaMagic.read_scroll(self, {{ _id = "elona.vanquish_hex", power = 300 }}, params) end, level = 5, - category = 53000, rarity = 400000, coefficient = 0, originalnameref2 = "scroll", @@ -428,7 +412,6 @@ data:add { return ElonaMagic.read_scroll(self, {{ _id = "elona.harvest_mana", power = 250 }}, params) end, level = 5, - category = 53000, rarity = 150000, coefficient = 0, originalnameref2 = "scroll", @@ -453,7 +436,6 @@ data:add { return ElonaMagic.read_scroll(self, {{ _id = "elona.effect_create_material", power = 250 }}, params) end, level = 5, - category = 53000, rarity = 700000, coefficient = 0, originalnameref2 = "scroll", @@ -478,7 +460,6 @@ data:add { return ElonaMagic.read_scroll(self, {{ _id = "elona.buff_divine_wisdom", power = 250 }}, params) end, level = 3, - category = 53000, rarity = 600000, coefficient = 0, originalnameref2 = "scroll", @@ -502,7 +483,6 @@ data:add { on_read = function(self, params) return ElonaMagic.read_scroll(self, {{ _id = "elona.sense_object", power = 500 }}, params) end, - category = 53000, coefficient = 0, originalnameref2 = "scroll", has_random_name = true, @@ -526,7 +506,6 @@ data:add { return ElonaMagic.read_scroll(self, {{ _id = "elona.effect_gain_skill_potential", power = 500 }}, params) end, level = 5, - category = 53000, rarity = 80000, coefficient = 0, originalnameref2 = "scroll", @@ -555,7 +534,6 @@ data:add { return ElonaMagic.read_scroll(self, {{ _id = "elona.effect_gain_faith", power = 300 }}, params) end, level = 5, - category = 53000, rarity = 300000, coefficient = 0, originalnameref2 = "scroll", @@ -584,7 +562,6 @@ data:add { return ElonaMagic.read_scroll(self, {{ _id = "elona.effect_gain_ally", power = 100 }}, params) end, level = 10, - category = 53000, rarity = 300000, coefficient = 0, originalnameref2 = "scroll", @@ -608,7 +585,6 @@ data:add { on_read = function(self, params) return ElonaMagic.read_scroll(self, {{ _id = "elona.effect_change_material", power = 10 }}, params) end, - category = 53000, coefficient = 0, originalnameref2 = "scroll", has_random_name = true, @@ -635,7 +611,6 @@ data:add { return ElonaMagic.read_scroll(self, {{ _id = "elona.effect_change_material", power = 180 }}, params) end, level = 15, - category = 53000, rarity = 500000, coefficient = 0, originalnameref2 = "scroll", @@ -660,7 +635,6 @@ data:add { return ElonaMagic.read_scroll(self, {{ _id = "elona.effect_change_material", power = 350 }}, params) end, level = 30, - category = 53000, rarity = 100000, coefficient = 0, originalnameref2 = "scroll", @@ -701,7 +675,6 @@ data:add { on_read = function(self, params) return ElonaMagic.read_scroll(self, {{ _id = "elona.effect_enchant_weapon", power = 200 }}, params) end, - category = 53000, rarity = 300000, coefficient = 0, originalnameref2 = "scroll", @@ -726,7 +699,6 @@ data:add { return ElonaMagic.read_scroll(self, {{ _id = "elona.effect_enchant_weapon", power = 400 }}, params) end, level = 10, - category = 53000, rarity = 100000, coefficient = 0, originalnameref2 = "scroll", @@ -750,7 +722,6 @@ data:add { on_read = function(self, params) return ElonaMagic.read_scroll(self, {{ _id = "elona.effect_enchant_armor", power = 200 }}, params) end, - category = 53000, rarity = 300000, coefficient = 0, originalnameref2 = "scroll", @@ -775,7 +746,6 @@ data:add { return ElonaMagic.read_scroll(self, {{ _id = "elona.effect_enchant_armor", power = 400 }}, params) end, level = 10, - category = 53000, rarity = 100000, coefficient = 0, originalnameref2 = "scroll", @@ -800,7 +770,6 @@ data:add { return ElonaMagic.read_scroll(self, {{ _id = "elona.effect_recharge", power = 300 }}, params) end, level = 5, - category = 53000, rarity = 500000, coefficient = 0, originalnameref2 = "scroll", @@ -825,7 +794,6 @@ data:add { return ElonaMagic.read_scroll(self, {{ _id = "elona.healing_rain", power = 400 }}, params) end, level = 12, - category = 53000, rarity = 500000, coefficient = 0, originalnameref2 = "scroll", @@ -852,7 +820,6 @@ data:add { on_read = function(self, params) return ElonaMagic.read_scroll(self, {{ _id = "elona.effect_flight", power = 150 }}, params) end, - category = 53000, rarity = 25000, coefficient = 0, has_random_name = true, @@ -875,7 +842,6 @@ data:add { on_read = function(self, params) return ElonaMagic.read_scroll(self, {{ _id = "elona.effect_escape", power = 100 }}, params) end, - category = 53000, rarity = 500000, coefficient = 0, originalnameref2 = "scroll", @@ -899,7 +865,6 @@ data:add { on_read = function(self, params) return ElonaMagic.read_scroll(self, {{ _id = "elona.resurrection", power = 2500 }}, params) end, - category = 55000, rarity = 3000, coefficient = 0, originalnameref2 = "book", @@ -927,7 +892,6 @@ data:add { return ElonaMagic.read_scroll(self, {{ _id = "elona.buff_contingency", power = 1500 }}, params) end, level = 5, - category = 53000, rarity = 3000, coefficient = 0, originalnameref2 = "scroll", @@ -955,7 +919,6 @@ data:add { return ElonaMagic.read_scroll(self, {{ _id = "elona.effect_name", power = 100 }}, params) end, level = 20, - category = 53000, rarity = 2000, coefficient = 0, originalnameref2 = "scroll", @@ -987,7 +950,6 @@ data:add { return ElonaMagic.read_scroll(self, {{ _id = "elona.effect_gain_younger_sister", power = 100 }}, params) end, level = 5, - category = 55000, rarity = 25000, coefficient = 0, has_random_name = true, @@ -1014,7 +976,6 @@ data:add { return ElonaMagic.read_scroll(self, {{ _id = "elona.effect_gain_cat_sister", power = 100 }}, params) end, level = 15, - category = 55000, rarity = 1000, coefficient = 0, has_random_name = true, @@ -1041,7 +1002,6 @@ data:add { return ElonaMagic.read_scroll(self, {{ _id = "elona.effect_gain_young_lady", power = 100 }}, params) end, level = 5, - category = 55000, rarity = 5000, coefficient = 0, has_random_name = true, @@ -1068,8 +1028,6 @@ data:add { value = 50000, weight = 500, fltselect = Enum.FltSelect.Sp, - category = 53000, - subcategory = 53100, coefficient = 100, can_read_in_world_map = true, @@ -1153,14 +1111,12 @@ data:add { weight = 500, on_read = deed_callback("elona.museum"), fltselect = Enum.FltSelect.Sp, - category = 53000, - subcategory = 53100, rarity = 1000, coefficient = 100, originalnameref2 = "deed", can_read_in_world_map = true, - param1 = 1, + -- param1 = 1, color = { 255, 215, 175 }, @@ -1180,14 +1136,12 @@ data:add { weight = 500, on_read = deed_callback("elona.shop"), fltselect = Enum.FltSelect.Sp, - category = 53000, - subcategory = 53100, rarity = 1000, coefficient = 100, originalnameref2 = "deed", can_read_in_world_map = true, - param1 = 1, + -- param1 = 1, color = { 255, 155, 155 }, @@ -1207,8 +1161,6 @@ data:add { weight = 500, on_read = deed_callback("elona.crop"), fltselect = Enum.FltSelect.Sp, - category = 53000, - subcategory = 53100, rarity = 1000, coefficient = 100, originalnameref2 = "deed", @@ -1232,8 +1184,6 @@ data:add { weight = 500, on_read = deed_callback("elona.storage_house"), fltselect = Enum.FltSelect.Sp, - category = 53000, - subcategory = 53100, rarity = 1000, coefficient = 100, originalnameref2 = "deed", @@ -1257,8 +1207,6 @@ data:add { weight = 500, on_read = deed_callback("elona.ranch"), fltselect = Enum.FltSelect.Sp, - category = 53000, - subcategory = 53100, rarity = 1000, coefficient = 100, originalnameref2 = "deed", @@ -1282,8 +1230,6 @@ data:add { weight = 500, on_read = deed_callback("elona.dungeon"), fltselect = Enum.FltSelect.Sp, - category = 53000, - subcategory = 53100, rarity = 1000, coefficient = 100, originalnameref2 = "deed", @@ -1313,7 +1259,6 @@ data:add { return ElonaMagic.read_scroll(self, {{ _id = "elona.effect_deed_of_inheritance", power = self.params.deed_of_heirship_quality }}) end, level = 3, - category = 53000, rarity = 250000, coefficient = 100, originalnameref2 = "deed", @@ -1338,7 +1283,6 @@ data:add { value = 100, weight = 100, fltselect = Enum.FltSelect.Sp, - category = 53000, rarity = 400000, coefficient = 100, @@ -1368,7 +1312,6 @@ data:add { return ElonaMagic.read_scroll(self, {{ _id = "elona.effect_treasure_map", power = 100 }}, params) end, level = 5, - category = 53000, rarity = 100000, coefficient = 100, @@ -1406,7 +1349,6 @@ data:add { value = 15000, weight = 500, fltselect = Enum.FltSelect.SpUnique, - category = 53000, rarity = 1000, coefficient = 100, originalnameref2 = "license", diff --git a/src/mod/elona/data/item/spellbook.lua b/src/mod/elona/data/item/spellbook.lua index 53628fa1a..e6258ba75 100644 --- a/src/mod/elona/data/item/spellbook.lua +++ b/src/mod/elona/data/item/spellbook.lua @@ -29,7 +29,6 @@ data:add { image = "elona.item_spellbook", value = 3200, weight = 380, - category = 54000, coefficient = 0, originalnameref2 = "spellbook", has_random_name = true, @@ -59,7 +58,6 @@ data:add { value = 5600, weight = 380, level = 6, - category = 54000, coefficient = 0, originalnameref2 = "spellbook", has_random_name = true, @@ -89,7 +87,6 @@ data:add { value = 6400, weight = 380, level = 10, - category = 54000, coefficient = 0, originalnameref2 = "spellbook", has_random_name = true, @@ -118,7 +115,6 @@ data:add { image = "elona.item_spellbook", value = 3800, weight = 380, - category = 54000, coefficient = 0, originalnameref2 = "spellbook", has_random_name = true, @@ -147,7 +143,6 @@ data:add { image = "elona.item_spellbook", value = 3800, weight = 380, - category = 54000, coefficient = 0, originalnameref2 = "spellbook", has_random_name = true, @@ -176,7 +171,6 @@ data:add { image = "elona.item_spellbook", value = 3800, weight = 380, - category = 54000, coefficient = 0, originalnameref2 = "spellbook", has_random_name = true, @@ -205,7 +199,6 @@ data:add { image = "elona.item_spellbook", value = 2400, weight = 380, - category = 54000, coefficient = 0, originalnameref2 = "spellbook", has_random_name = true, @@ -235,7 +228,6 @@ data:add { value = 6000, weight = 380, level = 5, - category = 54000, coefficient = 0, originalnameref2 = "spellbook", has_random_name = true, @@ -265,7 +257,6 @@ data:add { value = 8500, weight = 380, level = 12, - category = 54000, rarity = 800000, coefficient = 0, originalnameref2 = "spellbook", @@ -296,7 +287,6 @@ data:add { value = 25000, weight = 380, level = 15, - category = 54000, rarity = 100000, coefficient = 0, originalnameref2 = "spellbook", @@ -327,7 +317,6 @@ data:add { value = 8900, weight = 380, level = 8, - category = 54000, rarity = 300000, coefficient = 0, originalnameref2 = "spellbook", @@ -357,7 +346,6 @@ data:add { image = "elona.item_spellbook", value = 4500, weight = 380, - category = 54000, coefficient = 0, originalnameref2 = "spellbook", has_random_name = true, @@ -387,7 +375,6 @@ data:add { value = 9000, weight = 380, level = 8, - category = 54000, coefficient = 0, originalnameref2 = "spellbook", has_random_name = true, @@ -417,7 +404,6 @@ data:add { value = 15000, weight = 380, level = 10, - category = 54000, rarity = 700000, coefficient = 0, originalnameref2 = "spellbook", @@ -448,7 +434,6 @@ data:add { value = 35000, weight = 380, level = 15, - category = 54000, rarity = 300000, coefficient = 0, originalnameref2 = "spellbook", @@ -478,7 +463,6 @@ data:add { image = "elona.item_spellbook", value = 2500, weight = 380, - category = 54000, coefficient = 0, originalnameref2 = "spellbook", has_random_name = true, @@ -508,7 +492,6 @@ data:add { value = 7200, weight = 380, level = 6, - category = 54000, coefficient = 0, originalnameref2 = "spellbook", has_random_name = true, @@ -538,7 +521,6 @@ data:add { value = 9600, weight = 380, level = 12, - category = 54000, rarity = 800000, coefficient = 0, originalnameref2 = "spellbook", @@ -569,7 +551,6 @@ data:add { value = 6400, weight = 380, level = 10, - category = 54000, coefficient = 0, originalnameref2 = "spellbook", has_random_name = true, @@ -599,7 +580,6 @@ data:add { value = 4500, weight = 380, level = 3, - category = 54000, coefficient = 0, originalnameref2 = "spellbook", has_random_name = true, @@ -629,7 +609,6 @@ data:add { value = 5500, weight = 380, level = 5, - category = 54000, coefficient = 0, originalnameref2 = "spellbook", has_random_name = true, @@ -659,7 +638,6 @@ data:add { value = 5400, weight = 380, level = 3, - category = 54000, coefficient = 0, originalnameref2 = "spellbook", has_random_name = true, @@ -689,7 +667,6 @@ data:add { value = 5400, weight = 380, level = 3, - category = 54000, coefficient = 0, originalnameref2 = "spellbook", has_random_name = true, @@ -719,7 +696,6 @@ data:add { value = 8400, weight = 380, level = 10, - category = 54000, rarity = 800000, coefficient = 0, originalnameref2 = "spellbook", @@ -750,7 +726,6 @@ data:add { value = 12000, weight = 380, level = 15, - category = 54000, rarity = 700000, coefficient = 0, originalnameref2 = "spellbook", @@ -781,7 +756,6 @@ data:add { value = 40000, weight = 380, level = 15, - category = 54000, rarity = 20000, coefficient = 0, originalnameref2 = "spellbook", @@ -817,7 +791,6 @@ data:add { value = 2800, weight = 380, level = 3, - category = 54000, coefficient = 0, originalnameref2 = "spellbook", has_random_name = true, @@ -847,7 +820,6 @@ data:add { value = 8400, weight = 380, level = 10, - category = 54000, rarity = 600000, coefficient = 0, originalnameref2 = "spellbook", @@ -878,7 +850,6 @@ data:add { value = 4400, weight = 380, level = 8, - category = 54000, rarity = 500000, coefficient = 0, originalnameref2 = "spellbook", @@ -909,7 +880,6 @@ data:add { value = 7500, weight = 380, level = 8, - category = 54000, rarity = 700000, coefficient = 0, originalnameref2 = "spellbook", @@ -940,7 +910,6 @@ data:add { value = 12000, weight = 380, level = 13, - category = 54000, rarity = 700000, coefficient = 0, originalnameref2 = "spellbook", @@ -971,7 +940,6 @@ data:add { value = 4800, weight = 380, level = 7, - category = 54000, rarity = 700000, coefficient = 0, originalnameref2 = "spellbook", @@ -1002,7 +970,6 @@ data:add { value = 2600, weight = 380, level = 2, - category = 54000, coefficient = 0, originalnameref2 = "spellbook", has_random_name = true, @@ -1031,7 +998,6 @@ data:add { image = "elona.item_spellbook", value = 2500, weight = 380, - category = 54000, rarity = 700000, coefficient = 0, originalnameref2 = "spellbook", @@ -1062,7 +1028,6 @@ data:add { value = 6400, weight = 380, level = 10, - category = 54000, rarity = 700000, coefficient = 0, originalnameref2 = "spellbook", @@ -1093,7 +1058,6 @@ data:add { value = 11000, weight = 380, level = 14, - category = 54000, rarity = 200000, coefficient = 0, originalnameref2 = "spellbook", @@ -1124,7 +1088,6 @@ data:add { value = 3500, weight = 380, level = 2, - category = 54000, rarity = 700000, coefficient = 0, originalnameref2 = "spellbook", @@ -1155,7 +1118,6 @@ data:add { value = 9800, weight = 380, level = 11, - category = 54000, rarity = 300000, coefficient = 0, originalnameref2 = "spellbook", @@ -1186,7 +1148,6 @@ data:add { value = 3400, weight = 380, level = 3, - category = 54000, rarity = 800000, coefficient = 0, originalnameref2 = "spellbook", @@ -1217,7 +1178,6 @@ data:add { value = 3800, weight = 380, level = 3, - category = 54000, rarity = 700000, coefficient = 0, originalnameref2 = "spellbook", @@ -1247,7 +1207,6 @@ data:add { image = "elona.item_spellbook", value = 4000, weight = 380, - category = 54000, rarity = 600000, coefficient = 0, originalnameref2 = "spellbook", @@ -1278,7 +1237,6 @@ data:add { value = 20000, weight = 380, level = 15, - category = 54000, rarity = 100000, coefficient = 0, originalnameref2 = "spellbook", @@ -1309,7 +1267,6 @@ data:add { value = 28000, weight = 380, level = 5, - category = 54000, rarity = 100000, coefficient = 0, originalnameref2 = "spellbook", @@ -1339,7 +1296,6 @@ data:add { image = "elona.item_spellbook", value = 4500, weight = 380, - category = 54000, rarity = 800000, coefficient = 0, originalnameref2 = "spellbook", @@ -1370,7 +1326,6 @@ data:add { value = 6800, weight = 380, level = 4, - category = 54000, rarity = 600000, coefficient = 0, originalnameref2 = "spellbook", @@ -1401,7 +1356,6 @@ data:add { value = 9500, weight = 380, level = 7, - category = 54000, rarity = 300000, coefficient = 0, originalnameref2 = "spellbook", @@ -1432,7 +1386,6 @@ data:add { value = 5800, weight = 380, level = 5, - category = 54000, rarity = 300000, coefficient = 0, originalnameref2 = "spellbook", @@ -1463,7 +1416,6 @@ data:add { value = 7500, weight = 380, level = 8, - category = 54000, rarity = 500000, coefficient = 0, originalnameref2 = "spellbook", @@ -1494,7 +1446,6 @@ data:add { value = 5800, weight = 380, level = 4, - category = 54000, rarity = 500000, coefficient = 0, originalnameref2 = "spellbook", @@ -1524,7 +1475,6 @@ data:add { image = "elona.item_spellbook", value = 2000, weight = 380, - category = 54000, rarity = 400000, coefficient = 0, originalnameref2 = "spellbook", @@ -1555,7 +1505,6 @@ data:add { value = 7000, weight = 380, level = 10, - category = 54000, rarity = 200000, coefficient = 0, originalnameref2 = "spellbook", @@ -1586,7 +1535,6 @@ data:add { value = 3500, weight = 380, level = 5, - category = 54000, coefficient = 0, originalnameref2 = "spellbook", has_random_name = true, @@ -1615,7 +1563,6 @@ data:add { value = 2000, weight = 380, level = 3, - category = 54000, rarity = 5000000, coefficient = 0, @@ -1646,7 +1593,6 @@ data:add { value = 14200, weight = 380, level = 20, - category = 54000, rarity = 300000, coefficient = 0, originalnameref2 = "spellbook", @@ -1677,7 +1623,6 @@ data:add { value = 12500, weight = 380, level = 15, - category = 54000, rarity = 300000, coefficient = 0, originalnameref2 = "spellbook", @@ -1708,7 +1653,6 @@ data:add { value = 8500, weight = 380, level = 15, - category = 54000, rarity = 300000, coefficient = 0, originalnameref2 = "spellbook", @@ -1739,7 +1683,6 @@ data:add { value = 8500, weight = 380, level = 15, - category = 54000, rarity = 400000, coefficient = 0, originalnameref2 = "spellbook", @@ -1770,7 +1713,6 @@ data:add { value = 4000, weight = 380, level = 5, - category = 54000, rarity = 800000, coefficient = 0, originalnameref2 = "spellbook", @@ -1807,7 +1749,6 @@ data:add { image = "elona.item_recipe", value = 1000, weight = 50, - category = 54000, rarity = 50000, coefficient = 0, diff --git a/src/mod/elona/data/item/tool.lua b/src/mod/elona/data/item/tool.lua index 96252b90e..1ae66c097 100644 --- a/src/mod/elona/data/item/tool.lua +++ b/src/mod/elona/data/item/tool.lua @@ -413,7 +413,7 @@ data:add { coefficient = 100, elona_function = 13, - param1 = 100, + -- param1 = 100, categories = { "elona.misc_item" }, @@ -621,7 +621,7 @@ data:add { value = 150000, weight = 400, level = 20, - fltselect = Enum.FltSelect.Unique, + fltselect = 2, rarity = 10000, coefficient = 100, @@ -791,7 +791,7 @@ data:add { coefficient = 100, -- TODO implement everywhere in the code (see: Noel's dialog) - params = { secret_treasure_trait = "elona.perm_good" }, + -- params = { secret_treasure_trait = "elona.perm_good" }, elona_function = 29, is_precious = true, @@ -816,8 +816,8 @@ data:add { elona_function = 30, is_precious = true, - param1 = 446, - param2 = 300, + -- param1 = 446, + -- param2 = 300, cooldown_hours = 12, quality = Enum.Quality.Unique, @@ -843,8 +843,8 @@ data:add { elona_function = 30, is_precious = true, - param1 = 404, - param2 = 400, + -- param1 = 404, + -- param2 = 400, cooldown_hours = 8, quality = Enum.Quality.Unique, @@ -895,8 +895,8 @@ data:add { elona_function = 30, is_precious = true, - param1 = 1132, - param2 = 100, + -- param1 = 1132, + -- param2 = 100, cooldown_hours = 24, quality = Enum.Quality.Unique, @@ -1270,8 +1270,8 @@ data:add { elona_function = 30, is_precious = true, - param1 = 1132, - param2 = 100, + -- param1 = 1132, + -- param2 = 100, cooldown_hours = 24, color = { 255, 155, 155 }, @@ -1295,8 +1295,8 @@ data:add { elona_function = 30, is_precious = true, - param1 = 1132, - param2 = 100, + -- param1 = 1132, + -- param2 = 100, cooldown_hours = 24, color = { 255, 155, 155 }, @@ -1320,8 +1320,8 @@ data:add { elona_function = 30, is_precious = true, - param1 = 1132, - param2 = 100, + -- param1 = 1132, + -- param2 = 100, cooldown_hours = 24, color = { 255, 155, 155 }, @@ -1345,8 +1345,8 @@ data:add { elona_function = 30, is_precious = true, - param1 = 1132, - param2 = 100, + -- param1 = 1132, + -- param2 = 100, cooldown_hours = 24, color = { 255, 155, 155 }, diff --git a/src/mod/elona/data/item/tree.lua b/src/mod/elona/data/item/tree.lua index f1574e7ea..f96318cd9 100644 --- a/src/mod/elona/data/item/tree.lua +++ b/src/mod/elona/data/item/tree.lua @@ -15,7 +15,6 @@ data:add { image = "elona.item_tree_of_beech", value = 700, weight = 45000, - category = 80000, rarity = 3000000, coefficient = 100, originalnameref2 = "tree", @@ -31,7 +30,6 @@ data:add { image = "elona.item_tree_of_cedar", value = 500, weight = 38000, - category = 80000, rarity = 800000, coefficient = 100, originalnameref2 = "tree", @@ -48,7 +46,6 @@ data:add { value = 500, weight = 35000, fltselect = Enum.FltSelect.Sp, - category = 80000, rarity = 100000, coefficient = 100, originalnameref2 = "tree", @@ -65,7 +62,6 @@ data:add { image = "elona.item_tree_of_fruits", value = 2000, weight = 42000, - category = 80000, rarity = 100000, coefficient = 100, originalnameref2 = "tree", @@ -143,7 +139,6 @@ data:add { image = "elona.item_dead_tree", value = 500, weight = 20000, - category = 80000, rarity = 500000, coefficient = 100, categories = { @@ -158,7 +153,6 @@ data:add { image = "elona.item_tree_of_zelkova", value = 800, weight = 28000, - category = 80000, rarity = 1500000, coefficient = 100, originalnameref2 = "tree", @@ -174,7 +168,6 @@ data:add { image = "elona.item_tree_of_palm", value = 1000, weight = 39000, - category = 80000, rarity = 200000, coefficient = 100, originalnameref2 = "tree", @@ -190,7 +183,6 @@ data:add { image = "elona.item_tree_of_ash", value = 900, weight = 28000, - category = 80000, rarity = 500000, coefficient = 100, originalnameref2 = "tree", @@ -211,7 +203,6 @@ data:add { value = 500, weight = 14000, fltselect = Enum.FltSelect.Snow, - category = 80000, rarity = 250000, coefficient = 100, originalnameref2 = "tree", @@ -229,7 +220,6 @@ data:add { value = 1800, weight = 28000, fltselect = Enum.FltSelect.Snow, - category = 80000, rarity = 100000, coefficient = 100, originalnameref2 = "tree", @@ -248,7 +238,6 @@ data:add { weight = 35000, level = 30, fltselect = Enum.FltSelect.Snow, - category = 80000, rarity = 100000, coefficient = 100, categories = { diff --git a/src/mod/elona/data/item_type.lua b/src/mod/elona/data/item_type.lua index f76fc4557..9d5e14734 100644 --- a/src/mod/elona/data/item_type.lua +++ b/src/mod/elona/data/item_type.lua @@ -1,161 +1,161 @@ local categories = { { _id = "equip_melee", - ordering = 10000, + _ordering = 10000, is_major = true }, { _id = "equip_head", - ordering = 12000, + _ordering = 12000, is_major = true }, { _id = "equip_shield", - ordering = 14000, + _ordering = 14000, is_major = true }, { _id = "equip_body", - ordering = 16000, + _ordering = 16000, is_major = true }, { _id = "equip_leg", - ordering = 18000, + _ordering = 18000, is_major = true }, { _id = "equip_cloak", - ordering = 19000, + _ordering = 19000, is_major = true }, { _id = "equip_back", - ordering = 20000, + _ordering = 20000, is_major = true }, { _id = "equip_wrist", - ordering = 22000, + _ordering = 22000, is_major = true }, { _id = "equip_ranged", - ordering = 24000, + _ordering = 24000, is_major = true }, { _id = "equip_ammo", - ordering = 25000, + _ordering = 25000, is_major = true }, { _id = "equip_ring", - ordering = 32000, + _ordering = 32000, is_major = true }, { _id = "equip_neck", - ordering = 34000, + _ordering = 34000, is_major = true }, { _id = "drink", - ordering = 52000, + _ordering = 52000, is_major = true }, { _id = "scroll", - ordering = 53000, + _ordering = 53000, is_major = true }, { _id = "spellbook", - ordering = 54000, + _ordering = 54000, is_major = true }, { _id = "book", - ordering = 55000, + _ordering = 55000, is_major = true }, { _id = "rod", - ordering = 56000, + _ordering = 56000, is_major = true }, { _id = "food", - ordering = 57000, + _ordering = 57000, is_major = true }, { _id = "misc_item", - ordering = 59000, + _ordering = 59000, is_major = true }, { _id = "furniture", - ordering = 60000, + _ordering = 60000, is_major = true }, { _id = "furniture_well", - ordering = 60001, + _ordering = 60001, }, { _id = "furniture_altar", - ordering = 60002, + _ordering = 60002, is_major = true }, { _id = "remains", - ordering = 62000, + _ordering = 62000, is_major = true }, { _id = "junk", - ordering = 64000, + _ordering = 64000, is_major = true }, { _id = "gold", - ordering = 68000, + _ordering = 68000, is_major = true }, { _id = "platinum", - ordering = 69000, + _ordering = 69000, is_major = true }, { _id = "container", - ordering = 72000, + _ordering = 72000, is_major = true }, { _id = "ore", - ordering = 77000, + _ordering = 77000, is_major = true }, { _id = "tree", - ordering = 80000, + _ordering = 80000, is_major = true }, { _id = "cargo_food", - ordering = 91000, + _ordering = 91000, is_major = true }, { _id = "cargo", - ordering = 92000, + _ordering = 92000, is_major = true }, { _id = "bug", - ordering = 99999999, + _ordering = 99999999, parents = { "elona.bug" } @@ -169,312 +169,312 @@ local categories = { local subcategories = { { _id = "equip_melee_broadsword", - ordering = 10001, + _ordering = 10001, parents = { "elona.equip_melee" } }, { _id = "equip_melee_long_sword", - ordering = 10002, + _ordering = 10002, parents = { "elona.equip_melee" } }, { _id = "equip_melee_short_sword", - ordering = 10003, + _ordering = 10003, parents = { "elona.equip_melee" } }, { _id = "equip_melee_club", - ordering = 10004, + _ordering = 10004, parents = { "elona.equip_melee" } }, { _id = "equip_melee_hammer", - ordering = 10005, + _ordering = 10005, parents = { "elona.equip_melee" } }, { _id = "equip_melee_staff", - ordering = 10006, + _ordering = 10006, parents = { "elona.equip_melee" } }, { _id = "equip_melee_lance", - ordering = 10007, + _ordering = 10007, parents = { "elona.equip_melee" } }, { _id = "equip_melee_halberd", - ordering = 10008, + _ordering = 10008, parents = { "elona.equip_melee" } }, { _id = "equip_melee_hand_axe", - ordering = 10009, + _ordering = 10009, parents = { "elona.equip_melee" } }, { _id = "equip_melee_axe", - ordering = 10010, + _ordering = 10010, parents = { "elona.equip_melee" } }, { _id = "equip_melee_scythe", - ordering = 10011, + _ordering = 10011, parents = { "elona.equip_melee" } }, { _id = "equip_head_helm", - ordering = 12001, + _ordering = 12001, parents = { "elona.equip_head" } }, { _id = "equip_head_hat", - ordering = 12002, + _ordering = 12002, parents = { "elona.equip_head" } }, { _id = "equip_shield_shield", - ordering = 14003, + _ordering = 14003, parents = { "elona.equip_shield" } }, { _id = "equip_body_mail", - ordering = 16001, + _ordering = 16001, parents = { "elona.equip_body" } }, { _id = "equip_body_robe", - ordering = 16003, + _ordering = 16003, parents = { "elona.equip_body" } }, { _id = "equip_leg_heavy_boots", - ordering = 18001, + _ordering = 18001, parents = { "elona.equip_leg" } }, { _id = "equip_leg_shoes", - ordering = 18002, + _ordering = 18002, parents = { "elona.equip_leg" } }, { _id = "equip_back_girdle", - ordering = 19001, + _ordering = 19001, parents = { "elona.equip_cloak" } }, { _id = "equip_back_cloak", - ordering = 20001, + _ordering = 20001, parents = { "elona.equip_back" } }, { _id = "equip_wrist_gauntlet", - ordering = 22001, + _ordering = 22001, parents = { "elona.equip_wrist" } }, { _id = "equip_wrist_glove", - ordering = 22003, + _ordering = 22003, parents = { "elona.equip_wrist" } }, { _id = "equip_ranged_bow", - ordering = 24001, + _ordering = 24001, parents = { "elona.equip_ranged" } }, { _id = "equip_ranged_crossbow", - ordering = 24003, + _ordering = 24003, parents = { "elona.equip_ranged" } }, { _id = "equip_ranged_gun", - ordering = 24020, + _ordering = 24020, parents = { "elona.equip_ranged" } }, { _id = "equip_ranged_laser_gun", - ordering = 24021, + _ordering = 24021, parents = { "elona.equip_ranged" } }, { _id = "equip_ranged_thrown", - ordering = 24030, + _ordering = 24030, parents = { "elona.equip_ranged" } }, { _id = "equip_ammo_arrow", - ordering = 25001, + _ordering = 25001, parents = { "elona.equip_ammo" } }, { _id = "equip_ammo_bolt", - ordering = 25002, + _ordering = 25002, parents = { "elona.equip_ammo" } }, { _id = "equip_ammo_bullet", - ordering = 25020, + _ordering = 25020, parents = { "elona.equip_ammo" } }, { _id = "equip_ammo_energy_cell", - ordering = 25030, + _ordering = 25030, parents = { "elona.equip_ammo" } }, { _id = "equip_ring_ring", - ordering = 32001, + _ordering = 32001, parents = { "elona.equip_ring" } }, { _id = "equip_neck_armor", - ordering = 34001, + _ordering = 34001, parents = { "elona.equip_neck" } }, { _id = "drink_potion", - ordering = 52001, + _ordering = 52001, parents = { "elona.drink" } }, { _id = "drink_alcohol", - ordering = 52002, + _ordering = 52002, parents = { "elona.drink" } }, { _id = "scroll_deed", - ordering = 53100, + _ordering = 53100, parents = { "elona.scroll" } }, { _id = "food_flour", - ordering = 57001, + _ordering = 57001, parents = { "elona.food" } }, { _id = "food_noodle", - ordering = 57002, + _ordering = 57002, parents = { "elona.food" } }, { _id = "food_vegetable", - ordering = 57003, + _ordering = 57003, parents = { "elona.food" } }, { _id = "food_fruit", - ordering = 57004, + _ordering = 57004, parents = { "elona.food" } }, { _id = "crop_herb", - ordering = 58005, + _ordering = 58005, parents = { "elona.food" } }, { _id = "crop_seed", - ordering = 58500, + _ordering = 58500, parents = { "elona.food" } }, { _id = "misc_item_crafting", - ordering = 59500, + _ordering = 59500, parents = { "elona.misc_item" } }, { _id = "furniture_bed", -- sleeping bag/furniture - ordering = 60004, -- sleeping bag/furniture + _ordering = 60004, -- sleeping bag/furniture }, { _id = "furniture_instrument", - ordering = 60005, + _ordering = 60005, parents = { "elona.furniture" } @@ -483,18 +483,18 @@ local subcategories = { -- This is only used to generate items that appear in random -- overworld field maps. _id = "junk_in_field", -- subcategory 64000 - ordering = 64000, -- subcategory 64000 + _ordering = 64000, -- subcategory 64000 }, { _id = "junk_town", - ordering = 64100, + _ordering = 64100, parents = { "elona.junk" } }, { _id = "ore_valuable", - ordering = 77001, + _ordering = 77001, parents = { "elona.ore" } diff --git a/src/mod/elona/data/journal_page.lua b/src/mod/elona/data/journal_page.lua index 8b2661a89..b9293ed4d 100644 --- a/src/mod/elona/data/journal_page.lua +++ b/src/mod/elona/data/journal_page.lua @@ -10,7 +10,7 @@ data:add { _type = "base.journal_page", _id = "news", - ordering = 40000, + _ordering = 40000, render = function() -- >>>>>>>> shade2/command.hsp:907 buff=newsBuff ... @@ -83,7 +83,7 @@ data:add { _type = "base.journal_page", _id = "quest", - ordering = 45000, + _ordering = 45000, render = function() local main_quest_infos = Sidequest.iter_active_main_quests() @@ -157,7 +157,7 @@ data:add { _type = "base.journal_page", _id = "quest_item", - ordering = 50000, + _ordering = 50000, render = function() local quest_item_infos = get_quest_item_infos() @@ -201,7 +201,7 @@ data:add { _type = "base.journal_page", _id = "title_and_ranking", - ordering = 55000, + _ordering = 55000, render = function() -- >>>>>>>> shade2/command.hsp:951 noteadd " - Title & Ranking - ":noteadd "" ... @@ -238,7 +238,7 @@ data:add { _type = "base.journal_page", _id = "income_and_expense", - ordering = 60000, + _ordering = 60000, render = function() -- >>>>>>>> shade2/command.hsp:973 noteadd " - Income & Expense - ":noteadd "" ... @@ -288,7 +288,7 @@ data:add { _type = "base.journal_page", _id = "completed_quests", - ordering = 65000, + _ordering = 65000, render = function() local sub_quest_infos = Sidequest.iter_active_sub_quests() diff --git a/src/mod/elona/data/material_spot.lua b/src/mod/elona/data/material_spot.lua index b96c7e7c1..10b085e6d 100644 --- a/src/mod/elona/data/material_spot.lua +++ b/src/mod/elona/data/material_spot.lua @@ -47,7 +47,7 @@ data:add { is_solid = false, is_opaque = false, - params = { material_spot_info = "string" }, + params = { material_spot_info = types.data_id("elona.material_spot_feat_info") }, on_stepped_on = function(self, params) if params.chara:is_player() then diff --git a/src/mod/elona/data/quest/collect.lua b/src/mod/elona/data/quest/collect.lua index b088d9f18..c9e837e78 100644 --- a/src/mod/elona/data/quest/collect.lua +++ b/src/mod/elona/data/quest/collect.lua @@ -15,9 +15,9 @@ local Enum = require("api.Enum") local collect = { _id = "collect", _type = "elona_sys.quest", + _ordering = 10000, elona_id = 1011, - ordering = 10000, client_chara_type = 3, reward = "elona.supply", reward_fix = 60, diff --git a/src/mod/elona/data/quest/conquer.lua b/src/mod/elona/data/quest/conquer.lua index 227cb24b2..74d04f69e 100644 --- a/src/mod/elona/data/quest/conquer.lua +++ b/src/mod/elona/data/quest/conquer.lua @@ -12,9 +12,9 @@ local Gui = require("api.Gui") local conquer = { _id = "conquer", _type = "elona_sys.quest", + _ordering = 30000, elona_id = 1008, - ordering = 30000, client_chara_type = 8, reward = "elona.wear", reward_fix = 175, @@ -22,7 +22,7 @@ local conquer = { min_fame = 50000, chance = 20, - params = { enemy_id = "string" }, + params = { enemy_id = types.data_id("base.chara") }, reward_count = function() return Rand.rnd(Rand.rnd(4) + 1) + 3 end, diff --git a/src/mod/elona/data/quest/cook.lua b/src/mod/elona/data/quest/cook.lua index e1bb49de6..77ce1b965 100644 --- a/src/mod/elona/data/quest/cook.lua +++ b/src/mod/elona/data/quest/cook.lua @@ -13,9 +13,9 @@ local IItemFood = require("mod.elona.api.aspect.IItemFood") local cook = { _id = "cook", _type = "elona_sys.quest", + _ordering = 90000, elona_id = 1003, - ordering = 90000, client_chara_type = 3, reward = "elona.supply", reward_fix = 60, @@ -24,8 +24,8 @@ local cook = { chance = 6, params = { - food_type = "string", - food_quality = "number" + food_type = types.string, + food_quality = types.uint }, difficulty = 0, diff --git a/src/mod/elona/data/quest/deliver.lua b/src/mod/elona/data/quest/deliver.lua index ec3810923..fc504d34b 100644 --- a/src/mod/elona/data/quest/deliver.lua +++ b/src/mod/elona/data/quest/deliver.lua @@ -18,9 +18,9 @@ local Effect = require("mod.elona.api.Effect") local deliver = { _id = "deliver", _type = "elona_sys.quest", + _ordering = 80000, elona_id = 1002, - ordering = 80000, client_chara_type = 2, reward = "elona.supply", reward_fix = 70, diff --git a/src/mod/elona/data/quest/escort.lua b/src/mod/elona/data/quest/escort.lua index a1909ad02..21909a794 100644 --- a/src/mod/elona/data/quest/escort.lua +++ b/src/mod/elona/data/quest/escort.lua @@ -45,9 +45,9 @@ end local escort = { _id = "escort", _type = "elona_sys.quest", + _ordering = 40000, elona_id = 1007, - ordering = 40000, client_chara_type = 6, reward = "elona.supply", reward_fix = 140, diff --git a/src/mod/elona/data/quest/harvest.lua b/src/mod/elona/data/quest/harvest.lua index b4075dbde..675192e15 100644 --- a/src/mod/elona/data/quest/harvest.lua +++ b/src/mod/elona/data/quest/harvest.lua @@ -78,9 +78,9 @@ end local harvest = { _id = "harvest", _type = "elona_sys.quest", + _ordering = 60000, elona_id = 1006, - ordering = 60000, client_chara_type = 5, reward = "elona.supply", reward_fix = 60, @@ -94,7 +94,7 @@ local harvest = { return 30 end, - params = { required_weight = "number", current_weight = "number" }, + params = { required_weight = types.number, current_weight = types.number }, difficulty = function() return math.clamp(Rand.rnd(Chara.player():calc("level") + 5) + diff --git a/src/mod/elona/data/quest/hunt.lua b/src/mod/elona/data/quest/hunt.lua index bc2364587..cc3181c7a 100644 --- a/src/mod/elona/data/quest/hunt.lua +++ b/src/mod/elona/data/quest/hunt.lua @@ -10,9 +10,9 @@ local Event = require("api.Event") local hunt = { _id = "hunt", _type = "elona_sys.quest", + _ordering = 70000, elona_id = 1001, - ordering = 70000, client_chara_type = 1, reward = "elona.wear", reward_fix = 135, diff --git a/src/mod/elona/data/quest/huntex.lua b/src/mod/elona/data/quest/huntex.lua index 82a23fae4..87f9354e9 100644 --- a/src/mod/elona/data/quest/huntex.lua +++ b/src/mod/elona/data/quest/huntex.lua @@ -30,9 +30,9 @@ data:add(quest_huntex) local huntex = { _id = "huntex", _type = "elona_sys.quest", + _ordering = 20000, elona_id = 1010, - ordering = 20000, client_chara_type = 1, reward = "elona.supply", reward_fix = 140, @@ -40,7 +40,7 @@ local huntex = { min_fame = 30000, chance = 13, - params = { enemy_id = "string" }, + params = { enemy_id = types.data_id("base.chara") }, reward_count = function() return Rand.rnd(Rand.rnd(4) + 1) + 3 end, diff --git a/src/mod/elona/data/quest/party.lua b/src/mod/elona/data/quest/party.lua index 7951641ca..1b156d6d5 100644 --- a/src/mod/elona/data/quest/party.lua +++ b/src/mod/elona/data/quest/party.lua @@ -43,9 +43,9 @@ data:add(map_party) local party = { _id = "party", _type = "elona_sys.quest", + _ordering = 50000, elona_id = 1009, - ordering = 50000, client_chara_type = 7, reward = nil, reward_fix = 0, @@ -59,7 +59,7 @@ local party = { return 23 end, - params = { required_points = "number" }, + params = { required_points = types.number }, difficulty = function() local performer_skill = Chara.player():skill_level("elona.performer") diff --git a/src/mod/elona/data/quest/supply.lua b/src/mod/elona/data/quest/supply.lua index 39cd7d402..47e4a8182 100644 --- a/src/mod/elona/data/quest/supply.lua +++ b/src/mod/elona/data/quest/supply.lua @@ -13,9 +13,9 @@ local ElonaItem = require("mod.elona.api.ElonaItem") local supply = { _id = "supply", _type = "elona_sys.quest", + _ordering = 100000, elona_id = 1004, - ordering = 100000, client_chara_type = 3, reward = "elona.supply", reward_fix = 65, @@ -24,7 +24,7 @@ local supply = { chance = 5, params = { - target_item_id = "string" + target_item_id = types.data_id("base.item") }, difficulty = function() return math.clamp(Rand.rnd(Chara.player():calc("level") + 5) + 1, 1, 30) end, diff --git a/src/mod/elona/data/quest_reward.lua b/src/mod/elona/data/quest_reward.lua index 7b0c42f66..eb6285609 100644 --- a/src/mod/elona/data/quest_reward.lua +++ b/src/mod/elona/data/quest_reward.lua @@ -62,7 +62,7 @@ data:add { data:add { _id = "by_category", _type = "elona_sys.quest_reward", - params = { category = "string" }, + params = { category = types.data_id("base.item_type") }, generate = function(self, quest) return mkgenerate({self.category})(self, quest) end, diff --git a/src/mod/elona/data/race.lua b/src/mod/elona/data/race.lua index 06f04b4b2..e3ae84eb9 100644 --- a/src/mod/elona/data/race.lua +++ b/src/mod/elona/data/race.lua @@ -3,7 +3,7 @@ local race = { _id = "kobold", is_extra = true, - ordering = 20010, + _ordering = 20010, elona_id = 1, properties = { @@ -51,7 +51,7 @@ local race = { _id = "orc", is_extra = true, - ordering = 20020, + _ordering = 20020, elona_id = 2, properties = { @@ -98,7 +98,7 @@ local race = { _id = "troll", is_extra = true, - ordering = 20030, + _ordering = 20030, elona_id = 3, properties = { @@ -142,7 +142,7 @@ local race = { _id = "lizardman", is_extra = true, - ordering = 20040, + _ordering = 20040, elona_id = 4, properties = { @@ -190,7 +190,7 @@ local race = { _id = "minotaur", is_extra = true, - ordering = 20050, + _ordering = 20050, elona_id = 5, properties = { @@ -234,7 +234,7 @@ local race = { _id = "yerles", is_extra = false, - ordering = 10010, + _ordering = 10010, elona_id = 6, properties = { @@ -289,7 +289,7 @@ local race = { _id = "norland", is_extra = true, - ordering = 20060, + _ordering = 20060, elona_id = 7, properties = { @@ -340,7 +340,7 @@ local race = { _id = "eulderna", is_extra = false, - ordering = 10020, + _ordering = 10020, elona_id = 8, properties = { @@ -394,7 +394,7 @@ local race = { _id = "fairy", is_extra = false, - ordering = 10030, + _ordering = 10030, elona_id = 9, properties = { @@ -458,7 +458,7 @@ local race = { _id = "asura", is_extra = true, - ordering = 20070, + _ordering = 20070, elona_id = 10, properties = { @@ -501,7 +501,7 @@ local race = { _id = "slime", is_extra = true, - ordering = 20080, + _ordering = 20080, elona_id = 11, properties = { @@ -540,7 +540,7 @@ local race = { _id = "wolf", is_extra = true, - ordering = 20090, + _ordering = 20090, elona_id = 12, properties = { @@ -583,7 +583,7 @@ local race = { _id = "dwarf", is_extra = false, - ordering = 10040, + _ordering = 10040, elona_id = 13, properties = { @@ -636,7 +636,7 @@ local race = { _id = "juere", is_extra = false, - ordering = 10050, + _ordering = 10050, elona_id = 14, properties = { @@ -691,7 +691,7 @@ local race = { _id = "zombie", is_extra = true, - ordering = 20100, + _ordering = 20100, elona_id = 15, properties = { @@ -741,7 +741,7 @@ local race = { _id = "elea", is_extra = false, - ordering = 10060, + _ordering = 10060, elona_id = 16, properties = { @@ -795,7 +795,7 @@ local race = { _id = "rabbit", is_extra = true, - ordering = 20110, + _ordering = 20110, elona_id = 17, properties = { @@ -835,7 +835,7 @@ local race = { _id = "sheep", is_extra = true, - ordering = 20120, + _ordering = 20120, elona_id = 18, properties = { @@ -877,7 +877,7 @@ local race = { _id = "frog", is_extra = true, - ordering = 20130, + _ordering = 20130, elona_id = 19, properties = { @@ -914,7 +914,7 @@ local race = { _id = "centipede", is_extra = true, - ordering = 20140, + _ordering = 20140, elona_id = 20, properties = { @@ -952,7 +952,7 @@ local race = { _id = "snail", is_extra = false, - ordering = 10070, + _ordering = 10070, elona_id = 21, properties = { @@ -988,7 +988,7 @@ local race = { _id = "mandrake", is_extra = true, - ordering = 20150, + _ordering = 20150, elona_id = 22, properties = { @@ -1027,7 +1027,7 @@ local race = { _id = "beetle", is_extra = true, - ordering = 20160, + _ordering = 20160, elona_id = 23, properties = { @@ -1065,7 +1065,7 @@ local race = { _id = "mushroom", is_extra = true, - ordering = 20170, + _ordering = 20170, elona_id = 24, properties = { @@ -1105,7 +1105,7 @@ local race = { _id = "bat", is_extra = true, - ordering = 20180, + _ordering = 20180, elona_id = 25, properties = { @@ -1143,7 +1143,7 @@ local race = { _id = "ent", is_extra = true, - ordering = 20190, + _ordering = 20190, elona_id = 26, properties = { @@ -1184,7 +1184,7 @@ local race = { _id = "lich", is_extra = false, - ordering = 10080, + _ordering = 10080, elona_id = 27, properties = { @@ -1246,7 +1246,7 @@ local race = { _id = "hound", is_extra = true, - ordering = 20200, + _ordering = 20200, elona_id = 28, properties = { @@ -1289,7 +1289,7 @@ local race = { _id = "ghost", is_extra = true, - ordering = 20210, + _ordering = 20210, elona_id = 29, properties = { @@ -1341,7 +1341,7 @@ local race = { _id = "spirit", is_extra = true, - ordering = 20220, + _ordering = 20220, elona_id = 30, properties = { @@ -1385,7 +1385,7 @@ local race = { _id = "eye", is_extra = true, - ordering = 20230, + _ordering = 20230, elona_id = 31, properties = { @@ -1423,7 +1423,7 @@ local race = { _id = "wyvern", is_extra = true, - ordering = 20240, + _ordering = 20240, elona_id = 32, properties = { @@ -1464,7 +1464,7 @@ local race = { _id = "wasp", is_extra = true, - ordering = 20250, + _ordering = 20250, elona_id = 33, properties = { @@ -1502,7 +1502,7 @@ local race = { _id = "giant", is_extra = true, - ordering = 20260, + _ordering = 20260, elona_id = 34, properties = { @@ -1545,7 +1545,7 @@ local race = { _id = "imp", is_extra = true, - ordering = 20270, + _ordering = 20270, elona_id = 35, properties = { @@ -1590,7 +1590,7 @@ local race = { _id = "hand", is_extra = true, - ordering = 20280, + _ordering = 20280, elona_id = 36, properties = { @@ -1630,7 +1630,7 @@ local race = { _id = "snake", is_extra = true, - ordering = 20290, + _ordering = 20290, elona_id = 37, properties = { @@ -1667,7 +1667,7 @@ local race = { _id = "drake", is_extra = true, - ordering = 20300, + _ordering = 20300, elona_id = 38, properties = { @@ -1709,7 +1709,7 @@ local race = { _id = "goblin", is_extra = false, - ordering = 10090, + _ordering = 10090, elona_id = 39, properties = { @@ -1763,7 +1763,7 @@ local race = { _id = "bear", is_extra = true, - ordering = 20310, + _ordering = 20310, elona_id = 40, properties = { @@ -1808,7 +1808,7 @@ local race = { _id = "armor", is_extra = true, - ordering = 20320, + _ordering = 20320, elona_id = 41, properties = { @@ -1854,7 +1854,7 @@ local race = { _id = "medusa", is_extra = true, - ordering = 20330, + _ordering = 20330, elona_id = 42, properties = { @@ -1898,7 +1898,7 @@ local race = { _id = "cupid", is_extra = true, - ordering = 20340, + _ordering = 20340, elona_id = 43, properties = { @@ -1942,7 +1942,7 @@ local race = { _id = "phantom", is_extra = true, - ordering = 20350, + _ordering = 20350, elona_id = 44, properties = { breed_power = 35, @@ -1992,7 +1992,7 @@ local race = { _id = "harpy", is_extra = true, - ordering = 20360, + _ordering = 20360, elona_id = 45, properties = { breed_power = 420, @@ -2036,7 +2036,7 @@ local race = { _id = "dragon", is_extra = true, - ordering = 20370, + _ordering = 20370, elona_id = 46, properties = { @@ -2078,7 +2078,7 @@ local race = { _id = "dinosaur", is_extra = true, - ordering = 20380, + _ordering = 20380, elona_id = 47, properties = { @@ -2120,7 +2120,7 @@ local race = { _id = "cerberus", is_extra = true, - ordering = 20390, + _ordering = 20390, elona_id = 48, properties = { @@ -2164,7 +2164,7 @@ local race = { _id = "spider", is_extra = true, - ordering = 20400, + _ordering = 20400, elona_id = 49, properties = { @@ -2208,7 +2208,7 @@ local race = { _id = "golem", is_extra = false, - ordering = 10100, + _ordering = 10100, elona_id = 50, properties = { @@ -2270,7 +2270,7 @@ local race = { _id = "rock", is_extra = true, - ordering = 20410, + _ordering = 20410, elona_id = 51, properties = { @@ -2309,7 +2309,7 @@ local race = { _id = "crab", is_extra = true, - ordering = 20420, + _ordering = 20420, elona_id = 52, properties = { @@ -2353,7 +2353,7 @@ local race = { _id = "skeleton", is_extra = true, - ordering = 20430, + _ordering = 20430, elona_id = 53, properties = { @@ -2408,7 +2408,7 @@ local race = { _id = "piece", is_extra = true, - ordering = 20440, + _ordering = 20440, elona_id = 54, properties = { @@ -2456,7 +2456,7 @@ local race = { _id = "cat", is_extra = true, - ordering = 20450, + _ordering = 20450, elona_id = 55, properties = { @@ -2503,7 +2503,7 @@ local race = { _id = "dog", is_extra = true, - ordering = 20460, + _ordering = 20460, elona_id = 56, properties = { @@ -2548,7 +2548,7 @@ local race = { _id = "roran", is_extra = true, - ordering = 20470, + _ordering = 20470, elona_id = 57, properties = { @@ -2597,7 +2597,7 @@ local race = { _id = "rat", is_extra = true, - ordering = 20480, + _ordering = 20480, elona_id = 58, properties = { @@ -2639,7 +2639,7 @@ local race = { _id = "shell", is_extra = true, - ordering = 20490, + _ordering = 20490, elona_id = 59, properties = { @@ -2678,7 +2678,7 @@ local race = { _id = "catgod", is_extra = true, - ordering = 20500, + _ordering = 20500, elona_id = 60, properties = { @@ -2724,7 +2724,7 @@ local race = { _id = "machinegod", is_extra = true, - ordering = 20510, + _ordering = 20510, elona_id = 61, properties = { @@ -2769,7 +2769,7 @@ local race = { _id = "undeadgod", is_extra = true, - ordering = 20520, + _ordering = 20520, elona_id = 62, properties = { @@ -2812,7 +2812,7 @@ local race = { _id = "machine", is_extra = true, - ordering = 20530, + _ordering = 20530, elona_id = 63, properties = { @@ -2862,7 +2862,7 @@ local race = { _id = "wisp", is_extra = true, - ordering = 20540, + _ordering = 20540, elona_id = 64, properties = { @@ -2900,7 +2900,7 @@ local race = { _id = "chicken", is_extra = true, - ordering = 20550, + _ordering = 20550, elona_id = 65, properties = { @@ -2938,7 +2938,7 @@ local race = { _id = "stalker", is_extra = true, - ordering = 20560, + _ordering = 20560, elona_id = 66, properties = { @@ -2988,7 +2988,7 @@ local race = { _id = "catsister", is_extra = true, - ordering = 20570, + _ordering = 20570, elona_id = 67, properties = { @@ -3036,7 +3036,7 @@ local race = { _id = "mutant", is_extra = false, - ordering = 10110, + _ordering = 10110, elona_id = 68, properties = { @@ -3078,7 +3078,7 @@ local race = { _id = "yeek", is_extra = true, - ordering = 20580, + _ordering = 20580, elona_id = 69, properties = { @@ -3125,7 +3125,7 @@ local race = { _id = "yith", is_extra = true, - ordering = 20590, + _ordering = 20590, elona_id = 70, properties = { @@ -3172,7 +3172,7 @@ local race = { _id = "servant", is_extra = true, - ordering = 20600, + _ordering = 20600, elona_id = 71, properties = { @@ -3224,7 +3224,7 @@ local race = { _id = "horse", is_extra = true, - ordering = 20610, + _ordering = 20610, elona_id = 72, properties = { @@ -3263,7 +3263,7 @@ local race = { _id = "god", is_extra = true, - ordering = 20620, + _ordering = 20620, elona_id = 73, properties = { @@ -3309,7 +3309,7 @@ local race = { _id = "quickling", is_extra = true, - ordering = 20630, + _ordering = 20630, elona_id = 74, properties = { @@ -3359,7 +3359,7 @@ local race = { _id = "metal", is_extra = true, - ordering = 20640, + _ordering = 20640, elona_id = 75, properties = { @@ -3405,7 +3405,7 @@ local race = { _id = "bike", is_extra = true, - ordering = 20650, + _ordering = 20650, elona_id = 76, properties = { @@ -3453,7 +3453,7 @@ local race = -- For debug { _id = "slug", - ordering = 0, + _ordering = 0, is_extra = true, properties = { diff --git a/src/mod/elona/data/rank.lua b/src/mod/elona/data/rank.lua index febb4333d..f054729d8 100644 --- a/src/mod/elona/data/rank.lua +++ b/src/mod/elona/data/rank.lua @@ -3,17 +3,11 @@ data:add_type { fields = {} } -local function order(elona_id) - return 100000 + elona_id * 10000 -end - data:add { _type = "elona.rank", _id = "arena", elona_id = 0, - ordering = order(0), - -- >>>>>>>> shade2/init.hsp:1924 rankNorma(rankArena) =20 ... decay_period_days = 20, -- <<<<<<<< shade2/init.hsp:1924 rankNorma(rankArena) =20 .. @@ -32,8 +26,6 @@ data:add { _id = "pet_arena", elona_id = 1, - ordering = order(1), - -- >>>>>>>> shade2/init.hsp:1925 rankNorma(rankPetArena) =60 ... decay_period_days = 60, -- <<<<<<<< shade2/init.hsp:1925 rankNorma(rankPetArena) =60 .. @@ -52,8 +44,6 @@ data:add { _id = "crawler", elona_id = 2, - ordering = order(2), - -- >>>>>>>> shade2/init.hsp:1926 rankNorma(rankCrawler) =45 ... decay_period_days = 45, -- <<<<<<<< shade2/init.hsp:1926 rankNorma(rankCrawler) =45 .. @@ -72,8 +62,6 @@ data:add { _id = "museum", elona_id = 3, - ordering = order(3), - -- >>>>>>>> shade2/event.hsp:447 if (cnt=rankShop)or(cnt=rankVote)or(cnt=rankMuseu ... provides_salary_items = false, -- <<<<<<<< shade2/event.hsp:447 if (cnt=rankShop)or(cnt=rankVote)or(cnt=rankMuseu .. @@ -84,8 +72,6 @@ data:add { _id = "home", elona_id = 4, - ordering = order(4), - calc_income = function(income) -- >>>>>>>> shade2/event.hsp:413 if r=rankHome :p=p*60/100 ... return income * 60 / 100 @@ -100,8 +86,6 @@ data:add { _id = "shop", elona_id = 5, - ordering = order(5), - -- >>>>>>>> shade2/event.hsp:447 if (cnt=rankShop)or(cnt=rankVote)or(cnt=rankMuseu ... provides_salary_items = false, -- <<<<<<<< shade2/event.hsp:447 if (cnt=rankShop)or(cnt=rankVote)or(cnt=rankMuseu .. @@ -118,8 +102,6 @@ data:add { _id = "vote", elona_id = 6, - ordering = order(6), - -- >>>>>>>> shade2/init.hsp:1927 rankNorma(rankVote) =30 ... decay_period_days = 30, -- <<<<<<<< shade2/init.hsp:1927 rankNorma(rankVote) =30 .. @@ -141,8 +123,6 @@ data:add { elona_id = 7, provides_salary_items = true, - - ordering = order(7), } data:add { @@ -151,6 +131,4 @@ data:add { elona_id = 8, provides_salary_items = true, - - ordering = order(8), } diff --git a/src/mod/elona/data/sidequest.lua b/src/mod/elona/data/sidequest.lua index 0e2b43db1..2ad4f62a9 100755 --- a/src/mod/elona/data/sidequest.lua +++ b/src/mod/elona/data/sidequest.lua @@ -8,7 +8,7 @@ data:add { _type = "elona_sys.sidequest", _id = "tutorial", elona_id = 0, - ordering = order(0), + _ordering = order(0), progress = { [1] = "", @@ -28,7 +28,7 @@ data:add { _type = "elona_sys.sidequest", _id = "main_quest", elona_id = 2, - ordering = order(2), + _ordering = order(2), is_main_quest = true, @@ -50,7 +50,7 @@ data:add { _type = "elona_sys.sidequest", _id = "putit_attacks", elona_id = 200, - ordering = order(200), + _ordering = order(200), progress = { [1] = "sidequest._.elona.putit_attacks.progress._0", @@ -63,7 +63,7 @@ data:add { _type = "elona_sys.sidequest", _id = "thieves_hideout", elona_id = 201, - ordering = order(201), + _ordering = order(201), progress = { [1] = "sidequest._.elona.thieves_hideout.progress._0", @@ -76,7 +76,7 @@ data:add { _type = "elona_sys.sidequest", _id = "nightmare", elona_id = 202, - ordering = order(202), + _ordering = order(202), progress = { [1] = "sidequest._.elona.nightmare.progress._0", @@ -90,7 +90,7 @@ data:add { _type = "elona_sys.sidequest", _id = "pael_and_her_mom", elona_id = 203, - ordering = order(203), + _ordering = order(203), progress = { [1] = "sidequest._.elona.pael_and_her_mom.progress._0", @@ -111,7 +111,7 @@ data:add { _type = "elona_sys.sidequest", _id = "wife_collector", elona_id = 204, - ordering = order(204), + _ordering = order(204), progress = { [1] = "sidequest._.elona.wife_collector.progress._0", @@ -123,7 +123,7 @@ data:add { _type = "elona_sys.sidequest", _id = "puppys_cave", elona_id = 205, - ordering = order(205), + _ordering = order(205), progress = { [1] = "sidequest._.elona.puppys_cave.progress._0", @@ -136,7 +136,7 @@ data:add { _type = "elona_sys.sidequest", _id = "cat_house", elona_id = 206, - ordering = order(206), + _ordering = order(206), progress = { [1] = "sidequest._.elona.cat_house.progress._0", @@ -149,7 +149,7 @@ data:add { _type = "elona_sys.sidequest", _id = "defense_line", elona_id = 207, - ordering = order(207), + _ordering = order(207), progress = { [1] = "sidequest._.elona.defense_line.progress._0", @@ -163,7 +163,7 @@ data:add { _type = "elona_sys.sidequest", _id = "novice_knight", elona_id = 208, - ordering = order(208), + _ordering = order(208), progress = { [1] = "sidequest._.elona.novice_knight.progress._0", @@ -176,7 +176,7 @@ data:add { _type = "elona_sys.sidequest", _id = "kamikaze_attack", elona_id = 209, - ordering = order(209), + _ordering = order(209), progress = { [1] = "sidequest._.elona.kamikaze_attack.progress._0", @@ -190,7 +190,7 @@ data:add { _type = "elona_sys.sidequest", _id = "mias_dream", elona_id = 210, - ordering = order(210), + _ordering = order(210), progress = { [1] = "sidequest._.elona.mias_dream.progress._0", @@ -202,7 +202,7 @@ data:add { _type = "elona_sys.sidequest", _id = "rare_books", elona_id = 211, - ordering = order(211), + _ordering = order(211), progress = { [1] = "sidequest._.elona.rare_books.progress._0", @@ -214,7 +214,7 @@ data:add { _type = "elona_sys.sidequest", _id = "pyramid_trial", elona_id = 212, - ordering = order(212), + _ordering = order(212), progress = { [1] = "sidequest._.elona.pyramid_trial.progress._0", @@ -226,7 +226,7 @@ data:add { _type = "elona_sys.sidequest", _id = "red_blossom_in_palmia", elona_id = 213, - ordering = order(213), + _ordering = order(213), progress = { [1] = "sidequest._.elona.red_blossom_in_palmia.progress._0", @@ -239,7 +239,7 @@ data:add { _type = "elona_sys.sidequest", _id = "ambitious_scientist", elona_id = 214, - ordering = order(214), + _ordering = order(214), progress = { [1] = function(flag) @@ -255,7 +255,7 @@ data:add { _type = "elona_sys.sidequest", _id = "sewer_sweeping", elona_id = 215, - ordering = order(215), + _ordering = order(215), progress = { [1] = "sidequest._.elona.sewer_sweeping.progress._0", @@ -268,7 +268,7 @@ data:add { _type = "elona_sys.sidequest", _id = "minotaur_king", elona_id = 222, - ordering = order(222), + _ordering = order(222), progress = { [1] = "sidequest._.elona.minotaur_king.progress._0", @@ -281,7 +281,7 @@ data:add { _type = "elona_sys.sidequest", _id = "little_sister", elona_id = 223, - ordering = order(223), + _ordering = order(223), progress = { [1] = "sidequest._.elona.little_sister.progress._0", @@ -293,5 +293,5 @@ data:add { _type = "elona_sys.sidequest", _id = "kaneda_bike", elona_id = 224, - ordering = order(224), + _ordering = order(224), } diff --git a/src/mod/elona/data/trait_indicator.lua b/src/mod/elona/data/trait_indicator.lua index b0429b8b5..295097c30 100644 --- a/src/mod/elona/data/trait_indicator.lua +++ b/src/mod/elona/data/trait_indicator.lua @@ -4,8 +4,6 @@ data:add { _type = "base.trait_indicator", _id = "incognito", - ordering = 100000, - -- >>>>>>>> shade2/command.hsp:746 traitExtra cIncognito, lang("あなたは変装している","You are ... applies_to = function(chara) return chara:calc("is_anorexic") @@ -23,8 +21,6 @@ data:add { _type = "base.trait_indicator", _id = "pregnant", - ordering = 110000, - -- >>>>>>>> shade2/command.hsp:747 traitExtra cPregnant, lang("あなたは寄生されている","You are ... applies_to = function(chara) return chara:calc("is_pregnant") @@ -42,8 +38,6 @@ data:add { _type = "base.trait_indicator", _id = "anorexia", - ordering = 120000, - -- >>>>>>>> shade2/command.hsp:748 traitExtra cAnorexia, lang("あなたは拒食症だ","You have a ... applies_to = function(chara) return chara:calc("is_anorexic") @@ -61,8 +55,6 @@ data:add { _type = "base.trait_indicator", _id = "body_is_complicated", - ordering = 130000, - -- >>>>>>>> shade2/command.hsp:751 if cBodySpdFix(tc)!0{ ... applies_to = function(chara) -- TODO gene engineer @@ -83,8 +75,6 @@ data:add { _type = "base.trait_indicator", _id = "ether_disease_speed", - ordering = 140000, - -- >>>>>>>> shade2/command.hsp:746 traitExtra cIncognito, lang("あなたは変装している","You are ... applies_to = function(chara) return chara:calc("ether_disease_speed") ~= 0 diff --git a/src/mod/elona_sys/api/Command.lua b/src/mod/elona_sys/api/Command.lua index 16f8c4cee..9d653584f 100644 --- a/src/mod/elona_sys/api/Command.lua +++ b/src/mod/elona_sys/api/Command.lua @@ -483,15 +483,11 @@ function Command.interact(player) end function Command.journal(player) - local sort = function(a, b) - return a.ordering < b.ordering - end - local render = function(page) return page.render() end - local pages = data["base.journal_page"]:iter():into_sorted(sort):map(render):to_list() + local pages = data["base.journal_page"]:iter():map(render):to_list() -- TODO icon bar wrapper JournalMenu:new(pages):query() diff --git a/src/mod/elona_sys/api/Compat.lua b/src/mod/elona_sys/api/Compat.lua index eeee1a98a..5b7d10c9a 100644 --- a/src/mod/elona_sys/api/Compat.lua +++ b/src/mod/elona_sys/api/Compat.lua @@ -40,7 +40,7 @@ end function Compat.convert_122_item_category(category) assert(category) - return data["base.item_type"]:iter():filter(function(i) return i.ordering == category end):extract("_id"):nth(1) + return data["base.item_type"]:iter():filter(function(i) return i._ordering == category end):extract("_id"):nth(1) end local COLORS = { diff --git a/src/mod/elona_sys/api/Quest.lua b/src/mod/elona_sys/api/Quest.lua index 7c5d9078c..c8112d71b 100644 --- a/src/mod/elona_sys/api/Quest.lua +++ b/src/mod/elona_sys/api/Quest.lua @@ -149,8 +149,9 @@ function Quest.generate_from_proto(proto_id, chara, map) add_field(proto, quest, "reward_fix") for key, ty in pairs(proto.params or {}) do - if type(quest.params[key]) ~= ty then - error(("Generated quest '%s' expects parameter '%s' of type '%s', got '%s'"):format(proto._id, key, ty, type(quest.params[key]))) + local ok, err = types.check(quest.params[key], ty) + if not ok then + error(("Generated quest '%s' expects parameter '%s' of type '%s': %s"):format(proto._id, key, ty, err)) end end @@ -161,8 +162,9 @@ function Quest.generate_from_proto(proto_id, chara, map) local reward = data["elona_sys.quest_reward"]:ensure(quest.reward._id) if reward.params then for key, ty in pairs(reward.params) do - if type(quest.reward[key]) ~= ty then - error(("Quest reward '%s' expects parameter '%s' of type '%s', got '%s' (%s)"):format(quest.reward._id, key, ty, type(quest.reward[key]), proto._id)) + local ok, err = types.check(quest.reward[key], ty) + if not ok then + error(("Quest reward '%s' expects key '%s' of type '%s': %s"):format(quest.reward._id, key, ty, err)) end end end @@ -280,10 +282,7 @@ function Quest.generate(chara, map) Log.debug("Attempting to generate quest for client %d", uid) - -- Sort by ordering to preserve the imperative randomization - -- (sequential checks for rnd(n) == 0) local list = data["elona_sys.quest"]:iter():to_list() - table.sort(list, function(a, b) return a.ordering < b.ordering end) local fame = Chara.player():calc("fame") diff --git a/src/mod/elona_sys/dialog/init.lua b/src/mod/elona_sys/dialog/init.lua index a2b5a4d7e..23456a7d5 100644 --- a/src/mod/elona_sys/dialog/init.lua +++ b/src/mod/elona_sys/dialog/init.lua @@ -3,7 +3,7 @@ data:add_type { fields = { { name = "nodes", - type = types.map(types.identifier, types.any) -- TODO + type = types.map(types.string, types.any) -- TODO } } } diff --git a/src/mod/elona_sys/init.lua b/src/mod/elona_sys/init.lua index 76f466296..0d6a8d61c 100644 --- a/src/mod/elona_sys/init.lua +++ b/src/mod/elona_sys/init.lua @@ -96,7 +96,7 @@ data:add_type { }, { name = "progress", - type = types.map(types.int, types.locale_id) + type = types.map(types.int, types.some(types.locale_id, types.callback({"flag", types.int}, types.string))) } } } @@ -230,14 +230,6 @@ How much time to wait when running this animation, in milliseconds. default = nil, doc = [[ How many frames this animation holds. Omit to default to the asset's `count_x` property. -]] - }, - { - name = "wait", - type = types.optional(types.number), - default = 3.5, - doc = [[ -How much time to wait between frames. ]] }, { diff --git a/src/mod/elona_sys/sidequest/api/Sidequest.lua b/src/mod/elona_sys/sidequest/api/Sidequest.lua index 1eb05fbb6..a764d79dc 100755 --- a/src/mod/elona_sys/sidequest/api/Sidequest.lua +++ b/src/mod/elona_sys/sidequest/api/Sidequest.lua @@ -98,7 +98,7 @@ end local function sort(a, b) local proto_a = data["elona_sys.sidequest"]:ensure(a) local proto_b = data["elona_sys.sidequest"]:ensure(a) - return proto_a.ordering < proto_b.ordering + return proto_a._ordering < proto_b._ordering end function Sidequest.iter_active_main_quests() diff --git a/src/mod/noafindskitten/data/quest.lua b/src/mod/noafindskitten/data/quest.lua index 78ae82dc2..3fc85e98e 100644 --- a/src/mod/noafindskitten/data/quest.lua +++ b/src/mod/noafindskitten/data/quest.lua @@ -11,7 +11,6 @@ data:add { _type = "elona_sys.quest", _id = "noafindskitten", - ordering = 200000, client_chara_type = 1, reward = "elona.wear", reward_fix = 135, diff --git a/src/mod/omake_overhaul/data/titles/title.lua b/src/mod/omake_overhaul/data/titles/title.lua index 1850ba7bd..6860f1781 100644 --- a/src/mod/omake_overhaul/data/titles/title.lua +++ b/src/mod/omake_overhaul/data/titles/title.lua @@ -4,17 +4,12 @@ local Title = require("mod.titles.api.Title") local MapObject = require("api.MapObject") local Event = require("api.Event") -local function order(elona_id) - return 100000 + elona_id * 10000 -end - data:add { _type = "titles.title", _id = "decoy", elona_variant_ids = { oomsest = 0 }, - ordering = order(0), localize_info = function(info) -- >>>>>>>> oomSEST/src/southtyris.hsp:42487 if (title_pos == 1) { ... @@ -45,7 +40,6 @@ data:add { elona_variant_ids = { oomsest = 1 }, - ordering = order(1), localize_info = function(info) -- >>>>>>>> oomSEST/src/southtyris.hsp:42487 if (title_pos == 1) { ... @@ -69,7 +63,6 @@ data:add { elona_variant_ids = { oomsest = 25 }, - ordering = order(25), localize_info = function(info) -- >>>>>>>> oomSEST/src/southtyris.hsp:42575 if (title_pos == 25) { ... diff --git a/src/mod/simple_indicators/api/gui/UiSimpleIndicatorsWidget.lua b/src/mod/simple_indicators/api/gui/UiSimpleIndicatorsWidget.lua index e1ec3a86b..bd35dd39e 100644 --- a/src/mod/simple_indicators/api/gui/UiSimpleIndicatorsWidget.lua +++ b/src/mod/simple_indicators/api/gui/UiSimpleIndicatorsWidget.lua @@ -29,7 +29,6 @@ function UiSimpleIndicatorsWidget:set_data(player) local text = proto.render(player) if text ~= nil then local ind = { - ordering = proto.ordering or 100000, text = tostring(text) } self.indicators[#self.indicators + 1] = ind @@ -41,8 +40,6 @@ function UiSimpleIndicatorsWidget:set_data(player) local th = Draw.text_height() self.height = #self.indicators * th self.y = Gui.message_window_y() - 30 - self.height - - table.sort(self.indicators, function(a, b) return a.ordering < b.ordering end) end function UiSimpleIndicatorsWidget:relayout(x, y) diff --git a/src/mod/simple_indicators/data/simple_indicators/indicator.lua b/src/mod/simple_indicators/data/simple_indicators/indicator.lua index 428d778e7..65e17293f 100644 --- a/src/mod/simple_indicators/data/simple_indicators/indicator.lua +++ b/src/mod/simple_indicators/data/simple_indicators/indicator.lua @@ -12,8 +12,6 @@ data:add { _type = "simple_indicators.indicator", _id = "stamina", - ordering = 100000, - render = function(player) return ("ST:%d/%d"):format(player.stamina, player:calc("max_stamina")) end diff --git a/src/mod/smithing/data/simple_indicators/indicator.lua b/src/mod/smithing/data/simple_indicators/indicator.lua index 81ba9bcbe..145ff9707 100644 --- a/src/mod/smithing/data/simple_indicators/indicator.lua +++ b/src/mod/smithing/data/simple_indicators/indicator.lua @@ -11,8 +11,6 @@ data:add { _type = "simple_indicators.indicator", _id = "hammer_level", - ordering = 1000000, - render = function(player) -- >>>>>>>> oomSEST/src/net.hsp:896 if (hammerNoPlus@st > 0) { ... if not Item.is_alive(global.tracked_hammer) @@ -40,8 +38,6 @@ data:add { _type = "simple_indicators.indicator", _id = "sps", - ordering = 1001000, - render = function(player) -- >>>>>>>> oomSEST/src/net.hsp:914 if (length(spsIntervals) == 0) { ... local skin_sum = fun.wrap(global.sps_intervals:iter()):sum() diff --git a/src/mod/sokoban/data/quest.lua b/src/mod/sokoban/data/quest.lua index 8eccf0461..22240e6b5 100644 --- a/src/mod/sokoban/data/quest.lua +++ b/src/mod/sokoban/data/quest.lua @@ -10,7 +10,6 @@ data:add { _type = "elona_sys.quest", _id = "sokoban", - ordering = 200000, client_chara_type = 1, reward = "elona.wear", reward_fix = 135, diff --git a/src/mod/sokoban/data/sokoban/board.lua b/src/mod/sokoban/data/sokoban/board.lua index e5d31551e..4eff77242 100644 --- a/src/mod/sokoban/data/sokoban/board.lua +++ b/src/mod/sokoban/data/sokoban/board.lua @@ -2,7 +2,7 @@ data:add_type { name = "board", fields = { { - name = "layout", + name = "board", type = types.string, template = true } diff --git a/src/mod/titles/api/gui/TitlesMenu.lua b/src/mod/titles/api/gui/TitlesMenu.lua index f4aabe699..9643a7db0 100644 --- a/src/mod/titles/api/gui/TitlesMenu.lua +++ b/src/mod/titles/api/gui/TitlesMenu.lua @@ -70,16 +70,13 @@ function TitlesMenu.generate_list(chara) return { _id = title._id, - ordering = title.ordering, name = title_name, condition = title_condition, color = color } end - local sort = function(a, b) return a.ordering < b.ordering end - - return data["titles.title"]:iter():map(map):into_sorted(sort):to_list() + return data["titles.title"]:iter():map(map):to_list() end function TitlesMenu:init(chara) diff --git a/src/mod/tools/api/Tools.lua b/src/mod/tools/api/Tools.lua index 3485f68fb..14c4992fc 100644 --- a/src/mod/tools/api/Tools.lua +++ b/src/mod/tools/api/Tools.lua @@ -310,20 +310,6 @@ function Tools.categories_flt_differ() return result end -function Tools.categories_for_subcategories() - -- extract the primary category for each subcategory. - local cat = Tools.partition(data["base.item"], "subcategory", "category") - cat[64000] = nil - cat["nil"] = nil - - local map = function(k, v) - local subcategory = data["base.item_type"]:iter():filter(function(i) return i.ordering == tonumber(k) end):nth(1) - local item_type = table.unique(v) - return (subcategory and subcategory._id) or k, item_type - end - return fun.iter(cat):map(map):filter(function(k, v) return #v > 1 end):to_map() -end - function Tools.partition(tbl, key, extract) extract = extract or "_id" local f = function(i) diff --git a/src/mod/visual_ai/api/gui/VisualAIBlockList.lua b/src/mod/visual_ai/api/gui/VisualAIBlockList.lua index 4440e6de2..0f34db922 100644 --- a/src/mod/visual_ai/api/gui/VisualAIBlockList.lua +++ b/src/mod/visual_ai/api/gui/VisualAIBlockList.lua @@ -116,9 +116,6 @@ function VisualAIBlockList:set_category(category_idx) end local entries = data["visual_ai.block"]:iter():filter(pred):map(map):to_list() - local sort = function(a, b) return a.proto.ordering < b.proto.ordering end - table.sort(entries, sort) - self.model:set_data(entries) self:_recalc_layout() diff --git a/src/mod/visual_ai/data/visual_ai/block.lua b/src/mod/visual_ai/data/visual_ai/block.lua index 8df230291..4fc4bf184 100644 --- a/src/mod/visual_ai/data/visual_ai/block.lua +++ b/src/mod/visual_ai/data/visual_ai/block.lua @@ -28,7 +28,7 @@ data:add_type { }, { name = "target_source", - type = types.optional(types.literal("character", "items_on_self", "items_on_ground")) + type = types.optional(types.literal("character", "items_on_self", "items_on_ground", "position")) }, { name = "target_filter", @@ -68,7 +68,7 @@ data:add_type { template = true }, { - name = "action", + name = "condition", type = types.optional(types.callback({"self", types.table, "chara", types.map_object("base.chara"), "target", types.some(types.map_object("any"), ty_pos), diff --git a/src/mod/visual_ai/data/visual_ai/block/action.lua b/src/mod/visual_ai/data/visual_ai/block/action.lua index aa4aa8a8d..f99e7f558 100644 --- a/src/mod/visual_ai/data/visual_ai/block/action.lua +++ b/src/mod/visual_ai/data/visual_ai/block/action.lua @@ -10,10 +10,6 @@ local Const = require("api.Const") local Itemgen = require("mod.elona.api.Itemgen") local Rand = require("api.Rand") local Filters = require("mod.elona.api.Filters") -local Item = require("api.Item") -local ICharaVisualAI = require("mod.visual_ai.api.aspect.ICharaVisualAI") - -local order = UidTracker:new(30000) data:add { _type = "visual_ai.block", @@ -23,7 +19,6 @@ data:add { vars = {}, is_terminal = true, - ordering = order:get_next_and_increment(), action = function(self, chara, target, ty) if ty == "map_object" then @@ -62,7 +57,6 @@ data:add { vars = { threshold = { type = "integer", min_value = 0, default = 3 } }, - ordering = order:get_next_and_increment(), format_name = function(proto, vars) return I18N.get("visual_ai.block." .. proto._id .. ".name", vars.threshold) @@ -100,7 +94,6 @@ data:add { vars = { skill_id = utils.vars.known_skill }, - ordering = order:get_next_and_increment(), format_name = function(proto, vars) local name @@ -148,7 +141,6 @@ data:add { vars = {}, is_terminal = true, - ordering = order:get_next_and_increment(), applies_to = "any", @@ -185,7 +177,6 @@ data:add { vars = { threshold = { type = "integer", min_value = 0, default = 3 } }, - ordering = order:get_next_and_increment(), format_name = function(proto, vars) return I18N.get("visual_ai.block." .. proto._id .. ".name", vars.threshold) @@ -232,7 +223,6 @@ data:add { vars = {}, is_terminal = true, - ordering = order:get_next_and_increment(), applies_to = "map_object", @@ -257,7 +247,6 @@ data:add { vars = {}, is_terminal = true, - ordering = order:get_next_and_increment(), applies_to = "map_object", @@ -289,7 +278,6 @@ data:add { }, is_terminal = true, - ordering = order:get_next_and_increment(), applies_to = "map_object", @@ -326,7 +314,6 @@ data:add { is_terminal = true, color = {50, 180, 100}, - ordering = order:get_next_and_increment(), applies_to = "map_object", @@ -352,7 +339,6 @@ data:add { is_terminal = true, color = {50, 180, 100}, - ordering = order:get_next_and_increment(), applies_to = "map_object", @@ -385,7 +371,6 @@ data:add { is_terminal = false, color = {50, 180, 100}, icon = "visual_ai.icon_joystick_right", - ordering = order:get_next_and_increment(), applies_to = "map_object", @@ -405,7 +390,6 @@ data:add { is_terminal = true, color = {50, 180, 100}, icon = "visual_ai.icon_diamond", - ordering = order:get_next_and_increment(), applies_to = "any", @@ -432,7 +416,6 @@ data:add { is_terminal = true, color = {100, 50, 180}, icon = "visual_ai.icon_target", - ordering = order:get_next_and_increment(), applies_to = "any", @@ -461,7 +444,6 @@ data:add { is_terminal = false, color = {100, 40, 100}, icon = "visual_ai.icon_download", - ordering = order:get_next_and_increment(), applies_to = "map_object", @@ -484,7 +466,6 @@ data:add { is_terminal = true, color = {180, 140, 100}, icon = "visual_ai.icon_flag", - ordering = order:get_next_and_increment(), applies_to = "any", @@ -507,7 +488,6 @@ data:add { is_terminal = true, color = {180, 140, 100}, icon = "visual_ai.icon_stop", - ordering = order:get_next_and_increment(), applies_to = "any", diff --git a/src/mod/visual_ai/data/visual_ai/block/condition.lua b/src/mod/visual_ai/data/visual_ai/block/condition.lua index 8fb392fa9..5fc869c9b 100644 --- a/src/mod/visual_ai/data/visual_ai/block/condition.lua +++ b/src/mod/visual_ai/data/visual_ai/block/condition.lua @@ -1,20 +1,16 @@ local I18N = require("api.I18N") local utils = require("mod.visual_ai.internal.utils") -local UidTracker = require("api.UidTracker") local Pos = require("api.Pos") local ElonaAction = require("mod.elona.api.ElonaAction") local Const = require("api.Const") local Rand = require("api.Rand") -local order = UidTracker:new(10000) - data:add { _type = "visual_ai.block", _id = "condition_target_in_sight", type = "condition", vars = {}, - ordering = order:get_next_and_increment(), condition = function(self, chara, target, ty) return chara:has_los(target.x, target.y) @@ -32,7 +28,6 @@ data:add { comparator = utils.vars.comparator, threshold = { type = "integer", min_value = 0, max_value = 100, default = 100, increment_amount = 10 } }, - ordering = order:get_next_and_increment(), format_name = function(proto, vars) return I18N.get("visual_ai.block." .. proto._id .. ".name", "visual_ai.var.hp_mp_sp." .. vars.kind, vars.comparator, vars.threshold) @@ -51,7 +46,6 @@ data:add { type = "condition", vars = {}, - ordering = order:get_next_and_increment(), condition = function(self, chara, target) return Pos.dist(target.x, target.y, chara.x, chara.y) <= 1 @@ -64,7 +58,6 @@ data:add { type = "condition", vars = {}, - ordering = order:get_next_and_increment(), condition = function(self, chara, target) local ranged, ammo = ElonaAction.get_ranged_weapon_and_ammo(chara) @@ -85,7 +78,6 @@ data:add { comparator = utils.vars.comparator, threshold = { type = "integer", min_value = 0, default = 3 } }, - ordering = order:get_next_and_increment(), format_name = function(proto, vars) return I18N.get("visual_ai.block." .. proto._id .. ".name", vars.comparator, vars.threshold) @@ -104,7 +96,6 @@ data:add { vars = { skill_id = utils.vars.known_skill }, - ordering = order:get_next_and_increment(), format_name = function(proto, vars) local name @@ -140,7 +131,6 @@ data:add { vars = { chance = { type = "integer", min_value = 0, max_value = 100, default = 50, increment_amount = 10 } }, - ordering = order:get_next_and_increment(), format_name = function(proto, vars) return I18N.get("visual_ai.block." .. proto._id .. ".name", vars.chance) diff --git a/src/mod/visual_ai/data/visual_ai/block/special.lua b/src/mod/visual_ai/data/visual_ai/block/special.lua index 5fa4f386c..c22bb9f99 100644 --- a/src/mod/visual_ai/data/visual_ai/block/special.lua +++ b/src/mod/visual_ai/data/visual_ai/block/special.lua @@ -1,7 +1,3 @@ -local UidTracker = require("api.UidTracker") - -local order = UidTracker:new(40000) - data:add { _type = "visual_ai.block", _id = "special_clear_target", @@ -10,5 +6,4 @@ data:add { is_terminal = false, color = {180, 50, 50}, icon = "visual_ai.icon_cross", - ordering = order:get_next_and_increment(), } diff --git a/src/mod/visual_ai/data/visual_ai/block/target.lua b/src/mod/visual_ai/data/visual_ai/block/target.lua index 3284e2d49..74d240a73 100644 --- a/src/mod/visual_ai/data/visual_ai/block/target.lua +++ b/src/mod/visual_ai/data/visual_ai/block/target.lua @@ -1,12 +1,8 @@ -local UidTracker = require("api.UidTracker") local Enum = require("api.Enum") local Pos = require("api.Pos") local I18N = require("api.I18N") local Chara = require("api.Chara") local utils = require("mod.visual_ai.internal.utils") -local ICharaVisualAI = require("mod.visual_ai.api.aspect.ICharaVisualAI") - -local order = UidTracker:new(20000) data:add { _type = "visual_ai.block", @@ -16,8 +12,6 @@ data:add { color = {80, 100, 180}, icon = "visual_ai.icon_singleplayer", - ordering = order:get_next_and_increment(), - target_source = "character", target_filter = function(self, chara, candidate) @@ -33,8 +27,6 @@ data:add { color = {80, 100, 180}, icon = "visual_ai.icon_singleplayer", - ordering = order:get_next_and_increment(), - target_source = "character", target_filter = function(self, chara, candidate) @@ -50,8 +42,6 @@ data:add { color = {80, 100, 180}, icon = "visual_ai.icon_multiplayer", - ordering = order:get_next_and_increment(), - target_source = "character", target_filter = function(self, chara, candidate) @@ -67,8 +57,6 @@ data:add { color = {180, 100, 80}, icon = "visual_ai.icon_multiplayer", - ordering = order:get_next_and_increment(), - target_source = "character", target_filter = function(self, chara, candidate) @@ -84,8 +72,6 @@ data:add { color = {180, 180, 80}, icon = "visual_ai.icon_multiplayer", - ordering = order:get_next_and_increment(), - target_source = "character", target_filter = function(self, chara, candidate) @@ -101,8 +87,6 @@ data:add { color = {50, 180, 100}, icon = "visual_ai.icon_diamond", - ordering = order:get_next_and_increment(), - target_source = "items_on_ground", target_filter = function(self, chara, candidate) @@ -119,8 +103,6 @@ data:add { color = {50, 180, 100}, vars = {}, - ordering = order:get_next_and_increment(), - target_source = "items_on_self", target_filter = function(self, chara, candidate) @@ -140,8 +122,6 @@ data:add { comparator = utils.vars.comparator, threshold = { type = "integer", min_value = 0, max_value = 100, default = 100, increment_amount = 10 } }, - ordering = order:get_next_and_increment(), - applies_to = "map_object", format_name = function(proto, vars) @@ -168,8 +148,6 @@ data:add { color = {140, 100, 140}, icon = "visual_ai.icon_return", - ordering = order:get_next_and_increment(), - target_order = function(self, chara, candidate_a, candidate_b) return Pos.dist(chara.x, chara.y, candidate_a.x, candidate_a.y) < Pos.dist(chara.x, chara.y, candidate_b.x, candidate_b.y) @@ -184,8 +162,6 @@ data:add { color = {140, 100, 140}, icon = "visual_ai.icon_return", - ordering = order:get_next_and_increment(), - target_order = function(self, chara, candidate_a, candidate_b) return Pos.dist(chara.x, chara.y, candidate_a.x, candidate_a.y) > Pos.dist(chara.x, chara.y, candidate_b.x, candidate_b.y) @@ -203,8 +179,6 @@ data:add { kind = { type = "enum", choices = { "hp", "mp", "stamina" }}, comparator = utils.vars.comparator_partial, }, - ordering = order:get_next_and_increment(), - applies_to = "map_object", format_name = function(proto, vars) @@ -230,8 +204,6 @@ data:add { color = {100, 40, 100}, icon = "visual_ai.icon_singleplayer", - ordering = order:get_next_and_increment(), - target_source = "any", target_filter = function(self, chara, candidate, ty) @@ -249,8 +221,6 @@ data:add { color = {100, 40, 100}, icon = "visual_ai.icon_singleplayer", - ordering = order:get_next_and_increment(), - target_source = "character", target_filter = function(self, chara, candidate) @@ -272,8 +242,6 @@ data:add { y = { type = "integer", min_value = 0 }, }, - ordering = order:get_next_and_increment(), - format_name = function(proto, vars) return I18N.get("visual_ai.block." .. proto._id .. ".name", vars.x, vars.y) end, @@ -294,8 +262,6 @@ data:add { color = {160, 160, 130}, icon = "visual_ai.icon_target", - ordering = order:get_next_and_increment(), - target_source = "position", target_filter = function(self, chara, candidate) diff --git a/src/util/types.lua b/src/util/types.lua index 45d7731d6..6194d440c 100644 --- a/src/util/types.lua +++ b/src/util/types.lua @@ -859,13 +859,17 @@ end do local fields_checker = class.class("fields_checker", ITypeChecker) - function fields_checker:init(fields) + function fields_checker:init(fields, array_part) for key, checker in pairs(fields) do if not is_type_checker(checker) then error(("Object for field '%s' is not a type checker (%s)"):format(key, checker)) end end + if array_part then + assert(is_type_checker(array_part)) + end self.fields = fields + self.array_part = array_part end function fields_checker:check(obj, ctxt) if not types.table:check(obj, ctxt) then @@ -881,6 +885,17 @@ do ctxt:pop() end + if self.array_part then + for i, val in ipairs(self.fields) do + ctxt:push(i, val) + local ok, err = self.array_part:check(val, ctxt) + if not ok then + return false, err + end + ctxt:pop() + end + end + return true end function fields_checker:__tostring() From 4b765b39c2f3955a2ae2d9d0a1a380f186f52b9a Mon Sep 17 00:00:00 2001 From: Ruin0x11 Date: Fri, 10 Sep 2021 00:32:08 -0700 Subject: [PATCH 10/17] Refactor ai_calm --- src/api/InstancedMap.lua | 2 +- src/internal/data/schemas.lua | 23 ++++++++ src/internal/data_table.lua | 4 +- src/mod/elona/api/FieldMap.lua | 2 +- src/mod/elona/data/chara.lua | 53 ------------------ src/mod/elona/data/map_archetype/dungeon.lua | 20 +++---- .../elona/data/map_archetype/instanced.lua | 6 +- .../elona/data/map_archetype/player_owned.lua | 2 +- src/mod/elona/data/map_archetype/special.lua | 10 ++-- src/mod/elona/data/map_archetype/town.lua | 48 ++++++++-------- src/mod/elona/data/map_archetype/unique.lua | 56 +++++++++---------- src/mod/elona/data/map_archetype/world.lua | 6 +- src/mod/elona/data/quest/harvest.lua | 2 +- src/mod/elona/data/quest/huntex.lua | 2 +- src/mod/elona/data/quest/party.lua | 2 +- 15 files changed, 104 insertions(+), 134 deletions(-) diff --git a/src/api/InstancedMap.lua b/src/api/InstancedMap.lua index cc276fdb1..a9121800c 100644 --- a/src/api/InstancedMap.lua +++ b/src/api/InstancedMap.lua @@ -152,7 +152,7 @@ local fallbacks = { appearance = "", tileset = "elona.dungeon", tile_type = 2, - default_ai_calm = 1, + default_ai_calm = "base.calm_roam", crowd_density = 0, max_crowd_density = 0, is_user_map = false, diff --git a/src/internal/data/schemas.lua b/src/internal/data/schemas.lua index 525b605d4..36ee445e7 100644 --- a/src/internal/data/schemas.lua +++ b/src/internal/data/schemas.lua @@ -99,6 +99,21 @@ Relative strength of this character. default = 100, doc = [[ Chance this unit will take an idle action if they have no target. +]] + }, + { + -- TODO should be ID + name = "ai_calm_action", + type = types.optional(types.string), + doc = [[ +Idle AI action this unit will take if they have no target. +]] + }, + { + name = "ai_calm_action", + type = types.optional(types.data_id("base.ai_action")), + doc = [[ +Idle AI action this unit will take if they have no target. ]] }, { @@ -235,6 +250,14 @@ large level difference against the character's level. Higher means a smaller range of dungeon levels the character appears in. Lower means the character has a greater chance of appearing in both high-level and low-level dungeons. +]] + }, + { + name = "loot_type", + type = types.optional(types.data_id("base.loot_type")), + default = nil, + doc = [[ +Type of loot this character drops on death. ]] }, { diff --git a/src/internal/data_table.lua b/src/internal/data_table.lua index 936dc4f1a..2ecca29e1 100644 --- a/src/internal/data_table.lua +++ b/src/internal/data_table.lua @@ -317,10 +317,10 @@ end function data_table:validate_all(verbose) local errors = {} for _, _type, proxy in self:iter() do - for _id, entry in proxy:iter() do + for _, entry in proxy:iter() do local ok, err = proxy:validate(entry, verbose) if not ok then - errors[#errors+1] = { _type = _type, _id = _id, error = err } + errors[#errors+1] = { _type = _type, _id = entry._id, error = err } end end end diff --git a/src/mod/elona/api/FieldMap.lua b/src/mod/elona/api/FieldMap.lua index 156ca4892..a7f8006c0 100755 --- a/src/mod/elona/api/FieldMap.lua +++ b/src/mod/elona/api/FieldMap.lua @@ -40,7 +40,7 @@ function FieldMap.generate(stood_tile, width, height, outer_map) map.level = 1 map.is_indoor = false map.has_anchored_npcs = false - map.default_ai_calm = 0 + map.default_ai_calm = "base.calm_null" map.default_tile = field.fog return map diff --git a/src/mod/elona/data/chara.lua b/src/mod/elona/data/chara.lua index f66771fe6..8cee1877a 100644 --- a/src/mod/elona/data/chara.lua +++ b/src/mod/elona/data/chara.lua @@ -53,7 +53,6 @@ local chara = { tags = { "man" }, level = 35, portrait = "random", - ai_calm = 2, can_talk = true, relation = Enum.Relation.Neutral, race = "elona.norland", @@ -75,7 +74,6 @@ local chara = { tags = { "man" }, level = 22, portrait = "random", - ai_calm = 3, relation = Enum.Relation.Neutral, race = "elona.juere", class = "elona.gunner", @@ -94,7 +92,6 @@ local chara = { tags = { "man" }, level = 20, portrait = "random", - ai_calm = 2, can_talk = true, relation = Enum.Relation.Neutral, race = "elona.norland", @@ -114,7 +111,6 @@ local chara = { tags = { "man" }, level = 20, portrait = "random", - ai_calm = 2, can_talk = true, has_own_name = true, relation = Enum.Relation.Neutral, @@ -134,7 +130,6 @@ local chara = { tags = { "man" }, level = 40, portrait = "random", - ai_calm = 2, can_talk = true, has_own_name = true, relation = Enum.Relation.Neutral, @@ -154,7 +149,6 @@ local chara = { tags = { "man" }, level = 20, portrait = "random", - ai_calm = 2, can_talk = true, has_own_name = true, relation = Enum.Relation.Neutral, @@ -174,7 +168,6 @@ local chara = { tags = { "man" }, level = 50, portrait = "random", - ai_calm = 2, can_talk = true, has_own_name = true, relation = Enum.Relation.Neutral, @@ -194,7 +187,6 @@ local chara = { tags = { "man" }, level = 20, portrait = "random", - ai_calm = 2, can_talk = true, has_own_name = true, relation = Enum.Relation.Neutral, @@ -214,7 +206,6 @@ local chara = { tags = { "man" }, level = 40, portrait = "random", - ai_calm = 2, can_talk = true, has_own_name = true, relation = Enum.Relation.Neutral, @@ -234,7 +225,6 @@ local chara = { tags = { "man" }, level = 69, portrait = "random", - ai_calm = 2, can_talk = true, has_own_name = true, relation = Enum.Relation.Neutral, @@ -640,7 +630,6 @@ local chara = { loot_type = "elona.humanoid", tags = { "man" }, level = 1, - ai_calm = 5, can_talk = true, relation = Enum.Relation.Neutral, race = "elona.norland", @@ -1416,7 +1405,6 @@ local chara = { elona_id = 287, loot_type = "elona.animal", level = 20, - ai_calm = 3, relation = Enum.Relation.Enemy, race = "elona.drake", image = "elona.chara_mass_monster", @@ -1445,7 +1433,6 @@ local chara = { elona_id = 327, loot_type = "elona.animal", level = 52, - ai_calm = 3, relation = Enum.Relation.Enemy, race = "elona.machine", image = "elona.chara_cube", @@ -1587,7 +1574,6 @@ local chara = { tags = { "man" }, level = 32, portrait = "random", - ai_calm = 5, can_talk = true, has_own_name = true, relation = Enum.Relation.Neutral, @@ -1635,7 +1621,6 @@ local chara = { tags = { "man" }, level = 16, portrait = "random", - ai_calm = 5, can_talk = true, has_own_name = true, relation = Enum.Relation.Dislike, @@ -1705,7 +1690,6 @@ local chara = { loot_type = nil, tags = { "man" }, level = 35, - ai_calm = 3, can_talk = true, relation = Enum.Relation.Neutral, race = "elona.norland", @@ -1808,7 +1792,6 @@ local chara = { tags = { "man" }, level = 8, portrait = "random", - ai_calm = 5, can_talk = true, has_own_name = true, relation = Enum.Relation.Neutral, @@ -2363,7 +2346,6 @@ local chara = { elona_id = 15, loot_type = "elona.insect", level = 4, - ai_calm = 3, relation = Enum.Relation.Enemy, race = "elona.mushroom", rarity = 50000, @@ -2387,7 +2369,6 @@ local chara = { elona_id = 283, loot_type = "elona.insect", level = 8, - ai_calm = 3, relation = Enum.Relation.Enemy, race = "elona.mushroom", image = "elona.chara_spore_mushroom", @@ -2414,7 +2395,6 @@ local chara = { elona_id = 284, loot_type = "elona.insect", level = 21, - ai_calm = 3, relation = Enum.Relation.Enemy, race = "elona.mushroom", image = "elona.chara_spore_mushroom", @@ -2906,7 +2886,6 @@ local chara = { tags = { "man" }, level = 5, portrait = "random", - ai_calm = 2, has_own_name = true, relation = Enum.Relation.Neutral, race = "elona.norland", @@ -3853,7 +3832,6 @@ local chara = { elona_id = 67, loot_type = "elona.animal", level = 2, - ai_calm = 3, relation = Enum.Relation.Enemy, race = "elona.eye", resistances = { @@ -3881,7 +3859,6 @@ local chara = { elona_id = 315, loot_type = "elona.animal", level = 14, - ai_calm = 3, relation = Enum.Relation.Enemy, race = "elona.eye", class = "elona.predator", @@ -3918,7 +3895,6 @@ local chara = { elona_id = 316, loot_type = "elona.animal", level = 7, - ai_calm = 3, relation = Enum.Relation.Enemy, race = "elona.eye", resistances = { @@ -3955,7 +3931,6 @@ local chara = { elona_id = 314, loot_type = "elona.animal", level = 29, - ai_calm = 3, relation = Enum.Relation.Enemy, race = "elona.eye", class = "elona.predator", @@ -4241,7 +4216,6 @@ local chara = { loot_type = "elona.humanoid", tags = { "undead" }, level = 4, - ai_calm = 3, relation = Enum.Relation.Enemy, race = "elona.hand", coefficient = 400, @@ -4272,7 +4246,6 @@ local chara = { loot_type = "elona.humanoid", tags = { "undead" }, level = 11, - ai_calm = 3, relation = Enum.Relation.Enemy, race = "elona.hand", color = { 225, 195, 255 }, @@ -4302,7 +4275,6 @@ local chara = { loot_type = "elona.humanoid", tags = { "undead" }, level = 15, - ai_calm = 3, relation = Enum.Relation.Enemy, race = "elona.hand", class = "elona.warrior", @@ -4404,7 +4376,6 @@ local chara = { elona_id = 93, loot_type = "elona.insect", level = 8, - ai_calm = 3, relation = Enum.Relation.Enemy, race = "elona.mandrake", image = "elona.chara_chaos_flower", @@ -4425,7 +4396,6 @@ local chara = { elona_id = 94, loot_type = "elona.insect", level = 19, - ai_calm = 3, relation = Enum.Relation.Enemy, race = "elona.mandrake", image = "elona.chara_chaos_flower", @@ -6197,7 +6167,6 @@ local chara = { tags = { "man" }, level = 45, portrait = "elona.gilbert", - ai_calm = 2, can_talk = true, relation = Enum.Relation.Neutral, race = "elona.juere", @@ -6218,7 +6187,6 @@ local chara = { elona_id = 232, loot_type = "elona.humanoid", level = 17, - ai_calm = 3, relation = Enum.Relation.Enemy, race = "elona.yerles", class = "elona.gunner", @@ -6466,7 +6434,6 @@ local chara = { tags = { "man" }, level = 4, portrait = "elona.woman17", - ai_calm = 2, can_talk = true, relation = Enum.Relation.Neutral, race = "elona.roran", @@ -6487,7 +6454,6 @@ local chara = { tags = { "man" }, level = 5, portrait = "elona.man17", - ai_calm = 2, can_talk = true, relation = Enum.Relation.Neutral, race = "elona.norland", @@ -7062,7 +7028,6 @@ local chara = { elona_id = 345, loot_type = "elona.humanoid", level = 22, - ai_calm = 3, can_talk = true, relation = Enum.Relation.Neutral, race = "elona.bike", @@ -7085,7 +7050,6 @@ local chara = { elona_id = 346, loot_type = "elona.humanoid", level = 8, - ai_calm = 3, can_talk = true, relation = Enum.Relation.Dislike, race = "elona.bike", @@ -7306,7 +7270,6 @@ local chara = { loot_type = "elona.insect", tags = { "undead" }, level = 7, - ai_calm = 3, relation = Enum.Relation.Enemy, race = "elona.mandrake", image = "elona.chara_pumpkin", @@ -7334,7 +7297,6 @@ local chara = { loot_type = "elona.insect", tags = { "undead" }, level = 5, - ai_calm = 3, relation = Enum.Relation.Enemy, race = "elona.mandrake", image = "elona.chara_pumpkin", @@ -7364,7 +7326,6 @@ local chara = { loot_type = "elona.insect", tags = { "undead" }, level = 18, - ai_calm = 3, relation = Enum.Relation.Enemy, race = "elona.mandrake", image = "elona.chara_pumpkin", @@ -7394,7 +7355,6 @@ local chara = { loot_type = "elona.insect", tags = { "undead" }, level = 30, - ai_calm = 3, relation = Enum.Relation.Enemy, race = "elona.mandrake", image = "elona.chara_pumpkin", @@ -7470,7 +7430,6 @@ local chara = { elona_id = 202, loot_type = "elona.humanoid", level = 80, - ai_calm = 3, can_talk = true, relation = Enum.Relation.Neutral, race = "elona.giant", @@ -7503,7 +7462,6 @@ local chara = { tags = { "man" }, level = 10, portrait = "random", - ai_calm = 3, can_talk = true, relation = Enum.Relation.Neutral, race = "elona.norland", @@ -7603,7 +7561,6 @@ local chara = { loot_type = "elona.humanoid", tags = { "man" }, level = 1, - ai_calm = 4, can_talk = true, relation = Enum.Relation.Dislike, race = "elona.roran", @@ -7637,7 +7594,6 @@ local chara = { tags = { "man" }, level = 10, portrait = "elona.woman16", - ai_calm = 3, can_talk = true, relation = Enum.Relation.Neutral, race = "elona.roran", @@ -7659,7 +7615,6 @@ local chara = { tags = { "man" }, level = 15, portrait = "elona.woman14", - ai_calm = 3, can_talk = true, relation = Enum.Relation.Neutral, race = "elona.roran", @@ -7681,7 +7636,6 @@ local chara = { tags = { "man" }, level = 10, portrait = "elona.man15", - ai_calm = 2, can_talk = true, relation = Enum.Relation.Neutral, race = "elona.norland", @@ -7703,7 +7657,6 @@ local chara = { tags = { "man" }, level = 7, portrait = "elona.man19", - ai_calm = 3, can_talk = true, relation = Enum.Relation.Neutral, race = "elona.norland", @@ -7725,7 +7678,6 @@ local chara = { tags = { "man" }, level = 15, portrait = "elona.arnord", - ai_calm = 3, can_talk = true, relation = Enum.Relation.Neutral, race = "elona.norland", @@ -8001,7 +7953,6 @@ local chara = { elona_id = 218, loot_type = "elona.animal", level = 45, - ai_calm = 3, relation = Enum.Relation.Enemy, race = "elona.yith", class = "elona.predator", @@ -8529,7 +8480,6 @@ local chara = { tags = { "man" }, level = 10, portrait = "elona.balzak", - ai_calm = 5, can_talk = true, relation = Enum.Relation.Neutral, race = "elona.norland", @@ -8585,7 +8535,6 @@ local chara = { tags = { "man" }, level = 38, portrait = "elona.man6", - ai_calm = 3, can_talk = true, relation = Enum.Relation.Neutral, race = "elona.norland", @@ -8640,7 +8589,6 @@ local chara = { tags = { "man" }, level = 38, portrait = "elona.man6", - ai_calm = 3, can_talk = true, relation = Enum.Relation.Neutral, race = "elona.juere", @@ -8681,7 +8629,6 @@ local chara = { tags = { "man" }, level = 38, portrait = "elona.man6", - ai_calm = 3, can_talk = true, relation = Enum.Relation.Neutral, race = "elona.norland", diff --git a/src/mod/elona/data/map_archetype/dungeon.lua b/src/mod/elona/data/map_archetype/dungeon.lua index f7fcf66de..b15dc8844 100644 --- a/src/mod/elona/data/map_archetype/dungeon.lua +++ b/src/mod/elona/data/map_archetype/dungeon.lua @@ -25,7 +25,7 @@ do types = { "dungeon" }, is_indoor = true, has_anchored_npcs = true, - default_ai_calm = 0, + default_ai_calm = "base.calm_null", shows_floor_count_in_name = true, material_spot_type = "elona.dungeon" } @@ -124,7 +124,7 @@ do properties = { types = { "dungeon" }, is_indoor = true, - default_ai_calm = 0, + default_ai_calm = "base.calm_null", prevents_domination = true, material_spot_type = "elona.dungeon" } @@ -188,7 +188,7 @@ do types = { "dungeon" }, is_indoor = true, has_anchored_npcs = true, - default_ai_calm = 0, + default_ai_calm = "base.calm_null", material_spot_type = "elona.building" } } @@ -274,7 +274,7 @@ do types = { "dungeon" }, is_indoor = true, has_anchored_npcs = true, - default_ai_calm = 0, + default_ai_calm = "base.calm_null", material_spot_type = "elona.dungeon" } } @@ -346,7 +346,7 @@ do types = { "dungeon" }, is_indoor = true, has_anchored_npcs = true, - default_ai_calm = 0, + default_ai_calm = "base.calm_null", material_spot_type = "elona.building" } } @@ -423,7 +423,7 @@ do types = { "dungeon" }, is_indoor = true, has_anchored_npcs = true, - default_ai_calm = 0, + default_ai_calm = "base.calm_null", material_spot_type = "elona.dungeon" } } @@ -482,7 +482,7 @@ do types = { "dungeon" }, is_indoor = true, has_anchored_npcs = true, - default_ai_calm = 0, + default_ai_calm = "base.calm_null", material_spot_type = "elona.dungeon" } } @@ -536,7 +536,7 @@ do properties = { types = { "dungeon" }, is_indoor = true, - default_ai_calm = 0, + default_ai_calm = "base.calm_null", is_generated_every_time = true, material_spot_type = "elona.dungeon" }, @@ -593,7 +593,7 @@ do types = { "dungeon" }, is_indoor = true, has_anchored_npcs = true, - default_ai_calm = 0, + default_ai_calm = "base.calm_null", material_spot_type = "elona.dungeon" } } @@ -666,7 +666,7 @@ do types = { "dungeon" }, is_indoor = true, has_anchored_npcs = true, - default_ai_calm = 0, + default_ai_calm = "base.calm_null", material_spot_type = "elona.dungeon" } } diff --git a/src/mod/elona/data/map_archetype/instanced.lua b/src/mod/elona/data/map_archetype/instanced.lua index a56f053b6..f7c77e75a 100644 --- a/src/mod/elona/data/map_archetype/instanced.lua +++ b/src/mod/elona/data/map_archetype/instanced.lua @@ -29,7 +29,7 @@ do is_temporary = false, is_not_renewable = true, has_anchored_npcs = true, - default_ai_calm = 1, + default_ai_calm = "base.calm_roam", max_crowd_density = 0, tileset = "elona.dungeon", material_spot_type = "elona.dungeon" @@ -138,7 +138,7 @@ do is_indoor = true, is_temporary = false, is_not_renewable = true, - default_ai_calm = 1, + default_ai_calm = "base.calm_roam", max_crowd_density = 0, tileset = "elona.dungeon", material_spot_type = "elona.dungeon" @@ -263,7 +263,7 @@ do is_indoor = true, is_not_renewable = true, max_crowd_density = 0, - default_ai_calm = 0, + default_ai_calm = "base.calm_null", tileset = "elona.dungeon", material_spot_type = "elona.dungeon" }, diff --git a/src/mod/elona/data/map_archetype/player_owned.lua b/src/mod/elona/data/map_archetype/player_owned.lua index f0411afa7..b49eba4d7 100644 --- a/src/mod/elona/data/map_archetype/player_owned.lua +++ b/src/mod/elona/data/map_archetype/player_owned.lua @@ -32,7 +32,7 @@ local your_home = { level = 1, is_indoor = true, has_anchored_npcs = true, - default_ai_calm = 1, + default_ai_calm = "base.calm_roam", tileset = "elona.home", is_fixed = true, diff --git a/src/mod/elona/data/map_archetype/special.lua b/src/mod/elona/data/map_archetype/special.lua index a193ce4ef..122955a01 100644 --- a/src/mod/elona/data/map_archetype/special.lua +++ b/src/mod/elona/data/map_archetype/special.lua @@ -18,7 +18,7 @@ do types = { "quest" }, level = 1, is_indoor = true, - default_ai_calm = 1, + default_ai_calm = "base.calm_roam", tileset = "elona.home", reveals_fog = true, prevents_monster_ball = true, @@ -58,7 +58,7 @@ do tileset = "elona.tower_1", level = 1, is_indoor = true, - default_ai_calm = 0, + default_ai_calm = "base.calm_null", max_crowd_density = 0, reveals_fog = true, is_temporary = true, @@ -93,7 +93,7 @@ do tileset = "elona.tower_1", level = 1, is_indoor = true, - default_ai_calm = 0, + default_ai_calm = "base.calm_null", max_crowd_density = 0, reveals_fog = true, is_temporary = true, @@ -130,7 +130,7 @@ do is_indoor = false, is_temporary = true, max_crowd_density = 0, - default_ai_calm = 0, + default_ai_calm = "base.calm_null", shows_floor_count_in_name = true, prevents_building_shelter = true } @@ -154,7 +154,7 @@ do level = 1, is_indoor = false, max_crowd_density = 0, - default_ai_calm = 0 + default_ai_calm = "base.calm_null" } } diff --git a/src/mod/elona/data/map_archetype/town.lua b/src/mod/elona/data/map_archetype/town.lua index 1585fd5b3..7ff91ff92 100644 --- a/src/mod/elona/data/map_archetype/town.lua +++ b/src/mod/elona/data/map_archetype/town.lua @@ -37,7 +37,7 @@ do is_indoor = false, is_temporary = false, has_anchored_npcs = true, - default_ai_calm = 1, + default_ai_calm = "base.calm_roam", max_crowd_density = 40, trainer_skills = { "elona.alchemy", @@ -233,7 +233,7 @@ do level = 1, is_indoor = false, has_anchored_npcs = true, - default_ai_calm = 1, + default_ai_calm = "base.calm_roam", quest_town_id = 2, trainer_skills = { "elona.healing", @@ -401,7 +401,7 @@ do level = 1, is_indoor = false, has_anchored_npcs = true, - default_ai_calm = 1, + default_ai_calm = "base.calm_roam", max_crowd_density = 45, quest_town_id = 3, trainer_skills = { @@ -517,11 +517,11 @@ do chara = Chara.create("elona.stersha", 7, 2, nil, map) chara:add_role("elona.royal_family") - chara.ai_calm = 3 + chara.ai_calm_action = "base.calm_stand" chara = Chara.create("elona.xabi", 6, 2, nil, map) chara:add_role("elona.royal_family") - chara.ai_calm = 3 + chara.ai_calm_action = "base.calm_stand" chara = Chara.create("elona.elder", 49, 11, nil, map) chara:add_role("elona.elder") @@ -539,39 +539,39 @@ do chara = Chara.create("elona.guard", 16, 5, nil, map) chara:add_role("elona.guard") - chara.ai_calm = 3 + chara.ai_calm_action = "base.calm_stand" chara = Chara.create("elona.guard", 16, 9, nil, map) chara:add_role("elona.guard") - chara.ai_calm = 3 + chara.ai_calm_action = "base.calm_stand" chara = Chara.create("elona.guard", 5, 3, nil, map) chara:add_role("elona.guard") - chara.ai_calm = 3 + chara.ai_calm_action = "base.calm_stand" chara = Chara.create("elona.guard", 8, 3, nil, map) chara:add_role("elona.guard") - chara.ai_calm = 3 + chara.ai_calm_action = "base.calm_stand" chara = Chara.create("elona.guard", 35, 14, nil, map) chara:add_role("elona.guard") - chara.ai_calm = 3 + chara.ai_calm_action = "base.calm_stand" chara = Chara.create("elona.guard", 38, 14, nil, map) chara:add_role("elona.guard") - chara.ai_calm = 3 + chara.ai_calm_action = "base.calm_stand" chara = Chara.create("elona.guard", 29, 2, nil, map) chara:add_role("elona.guard") - chara.ai_calm = 3 + chara.ai_calm_action = "base.calm_stand" chara = Chara.create("elona.guard", 19, 18, nil, map) chara:add_role("elona.guard") - chara.ai_calm = 3 + chara.ai_calm_action = "base.calm_stand" chara = Chara.create("elona.guard", 22, 18, nil, map) chara:add_role("elona.guard") - chara.ai_calm = 3 + chara.ai_calm_action = "base.calm_stand" for _=1,5 do chara = Chara.create("elona.citizen", nil, nil, nil, map) @@ -641,7 +641,7 @@ do level = 1, is_indoor = false, has_anchored_npcs = true, - default_ai_calm = 1, + default_ai_calm = "base.calm_roam", quest_town_id = 4, trainer_skills = { "elona.lock_picking", @@ -799,7 +799,7 @@ do level = 1, is_indoor = false, has_anchored_npcs = true, - default_ai_calm = 1, + default_ai_calm = "base.calm_roam", quest_town_id = 5, trainer_skills = { "elona.negotiation", @@ -987,7 +987,7 @@ do deepest_dungeon_level = 1, is_indoor = false, has_anchored_npcs = true, - default_ai_calm = 1, + default_ai_calm = "base.calm_roam", quest_town_id = 6, has_snow = true, max_crowd_density = 35, @@ -1070,7 +1070,7 @@ do chara.is_only_in_christmas = true chara = Chara.create("elona.bartender", 17, 8, nil, map) - chara.ai_calm = 3 + chara.ai_calm_action = "base.calm_stand" chara.relation = Enum.Relation.Neutral chara.is_only_in_christmas = true chara:add_role("elona.shopkeeper", {inventory_id="elona.food_vendor"}) @@ -1078,7 +1078,7 @@ do chara.name = I18N.get("chara.job.food_vendor", chara.name) chara = Chara.create("elona.hot_spring_maniac", 25, 8, nil, map) - chara.ai_calm = 3 + chara.ai_calm_action = "base.calm_stand" chara.relation = Enum.Relation.Neutral chara.is_only_in_christmas = true chara:add_role("elona.shopkeeper", {inventory_id="elona.souvenir_vendor"}) @@ -1086,7 +1086,7 @@ do chara.name = I18N.get("chara.job.souvenir_vendor", Text.random_name()) chara = Chara.create("elona.rogue", 24, 22, nil, map) - chara.ai_calm = 3 + chara.ai_calm_action = "base.calm_stand" chara.relation = Enum.Relation.Neutral chara.is_only_in_christmas = true chara:add_role("elona.shopkeeper", {inventory_id="elona.souvenir_vendor"}) @@ -1094,14 +1094,14 @@ do chara.name = I18N.get("chara.job.souvenir_vendor", Text.random_name()) chara = Chara.create("elona.shopkeeper", 38, 12, nil, map) - chara.ai_calm = 3 + chara.ai_calm_action = "base.calm_stand" chara:add_role("elona.shopkeeper", {inventory_id="elona.blackmarket"}) chara.shop_rank = 10 chara.name = I18N.get("chara.job.blackmarket", Text.random_name()) chara.is_only_in_christmas = true chara = Chara.create("elona.rogue", 28, 9, nil, map) - chara.ai_calm = 3 + chara.ai_calm_action = "base.calm_stand" chara.relation = Enum.Relation.Neutral chara.is_only_in_christmas = true chara:add_role("elona.shopkeeper", {inventory_id="elona.street_vendor"}) @@ -1109,7 +1109,7 @@ do chara.name = I18N.get("chara.job.street_vendor", Text.random_name()) chara = Chara.create("elona.rogue", 29, 24, nil, map) - chara.ai_calm = 3 + chara.ai_calm_action = "base.calm_stand" chara.faction = Enum.Relation.Neutral chara.is_only_in_christmas = true chara:add_role("elona.shopkeeper", {inventory_id="elona.street_vendor"}) @@ -1403,7 +1403,7 @@ do level = 1, is_indoor = false, has_anchored_npcs = true, - default_ai_calm = 1, + default_ai_calm = "base.calm_roam", quest_town_id = 7, trainer_skills = { "elona.casting", diff --git a/src/mod/elona/data/map_archetype/unique.lua b/src/mod/elona/data/map_archetype/unique.lua index 1b0245542..6767b1509 100644 --- a/src/mod/elona/data/map_archetype/unique.lua +++ b/src/mod/elona/data/map_archetype/unique.lua @@ -29,7 +29,7 @@ do level = 1, is_indoor = false, has_anchored_npcs = true, - default_ai_calm = 1, + default_ai_calm = "base.calm_roam", max_crowd_density = 7, } } @@ -93,7 +93,7 @@ do is_indoor = false, max_crowd_density = 10, has_anchored_npcs = true, - default_ai_calm = 1 + default_ai_calm = "base.calm_roam" } } @@ -170,7 +170,7 @@ do turn_cost = 100000, level = 1, is_indoor = true, - default_ai_calm = 0, + default_ai_calm = "base.calm_null", max_crowd_density = 0, prevents_teleport = true, prevents_return = true, @@ -207,13 +207,13 @@ local function on_generate_border(map) chara:add_role("elona.shopkeeper", { inventory_id = "elona.general_vendor" }) chara.shop_rank = 10 chara.name = I18N.get("chara.job.general_vendor", chara.name) - chara.ai_calm = 3 + chara.ai_calm_action = "base.calm_stand" chara = Chara.create("elona.shopkeeper", 5, 17, nil, map) chara:add_role("elona.shopkeeper", { inventory_id = "elona.trader" }) chara.shop_rank = 12 chara.name = I18N.get("chara.job.trader", chara.name) - chara.ai_calm = 3 + chara.ai_calm_action = "base.calm_stand" chara = Chara.create("elona.shopkeeper", 16, 19, nil, map) chara:add_role("elona.shopkeeper", { inventory_id = "elona.innkeeper" }) @@ -242,11 +242,11 @@ local function on_generate_border(map) chara = Chara.create("elona.guard", 5, 7, nil, map) chara:add_role("elona.guard") - chara.ai_calm = 3 + chara.ai_calm_action = "base.calm_stand" chara = Chara.create("elona.guard", 8, 7, nil, map) chara:add_role("elona.guard") - chara.ai_calm = 3 + chara.ai_calm_action = "base.calm_stand" end do @@ -266,7 +266,7 @@ do level = 1, is_indoor = false, has_anchored_npcs = true, - default_ai_calm = 1, + default_ai_calm = "base.calm_roam", max_crowd_density = 0, } } @@ -331,7 +331,7 @@ do level = 1, is_indoor = false, has_anchored_npcs = true, - default_ai_calm = 1, + default_ai_calm = "base.calm_roam", max_crowd_density = 0, } } @@ -386,7 +386,7 @@ do level = 1, is_indoor = false, has_anchored_npcs = true, - default_ai_calm = 1, + default_ai_calm = "base.calm_roam", }, } data:add(south_tyris_north_border) @@ -440,7 +440,7 @@ do level = 1, is_indoor = true, has_anchored_npcs = true, - default_ai_calm = 1, + default_ai_calm = "base.calm_roam", max_crowd_density = 0, } } @@ -457,22 +457,22 @@ do chara = Chara.create("elona.the_leopard_warrior", 26, 16, nil, map) chara:add_role("elona.special") - chara.ai_calm = 3 + chara.ai_calm_action = "base.calm_stand" chara = Chara.create("elona.town_child", 25, 15, nil, map) - chara.ai_calm = 3 + chara.ai_calm_action = "base.calm_stand" chara = Chara.create("elona.town_child", 25, 17, nil, map) - chara.ai_calm = 3 + chara.ai_calm_action = "base.calm_stand" chara = Chara.create("elona.town_child", 27, 18, nil, map) - chara.ai_calm = 3 + chara.ai_calm_action = "base.calm_stand" chara = Chara.create("elona.town_child", 27, 16, nil, map) - chara.ai_calm = 3 + chara.ai_calm_action = "base.calm_stand" chara = Chara.create("elona.town_child", 26, 17, nil, map) - chara.ai_calm = 3 + chara.ai_calm_action = "base.calm_stand" chara = Chara.create("elona.silvia", 4, 3, nil, map) chara:add_role("elona.special") @@ -544,7 +544,7 @@ do level = 1, is_indoor = false, has_anchored_npcs = true, - default_ai_calm = 1, + default_ai_calm = "base.calm_roam", reveals_fog = true, } } @@ -605,7 +605,7 @@ do level = 1, is_indoor = false, has_anchored_npcs = true, - default_ai_calm = 1, + default_ai_calm = "base.calm_roam", has_snow = true, max_crowd_density = 0, } @@ -677,7 +677,7 @@ do level = 1, is_indoor = true, has_anchored_npcs = true, - default_ai_calm = 1, + default_ai_calm = "base.calm_roam", max_crowd_density = 10, } } @@ -764,7 +764,7 @@ do level = 1, is_indoor = false, has_anchored_npcs = true, - default_ai_calm = 1, + default_ai_calm = "base.calm_roam", max_crowd_density = 20, } } @@ -866,7 +866,7 @@ do level = 1, is_indoor = true, has_anchored_npcs = true, - default_ai_calm = 1, + default_ai_calm = "base.calm_roam", reveals_fog = true, max_crowd_density = 0, } @@ -946,7 +946,7 @@ do level = 33, is_indoor = true, has_anchored_npcs = true, - default_ai_calm = 1, + default_ai_calm = "base.calm_roam", max_crowd_density = 0, } } @@ -999,7 +999,7 @@ do max_crowd_density = 0, is_indoor = true, has_anchored_npcs = true, - default_ai_calm = 1 + default_ai_calm = "base.calm_roam" } } function fort_of_chaos_machine.on_generate_map(area, floor) @@ -1053,7 +1053,7 @@ do max_crowd_density = 0, is_indoor = true, has_anchored_npcs = true, - default_ai_calm = 1 + default_ai_calm = "base.calm_roam" } } function fort_of_chaos_collapsed.on_generate_map(area, floor) @@ -1105,7 +1105,7 @@ do level = -999999, is_indoor = true, has_anchored_npcs = true, - default_ai_calm = 1, + default_ai_calm = "base.calm_roam", max_crowd_density = 0, item_on_floor_limit = 5, @@ -1154,7 +1154,7 @@ do level = 20, is_indoor = true, has_anchored_npcs = true, - default_ai_calm = 0, + default_ai_calm = "base.calm_null", max_crowd_density = 40, prevents_teleport = true, material_spot_type = "elona.dungeon" @@ -1200,7 +1200,7 @@ do level = 21, is_indoor = true, has_anchored_npcs = true, - default_ai_calm = 0, + default_ai_calm = "base.calm_null", max_crowd_density = 0, prevents_teleport = true, material_spot_type = "elona.dungeon" diff --git a/src/mod/elona/data/map_archetype/world.lua b/src/mod/elona/data/map_archetype/world.lua index 1bc674b62..7af01acfd 100644 --- a/src/mod/elona/data/map_archetype/world.lua +++ b/src/mod/elona/data/map_archetype/world.lua @@ -17,7 +17,7 @@ do turn_cost = 50000, is_indoor = false, has_anchored_npcs = true, - default_ai_calm = 0, + default_ai_calm = "base.calm_null", }, } @@ -87,7 +87,7 @@ do is_indoor = false, has_anchored_npcs = true, max_crowd_density = 0, - default_ai_calm = 0 + default_ai_calm = "base.calm_null" } -- areas = { -- { map = generate_122("elona.south_tyris_north_border"), x = 42, y = 1 }, @@ -127,7 +127,7 @@ do level = 1, is_indoor = false, has_anchored_npcs = true, - default_ai_calm = 0 + default_ai_calm = "base.calm_null" }, } data:add(test_world) diff --git a/src/mod/elona/data/quest/harvest.lua b/src/mod/elona/data/quest/harvest.lua index 675192e15..608e820da 100644 --- a/src/mod/elona/data/quest/harvest.lua +++ b/src/mod/elona/data/quest/harvest.lua @@ -38,7 +38,7 @@ local quest_harvest = { is_indoor = false, is_temporary = true, max_crowd_density = 15, - default_ai_calm = 0, + default_ai_calm = "base.calm_null", shows_floor_count_in_name = true, prevents_building_shelter = true } diff --git a/src/mod/elona/data/quest/huntex.lua b/src/mod/elona/data/quest/huntex.lua index 87f9354e9..6063344c0 100644 --- a/src/mod/elona/data/quest/huntex.lua +++ b/src/mod/elona/data/quest/huntex.lua @@ -20,7 +20,7 @@ local quest_huntex = { is_indoor = false, is_temporary = true, max_crowd_density = 0, - default_ai_calm = 0, + default_ai_calm = "base.calm_null", shows_floor_count_in_name = true, prevents_building_shelter = true } diff --git a/src/mod/elona/data/quest/party.lua b/src/mod/elona/data/quest/party.lua index 1b156d6d5..13ab1b128 100644 --- a/src/mod/elona/data/quest/party.lua +++ b/src/mod/elona/data/quest/party.lua @@ -23,7 +23,7 @@ local map_party = { is_indoor = false, is_temporary = true, max_crowd_density = 0, - default_ai_calm = 0, + default_ai_calm = "base.calm_null", shows_floor_count_in_name = true, prevents_building_shelter = true } From 264ff0cc6d65f2ea1faf45b549f6b19369fdb393 Mon Sep 17 00:00:00 2001 From: Ruin0x11 Date: Fri, 10 Sep 2021 01:00:21 -0700 Subject: [PATCH 11/17] Fix validation errors in `base.chara` --- src/internal/data/schemas.lua | 216 +++++++++++++++++++++++++++++++--- src/mod/content/init.lua | 20 ---- src/mod/elona/data/chara.lua | 1 - src/util/types.lua | 2 +- 4 files changed, 202 insertions(+), 37 deletions(-) diff --git a/src/internal/data/schemas.lua b/src/internal/data/schemas.lua index 36ee445e7..1c4ea116f 100644 --- a/src/internal/data/schemas.lua +++ b/src/internal/data/schemas.lua @@ -75,6 +75,33 @@ local ty_item_filter = types.fields { ownerless = types.boolean, } +local ty_ai_action = types.all( + types.fields { + id = types.data_id("base.ai_action") + }, + types.map(types.string, types.any) +) + +local ty_chara_ai_actions = types.fields { + main = types.optional(types.list(ty_ai_action)), + sub = types.optional(types.list(ty_ai_action)) +} + +local ty_equip_spec = types.map( + types.string, + types.fields { + _id = types.optional(types.data_id("base.item")), + category = types.optional(types.data_id("base.item_type")), + quality = types.optional(types.enum(Enum.Quality)) + } +) + +local ty_drop = types.fields { + _id = types.data_id("base.item"), + amount = types.uint, + on_create = types.callback("item", types.map_object("base.item"), "chara", types.map_object("base.chara"), "attacker", types.optional(types.map_object("base.chara"))) +} + data:add_type( { name = "chara", @@ -91,6 +118,18 @@ data:add_type( template = true, doc = [[ Relative strength of this character. +]] + }, + { + name = "quality", + type = types.optional(types.enum(Enum.Quality)), + }, + { + name = "ai_actions", + type = ty_chara_ai_actions, + default = {}, + doc = [[ +Chance this unit will take an idle action if they have no target. ]] }, { @@ -110,10 +149,11 @@ Idle AI action this unit will take if they have no target. ]] }, { - name = "ai_calm_action", - type = types.optional(types.data_id("base.ai_action")), + name = "ai_sub_action_chance", + type = types.uint, + default = 0, doc = [[ -Idle AI action this unit will take if they have no target. +Chance this character will use an AI sub action. ]] }, { @@ -126,7 +166,7 @@ Minimum distance before this unit starts moving toward their target. }, { name = "portrait", - type = types.optional(types.data_id("base.portrait")), + type = types.optional(types.some(types.data_id("base.portrait"), types.literal("random"))), default = nil, doc = [[ Portrait displayed when conversing with this character. @@ -148,6 +188,11 @@ Remove this to use the character's sprite instead. A list of strings used for filtering during character generation. ]] }, + { + name = "has_own_name", + type = types.boolean, + default = false, + }, { name = "can_talk", type = types.boolean, @@ -167,6 +212,11 @@ What alignment this character has. This determines if it will act hostile toward the player on first sight. ]] }, + { + -- TODO should be data ID in key positions + name = "initial_equipment", + type = ty_equip_spec + }, { name = "race", type = types.data_id("base.race"), @@ -292,6 +342,75 @@ This is for making characters say custom text on certain events. type = types.optional(types.int), default = nil }, + { + -- TODO + name = "eqtwohand", + type = types.optional(types.int), + default = nil + }, + { + -- TODO + name = "eqrange", + type = types.optional(types.some(types.uint, types.tuple(types.uint, types.uint))), + default = nil + }, + { + -- TODO + name = "eqrange_0", + type = types.optional(types.int), + default = nil + }, + { + -- TODO + name = "eqrange_1", + type = types.optional(types.int), + default = nil + }, + { + -- TODO + name = "eqammo", + type = types.optional(types.tuple(types.uint, types.uint)), + default = nil + }, + { + -- TODO + name = "eqammo_0", + type = types.optional(types.int), + default = nil + }, + { + -- TODO + name = "eqammo_1", + type = types.optional(types.int), + default = nil + }, + { + -- TODO + name = "eqring1", + type = types.optional(types.int), + default = nil + }, + { + -- TODO + name = "eqmultiweapon", + type = types.optional(types.int), + default = nil + }, + { + name = "effect_immunities", + type = types.list(types.data_id("base.effect")), + default = {} + }, + { + name = "unarmed_element_id", + type = types.optional(types.data_id("base.element")), + default = nil + }, + { + name = "unarmed_element_power", + type = types.optional(types.int), + default = nil + }, { name = "creaturepack", type = types.enum(Enum.CharaCategory), @@ -338,6 +457,83 @@ Color to display on the character's sprite. type = types.boolean, default = false }, + { + name = "splits", + type = types.boolean, + default = false + }, + { + name = "splits2", + type = types.boolean, + default = false + }, + { + name = "has_lay_hand", + type = types.boolean, + default = false + }, + { + name = "can_cast_rapid_magic", + type = types.boolean, + default = false + }, + { + name = "is_invisible", + type = types.boolean, + default = false + }, + { + name = "is_floating", + type = types.boolean, + default = false + }, + { + name = "is_immune_to_mines", + type = types.boolean, + default = false + }, + { + name = "is_explodable", + type = types.boolean, + default = false + }, + { + name = "always_drops_gold", + type = types.boolean, + default = false + }, + { + name = "ai_regenerates_mana", + type = types.boolean, + default = false + }, + { + name = "rich_loot_amount", + type = types.uint, + default = 0 + }, + { + name = "can_use_snow", + type = types.boolean, + default = false + }, + { + name = "is_immune_to_elemental_damage", + type = types.boolean, + default = false + }, + { + name = "on_initialize_equipment", + type = types.optional(types.callback("self", types.map_object("base.chara"), "params", types.table, "equip_spec", ty_equip_spec)), + }, + { + name = "on_drop_loot", + type = types.optional(types.callback("self", types.map_object("base.chara"), "params", types.table, "drops", types.list(ty_drop))), + }, + { + name = "calc_initial_gold", + type = types.optional(types.callback({"self", types.map_object("base.chara")}, types.uint)), + }, { name = "ai", type = types.data_id("base.ai_action"), @@ -350,7 +546,7 @@ AI callback to run on this character's turn. name = "damage_reaction", type = types.optional( types.fields { - _id = types.data_id("base.damage_reaction"), + id = types.data_id("base.damage_reaction"), power = types.int } ), @@ -493,10 +689,7 @@ Skills this character will already know when they're created. noise = 0, relation = 0, - splits = nil, - splits2 = nil, is_quick_tempered = nil, - has_lay_hand = nil, is_lay_hand_available = nil, is_invisible = nil, is_summoned = nil, @@ -2516,13 +2709,6 @@ data:add_type { } } -local ty_equip_spec = types.map(types.string, types.fields { category = types.data_id("base.item_type"), quality = types.enum(Enum.Quality)}) -local ty_drop = types.fields { - _id = types.data_id("base.item"), - amount = types.uint, - on_create = types.callback("item", types.map_object("base.item"), "chara", types.map_object("base.chara"), "attacker", types.optional(types.map_object("base.chara"))) -} - data:add_type { name = "equipment_type", fields = { diff --git a/src/mod/content/init.lua b/src/mod/content/init.lua index 220eeff06..0726e94aa 100644 --- a/src/mod/content/init.lua +++ b/src/mod/content/init.lua @@ -4,31 +4,11 @@ data:add { _type = "base.chara", _id = "player", - name = "player", race = "elona.norland", class = "elona.tourist", relation = Enum.Relation.Neutral, image = "elona.chara_rabbit", level = 1, - max_hp = 50, - max_mp = 10, rarity = 0, coefficient = 400, - - body_parts = { - "elona.head", - "elona.neck", - "elona.back", - "elona.body", - "elona.hand", - "elona.hand", - "elona.ring", - "elona.ring", - "elona.arm", - "elona.arm", - "elona.waist", - "elona.leg", - "elona.ranged", - "elona.ammo" - } } diff --git a/src/mod/elona/data/chara.lua b/src/mod/elona/data/chara.lua index 8cee1877a..0e5bf7aab 100644 --- a/src/mod/elona/data/chara.lua +++ b/src/mod/elona/data/chara.lua @@ -19,7 +19,6 @@ local eating_effect = require("mod.elona.data.chara.eating_effect") local chara = { { _id = "bug", - _doc = "bug", elona_id = 0, loot_type = "elona.humanoid", level = 1, diff --git a/src/util/types.lua b/src/util/types.lua index 6194d440c..eb77e7860 100644 --- a/src/util/types.lua +++ b/src/util/types.lua @@ -852,7 +852,7 @@ do end s[#s+1] = tostring(checker) end - return ("all<%s>"):format(table.concat(", ")) + return ("all<%s>"):format(print_list(self.checkers)) end types.all = wrap(all_checker) end From 9235ec0790cf2f0d4b280d6604094573f5631368 Mon Sep 17 00:00:00 2001 From: Ruin0x11 Date: Fri, 10 Sep 2021 02:07:40 -0700 Subject: [PATCH 12/17] Fix various validation errors --- src/internal/data/schemas.lua | 102 +++++++++++++- src/internal/data_table.lua | 3 + src/mod/elona/api/Wish.lua | 10 +- .../elona/data/dialog/special/quest_giver.lua | 1 - .../elona/data/dialog/unique/larnneire.lua | 1 - src/mod/elona/data/dialog/unique/miches.lua | 1 - src/mod/elona/data/effect.lua | 38 ++--- src/mod/elona/data/encounter.lua | 2 +- src/mod/elona/data/food_type.lua | 28 ++++ src/mod/elona/data/item_material.lua | 20 +++ src/mod/elona/data/magic/skill.lua | 1 - src/mod/elona/data/material_spot.lua | 8 +- src/mod/elona/data/nefia.lua | 4 + src/mod/elona/data/quest/collect.lua | 1 - src/mod/elona/data/quest/cook.lua | 1 - src/mod/elona/data/quest/deliver.lua | 1 - src/mod/elona/data/quest/supply.lua | 1 - src/mod/elona/data/rank.lua | 20 ++- src/mod/elona/data/shop_inventory.lua | 29 +++- src/mod/elona/data/weather.lua | 7 +- src/mod/elona/data/wish_handler.lua | 18 +-- src/mod/elona/init/god.lua | 10 +- src/mod/elona_sys/init.lua | 133 ++++++++++++++++-- src/mod/elona_sys/map_tileset/init.lua | 11 +- src/mod/smithing/data/trait.lua | 2 +- src/mod/titles/data/titles/title.lua | 2 +- src/util/types.lua | 2 +- 27 files changed, 375 insertions(+), 82 deletions(-) diff --git a/src/internal/data/schemas.lua b/src/internal/data/schemas.lua index 1c4ea116f..4cd260a66 100644 --- a/src/internal/data/schemas.lua +++ b/src/internal/data/schemas.lua @@ -1293,9 +1293,24 @@ data:add_type( name = "skills", type = types.map(types.data_id("base.skill"), types.number) }, + { + name = "traits", + type = types.map(types.data_id("base.trait"), types.number), + default = {} + }, { name = "body_parts", type = types.list(types.data_id("base.body_part")), + }, + { + name = "resistances", + type = types.list(types.data_id("base.element")), + default = {} + }, + { + name = "effect_immunities", + type = types.list(types.data_id("base.effect")), + default = {} } }, } @@ -1787,6 +1802,7 @@ data:add_type { } local ty_target_type = types.literal("self", "nearby", "self_or_nearby", "enemy", "other", "location", "direction", "target_or_location") +local ty_triggered_by = types.literal("spell", "action", "wand", "potion", "potion_thrown", "potion_spilt", "use", "open") data:add_type { name = "enchantment_skill", @@ -1885,16 +1901,35 @@ Stamina cost of the ammo when fired. } } +local ty_dice = types.fields_strict { + x = types.number, + y = types.number, + bonus = types.number +} + data:add_type { name = "skill", fields = { + { + name = "elona_id", + indexed = true, + type = types.optional(types.uint), + }, { name = "type", - type = types.literal("stat", "stat_special", "skill", "weapon_proficiency"), + type = types.literal("stat", "stat_special", "skill", "spell", "action", "skill_action", "effect", "weapon_proficiency"), default = "skill", template = true, doc = [[ Determines how this skill is treated in the interface. +]] + }, + { + name = "is_main_skill", + type = types.boolean, + default = false, + doc = [[ +If true, this skill will gain a level bonus for every character that is created. ]] }, { @@ -1942,6 +1977,56 @@ Difficulty of triggering this skill. Used only when the skill's `type` is "spell" or "action". ]] }, + { + name = "effect_id", + type = types.optional(types.data_id("elona_sys.magic")), + }, + { + name = "is_rapid_magic", + type = types.boolean, + default = false, + }, + { + name = "alignment", + type = types.optional(types.literal("positive", "negative")), + }, + { + name = "calc_initial_level", + type = types.optional(types.callback("level", types.number, "chara", types.map_object("base.chara"))), + }, + { + name = "calc_critical_damage", + type = types.optional(types.callback("self", types.table, "params", types.table)), + }, + { + name = "on_check_can_cast", + type = types.optional(types.callback({"skill_data", types.data_entry("base.skill"), "caster", types.map_object("base.chara")}, types.boolean)), + }, + { + name = "on_choose_target", + type = types.optional(types.callback("target_type", ty_target_type, + "range", types.number, + "caster", types.map_object("base.chara"), + "triggered_by", ty_triggered_by, + "ai_target", types.map_object("base.chara"), + "check_ranged_if_self", types.boolean)), + }, + { + name = "calc_desc", + type = types.optional(types.callback("chara", types.map_object("base.chara"), + "power", types.number, + "dice", ty_dice)), + }, + { + name = "calc_mp_cost", + type = types.optional(types.callback("skill_entry", types.data_entry("base.skill"), + "chara", types.map_object("base.chara"))), + }, + { + -- TODO should be themable + name = "attack_animation", + type = types.optional(types.uint), + }, { name = "target_type", type = ty_target_type, @@ -2038,6 +2123,11 @@ data:add_type { { name = "file", type = types.path + }, + { + name = "volume", + type = types.number, + default = 1.0 } } } @@ -2260,7 +2350,15 @@ data:add_type { { name = "elona_txt_id", type = types.optional(types.string) - } + }, + { + name = "variant_ids", + type = types.optional(types.table) + }, + { + name = "variant_txt_ids", + type = types.optional(types.table) + }, } } diff --git a/src/internal/data_table.lua b/src/internal/data_table.lua index 2ecca29e1..f4f2623ae 100644 --- a/src/internal/data_table.lua +++ b/src/internal/data_table.lua @@ -328,6 +328,9 @@ function data_table:validate_all(verbose) end local function sort_data_entries(a, b) + if a._ordering == b._ordering then + return a._id < b._id + end return a._ordering < b._ordering end diff --git a/src/mod/elona/api/Wish.lua b/src/mod/elona/api/Wish.lua index 988d18bd0..b1a603b00 100644 --- a/src/mod/elona/api/Wish.lua +++ b/src/mod/elona/api/Wish.lua @@ -35,16 +35,8 @@ end function Wish.grant_wish(wish, chara) chara = chara or Chara.player() - local sort = function(a, b) - if a.priority == b.priority then - return a._id < b._id - end - - return a.priority < b.priority - end - local did_something = false - for _, handler in data["elona.wish_handler"]:iter():into_sorted(sort) do + for _, handler in data["elona.wish_handler"]:iter() do local result = handler.on_wish(wish, chara) if result then did_something = true diff --git a/src/mod/elona/data/dialog/special/quest_giver.lua b/src/mod/elona/data/dialog/special/quest_giver.lua index 33f554d05..75a4c565e 100644 --- a/src/mod/elona/data/dialog/special/quest_giver.lua +++ b/src/mod/elona/data/dialog/special/quest_giver.lua @@ -5,7 +5,6 @@ data:add { _type = "elona_sys.dialog", _id = "quest_giver", - root = "talk.npc.quest_giver", nodes = { quest_about = { text = function(t) diff --git a/src/mod/elona/data/dialog/unique/larnneire.lua b/src/mod/elona/data/dialog/unique/larnneire.lua index d1dd3300c..47e284484 100755 --- a/src/mod/elona/data/dialog/unique/larnneire.lua +++ b/src/mod/elona/data/dialog/unique/larnneire.lua @@ -2,7 +2,6 @@ data:add { _type = "elona_sys.dialog", _id = "larnneire", - root = "talk.unique.larnneire", nodes = { __start = { text = { diff --git a/src/mod/elona/data/dialog/unique/miches.lua b/src/mod/elona/data/dialog/unique/miches.lua index 322a4516c..c1be0938a 100755 --- a/src/mod/elona/data/dialog/unique/miches.lua +++ b/src/mod/elona/data/dialog/unique/miches.lua @@ -9,7 +9,6 @@ data:add { _type = "elona_sys.dialog", _id = "miches", - root = "talk.unique.miches", nodes = { __start = function() local flag = Sidequest.progress("elona.putit_attacks") diff --git a/src/mod/elona/data/effect.lua b/src/mod/elona/data/effect.lua index 733db22bf..52e4ed096 100644 --- a/src/mod/elona/data/effect.lua +++ b/src/mod/elona/data/effect.lua @@ -37,8 +37,8 @@ end data:add { _type = "base.ui_indicator", _id = "nutrition", + _ordering = 10000, - ordering = 10000, indicator = indicator_nutrition } @@ -57,8 +57,8 @@ end data:add { _type = "base.ui_indicator", _id = "burden", + _ordering = 190000, - ordering = 190000, indicator = indicator_burden } @@ -82,8 +82,8 @@ end data:add { _type = "base.ui_indicator", _id = "stamina", + _ordering = 180000, - ordering = 180000, indicator = indicator_stamina } @@ -109,8 +109,8 @@ end data:add { _type = "base.ui_indicator", _id = "awake_hours", + _ordering = 170000, - ordering = 170000, indicator = indicator_awake_hours } @@ -118,7 +118,7 @@ local effect = { { _id = "sick", - ordering = 20000, + _ordering = 20000, color = {80, 120, 0}, indicator = function(chara) local turns = chara:effect_turns("elona.sick") @@ -182,7 +182,7 @@ local effect = { { _id = "poison", - ordering = 30000, + _ordering = 30000, color = { 0, 150, 0 }, emotion_icon = "elona.skull", indicator = function(chara) @@ -239,7 +239,7 @@ local effect = { { _id = "sleep", - ordering = 40000, + _ordering = 40000, color = {0, 50, 50}, emotion_icon = "elona.sleep", indicator = function(chara) @@ -303,7 +303,7 @@ local effect = { }, { _id = "blindness", - ordering = 50000, + _ordering = 50000, color = {100, 100, 0}, indicator = "effect.elona.blindness.indicator", emotion_icon = "elona.blind", @@ -357,7 +357,7 @@ local effect = { }, { _id = "paralysis", - ordering = 60000, + _ordering = 60000, color = {0, 100, 100}, indicator = "effect.elona.paralysis.indicator", emotion_icon = "elona.paralyze", @@ -402,7 +402,7 @@ local effect = { }, { _id = "choking", - ordering = 70000, + _ordering = 70000, color = {0, 100, 100}, indicator = "effect.elona.choking.indicator", @@ -434,7 +434,7 @@ local effect = { }, { _id = "confusion", - ordering = 80000, + _ordering = 80000, color = {100, 0, 100}, indicator = "effect.elona.confusion.indicator", emotion_icon = "elona.confuse", @@ -471,7 +471,7 @@ local effect = { }, { _id = "fear", - ordering = 90000, + _ordering = 90000, color = {100, 0, 100}, indicator = "effect.elona.fear.indicator", emotion_icon = "elona.fear", @@ -496,7 +496,7 @@ local effect = { }, { _id = "dimming", - ordering = 100000, + _ordering = 100000, color = {0, 100, 100}, emotion_icon = "elona.dim", @@ -561,7 +561,7 @@ local effect = { }, { _id = "fury", - ordering = 110000, + _ordering = 110000, color = {150, 0, 0}, indicator = function(chara) local turns = chara:effect_turns("elona.fury") @@ -578,7 +578,7 @@ local effect = { }, { _id = "bleeding", - ordering = 120000, + _ordering = 120000, color = {150, 0, 0}, emotion_icon = "elona.bleed", indicator = function(chara) @@ -626,7 +626,7 @@ local effect = { }, { _id = "insanity", - ordering = 130000, + _ordering = 130000, color = {150, 100, 0}, emotion_icon = "elona.insane", indicator = function(chara) @@ -684,7 +684,7 @@ local effect = { }, { _id = "drunk", - ordering = 140000, + _ordering = 140000, color = {100, 0, 100}, indicator = "effect.elona.drunk.indicator", emotion_icon = "elona.happy", @@ -701,7 +701,7 @@ local effect = { }, { _id = "wet", - ordering = 150000, + _ordering = 150000, color = {0, 0, 160}, indicator = "effect.elona.wet.indicator", @@ -711,7 +711,7 @@ local effect = { }, { _id = "gravity", - ordering = 160000, + _ordering = 160000, color = {0, 80, 80}, indicator = "effect.elona.gravity.indicator" }, diff --git a/src/mod/elona/data/encounter.lua b/src/mod/elona/data/encounter.lua index d4fa34a64..f947635b0 100644 --- a/src/mod/elona/data/encounter.lua +++ b/src/mod/elona/data/encounter.lua @@ -13,7 +13,7 @@ Controls the level of the encounter. }, { name = "before_encounter_start", - type = types.callback({"level", types.uint, "outer_map", types.class(InstancedMap), "outer_x", types.uint, "outer_y", types.uint}, types.number), + type = types.optional(types.callback({"level", types.uint, "outer_map", types.class(InstancedMap), "outer_x", types.uint, "outer_y", types.uint}, types.number)), template = true, doc = [[ This is run before the player is transported to the encounter map. diff --git a/src/mod/elona/data/food_type.lua b/src/mod/elona/data/food_type.lua index a98bb1718..006ec275b 100644 --- a/src/mod/elona/data/food_type.lua +++ b/src/mod/elona/data/food_type.lua @@ -1,6 +1,34 @@ data:add_type { name = "food_type", fields = { + { + name = "elona_id", + indexed = true, + type = types.optional(types.uint) + }, + { + name = "uses_chara_name", + type = types.boolean, + default = false + }, + { + name = "exp_gains", + type = types.list(types.fields { _id = types.data_id("base.skill"), amount = types.number }), + default = {} + }, + { + name = "base_nutrition", + type = types.number, + }, + { + name = "item_chips", + type = types.map(types.uint, types.data_id("base.chip")), + default = {} + }, + { + name = "quest_reward_category", + type = types.optional(types.data_id("elona_sys.quest_reward")), + }, } } diff --git a/src/mod/elona/data/item_material.lua b/src/mod/elona/data/item_material.lua index b5ed39589..cf89dec46 100644 --- a/src/mod/elona/data/item_material.lua +++ b/src/mod/elona/data/item_material.lua @@ -1,3 +1,10 @@ +-- TODO join with definition in `base` +local ty_enchantment_def = types.fields { + _id = types.data_id("base.enchantment"), + power = types.number, + params = types.optional(types.table) +} + data:add_type { name = "item_material", fields = { @@ -58,6 +65,19 @@ data:add_type { name = "no_furniture", type = types.boolean, default = false + }, + { + name = "on_refresh", + type = types.optional(types.callback("item", types.map_object("base.item"))), + }, + { + name = "on_equipper_refresh", + type = types.optional(types.callback("chara", types.map_object("base.chara"), "item", types.map_object("base.item"))), + }, + { + name = "enchantments", + type = types.list(ty_enchantment_def), + default = {} } }, } diff --git a/src/mod/elona/data/magic/skill.lua b/src/mod/elona/data/magic/skill.lua index 50cd23006..4da5f3d9f 100644 --- a/src/mod/elona/data/magic/skill.lua +++ b/src/mod/elona/data/magic/skill.lua @@ -319,7 +319,6 @@ data:add { type = "skill_action", effect_id = "elona.riding", related_skill = "elona.stat_will", - ability_type = 0, target_type = "nearby", } diff --git a/src/mod/elona/data/material_spot.lua b/src/mod/elona/data/material_spot.lua index 10b085e6d..c2ed6e6d6 100644 --- a/src/mod/elona/data/material_spot.lua +++ b/src/mod/elona/data/material_spot.lua @@ -19,7 +19,7 @@ data:add_type { { name = "get_verb", type = types.locale_id, - default = nil, + default = "activity.material.get_verb.get" }, { name = "materials", @@ -108,7 +108,7 @@ data:add_type { fields = { { - name = "auto_turn_anim", + name = "activity_auto_turn_anim", type = types.data_id("base.auto_turn_anim"), default = "base.searching", template = true @@ -143,6 +143,10 @@ data:add_type { default = nil, template = true }, + { + name = "on_calc_materials", + type = types.optional(types.callback({"self", types.map_object("base.chara"), "params", types.table, "result", types.any}, types.table)) + }, { name = "on_stepped_on_text", type = types.locale_id, diff --git a/src/mod/elona/data/nefia.lua b/src/mod/elona/data/nefia.lua index e84efad64..2988c371b 100644 --- a/src/mod/elona/data/nefia.lua +++ b/src/mod/elona/data/nefia.lua @@ -17,6 +17,10 @@ data:add_type { name = "image", type = types.data_id("base.chip") }, + { + name = "color", + type = types.optional(types.color) + }, { name = "on_generate_floor", type = types.callback({"area", types.class(InstancedArea), "floor", types.uint}, types.class(InstancedMap)) diff --git a/src/mod/elona/data/quest/collect.lua b/src/mod/elona/data/quest/collect.lua index c9e837e78..110f7d018 100644 --- a/src/mod/elona/data/quest/collect.lua +++ b/src/mod/elona/data/quest/collect.lua @@ -108,7 +108,6 @@ data:add { _type = "elona_sys.dialog", _id = "quest_collect", - root = "talk.npc.quest_giver", nodes = { give = function(t) -- TODO generalize with dialog argument diff --git a/src/mod/elona/data/quest/cook.lua b/src/mod/elona/data/quest/cook.lua index 77ce1b965..bf8a81628 100644 --- a/src/mod/elona/data/quest/cook.lua +++ b/src/mod/elona/data/quest/cook.lua @@ -85,7 +85,6 @@ data:add { _type = "elona_sys.dialog", _id = "quest_cook", - root = "talk.npc.quest_giver", nodes = { give = function(t) -- TODO generalize with dialog argument diff --git a/src/mod/elona/data/quest/deliver.lua b/src/mod/elona/data/quest/deliver.lua index fc504d34b..0fae60902 100644 --- a/src/mod/elona/data/quest/deliver.lua +++ b/src/mod/elona/data/quest/deliver.lua @@ -188,7 +188,6 @@ data:add { _type = "elona_sys.dialog", _id = "quest_deliver", - root = "talk.npc.quest_giver", nodes = { backpack_full = { text = { diff --git a/src/mod/elona/data/quest/supply.lua b/src/mod/elona/data/quest/supply.lua index 47e4a8182..918fb7b22 100644 --- a/src/mod/elona/data/quest/supply.lua +++ b/src/mod/elona/data/quest/supply.lua @@ -70,7 +70,6 @@ data:add { _type = "elona_sys.dialog", _id = "quest_supply", - root = "talk.npc.quest_giver", nodes = { trade = function(t) Gui.mes_c("TODO", "Yellow") diff --git a/src/mod/elona/data/rank.lua b/src/mod/elona/data/rank.lua index f054729d8..2ec53967a 100644 --- a/src/mod/elona/data/rank.lua +++ b/src/mod/elona/data/rank.lua @@ -1,6 +1,24 @@ data:add_type { name = "rank", - fields = {} + fields = { + { + name = "elona_id", + indexed = true, + type = types.optional(types.uint) + }, + { + name = "decay_period_days", + type = types.optional(types.number) + }, + { + name = "provides_salary_items", + type = types.optional(types.boolean) + }, + { + name = "calc_income", + type = types.optional(types.callback({"income", types.number}, types.number)) + }, + } } data:add { diff --git a/src/mod/elona/data/shop_inventory.lua b/src/mod/elona/data/shop_inventory.lua index 0928b3c26..deecfa4a9 100755 --- a/src/mod/elona/data/shop_inventory.lua +++ b/src/mod/elona/data/shop_inventory.lua @@ -89,13 +89,18 @@ Available properties: local ty_item_categories = types.some(types.data_id("base.item_type"), types.list(types.data_id("base.item_type"))) local ty_shop_inv_rule = types.fields { - one_in = types.uint, - all_but_one_in = types.uint, - categories = ty_item_categories, - id = types.some(types.data_id("base.item"), types.literal("Skip")), - choices = types.list(types.fields { categories = types.some(types.data_id("base.item_type"), types.list(types.data_id("base.item_type"))) }), - predicate = types.callback({"args", types.table}, types.boolean), - on_generate = types.callback({}, types.table), -- TODO recursive types + one_in = types.optional(types.uint), + all_but_one_in = types.optional(types.uint), + categories = types.optional(ty_item_categories), + id = types.optional(types.some(types.data_id("base.item"), types.literal("Skip"))), + choices = types.optional(types.list(types.fields { + -- TODO recursive types + categories = types.optional(types.some(types.data_id("base.item_type"), + types.list(types.data_id("base.item_type")))), + choices = types.optional(types.table) + })), + predicate = types.optional(types.callback({"args", types.table}, types.boolean)), + on_generate = types.optional(types.callback({}, types.table)), -- TODO recursive types } data:add_type( @@ -126,6 +131,16 @@ data:add_type( name = "restock_interval", type = types.positive(types.number) }, + { + name = "is_temporary", + type = types.boolean, + default = false + }, + { + name = "ignores_noshop", + type = types.boolean, + default = false + }, } } ) diff --git a/src/mod/elona/data/weather.lua b/src/mod/elona/data/weather.lua index c348b9337..20da8e03f 100644 --- a/src/mod/elona/data/weather.lua +++ b/src/mod/elona/data/weather.lua @@ -17,6 +17,11 @@ local Hunger = require("mod.elona.api.Hunger") data:add_type { name = "weather", fields = { + { + name = "elona_id", + indexed = true, + type = types.optional(types.uint) + }, { name = "travel_speed_modifier", type = types.callback({"turns", types.number}, types.number), @@ -39,7 +44,7 @@ data:add_type { }, { name = "outdoor_shadow", - type = types.callback({"shadow", types.color}, types.color), + type = types.optional(types.callback({"shadow", types.color}, types.color)), template = true }, { diff --git a/src/mod/elona/data/wish_handler.lua b/src/mod/elona/data/wish_handler.lua index 86ca1a2dc..5631e0466 100644 --- a/src/mod/elona/data/wish_handler.lua +++ b/src/mod/elona/data/wish_handler.lua @@ -26,19 +26,7 @@ data:add_type { doc = [[ Code to run on wish. `wish` contains the wish text. `chara` contains the wishing character. ]] - }, - { - name = "ordering", - type = types.int, - default = 0, - template = true, - doc = [[ -Order to run the handler in. Lower values get checked before later ones. - -This is important as the item/skill name matchers can match an arbitrary string, -so more specific handlers should have lower priority than those. -]] - }, + } } } @@ -49,7 +37,7 @@ local function match_any(wish, locale_key) return fun.iter(cands):any(match) end -local function add_wish_handler(_id, match, on_wish, priority) +local function add_wish_handler(_id, match, on_wish, ordering) if type(match) == "string" then local match_ = match match = function(wish, chara) @@ -70,9 +58,9 @@ local function add_wish_handler(_id, match, on_wish, priority) data:add { _type = "elona.wish_handler", _id = _id, + _ordering = ordering, on_wish = on_wish, - priority = priority } end diff --git a/src/mod/elona/init/god.lua b/src/mod/elona/init/god.lua index d0cab280d..168a61ea3 100644 --- a/src/mod/elona/init/god.lua +++ b/src/mod/elona/init/god.lua @@ -3,19 +3,19 @@ local God = require("mod.elona.api.God") local ty_god_item = types.fields { id = types.data_id("base.item"), - no_stack = types.boolean, - only_once = types.boolean, - properties = types.table + no_stack = types.optional(types.boolean), + only_once = types.optional(types.boolean), + properties = types.optional(types.table), } local ty_god_offering = types.some( types.fields_strict { type = types.literal("category"), - id = types.data_id("base.item_type") + id = types.data_id("base.item_type"), }, types.fields_strict { type = types.literal("item"), - id = types.data_id("base.item") + id = types.data_id("base.item"), } ) diff --git a/src/mod/elona_sys/init.lua b/src/mod/elona_sys/init.lua index 0d6a8d61c..37bd1b90a 100644 --- a/src/mod/elona_sys/init.lua +++ b/src/mod/elona_sys/init.lua @@ -1,11 +1,17 @@ local InventoryContext = require("api.gui.menu.InventoryContext") local InventoryWrapper = require("api.gui.menu.InventoryWrapper") +local InstancedMap = require("api.InstancedMap") local ty_quest = types.table -- TODO data:add_type { name = "quest", fields = { + { + name = "elona_id", + indexed = true, + type = types.optional(types.uint) + }, { name = "client_chara_type", type = types.uint, @@ -24,7 +30,7 @@ data:add_type { }, { name = "chance", - type = types.uint + type = types.some(types.uint, types.callback({"client", types.table, "town", types.class(InstancedMap)}, types.number)), }, { name = "params", @@ -42,26 +48,59 @@ data:add_type { name = "deadline_days", type = types.optional(types.callback({}, types.number)) }, + { + name = "calc_reward_gold", + type = types.optional(types.callback({"quest", ty_quest, "gold", types.uint}, types.uint)) + }, + { + name = "calc_reward_platinum", + type = types.optional(types.callback({"quest", ty_quest, "platinum", types.uint}, types.uint)) + }, + { + name = "calc_reward_item_count", + type = types.optional(types.callback({"quest", ty_quest, "item_count", types.uint}, types.uint)) + }, + { + name = "reward_count", + type = types.optional(types.callback({"quest", ty_quest}, types.uint)) + }, { name = "generate", type = types.callback({"quest", ty_quest, "client", types.map_object("base.chara")}, types.boolean) }, { name = "on_accept", - type = types.callback({"quest", ty_quest}, {types.boolean, types.optional(types.locale_id)}) + type = types.optional(types.callback({"quest", ty_quest}, {types.boolean, types.optional(types.locale_id)})) }, { name = "on_failure", - type = types.callback({"quest", ty_quest}) + type = types.optional(types.callback("quest", ty_quest)) }, { name = "on_complete", type = types.callback({}, types.locale_id) }, + { + name = "on_time_expired", + type = types.optional(types.callback("quest", ty_quest)) + }, + { + name = "locale_data", + type = types.optional(types.callback({"quest", ty_quest}, types.table)) + }, + { + name = "target_chara_uids", + type = types.optional(types.callback({"quest", ty_quest}, types.list(types.uint))) + }, { name = "prevents_return", type = types.boolean, default = false + }, + { + name = "prevents_pickpocket", + type = types.boolean, + default = false } } } @@ -77,6 +116,15 @@ data:add_type { { name = "generate", type = types.callback({"quest_reward", types.table, "quest", ty_quest}) + }, + { + name = "localize", + type = types.optional(types.callback({"self", types.table}, types.string)) + }, + { + name = "params", + type = types.map(types.string, types.type), + default = {} } } } @@ -101,6 +149,7 @@ data:add_type { } } +-- TODO unify with definition in `base` mod local ty_dice = types.fields_strict { x = types.number, y = types.number, @@ -164,13 +213,18 @@ Function run when the magic is cast. name = "related_skill", type = types.data_id("base.skill") }, + { + name = "alignment", + type = types.optional(types.literal("positive", "negative")) + }, { name = "cost", type = types.number }, { name = "range", - type = types.uint + type = types.uint, + default = 0, }, { name = "type", @@ -200,6 +254,18 @@ Run the logic for this buff, if any. This can be omitted if the effect is implemented in event handlers, like for Silence. ]] }, + { + name = "on_add", + type = types.optional(types.callback("self", types.data_entry("base.buff"), "params", types.table)), + }, + { + name = "on_remove", + type = types.optional(types.callback("self", types.data_entry("base.buff"), "chara", types.map_object("base.chara"))), + }, + { + name = "on_expire", + type = types.optional(types.callback("self", types.data_entry("base.buff"), "chara", types.map_object("base.chara"))), + }, { name = "params", type = types.callback({"self", types.data_entry("base.buff"), "params", types.table}, types.fields_strict { duration = types.number, power = types.number }) @@ -208,6 +274,16 @@ implemented in event handlers, like for Silence. -- TODO needs to be themable name = "image", type = types.uint + }, + { + name = "target_rider", + type = types.boolean, + default = false + }, + { + name = "no_remove_on_heal", + type = types.boolean, + default = false } }, } @@ -215,6 +291,11 @@ implemented in event handlers, like for Silence. data:add_type { name = "basic_anim", fields = { + { + name = "elona_id", + indexed = true, + type = types.optional(types.uint) + }, { name = "wait", type = types.number, @@ -288,7 +369,7 @@ data:add_type { }, { name = "sources", - type = types.list(types.literal("chara", "equipment", "target", "container", "shop", "target_equipment", "ground")) + type = types.list(types.literal("chara", "equipment", "target", "target_optional", "container", "shop", "target_equipment", "ground")) }, { name = "shortcuts", @@ -309,25 +390,51 @@ data:add_type { type = types.boolean, default = false, }, + { + name = "show_target_equip", + type = types.boolean, + default = false + }, { name = "window_title", type = types.locale_id }, { name = "query_text", - type = types.locale_id + type = types.some(types.locale_id, types.callback({"ctxt", types.class(InventoryContext), "item", types.map_object("base.item")}, types.string)) }, { name = "window_detail_header", type = types.locale_id }, + { + name = "default_amount", + type = types.optional(types.uint) + }, + { + name = "allow_special_owned", + type = types.boolean, + default = false + }, + { + name = "params", + type = types.map(types.string, types.type) + }, { name = "keybinds", type = types.optional(types.callback({"ctxt", types.class(InventoryContext)}, types.map(types.string, types.callback("wrapper", types.class(InventoryWrapper))))) }, { name = "key_hints", - type = types.optional(types.callback({"ctxt", types.class(InventoryContext)}, types.list(ty_key_hint))) + type = types.optional( + types.some( + types.list(ty_key_hint), + types.callback({"ctxt", types.class(InventoryContext)}, types.list(ty_key_hint))) + ) + }, + { + name = "get_item_name", + type = types.optional(types.callback({"name", types.string, "item", types.map_object("base.item")}, types.string)) }, { name = "get_item_detail_text", @@ -345,6 +452,10 @@ data:add_type { name = "after_filter", type = types.optional(types.callback({"ctxt", types.class(InventoryContext), "filtered", types.list(ty_ctxt_item)}, types.optional(types.string))) }, + { + name = "on_query", + type = types.optional(types.callback("ctxt", types.class(InventoryContext))) + }, { name = "can_select", type = types.optional(types.callback({"ctxt", types.class(InventoryContext), "item", types.map_object("base.item")}, types.boolean)) @@ -395,6 +506,10 @@ local ty_scene_entry = types.some( [1] = types.literal("mc"), [2] = types.data_id("base.music"), }, + types.fields_strict { + [1] = types.literal("se"), + [2] = types.data_id("base.sound"), + }, types.fields_strict { [1] = types.literal("txt"), [2] = types.string @@ -406,7 +521,9 @@ local ty_scene_entry = types.some( }, types.fields_strict { [1] = types.literal("actor"), - [2] = types.fields_strict { name = types.string, portrait = types.data_id("base.portrait") } + [2] = types.uint, + name = types.string, + portrait = types.data_id("base.portrait") } ) diff --git a/src/mod/elona_sys/map_tileset/init.lua b/src/mod/elona_sys/map_tileset/init.lua index fc368b751..0d04cfeed 100644 --- a/src/mod/elona_sys/map_tileset/init.lua +++ b/src/mod/elona_sys/map_tileset/init.lua @@ -12,7 +12,16 @@ data:add_type { }, { name = "fog", - type = types.data_id("base.map_tile") + type = types.some(types.data_id("base.map_tile"), types.callback({"x", types.uint, "y", types.uint, "tile", types.table}, types.data_id("base.map_tile"))) + }, + { + name = "door", + type = types.optional(types.fields + { + open_tile = types.data_id("base.chip"), + closed_tile = types.data_id("base.chip") + } + ) } } } diff --git a/src/mod/smithing/data/trait.lua b/src/mod/smithing/data/trait.lua index db9392cb0..970e167b6 100644 --- a/src/mod/smithing/data/trait.lua +++ b/src/mod/smithing/data/trait.lua @@ -8,7 +8,7 @@ data:add { level_max = 3, type = "feat", - can_learn = function(self, chara) + can_acquire = function(self, chara) return chara:is_player() end, } diff --git a/src/mod/titles/data/titles/title.lua b/src/mod/titles/data/titles/title.lua index 17749ec0e..9c963d8ad 100644 --- a/src/mod/titles/data/titles/title.lua +++ b/src/mod/titles/data/titles/title.lua @@ -16,7 +16,7 @@ data:add_type { }, { name = "on_refresh", - type = types.callback("chara", types.map_object("base.chara"), "effect_on", types.boolean) + type = types.optional(types.callback("chara", types.map_object("base.chara"), "effect_on", types.boolean)) } } } diff --git a/src/util/types.lua b/src/util/types.lua index eb77e7860..89b2caad2 100644 --- a/src/util/types.lua +++ b/src/util/types.lua @@ -570,7 +570,7 @@ do return false, type_error(self) end - if class.uses_interface(self.iface, obj) then + if class.uses_interface(obj, self.iface) then return true end From f0e77b2b53f8e010e18f5c37a77eb4bbf61d74f9 Mon Sep 17 00:00:00 2001 From: Ruin0x11 Date: Fri, 10 Sep 2021 02:51:07 -0700 Subject: [PATCH 13/17] Finish adding validation for all data types --- src/game/startup.lua | 12 +- src/internal/data/events.lua | 11 +- src/internal/data/schemas.lua | 215 +++++++++++++++++- src/mod/elona/api/God.lua | 22 +- src/mod/elona/data/chip.lua | 1 - src/mod/elona/data/enchantment.lua | 8 +- src/mod/elona/data/item/spellbook.lua | 2 +- src/mod/elona/data/map_archetype/dungeon.lua | 1 - .../elona/data/map_archetype/instanced.lua | 2 +- src/mod/elona/data/map_archetype/special.lua | 7 +- src/mod/elona/data/map_archetype/unique.lua | 4 - src/mod/elona/data/material_spot.lua | 2 +- src/mod/elona/data/music.lua | 4 +- src/mod/elona/data/scenario.lua | 2 - src/mod/noafindskitten/data/map_template.lua | 4 +- src/mod/smithing/data/activity.lua | 2 +- 16 files changed, 241 insertions(+), 58 deletions(-) diff --git a/src/game/startup.lua b/src/game/startup.lua index e68352fe2..757e2c06c 100644 --- a/src/game/startup.lua +++ b/src/game/startup.lua @@ -105,9 +105,6 @@ function startup.run(mods) Log.warn("JIT compiler is _off_ due to sethook/debug settings.") end - -- For determinism during mod loading. - Rand.set_seed(0) - require("internal.data.base") progress("Loading mods...") @@ -115,6 +112,15 @@ function startup.run(mods) mod.load_mods(mods) data:run_all_edits() data:sort_all() + local errs = data:validate_all() + local strict = true + if strict and #errs > 0 then + for _, v in ipairs(errs) do + Log.error("%s:%s: %s", v._type, v._id, v.error) + end + local v = errs[1] + error(("%s:%s: %s"):format(v._type, v._id, v.error)) + end -- data is finalized at this point. diff --git a/src/internal/data/events.lua b/src/internal/data/events.lua index 7ae873ff3..807a59e4e 100755 --- a/src/internal/data/events.lua +++ b/src/internal/data/events.lua @@ -10,16 +10,7 @@ data:add_multi( { _id = "before_handle_self_event" }, { _id = "before_ai_decide_action" }, { _id = "after_chara_damaged", }, - { - _id = "on_calc_damage", - - params = { - { name = "test", type = "int", desc = "zxc" } - }, - returns = { - { type = "int?" } - } - }, + { _id = "on_calc_damage", }, { _id = "after_damage_hp", }, { _id = "on_damage_chara", }, { _id = "on_kill_chara", }, diff --git a/src/internal/data/schemas.lua b/src/internal/data/schemas.lua index 4cd260a66..e59d005b4 100644 --- a/src/internal/data/schemas.lua +++ b/src/internal/data/schemas.lua @@ -53,6 +53,8 @@ local ty_light = types.fields { always_on = types.optional(types.boolean) } +local ty_shadow_type = types.literal("normal", "drop_shadow") + local ty_chara_filter = types.fields { quality = types.enum(Enum.Quality), level = types.uint, @@ -269,6 +271,11 @@ The character's female image. Can be nil to use the race's default image. The character's gender, either "male" or "female". ]] }, + { + name = "shadow_type", + type = ty_shadow_type, + default = "normal" + }, { name = "fltselect", type = types.enum(Enum.FltSelect), @@ -764,6 +771,11 @@ Relative strength of this item. The item's image. ]] }, + { + name = "shadow_type", + type = ty_shadow_type, + default = "normal" + }, { name = "rarity", type = types.int, @@ -1102,7 +1114,17 @@ data:add_type { doc = [[ If true, don't randomly generate items with this category in the wild. ]] - } + }, + { + name = "is_major", + type = types.boolean, + default = false + }, + { + name = "parents", + type = types.list(types.data_id("base.item_type")), + default = {}, + }, } } @@ -1115,6 +1137,10 @@ data:add_type( indexed = true, type = types.optional(types.uint), }, + { + name = "elona_sub_id", + type = types.optional(types.uint), + }, { name = "params", type = types.map(types.string, types.fields { type = types.type, default = types.optional(types.any) }), @@ -1130,14 +1156,27 @@ data:add_type( type = types.boolean, default = true, }, + { + name = "shadow_type", + type = ty_shadow_type, + default = "normal" + }, { name = "image", - type = types.data_id("base.chip"), + type = types.optional(types.data_id("base.chip")), }, { name = "on_refresh", type = types.optional(types.callback("self", types.map_object("base.feat"), "params", types.table)) }, + { + name = "on_search", + type = types.optional(types.callback("self", types.map_object("base.feat"), "params", types.table)) + }, + { + name = "on_search_from_distance", + type = types.optional(types.callback("self", types.map_object("base.feat"), "params", types.table)) + }, { name = "on_bumped_into", type = types.optional(types.callback("self", types.map_object("base.feat"), "params", types.table)) @@ -1235,6 +1274,11 @@ data:add_type( { name = "class", fields = { + { + name = "is_extra", + type = types.boolean, + default = false + }, { name = "properties", type = types.map(types.string, types.any), @@ -1280,6 +1324,7 @@ data:add_type( { name = "height", type = types.number, + default = 10, }, { name = "age_min", @@ -1335,7 +1380,13 @@ data:add_type( }, { name = "can_resist", - type = types.optional(types.boolean) + type = types.boolean, + default = false + }, + { + name = "preserves_sleep", + type = types.boolean, + default = false }, { name = "sound", @@ -1370,6 +1421,11 @@ data:add_type( type = types.optional(types.callback("chara", types.map_object("base.chara"), "params", types.table)) -- TODO }, + { + name = "after_apply_damage", + type = types.optional(types.callback("chara", types.map_object("base.chara"), + "params", types.table)) -- TODO + }, { name = "on_kill", type = types.optional(types.callback("chara", types.map_object("base.chara"), @@ -1403,6 +1459,14 @@ data:add_type{ name = "emotion_icon", type = types.optional(types.string) -- TODO }, + { + name = "on_add", + type = types.optional(types.callback("chara", types.map_object("base.chara"))) + }, + { + name = "on_remove", + type = types.optional(types.callback("chara", types.map_object("base.chara"))) + }, { name = "on_turn_start", type = types.optional(types.callback("chara", types.map_object("base.chara"))) @@ -1490,6 +1554,18 @@ data:add_type( type = types.boolean, default = false }, + { + name = "on_start", + type = types.optional(types.callback("self", types.interface(IActivity), "params", types.table)) + }, + { + name = "on_finish", + type = types.optional(types.callback("self", types.interface(IActivity), "params", types.table)) + }, + { + name = "on_pass_turns", + type = types.optional(types.callback({"self", types.interface(IActivity), "params", types.table}, types.string)) + }, { name = "on_interrupt", type = types.literal("ignore", "prompt", "stop"), @@ -1539,7 +1615,7 @@ local ty_image_entry = types.some( types.fields_strict { image = types.path, count_x = types.optional(types.uint), - key_color = types.optional(types.color) + key_color = types.optional(types.some(types.color, types.literal("none"))) }, -- { @@ -1559,7 +1635,7 @@ local ty_image_entry = types.some( y = types.uint, count_x = types.optional(types.uint), count_y = types.optional(types.uint), - key_color = types.optional(types.color) + key_color = types.optional(types.some(types.color, types.literal("none"))) } ) @@ -1615,6 +1691,11 @@ data:add_type { type = types.boolean, default = false, }, + { + name = "is_feat", + type = types.boolean, + default = false, + }, { name = "show_name", type = types.boolean, @@ -1654,12 +1735,19 @@ data:add_type { } } +local ty_alignment = types.literal("positive", "negative") + data:add_type { name = "enchantment", fields = { + { + name = "elona_id", + indexed = true, + type = types.optional(types.uint) + }, { name = "level", - type = types.uint, + type = types.int, default = 1, template = true, doc = [[ @@ -1740,9 +1828,13 @@ can be applied to any item generated randomly. type = types.optional(types.callback("power", types.number, "enc_params", types.table, "item", types.map_object("base.item"), "chara", types.map_object("base.chara"))), template = true, }, + { + name = "compare", + type = types.optional(types.callback({"my_params", types.table, "other_params", types.table}, types.boolean)), + }, { name = "alignment", - type = types.literal("positive", "negative"), + type = types.some(ty_alignment, types.callback({"power", types.number}, ty_alignment)), default = "positive", template = true, doc = [[ @@ -1762,6 +1854,11 @@ Determines if this enchantment is beneficial or not. One of "positive" or "negat How to adjust the power when applying the enchantment. ]] }, + { + name = "no_merge", + type = types.boolean, + default = false + } } } @@ -1897,6 +1994,23 @@ Controls the starting amount of ammo. doc = [[ Stamina cost of the ammo when fired. ]] + }, + { + name = "on_calc_damage", + type = types.optional(types.callback({"ammo", types.map_object("base.item"), "params", types.table}, types.fields { damage = types.number })), + }, + { + name = "on_ranged_attack", + type = types.optional(types.callback("chara", types.map_object("base.chara"), + "weapon", types.optional(types.map_object("base.item")), + "target", types.map_object("base.chara"), + "skill", types.data_id("base.skill"), + "ammo", types.map_object("base.item"), + "ammo_enchantment_id", types.data_id("base.skill"))), + }, + { + name = "on_attack_hit", + type = types.optional(types.callback("chara", types.map_object("base.chara"), "params", types.table)), } } } @@ -1907,6 +2021,14 @@ local ty_dice = types.fields_strict { bonus = types.number } +local ty_damage_params = types.fields { + dmgfix = types.number, + dice_x = types.int, + dice_y = types.int, + multiplier = types.number, + pierce_rate = types.number +} + data:add_type { name = "skill", fields = { @@ -1988,7 +2110,7 @@ Used only when the skill's `type` is "spell" or "action". }, { name = "alignment", - type = types.optional(types.literal("positive", "negative")), + type = types.optional(ty_alignment), }, { name = "calc_initial_level", @@ -1998,6 +2120,19 @@ Used only when the skill's `type` is "spell" or "action". name = "calc_critical_damage", type = types.optional(types.callback("self", types.table, "params", types.table)), }, + { + name = "calc_damage_params", + type = types.optional(types.callback({"self", types.data_entry("base.skill"), + "chara", types.map_object("base.chara"), + "weapon", types.optional(types.map_object("base.item")), + "target", types.map_object("base.chara")}, + ty_damage_params + )), + }, + { + name = "calc_final", + type = types.optional(types.callback({"level", types.int}, types.fields { level = types.int, potential = types.uint })), + }, { name = "on_check_can_cast", type = types.optional(types.callback({"skill_data", types.data_entry("base.skill"), "caster", types.map_object("base.chara")}, types.boolean)), @@ -2306,6 +2441,11 @@ It can either be a string referencing an image file, or a table with these conte type = types.optional(types.uint), default = 0 }, + { + -- TODO + name = "effect", + type = types.optional(types.uint), + }, { name = "is_tall", type = types.boolean, @@ -2333,7 +2473,10 @@ data:add_type { fields = { { name = "act", - type = types.callback({"chara", types.map_object("base.chara"), "params", types.table}, types.boolean), + type = types.some( + types.callback({"chara", types.map_object("base.chara"), "params", types.table}, types.boolean), + types.list(types.data_id("base.ai_action")) + ), template = true, doc = [[ Runs arbitrary AI actions. Is passed the character and extra parameters, differing depending on the action. @@ -2444,6 +2587,10 @@ data:add_type { data:add_type { name = "map_archetype", fields = { + { + name = "elona_id", + type = types.optional(types.uint) + }, { name = "starting_pos", type = types.optional(types.callback("map", types.class(InstancedMap), @@ -2490,7 +2637,7 @@ Used for restoring towns to their pristine condition after destroying their terr ]] }, { - name = "on_map_loaded_events", + name = "on_map_loaded", type = types.optional(types.callback("map", types.class(InstancedMap), "params", types.table)), template = true, doc = [[ @@ -2502,7 +2649,7 @@ Callback run when this map is about to be entered. type = types.optional(types.callback("map", types.class(InstancedMap), "params", types.table)), template = true, doc = [[ -Callback run when this map is being entered (after on_map_loaded_events). +Callback run when this map is being entered (after on_map_loaded is called). ]] }, { @@ -2541,9 +2688,15 @@ Additional events to bind to this map when it is loaded. } } +local ty_area_type = types.literal("town", "dungeon", "guild", "shelter", "field", "quest", "player_owned", "world_map") + data:add_type { name = "area_archetype", fields = { + { + name = "elona_id", + type = types.optional(types.uint) + }, { name = "on_generate_floor", type = types.optional(types.callback({"area", types.class(InstancedArea), "floor", types.int}, types.class(InstancedMap))), @@ -2571,6 +2724,23 @@ set `is_temporary` to `true` on the generated map. Image this area will have when created with Area.create_entrance(). ]] }, + { + name = "types", + type = types.list(ty_area_type), + default = {} + }, + { + name = "metadata", + type = types.fields { + can_return_to = types.optional(types.boolean) + }, + default = {} + }, + { + name = "floors", + type = types.map(types.int, types.data_id("base.map_archetype")), + default = {} + }, { name = "deepest_floor", type = types.optional(types.int), @@ -2772,14 +2942,35 @@ Callback run immediately after this option is changed in the settings menu. validation = "permissive" } +local ty_config_menu_item = types.some( + types.data_id("base.config_option"), + types.fields { _type = types.literal("base.config_menu"), _id = types.data_id("base.config_menu") } +) + data:add_type { name = "config_menu", fields = { { name = "items", - type = types.list(types.data_id("base.config_option")), + type = types.list(ty_config_menu_item), doc = [[ List of config options in this config menu. +]] + }, + { + name = "menu_width", + type = types.uint, + default = 440, + doc = [[ +Height of this menu in pixels, when using the default config menu UI. +]] + }, + { + name = "menu_height", + type = types.uint, + default = 300, + doc = [[ +Height of this menu in pixels, when using the default config menu UI. ]] } } diff --git a/src/mod/elona/api/God.lua b/src/mod/elona/api/God.lua index 7f3cc6d73..a0f73705f 100644 --- a/src/mod/elona/api/God.lua +++ b/src/mod/elona/api/God.lua @@ -122,19 +122,23 @@ function God.can_offer_item_to(god_id, item) return false end -local function mkblessing(cb) - return function(skill, coefficient, add) - return function(chara) - if chara["has_" .. cb](chara, skill) then - local amount = math.clamp((chara.piety or 0) / coefficient, 1, add + chara:skill_level("elona.faith") / 10) - chara["mod_" .. cb .. "_level"](chara, skill, amount, "add") - end +function God.make_skill_blessing(skill_id, coefficient, add) + return function(chara) + if chara:has_skill(skill_id) then + local amount = math.clamp((chara.piety or 0) / coefficient, 1, add + chara:skill_level("elona.faith") / 10) + chara:mod_skill_level(skill_id, amount, "add") end end end -God.make_skill_blessing = mkblessing("skill") -God.make_resist_blessing = mkblessing("resist") +function God.make_resist_blessing(resist_id, coefficient, add) + return function(chara) + if chara:has_resist(resist_id) then + local amount = math.clamp((chara.piety or 0) / coefficient, 1, add + chara:skill_level("elona.faith") / 10) + chara:mod_resist_level(resist_id, amount, "add") + end + end +end function God.switch_religion_with_penalty(chara, new_god) -- >>>>>>>> shade2/god.hsp:238 gosub *screen_drawStatus ... diff --git a/src/mod/elona/data/chip.lua b/src/mod/elona/data/chip.lua index d491418e0..815018691 100644 --- a/src/mod/elona/data/chip.lua +++ b/src/mod/elona/data/chip.lua @@ -1020,7 +1020,6 @@ local feat_chips = { _id = "hidden", elona_id = 233, elona_atlas = 1, - offset_bottom = 48, y_offset = 56 }, { diff --git a/src/mod/elona/data/enchantment.lua b/src/mod/elona/data/enchantment.lua index 133692a63..80064fd55 100644 --- a/src/mod/elona/data/enchantment.lua +++ b/src/mod/elona/data/enchantment.lua @@ -366,7 +366,7 @@ data:add { value = 300, rarity = 15000, - params = { enchantment_skill_id = "id:base.enchantment_skill" }, + params = { enchantment_skill_id = types.data_id("base.enchantment_skill") }, on_generate = function(self, item, params) -- >>>>>>>> shade2/item_data.hsp:578 if enc=encProc{ .. -- Find a list of invokable skills that can be added onto this item. @@ -458,9 +458,9 @@ data:add { -- <<<<<<<< shade2/item_data.hsp:612 if refType@=fltAmmo:return .. params = { - ammo_enchantment_id = "id:base.ammo_enchantment", - ammo_max = "number", - ammo_current = "number" + ammo_enchantment_id = types.data_id("base.ammo_enchantment"), + ammo_max = types.uint, + ammo_current = types.uint }, compare = function(my_params, other_params) return my_params.ammo_enchantment_id == other_params.ammo_enchantment_id diff --git a/src/mod/elona/data/item/spellbook.lua b/src/mod/elona/data/item/spellbook.lua index e6258ba75..eefbbde07 100644 --- a/src/mod/elona/data/item/spellbook.lua +++ b/src/mod/elona/data/item/spellbook.lua @@ -15,7 +15,7 @@ data:add { fields = { { name = "can_be_reserved", - type = "boolean", + type = types.boolean, default = true } } diff --git a/src/mod/elona/data/map_archetype/dungeon.lua b/src/mod/elona/data/map_archetype/dungeon.lua index b15dc8844..1fcd69997 100644 --- a/src/mod/elona/data/map_archetype/dungeon.lua +++ b/src/mod/elona/data/map_archetype/dungeon.lua @@ -528,7 +528,6 @@ do _type = "base.map_archetype", elona_id = 27, - image = "elona.feat_area_dungeon", starting_pos = MapEntrance.stairs_up, chara_filter = Dungeon.default_chara_filter, diff --git a/src/mod/elona/data/map_archetype/instanced.lua b/src/mod/elona/data/map_archetype/instanced.lua index f7c77e75a..226055f15 100644 --- a/src/mod/elona/data/map_archetype/instanced.lua +++ b/src/mod/elona/data/map_archetype/instanced.lua @@ -254,7 +254,7 @@ do _id = "test_site", _type = "base.map_archetype", - unique = true, + -- unique = true, properties = { music = "elona.puti", diff --git a/src/mod/elona/data/map_archetype/special.lua b/src/mod/elona/data/map_archetype/special.lua index 122955a01..22a56fd58 100644 --- a/src/mod/elona/data/map_archetype/special.lua +++ b/src/mod/elona/data/map_archetype/special.lua @@ -10,7 +10,6 @@ do elona_id = 35, on_generate_map = util.generate_122("dungeon1"), - image = "elona.feat_area_border_tent", starting_pos = MapEntrance.south, @@ -66,7 +65,7 @@ do prevents_monster_ball = true } } - function arena.on_generate(area, floor) + function arena.on_generate_map(area, floor) local map = Elona122Map.generate("arena_1") map:set_archetype("elona.arena", { set_properties = true }) @@ -102,7 +101,7 @@ do prevents_monster_ball = true } } - function pet_arena.on_generate(area, floor) + function pet_arena.on_generate_map(area, floor) local map = Elona122Map.generate("arena_2") map:set_archetype("elona.pet_arena", { set_properties = true }) @@ -166,7 +165,7 @@ do elona_id = 9, types = { "field" }, - deepest_level = 45, + deepest_floor = 45, floors = { [1] = "elona.rq" diff --git a/src/mod/elona/data/map_archetype/unique.lua b/src/mod/elona/data/map_archetype/unique.lua index 6767b1509..49cad44de 100644 --- a/src/mod/elona/data/map_archetype/unique.lua +++ b/src/mod/elona/data/map_archetype/unique.lua @@ -18,8 +18,6 @@ do _type = "base.map_archetype", elona_id = 10, - image = "elona.feat_area_crypt", - starting_pos = MapEntrance.edge, properties = { @@ -1041,8 +1039,6 @@ do _type = "base.map_archetype", elona_id = 24, - image = "elona.feat_area_god", - starting_pos = MapEntrance.south, properties = { diff --git a/src/mod/elona/data/material_spot.lua b/src/mod/elona/data/material_spot.lua index c2ed6e6d6..6abee3e37 100644 --- a/src/mod/elona/data/material_spot.lua +++ b/src/mod/elona/data/material_spot.lua @@ -47,7 +47,7 @@ data:add { is_solid = false, is_opaque = false, - params = { material_spot_info = types.data_id("elona.material_spot_feat_info") }, + params = { material_spot_info = { type = types.data_id("elona.material_spot_feat_info") } }, on_stepped_on = function(self, params) if params.chara:is_player() then diff --git a/src/mod/elona/data/music.lua b/src/mod/elona/data/music.lua index 0f3f1a434..c44a1aba9 100755 --- a/src/mod/elona/data/music.lua +++ b/src/mod/elona/data/music.lua @@ -5,12 +5,12 @@ data:add { fields = { { name = "can_randomly_generate", - type = "boolean", + type = types.boolean, default = true }, { name = "music_number", - type = "integer?", + type = types.optional(types.uint), default = nil } } diff --git a/src/mod/elona/data/scenario.lua b/src/mod/elona/data/scenario.lua index 096247984..cbbec1119 100644 --- a/src/mod/elona/data/scenario.lua +++ b/src/mod/elona/data/scenario.lua @@ -92,7 +92,5 @@ data:add { _type = "base.scenario", _id = "elona", - name = "Normal", - on_game_start = start } diff --git a/src/mod/noafindskitten/data/map_template.lua b/src/mod/noafindskitten/data/map_template.lua index f189f429d..c6a39f858 100644 --- a/src/mod/noafindskitten/data/map_template.lua +++ b/src/mod/noafindskitten/data/map_template.lua @@ -22,8 +22,8 @@ data:add { _id = "object", params = { - is_kitten = "boolean", - description = "string", + is_kitten = { type = types.boolean, default = false }, + description = { type = types.string } }, image = "noafindskitten.object", diff --git a/src/mod/smithing/data/activity.lua b/src/mod/smithing/data/activity.lua index 951ac37d8..9c52d156d 100644 --- a/src/mod/smithing/data/activity.lua +++ b/src/mod/smithing/data/activity.lua @@ -10,7 +10,7 @@ data:add { _type = "base.activity", _id = "upgrade_hammer", - params = { hammer = "table" }, + params = { hammer = types.map_object("base.chara") }, default_turns = SmithingFormula.calc_hammer_activity_turns, animation_wait = 20, From df82e04f5ece3f05a0a8fe396c26057ee33d35b1 Mon Sep 17 00:00:00 2001 From: Ruin0x11 Date: Sat, 11 Sep 2021 14:27:47 -0700 Subject: [PATCH 14/17] Prevent flickering in chara make feats menu --- src/api/gui/menu/FeatsMenu.lua | 6 ++++++ src/mod/elona/data/trait.lua | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/api/gui/menu/FeatsMenu.lua b/src/api/gui/menu/FeatsMenu.lua index 9737e9f4a..f66ce053c 100644 --- a/src/api/gui/menu/FeatsMenu.lua +++ b/src/api/gui/menu/FeatsMenu.lua @@ -315,12 +315,18 @@ function FeatsMenu:update() -- Because most callbacks expect the given character to be built, you cannot call `refresh` during character making. self.chara:refresh() end + + if self.chara_make and self.chara.feats_acquirable <= 0 then + return true + end + self.data = FeatsMenu.generate_list(self.chara) self.pages:set_data(self.data) local filter = function(_, i) return i.type == "have" and i.trait._id == item.trait._id end + local index = self.pages:iter_all_pages():enumerate():filter(filter):nth(1) self.pages:select(index) diff --git a/src/mod/elona/data/trait.lua b/src/mod/elona/data/trait.lua index 9f8cc9017..1790d2147 100644 --- a/src/mod/elona/data/trait.lua +++ b/src/mod/elona/data/trait.lua @@ -43,7 +43,7 @@ local trait = { type = "feat", -- >>>>>>>> shade2/trait.hsp:153 spGain(actLeadership) ... - on_modify_level = gain_or_lose_action("elona.action_leadership"), + on_modify_level = gain_or_lose_action("elona.action_cheer"), -- <<<<<<<< shade2/trait.hsp:153 spGain(actLeadership) .. }, { From 565af4fb6eb308c9e2643ff6df14fbb463ea8b79 Mon Sep 17 00:00:00 2001 From: Ruin0x11 Date: Sat, 11 Sep 2021 16:51:13 -0700 Subject: [PATCH 15/17] Fix regressions --- editor/emacs/open-nefia.el | 4 +- src/api/Activity.lua | 43 ++------------------ src/api/Feat.lua | 40 +----------------- src/api/InstancedArea.lua | 2 +- src/api/Object.lua | 49 +++++++++++++++++++++++ src/api/test/Assert.lua | 7 ++-- src/internal/data/fallbacks.lua | 1 + src/internal/data/schemas.lua | 2 +- src/mod/base/data/keybind.lua | 4 +- src/mod/elona/data/activity/searching.lua | 2 +- src/mod/elona/test/api/Home.lua | 2 +- src/mod/elona/test/event/charagen.lua | 4 +- src/test/api/Activity.lua | 14 ++++--- src/test/api/Feat.lua | 18 ++++----- src/util/types.lua | 4 +- 15 files changed, 89 insertions(+), 107 deletions(-) diff --git a/editor/emacs/open-nefia.el b/editor/emacs/open-nefia.el index 007d8f0be..d27378830 100644 --- a/editor/emacs/open-nefia.el +++ b/editor/emacs/open-nefia.el @@ -607,14 +607,14 @@ removed. Return the new string. If STRING is nil, return nil." (defun open-nefia--run-lua (file switches) (with-current-buffer (get-buffer-create (open-nefia--repl-buffer-name)) (erase-buffer) - (compilation-shell-minor-mode 1) (let ((process (apply 'start-process (buffer-name) (current-buffer) (open-nefia--lua-headless-executable-name) (append (list (open-nefia--repl-file file)) switches)))) (ansi-color-for-comint-mode-on) (comint-mode) - (set-process-filter process 'comint-output-filter)))) + (set-process-filter process 'comint-output-filter) + (compilation-shell-minor-mode 1)))) (defun open-nefia--start-repl-1 (file &rest switches) (save-some-buffers (not compilation-ask-about-save) diff --git a/src/api/Activity.lua b/src/api/Activity.lua index 0b4a8925d..cb97e44b5 100644 --- a/src/api/Activity.lua +++ b/src/api/Activity.lua @@ -1,49 +1,12 @@ local Object = require("api.Object") -local data = require("internal.data") local Activity = {} -local function copy_params(activity, params) - local proto = data["base.activity"]:ensure(activity._id) - local found = table.set{} - - for property, entry in pairs(proto.params or {}) do - local value = params[property] - local error_msg = "Invalid parameter passed for activity with ID '%d': " - local checker - if types.is_type_checker(entry) then - checker = entry - else - checker = entry.type - if value == nil then - value = entry.default - error_msg = "Invalid default parameter for activity with ID '%d': " - end - end - local ok, err = types.check(value, checker) - if not ok then - error((error_msg):format(activity._id), err) - end - activity.params[property] = value - end - - if table.count(found) ~= table.count(params) then - for k, v in pairs(params) do - if not proto.params[k] then - error(("Activity '%s' does not accept parameter '%s'"):format(activity._id, k)) - end - end - end -end - -function Activity.create(id, params) - local obj = Object.generate_from("base.activity", id) +function Activity.create(_id, params) + local obj = Object.generate_from("base.activity", _id) Object.finalize(obj) - obj.params = {} - if params then - copy_params(obj, params) - end + obj.params = Object.copy_params(obj.proto.params, params, "base.activity", _id) return obj end diff --git a/src/api/Feat.lua b/src/api/Feat.lua index 7bedb3bec..d7ac0d7ff 100644 --- a/src/api/Feat.lua +++ b/src/api/Feat.lua @@ -1,9 +1,8 @@ --- @module Feat -local data = require("internal.data") local Log = require("api.Log") -local Event = require("api.Event") local Map = require("api.Map") +local Object = require("api.Object") local MapObject = require("api.MapObject") local ILocation = require("api.ILocation") local field = require("game.field") @@ -55,38 +54,6 @@ function Feat.is_alive(feat, map) return their_map.uid == map.uid end -local function copy_params(feat, params) - local proto = data["base.feat"]:ensure(feat._id) - local found = table.set{} - for property, entry in pairs(proto.params or {}) do - local value = params[property] - local error_msg = "Invalid parameter passed for feat with ID '%d': " - local checker - if types.is_type_checker(entry) then - checker = entry - else - checker = entry.type - if value == nil then - value = entry.default - error_msg = "Invalid default parameter for feat with ID '%d': " - end - end - local ok, err = types.check(value, checker) - if not ok then - error((error_msg):format(feat._id), err) - end - feat.params[property] = value - end - - if table.count(found) ~= table.count(params) then - for k, v in pairs(params) do - if not proto.params[k] then - error(("Feat '%s' does not accept parameter '%s'"):format(feat._id, k)) - end - end - end -end - --- Creates a new feat. Returns the feat on success, or nil if --- creation failed. --- @@ -143,10 +110,7 @@ function Feat.create(id, x, y, params, where) } local feat = MapObject.generate_from("base.feat", id) - feat.params = {} - if params.params then - copy_params(feat, params.params) - end + feat.params = Object.copy_params(feat.proto.params, params.params, "base.feat", id) if where then feat = where:take_object(feat, x, y) diff --git a/src/api/InstancedArea.lua b/src/api/InstancedArea.lua index 4600ee665..f1d4f3003 100644 --- a/src/api/InstancedArea.lua +++ b/src/api/InstancedArea.lua @@ -95,7 +95,7 @@ end function InstancedArea:starting_floor() local archetype = self:archetype() - if archetype and archetype.floors then + if archetype and #archetype.floors > 0 then return fun.iter(table.keys(archetype.floors)):min() end diff --git a/src/api/Object.lua b/src/api/Object.lua index 557199b58..6d28a2992 100644 --- a/src/api/Object.lua +++ b/src/api/Object.lua @@ -140,4 +140,53 @@ function Object.mock(mt, tbl) return obj end +-- Validates a params table against the type definitions in an object's data +-- entry. +-- +-- For example, a door feat will be able to have an unlock difficulty set on it. +-- `proto_params` is the `params` table in the `base.feat`'s data definition and +-- looks like { difficulty = types.number }, and `passed_params` would have been +-- passed to `Feat.create()` and looks something like { difficulty = 25 }. +function Object.copy_params(proto_params, passed_params, _type, _id) + proto_params = proto_params or {} + passed_params = passed_params or {} + + local result = {} + + local found = table.set{} + + for property, entry in pairs(proto_params) do + local value = passed_params[property] + local error_msg = "%s '%s' received invalid value for parameter '%s': %s" + local checker + if types.is_type_checker(entry) then + checker = entry + else + checker = entry.type + if not types.is_type_checker(checker) then + error(("%s '%s' has invalid type checker for parameter '%s': %s"):format(_type, _id, property, checker)) + end + if value == nil then + value = entry.default + error_msg = "%s '%s' is missing required parameter '%s': %s" + end + end + local ok, err = types.check(value, checker) + if not ok then + error((error_msg):format(_type, _id, property, err)) + end + result[property] = value + end + + if table.count(found) ~= table.count(passed_params) then + for k, v in pairs(passed_params) do + if not proto_params[k] then + error(("%s '%s' does not accept parameter '%s'"):format(_type, _id, k)) + end + end + end + + return result +end + return Object diff --git a/src/api/test/Assert.lua b/src/api/test/Assert.lua index 6b3a53d58..22105003c 100644 --- a/src/api/test/Assert.lua +++ b/src/api/test/Assert.lua @@ -107,13 +107,14 @@ function Assert.no_matches(match, str) end function Assert.throws_error(f, err_match, ...) - local ok, err = pcall(f, ...) + local ok, err = xpcall(f, debug.traceback, ...) if ok then error("expected error, but was successful", 2) end if err_match then - if not err:match(err_match) then - error(("expected error to match '%s', got '%s'"):format(err_match, err), 2) + local first_line = string.split(tostring(err))[1] + if not first_line:match(err_match) then + error(("expected error to match:\n\t'%s'\ngot:\n\t'%s'"):format(err_match, err), 2) end end end diff --git a/src/internal/data/fallbacks.lua b/src/internal/data/fallbacks.lua index 317b3e065..582b28501 100644 --- a/src/internal/data/fallbacks.lua +++ b/src/internal/data/fallbacks.lua @@ -1,5 +1,6 @@ -- data that has to exist for no errors to occur local data = require("internal.data") +local Enum = require("api.Enum") data:add { _type = "base.map_tile", diff --git a/src/internal/data/schemas.lua b/src/internal/data/schemas.lua index e59d005b4..a052bc362 100644 --- a/src/internal/data/schemas.lua +++ b/src/internal/data/schemas.lua @@ -206,7 +206,7 @@ If true, you can talk to this character by bumping into them. { name = "relation", type = types.enum(Enum.Relation), - default = Enum.Relation.Enemy, + default = Enum.Relation.Neutral, template = true, doc = [[ What alignment this character has. diff --git a/src/mod/base/data/keybind.lua b/src/mod/base/data/keybind.lua index 049308a0a..c77007195 100644 --- a/src/mod/base/data/keybind.lua +++ b/src/mod/base/data/keybind.lua @@ -65,7 +65,7 @@ local keybinds = { skill = "a", close = "C", rest = "R", - target = "kp*", + target = {"kp*", "\\"}, dig = "D", use = "t", bash = "b", @@ -81,7 +81,7 @@ local keybinds = { give = "G", throw = "T", mode = "z", - mode2 = "kp*", + mode2 = {"kp*", "\\"}, ammo = "A", previous_page = "kp-", next_page = "kp+", diff --git a/src/mod/elona/data/activity/searching.lua b/src/mod/elona/data/activity/searching.lua index ad1c178db..336479982 100644 --- a/src/mod/elona/data/activity/searching.lua +++ b/src/mod/elona/data/activity/searching.lua @@ -20,7 +20,7 @@ data:add { _id = "searching", elona_id = 105, - params = { feat = types.map_object("base.feat"), no_more_materials = types.boolean }, + params = { feat = types.map_object("base.feat"), no_more_materials = types.optional(types.boolean) }, default_turns = function(self) return try_get_spot_info(self.params.feat, "activity_default_turns") or 20 diff --git a/src/mod/elona/test/api/Home.lua b/src/mod/elona/test/api/Home.lua index 8ba20d72e..316630f9c 100644 --- a/src/mod/elona/test/api/Home.lua +++ b/src/mod/elona/test/api/Home.lua @@ -53,7 +53,7 @@ function test_Home_add_salary_to_salary_chest() Rank.set("elona.shop", 1000) Home.add_salary_to_salary_chest(inv) - Assert.eq(4, inv:len()) + Assert.eq(5, inv:len()) local gold = inv:iter():filter(function(i) return i._id == "elona.gold_piece" end):nth(1) Assert.is_truthy(gold) diff --git a/src/mod/elona/test/event/charagen.lua b/src/mod/elona/test/event/charagen.lua index 8f016c07f..1ddf80cbd 100644 --- a/src/mod/elona/test/event/charagen.lua +++ b/src/mod/elona/test/event/charagen.lua @@ -20,13 +20,13 @@ function test_charagen_default_race_image_override() end function test_charagen_shade() - Rand.set_seed(5) + Rand.set_seed(24) local map = InstancedMap:new(10, 10) local chara = Chara.create("elona.shade", 4, 5, {level = 20}, map) Assert.not_eq("elona.shade", chara._id) Assert.eq(I18N.get("chara.job.shade"), chara.name) - Assert.eq(37, chara.level) + Assert.eq(1, chara.level) Assert.eq(true, map:has_object(chara)) Assert.eq(4, chara.x) Assert.eq(5, chara.y) diff --git a/src/test/api/Activity.lua b/src/test/api/Activity.lua index fe4b7d9c7..4ac72d56b 100644 --- a/src/test/api/Activity.lua +++ b/src/test/api/Activity.lua @@ -4,14 +4,18 @@ local Feat = require("api.Feat") function test_Activity_create__params_validation() Assert.throws_error(function() Activity.create("elona.searching", {feat=42}) end, - "Activity 'elona.searching' requires parameter 'feat' of type table") + "base.activity 'elona.searching' received invalid value for parameter 'feat': Value is not of type \"map_object\": 42") + + Assert.throws_error(function() Activity.create("elona.searching", {feat=nil}) end, + "base.activity 'elona.searching' received invalid value for parameter 'feat': Value is not of type \"map_object\": nil") + + local feat = Feat.create("elona.material_spot", nil, nil, {ownerless=true, params={material_spot_info="elona.spring"}}) + + Assert.throws_error(function() Activity.create("elona.searching", {feat=feat, dood=42}) end, + "base.activity 'elona.searching' does not accept parameter 'dood'") - local feat = Feat.create("elona.material_spot", nil, nil, {ownerless=true}) local activity = Activity.create("elona.searching", {feat=feat}) Assert.eq(feat, activity.params.feat) - - activity = Activity.create("elona.searching", {feat=nil}) - Assert.eq(nil, activity.params.feat) end function test_Activity_create__params_reserved_property_name() diff --git a/src/test/api/Feat.lua b/src/test/api/Feat.lua index 492a60546..233b54dd2 100644 --- a/src/test/api/Feat.lua +++ b/src/test/api/Feat.lua @@ -3,17 +3,17 @@ local Feat = require("api.Feat") function test_Feat_create__params_validation() Assert.throws_error(function() Feat.create("elona.material_spot", nil, nil, {ownerless=true, params={material_spot_info=42}}) end, - "Feat 'elona.material_spot' requires parameter 'material_spot_info' of type string") + "base.feat 'elona.material_spot' received invalid value for parameter 'material_spot_info': Value is not of type \"data_id\": 42") - Assert.throws_error(function() Feat.create("elona.material_spot", nil, nil, {ownerless=true, params={dood=42}}) end, - "Feat 'elona.material_spot' does not accept parameter 'dood'") + Assert.throws_error(function() Feat.create("elona.material_spot", nil, nil, {ownerless=true, params={material_spot_info="elona.sprint", dood=42}}) end, + "base.feat 'elona.material_spot' does not accept parameter 'dood'") - local feat = Feat.create("elona.material_spot", nil, nil, {ownerless=true,params={material_spot_info="elona.spring"}}) - Assert.eq("elona.spring", feat.params.material_spot_info) + Assert.throws_error(function() Feat.create("elona.material_spot", nil, nil, {ownerless=true, params={}}) end, + "base.feat 'elona.material_spot' is missing required parameter 'material_spot_info': Value is not of type \"data_id\": nil") - feat = Feat.create("elona.material_spot", nil, nil, {ownerless=true, params={}}) - Assert.eq(nil, feat.params.material_spot_info) + Assert.throws_error(function() Feat.create("elona.material_spot", nil, nil, {ownerless=true}) end, + "base.feat 'elona.material_spot' is missing required parameter 'material_spot_info': Value is not of type \"data_id\": nil") - feat = Feat.create("elona.material_spot", nil, nil, {ownerless=true}) - Assert.eq(nil, feat.params.material_spot_info) + local feat = Feat.create("elona.material_spot", nil, nil, {ownerless=true,params={material_spot_info="elona.spring"}}) + Assert.eq("elona.spring", feat.params.material_spot_info) end diff --git a/src/util/types.lua b/src/util/types.lua index 89b2caad2..11d504aac 100644 --- a/src/util/types.lua +++ b/src/util/types.lua @@ -1068,7 +1068,7 @@ do function map_object_checker:check(obj, ctxt) -- copied from MapObject.is_map_object() if not class.is_an("api.IMapObject", obj) then - return false, ("'%s' is not a map object"):format(obj, ctxt) + return false, type_error(self) end if self._type == "any" then @@ -1082,7 +1082,7 @@ do return true end function map_object_checker:__tostring() - return ("map_object<%s>"):format(self.iface) + return ("map_object<%s>"):format(self._type) end types.map_object = wrap(map_object_checker) end From 8be9f6f7f97906c41cba73e80122afbc7a7c6390 Mon Sep 17 00:00:00 2001 From: Ruin0x11 Date: Sat, 11 Sep 2021 17:18:18 -0700 Subject: [PATCH 16/17] Fix feats rendering shadows --- src/internal/data/schemas.lua | 6 +++--- src/internal/layer/chip_layer.lua | 29 +++++++---------------------- 2 files changed, 10 insertions(+), 25 deletions(-) diff --git a/src/internal/data/schemas.lua b/src/internal/data/schemas.lua index a052bc362..5a1f5b60b 100644 --- a/src/internal/data/schemas.lua +++ b/src/internal/data/schemas.lua @@ -53,7 +53,7 @@ local ty_light = types.fields { always_on = types.optional(types.boolean) } -local ty_shadow_type = types.literal("normal", "drop_shadow") +local ty_shadow_type = types.literal("none", "normal", "drop_shadow") local ty_chara_filter = types.fields { quality = types.enum(Enum.Quality), @@ -1159,7 +1159,7 @@ data:add_type( { name = "shadow_type", type = ty_shadow_type, - default = "normal" + default = "none" }, { name = "image", @@ -2454,7 +2454,7 @@ It can either be a string referencing an image file, or a table with these conte { name = "stack_height", type = types.optional(types.int), - default = 0 + default = 8 }, { name = "y_offset", diff --git a/src/internal/layer/chip_layer.lua b/src/internal/layer/chip_layer.lua index 13c6e1bb1..e127ad368 100644 --- a/src/internal/layer/chip_layer.lua +++ b/src/internal/layer/chip_layer.lua @@ -72,31 +72,15 @@ end function chip_layer:draw_drop_shadow(index, i, x, y, y_offset) local batch_ind = self.drop_shadow_batch_inds[index] local image = i.image - local x_offset = i.x_offset + local x_offset = i.x_offset or 0 local rotation = i.shadow_angle or 20 - local draw = true - local image_data = self.chip_batch.atlas.tiles[image] - local is_tall = false - if image_data then - local _, _, tw, th = image_data.quad:getViewport() - is_tall = tw * 2 == th - end - -- TODO no idea what the rotation amounts should be - if is_tall then - x_offset = i.x_offset + rotation / 2 - y_offset = y_offset - 4 - rotation = rotation / 2 - else - if (i.y_offset or 0) < self.chip_batch.tile_height / 2 then - x_offset = (i.x_offset or 0) + rotation / 80 + 2 - y_offset = y_offset - 2 - rotation = rotation / 16 - else - draw = false - end - end + x_offset = x_offset + rotation / 8 + y_offset = y_offset - 2 + rotation = rotation / 16 + + local draw = true if draw then if batch_ind == nil then @@ -253,6 +237,7 @@ function chip_layer:draw_one(index, ind, x, y, i, chip_type, map_size, z_order) end if shadow_type == "drop_shadow" then + -- -- Item drop shadow. -- From f8f17406cce4d4c9ed2175d5f69c21d692211d2f Mon Sep 17 00:00:00 2001 From: Ruin0x11 Date: Sat, 11 Sep 2021 17:18:32 -0700 Subject: [PATCH 17/17] Only update background layers from currently querying layer --- src/api/gui/IUiLayer.lua | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/api/gui/IUiLayer.lua b/src/api/gui/IUiLayer.lua index 4da77aa7a..0590f8fb7 100644 --- a/src/api/gui/IUiLayer.lua +++ b/src/api/gui/IUiLayer.lua @@ -109,12 +109,14 @@ function IUiLayer:query(z_order) success, res, canceled = xpcall( function() if config.base.update_unfocused_ui_layers then - local layers = draw.get_layers() - for i = 1, #layers-1 do - local layer = layers[i].layer - -- HACK - if not class.is_an(IHud, layer) then - layer:update(dt, false) + if self:is_querying() then + local layers = draw.get_layers() + for i = 1, #layers-1 do + local layer = layers[i].layer + -- HACK + if not class.is_an(IHud, layer) then + layer:update(dt, false) + end end end end