CONTAINER_TDCLS = tdcls();
CONTAINER_TDCLS.name = "CONTAINER_TDCLS";
function CONTAINER_TDCLS:create(para)
self.carry = {};
setmetatable(self.carry, { __mode = "v" });
self.owner = para.rid
end
function CONTAINER_TDCLS:destruct()
for _, ob in pairs(self.carry) do
destruct_object(ob);
end
end
function CONTAINER_TDCLS:combine_to_pos(property, dst_pos)
local pre_property = dst_pos;
if not is_object(pre_property) then
pre_property = self:get_pos_carry(dst_pos);
if not is_object(pre_property) then
return (self:load_property(property, dst_pos));
end
end
if not pre_property:can_combine(property) then
trace("原道具(%s/%d)无法与道具(%s/%d)进行合并。\n", pre_property:query("rid"),
pre_property:query("class_id"), property:query("rid"), property:query("class_id"));
return false;
end
if pre_property:query("amount") + property:query("amount") >
CALC_ITEM_MAX_AMOUNT(property) then
trace("原道具(%s/%d)与道具(%s/%d)进行合并后数量超过最大叠加数。\n", pre_property:query("rid"),
pre_property:query("class_id"), property:query("rid"), property:query("class_id"));
return false;
end
pre_property:add_amount(property:query("amount"));
self:drop(property);
return true;
end
function CONTAINER_TDCLS:drop(property)
if not property or not is_object(property) then
trace("drop的道具对象不存在\n");
return;
end
if string.len(property:query("pos") or "") > 0 then
self:get_owner():notify_property_delete(get_ob_rid(property))
end
if is_not_in_db(property) then
self:unload_property(property, not_auto_notify);
destruct_object(property);
return;
end
check_rid_vaild(get_ob_rid(property))
local table_name = property:get_save_oper();
local sql = SQL_D.delete_sql(table_name, {rid = property:query("rid")})
DB_D.execute_db(table_name, sql)
LOG_D.to_log(LOG_TYPE_DESTRUCT_PROPERTY, self.owner, property:get_rid(), tostring(property:query("class_id")), tostring(property:query("amount")), self:get_owner():query_log_channel());
self:unload_property(property, not_auto_notify);
destruct_object(property);
end
function CONTAINER_TDCLS:get_carry()
return (dup(self.carry));
end
function CONTAINER_TDCLS:get_carry_by_class_id(class_id)
local arr = {};
local x, y;
local read_pos = READ_POS;
for pos, ob in pairs(self.carry) do
x, y = read_pos(pos);
if ob:query("class_id") == class_id then
arr[#arr + 1] = ob;
end
end
return arr;
end
function CONTAINER_TDCLS:get_page_carry(page)
local arr = {};
local x, y;
local read_pos = READ_POS;
for pos, ob in pairs(self.carry) do
x, y = read_pos(pos);
if x == page then
arr[#arr + 1] = ob;
end
end
return arr;
end
function CONTAINER_TDCLS:get_range_page_carry(ps, pe, pages)
local arr = {};
local x, y;
local read_pos = READ_POS;
local page_table = {}
for _,v in ipairs(pages or {}) do
page_table[v] = true
end
for pos, ob in pairs(self.carry) do
x, y = read_pos(pos);
if (x >= ps and x <= pe) or (page_table[x]) then
arr[#arr + 1] = ob;
end
end
return arr;
end
function CONTAINER_TDCLS:get_page_carry_by_class_id(class_id)
local page = PROPERTY_D.get_property_info(class_id)["item_type"];
return (self:get_page_carry(page));
end
function CONTAINER_TDCLS:get_property_amount(class_id)
local amount = 0;
for _, ob in pairs(self.carry) do
if ob:query("class_id") == class_id then
amount = amount + ob:query("amount");
end
end
return amount;
end
function CONTAINER_TDCLS:cost_property_by_rid(rid, amount, bonus_type)
local ob = find_object_by_rid(rid)
if not ob then
return false
end
if not amount and ob:query("ob_type") and ob:query("ob_type") == OB_TYPE_EQUIP then
amount= 1
end
local num = ob:query("amount");
if num < amount then
return false;
end
local deduct_amount = ob:cost_amount(amount, bonus_type);
amount = amount - deduct_amount;
if amount <= 0 then
return true;
end
end
function CONTAINER_TDCLS:cost_property(class_id, amount, bonus_type)
if not amount or amount <= 0 then
return true
end
local num = self:get_property_amount(class_id);
if num < amount then
return false;
end
local deduct_amount, ob_rid;
for _, ob in pairs(self.carry) do
if ob:query("class_id") == class_id then
ob_rid = ob:get_rid();
deduct_amount = ob:cost_amount(amount, bonus_type);
amount = amount - deduct_amount;
if amount <= 0 then
return true;
end
end
end
end
function CONTAINER_TDCLS:get_page_range_carry(page, b, e)
local arr = self:get_page_carry(page);
if not arr then
return;
end
local arr2 = {};
local x, y;
local read_pos = READ_POS;
for _, ob in ipairs(arr) do
x, y = read_pos(ob:query("pos"));
if y >= b and y <= e then
arr2[#arr2 + 1] = ob;
end
end
return arr2;
end
function CONTAINER_TDCLS:get_property_pos(property)
return (property:query("pos"));
end
function CONTAINER_TDCLS:get_pos_carry(pos)
return self.carry[pos];
end
function CONTAINER_TDCLS:get_free_pos(property, can_combine)
local page = CONTAINER_D.get_page(property, self);
local x, y;
local size = self:get_container_size(page);
if not size then
return;
end
local pos, ob;
if can_combine and property:query("combine") and
property:query("combine") > 0 then
for i = 0, size - 1 do
pos = MAKE_POS(page, i);
ob = self:get_pos_carry(pos);
if is_object(ob) then
if ob:can_combine(property) then
return pos;
end
end
end
end
for i = 0, size - 1 do
pos = MAKE_POS(page, i);
ob = self:get_pos_carry(pos);
if not ob then
return pos;
end
end
return nil;
end
function CONTAINER_TDCLS:get_free_amount_by_page(page)
local size = self:get_container_size(page);
if not size then
return;
end
local number = 0;
for i = 0, size - 1 do
pos = MAKE_POS(page, i);
if not self:get_pos_carry(pos) then
number = number + 1;
end
end
return number;
end
function CONTAINER_TDCLS:is_available_pos(pos)
local x,y = READ_POS(pos);
local size = self:get_container_size(x);
if not size then
return;
end
return (y <= size - 1);
end
function CONTAINER_TDCLS:get_free_amount_by_class_id(class_id, can_combine)
local item_info = PROPERTY_D.get_property_info(class_id);
if not item_info then
return 0;
end
local page = item_info["item_type"];
local free_amount = self:get_free_amount_by_page(page);
if not can_combine then
return free_amount;
else
local combine_amount = CALC_ITEM_MAX_AMOUNT(class_id);
if combine_amount <= 1 then
return free_amount;
end
free_amount = free_amount * combine_amount;
local properties = self:get_carry_by_class_id(class_id);
for i, property in ipairs(properties) do
free_amount = free_amount + (combine_amount - property:query("amount"));
end
return free_amount;
end
end
function CONTAINER_TDCLS:check_free_amount_by_page(page, number)
local free_amount = 0;
local pos;
local size = self:get_container_size(page);
if not size then
return false;
end
for i = 0, size - 1 do
pos = MAKE_POS(page, i);
if not self:get_pos_carry(pos) then
free_amount = free_amount + 1;
if free_amount >= number then
return true;
end
end
end
return false;
end
function CONTAINER_TDCLS:check_free_amount_by_class_id(class_id, number)
local free_amount = 0;
local combine_amount = CALC_ITEM_MAX_AMOUNT(class_id);
if combine_amount < 1 then
return false;
end
local page = PROPERTY_D.get_property_info(class_id)["item_type"];
local size = self:get_container_size(page);
if not size then
return false;
end
for i = 0, size - 1 do
pos = MAKE_POS(page, i);
if not self:get_pos_carry(pos) then
free_amount = free_amount + combine_amount;
if free_amount >= number then
return true;
end
end
end
if combine_amount <= 1 then
return false;
end
for _, property in pairs(self.carry) do
if property:query("class_id") == class_id then
free_amount = free_amount + (combine_amount - property:query("amount"));
if free_amount >= number then
return true;
end
end
end
return false;
end
function CONTAINER_TDCLS:check_free_amount_by_multi_class_id(item_list)
local page_amount = {};
local page;
for _, info in ipairs(item_list) do
page = PROPERTY_D.get_property_info(info.class_id)["item_type"];
page_amount[page] = (page_amount[page] or 0) + 1;
end
local rest_amount;
for page, amount in pairs(page_amount) do
rest_amount = self:get_free_amount_by_page(page);
if rest_amount < amount then
return false;
end
end
return true;
end
function CONTAINER_TDCLS:add_property(class_id, amount, bonus_type)
if not amount then
amount = 1;
end
if not bonus_type then
bonus_type = BONUS_TYPE_GD;
end
local combine = 1;
if PROPERTY_D.get_item_dbase(class_id) then
combine = CALC_ITEM_MAX_AMOUNT(class_id);
end
local property_list = {};
while amount > 0 do
local info = { ob=self, class_id=class_id };
if amount > combine then
info["amount"] = combine;
else
info["amount"] = amount;
end
property_list[#property_list+1] = info;
amount = amount - combine;
end
local bonus_info = { property = property_list };
BONUS_D.do_bonus(bonus_info, bonus_type);
end
function CONTAINER_TDCLS:get_free_pos_by_page(page)
local size = self:get_container_size(page);
if not size then
return;
end
local pos;
for i = 0, size - 1 do
pos = MAKE_POS(page, i);
if not self:get_pos_carry(pos) then
return pos;
end
end
return nil;
end
function CONTAINER_TDCLS:get_page_carry_by_region(page, range, idx)
local size = self:get_container_size(page);
if not size then
return;
end
local b = math.floor(size/range)*(idx-1);
local e = b + range - 1;
return (self:get_page_range_carry(page, b, e));
end
function CONTAINER_TDCLS:get_free_pos_by_region(page, range, idx)
local size = self:get_container_size(page);
if not size then
return;
end
local b = math.floor(size/range)*(idx-1);
local e = b + range - 1;
local pos;
for i = b, e - 1 do
pos = MAKE_POS(page, i);
if not self:get_pos_carry(pos) then
return pos, b;
end
end
return nil;
end
function CONTAINER_TDCLS:init_property(property)
assert(property["pos"] and property["class_id"] and property["rid"], "pos class_id rid must be exist")
assert(self.carry[property["pos"]] == nil, "carry pos must nil")
property = PROPERTY_D.clone_object_from(property["class_id"], property, true)
if not property then
return false
end
property:set("owner", self.owner);
property:set_temp("container", self.owner);
self.carry[property:query("pos")] = property;
return true;
end
function CONTAINER_TDCLS:recieve_property(info, check_enough)
assert(info["class_id"] ~= nil, "class_id must no empty")
local item_info = PROPERTY_D.get_item_or_equip_info(info["class_id"])
if not item_info then
return false;
end
local page = CONTAINER_D.get_page_by_data(item_info);
local size = self:get_container_size(page);
if not size then
return false;
end
info["amount"] = info["amount"] or 1
local max_amount = CALC_ITEM_MAX_AMOUNT(item_info)
local pos, left_amount = nil, info["amount"]
local gain_list = {}
local empty_slot = {}
for i = 1, size - 1 do
pos = MAKE_POS(page, i)
local property = self:get_pos_carry(pos)
if not property then
empty_slot[#empty_slot+1] = pos
elseif property:query("class_id") == info["class_id"] then
local get_amount = math.max(0, max_amount - property:query("amount"))
if get_amount > 0 then
local real_get = math.min(get_amount, left_amount)
table.insert(gain_list, { pos = pos, amount = real_get })
left_amount = left_amount - real_get
end
if left_amount <= 0 then
break
end
end
end
if left_amount > 0 and #empty_slot > 0 then
for _, pos in ipairs(empty_slot) do
local real_get = math.min(max_amount, left_amount)
table.insert(gain_list, { pos = pos, amount = real_get })
left_amount = left_amount - real_get
if left_amount <= 0 then break end
end
end
if check_enough and left_amount > 0 then
return false, "背包空间不足"
end
local result_list = {}
for _,v in ipairs(gain_list) do
local property = PROPERTY_D.clone_object_from(info["class_id"], merge(dup(info), {amount = v.amount}), false)
self:load_property(property, v.pos)
local property = self.carry[v.pos]
table.insert(result_list, {rid = get_ob_rid(property), class_id = info["class_id"], amount = v.amount, pos = v.pos, ob_type = property:query("ob_type")})
end
return true, result_list
end
function CONTAINER_TDCLS:load_property(property, dst_pos, not_auto_notify, not_auto_arrange)
if property:query_temp("container") == self.owner then
self:unload_property(property, not_auto_notify);
end
if self:is_pos_occuppied(dst_pos) then
return (self:combine_to_pos(property, dst_pos));
end
local owner_rid = self.owner
local owner_ob = self:get_owner()
LOG_D.to_log(LOG_TYPE_CREATE_PROPERTY, self.owner, property:get_rid(), tostring(property:query("class_id")), tostring(property:query("amount")), self:get_owner():query_log_channel());
property:set("pos", dst_pos);
property:set("owner", self.owner);
property:set_temp("container", self.owner);
self.carry[dst_pos] = property;
self:get_owner():notify_property_loaded(property:get_rid())
return true;
end
function CONTAINER_TDCLS:get_owner()
return find_object_by_rid(self.owner)
end
function CONTAINER_TDCLS:unload_property(property, not_auto_notify)
local pos = property:query("pos");
local property_rid = property:query("rid");
property:delete_temp("container");
if pos then
self.carry[pos] = nil;
end
return true;
end
function CONTAINER_TDCLS:is_pos_occuppied(pos)
return (is_object(self.carry[pos]));
end
function CONTAINER_TDCLS:get_container_size(page)
local container_size = self:query("container_size") or {};
local size = container_size[page] or MAX_PAGE_SIZE[page];
return size;
end
function CONTAINER_TDCLS:set_container_size(page, size)
local container_size = self:query("container_size") or {};
container_size[page] = size;
self:set("container_size", container_size);
end
function CONTAINER_TDCLS:switch_pos(src_pos, dst_pos)
local src_ob = self.carry[src_pos];
local dst_ob = self.carry[dst_pos];
self.carry[src_pos] = nil;
self.carry[dst_pos] = nil;
if is_object(src_ob) then
src_ob:set("pos", dst_pos);
self.carry[dst_pos] = src_ob;
src_ob:notify_fields_updated("pos");
end
if is_object(dst_ob) then
dst_ob:set("pos", src_pos);
self.carry[src_pos] = dst_ob;
dst_ob:notify_fields_updated("pos");
end
end
function CONTAINER_TDCLS:switch_carry_pos_without_notify(src_pos, dst_pos)
local src_ob = self.carry[src_pos];
local dst_ob = self.carry[dst_pos];
self.carry[src_pos] = nil;
self.carry[dst_pos] = nil;
if src_ob and src_ob:is_equip() == true then
self.carry[dst_pos] = src_ob;
end
if dst_ob and dst_ob:is_equip() == true then
self.carry[src_pos] = dst_ob;
end
end