aboutsummaryrefslogtreecommitdiff
path: root/ch_core/kos.lua
blob: ac9bb837862d3121c323546925cf602519bedae7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
ch_core.open_submod("kos", {lib = true})

local player_name_to_trash_inv = {}
local trash_inv_width, trash_inv_height = 4, 2

local function return_zero()
	return 0
end

local function on_take(inv, listname, index, stack, player)
	local s = stack:to_string()
	s = s:sub(1, 1024)
	minetest.log("action", player:get_player_name().." retreived from the trash bin: "..s)
end

local inv_callbacks = {
	allow_move = return_zero,
	allow_put = return_zero,
	-- allow_take = yes,
	on_take = on_take,
}

local function on_joinplayer(player, _last_login)
	local player_name = player:get_player_name()
	local trash_inv = minetest.create_detached_inventory("ch_core_trash_"..player_name, inv_callbacks, player_name)
	trash_inv:set_size("main", trash_inv_width * trash_inv_height)
	player_name_to_trash_inv[player_name] = trash_inv
end

local function on_leaveplayer(player, _timeouted)
	local player_name = player:get_player_name()
	minetest.remove_detached_inventory("ch_core_trash_"..player_name)
	player_name_to_trash_inv[player_name] = nil
end

minetest.register_on_joinplayer(on_joinplayer)
minetest.register_on_leaveplayer(on_leaveplayer)

--[[
	Vrací nil, pokud pro danou postavu inventář koše neexistuje.
	Jinak vrací:
	{
		inventory = InvRef,
		location = string,
		listname = string,
		width = int,
		height = int,
	}
]]
function ch_core.get_trash_inventory(player_name)
	local result = {
		inventory = player_name_to_trash_inv[player_name],
		location = "detached:ch_core_trash_"..player_name,
		listname = "main",
		width = trash_inv_width,
		height = trash_inv_height,
	}
	if result.inventory ~= nil then
		return result
	end
end

--[[
	Smaže obsah zadaného inventáře a zaznamená to jako příkaz daného
	hráče/ky.
	player_name -- přihlašovací jméno hráče/ky nebo nil
	inv -- odkaz na inventář
	listname -- listname ke smazání
	description -- heslovitý popis kontextu mazání
]]
function ch_core.vyhodit_inventar(player_name, inv, listname, description)
	if not player_name then
		player_name = "???"
	end
	if not description then
		description = "???"
	end
	local t = inv:get_list(listname)
	if t == nil then
		return false
	end
	local craftitems, tools, item_strings = {}, {}, {}
	for _, stack in ipairs(t) do
		if not stack:is_empty() then
			if stack:get_stack_max() <= 1 then
				table.insert(tools, stack)
			else
				table.insert(craftitems, stack)
			end
			table.insert(item_strings, stack:to_string():sub(1, 1024))
		end
	end

	if #item_strings > 0 then
		minetest.log("action", "Player "..player_name.." trashed "..#item_strings.." items ("..description.."): "..table.concat(item_strings, ", "))
		local empty_list = {}
		inv:set_list(listname, empty_list)
		if player_name ~= "???" then

			-- Trash inventory:
			local trash_inv = player_name_to_trash_inv[player_name]
			if trash_inv ~= nil then
				local old_trash_list = trash_inv:get_list("main")
				trash_inv:set_list("main", empty_list)
				for i = #tools, 1, -1 do
					trash_inv:add_item("main", tools[i])
				end
				for i = #craftitems, 1, -1 do
					trash_inv:add_item("main", craftitems[i])
				end
				for i = #old_trash_list, 1, -1 do
					local stack = old_trash_list[i]
					if not stack:is_empty() then
						trash_inv:add_item("main", stack)
					end
				end
				if not trash_inv:is_empty("main") then
					old_trash_list = trash_inv:get_list("main")
					local n = 1
					while n < #old_trash_list and not old_trash_list[n + 1]:is_empty() do
						n = n + 1
					end
					-- reverse the list:
					for i = 1, math.floor(n / 2) do
						old_trash_list[i], old_trash_list[1 + n - i] = old_trash_list[1 + n - i], old_trash_list[i]
					end
					trash_inv:set_list("main", old_trash_list)
				end
			else
				minetest.log("warning", "Player "..player_name.." has no trash inventory!")
			end

			local trash_sound
			if #item_strings == 1 then
				trash_sound = ch_core.overridable.trash_one_sound
			else
				trash_sound = ch_core.overridable.trash_all_sound
			end
			if trash_sound ~= nil and trash_sound ~= "" then
				minetest.sound_play(trash_sound, { to_player = player_name, gain = 1.0 })
			end
		end
	end
	return true
end

function ch_core.vyhodit_predmet(player_name, stack, description)
	if not player_name then
		player_name = "???"
	end
	if not description then
		description = "???"
	end
	if stack == nil or stack:is_empty() then
		return false
	end
	minetest.log("action", "Player "..player_name.." trashed an item ("..description.."): "..stack:to_string():sub(1, 1024))
	local trash_inv = player_name_to_trash_inv[player_name]
	if trash_inv == nil then
		minetest.log("warning", "Player "..player_name.." has no trash inventory!")
	elseif trash_inv:room_for_item("main", stack) then
		trash_inv:add_item("main", stack)
	else
		-- shift the inventory:
		local list = trash_inv:get_list("main")
		for i = 1, #list - 1 do
			list[i] = list[i + 1]
		end
		list[#list] = stack
		trash_inv:set_list("main", list)
	end
	local trash_sound = ch_core.overridable.trash_one_sound
	if trash_sound ~= nil and trash_sound ~= "" then
		minetest.sound_play(trash_sound, { to_player = player_name, gain = 1.0 })
	end
	return true
end

-- přepsat minetest.item_drop:
local old_minetest_item_drop = minetest.item_drop
function minetest.item_drop(itemstack, dropper, pos)
	if minetest.is_player(dropper) then
		local player_name = assert(dropper:get_player_name())
		local offline_charinfo = ch_data.offline_charinfo[player_name]
		if
			offline_charinfo ~= nil and
			offline_charinfo.discard_drops ~= nil and
			offline_charinfo.discard_drops == 1 and
			ch_core.get_trash_inventory(player_name) ~= nil
		then
			ch_core.vyhodit_predmet(player_name, itemstack, "item_drop")
			return ItemStack()
		end
	end
	local dropper_name = "???"
	local dropper_pos = "(???)"
	if dropper ~= nil and dropper.get_player_name ~= nil and dropper.get_pos ~= nil then
		dropper_name = dropper:get_player_name()
		dropper_pos = core.pos_to_string(vector.round(dropper:get_pos()))
	elseif pos ~= nil then
		dropper_pos = core.pos_to_string(vector.round(pos))
	end
	local item_name = itemstack:get_name()
	if core.registered_items[item_name] ~= nil then
		core.log("action", "Item drop: "..dropper_name.." dropped "..itemstack:get_count().." of '"..item_name.."' at "..dropper_pos)
	end
	return old_minetest_item_drop(itemstack, dropper, pos)
end

ch_core.close_submod("kos")