-
Notifications
You must be signed in to change notification settings - Fork 1
/
init.lua
562 lines (489 loc) · 14.7 KB
/
init.lua
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
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
-- Minetest mod: Caches
-- requires default, Technic, Pipeworks, and Moreores
-- license: WTFPL
-- definitions
local tiers = {
{ name = "cache",
description = "Cache",
capacity = 10000,
material = "moreores:tin_ingot",
base = "group:tree",
texture = "caches_cache.png"
},
{ name = "cache_harden",
description = "Hardened Cache",
capacity = 40000,
material = "technic:carbon_steel_ingot",
base = "caches:cache",
texture = "caches_hardened.png"
},
{ name = "cache_reinfo",
description = "Reinforced Cache",
capacity = 160000,
material = "default:obsidian_glass",
base = "caches:cache_harden",
texture = "caches_reinforced.png"
},
{ name = "cache_arcane",
description = "Arcane Cache",
capacity = 640000,
material = "moreores:mithril_ingot",
base = "caches:cache_reinfo",
texture = "caches_arcane.png"
},
}
local default_texture = "default_obsidian_glass_detail.png"
-- update cache button toggles
local function update_formspec(pos)
local meta = minetest.get_meta(pos)
local name = meta:get_string("name")
local locked = meta:get_int("locked")
local output = meta:get_int("output")
if locked == 0 then
locks = "lock;Lock"
else
locks = "unlock;Unlock"
end
if output == 0 then
outs = "output;Output"
else
outs = "stop;Stop"
end
meta:set_string("showform", "size[4,3]"..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"button_exit[0,0;2,1;store;Store]"..
"button_exit[2,0;2,1;take;Take]"..
"button_exit[0,1;2,1;"..locks.."]"..
"button_exit[2,1;2,1;"..outs.."]"..
"button_exit[1,2;2,1;transfer;Transfer]"
)
end
-- find the entity associated with a cache, if any
local function find_visual(pos)
local objs = minetest.get_objects_inside_radius(pos, 0.65)
if objs then
for _, obj in pairs(objs) do
if obj and obj:get_luaentity() and
obj:get_luaentity().name == "caches:visual" then
return obj
end
end
end
end
-- get inventory image
local function get_inv_image(name)
local t = default_texture
local d = minetest.registered_items[name]
if name ~= "air" and d then
if d.inventory_image and #d.inventory_image > 0 then
t = d.inventory_image
else
local c = #d.tiles
local x = {}
for i, v in ipairs(d.tiles) do
if type(v) == "table" then
x[i] = v.name
else
x[i] = v
end
i = i + 1
end
if not x[3] then x[3] = x[1] end
if not x[4] then x[4] = x[3] end
t = minetest.inventorycube(x[1], x[3], x[4])
end
end
return t
end
-- update info about this cache
local function update_infotext(pos)
local meta = minetest.get_meta(pos)
local capacity = meta:get_int("capacity")
local count = meta:get_int("count")
local name = meta:get_string("name")
local locked = meta:get_int("locked")
local item = ""
if name ~= "air" then
local def = minetest.registered_items[name]
if def and def.description then item = def.description end
end
meta:set_string("infotext", item.." "..tostring(count).." / "..
tostring(capacity))
-- update visual
local obj = find_visual(pos)
if not obj then
local node = minetest.get_node(pos)
local bdir = minetest.facedir_to_dir(node.param2)
local fdir = vector.new(-bdir.x, 0, -bdir.z)
local pos2 = vector.add(pos, vector.multiply(fdir, 0.51))
obj = minetest.add_entity(pos2, "caches:visual")
if bdir.x < 0 then obj:setyaw(0.5 * math.pi) end
if bdir.z < 0 then obj:setyaw(math.pi) end
if bdir.x > 0 then obj:setyaw(1.5 * math.pi) end
end
if obj then
local t = get_inv_image(name)
if locked > 0 then t = t.."^caches_locked.png" end
obj:set_properties({textures = {t}})
end
end
-- put indicated stack of items into cache, returns leftovers
local function add_item(pos, stack)
local meta = minetest.get_meta(pos)
local name = meta:get_string("name")
local capacity = meta:get_int("capacity")
local cache_count = meta:get_int("count")
local locked = meta:get_int("locked")
local left_over = ItemStack(stack)
local stack_count = stack:get_count()
-- cancel if itemstack is 0 or a unique thing
if stack_count == 0 or stack:get_stack_max() == 1 then return stack end
if (locked == 0 and cache_count == 0) or stack:get_name() == name then
if cache_count < capacity then
local real_count = math.min(capacity - cache_count, stack_count)
meta:set_int("count", cache_count + real_count)
if stack:get_name() ~= name then
meta:set_string("name", stack:get_name())
end
if stack_count == real_count then
left_over:clear()
else
left_over:set_count(stack_count - real_count)
end
update_infotext(pos)
end
end
return left_over
end
-- return whether the the stack fully fits within the cache
local function room_for_item(pos, stack)
local meta = minetest.get_meta(pos)
local name = meta:get_string("name")
local capacity = meta:get_int("capacity")
local cache_count = meta:get_int("count")
local locked = meta:get_int("locked")
-- cancel if itemstack is 0 or a unique thing
if stack:get_count() == 0 or stack:get_stack_max() == 1 then return false end
if (locked == 0 and cache_count == 0) or stack:get_name() == name then
if cache_count + stack:get_count() <= capacity then
return true
else
return false
end
end
end
-- take items from cache and transfer them to inv
-- do_stack is an optional bool indicating whether to take a max stack
-- returns true if anything was transferred
local function remove_item(pos, inv, listname, do_stack)
local meta = minetest.get_meta(pos)
local cache_count = meta:get_int("count")
local locked = meta:get_int("locked")
if cache_count > 0 then
local name = meta:get_string("name")
local real_count = 1
if do_stack then
real_count = ItemStack(name):get_stack_max()
end
if real_count > cache_count then real_count = cache_count end
local stack = ItemStack(name)
stack:set_count(real_count)
if inv:room_for_item(listname, stack) then
inv:add_item(listname, stack)
meta:set_int("count", cache_count - real_count)
if cache_count == real_count and locked == 0 then
meta:set_string("name", "air")
end
update_infotext(pos)
return true
end
end
return false
end
-- check whether the player has access to the cache
local function can_access(pos, player)
if minetest.is_protected(pos, player) then
minetest.chat_send_player(player:get_player_name(),
"You are not permitted to access caches in this area.")
return false
end
return true
end
-- update description in itemstack
local function update_description(item, name, count, capacity)
local i = "Empty"
if name ~= "air" then
local def = minetest.registered_items[name]
if def and def.description then i = def.description end
end
local d = i.." "..tostring(count).." / "..tostring(capacity)
item:get_meta():set_string("description", d)
end
-- other features
minetest.register_on_player_receive_fields(function(player, formname, fields)
if string.sub(formname, 1, 12) ~= "caches:cache" then return end
local pos = minetest.string_to_pos(string.sub(formname, 13))
local meta = minetest.get_meta(pos)
local name = meta:get_string("name")
local capacity = meta:get_int("capacity")
local count = meta:get_int("count")
local locked = meta:get_int("locked")
if fields.store then
local inv = player:get_inventory()
if inv then
local n = name
local wield = player:get_wielded_item()
if count == 0 and locked == 0 then
n = wield:get_name()
end
local full_stack = ItemStack(n)
full_stack:set_count(full_stack:get_stack_max())
local stack = inv:remove_item("main", full_stack)
while room_for_item(pos, stack) and not stack:is_empty() do
add_item(pos, stack)
stack = inv:remove_item("main", full_stack)
end
if not stack:is_empty() then
local left = add_item(pos, stack)
inv:add_item("main", left)
end
end
end
if fields.take then
local inv = player:get_inventory()
if inv then
local b = true
while b do
b = remove_item(pos, inv, "main", true)
end
end
end
if fields.lock and name ~= "air" then
meta:set_int("locked", 1)
update_infotext(pos)
end
if fields.unlock then
meta:set_int("locked", 0)
update_infotext(pos)
end
if fields.output then
meta:set_int("output", 1)
local timer = minetest.get_node_timer(pos)
timer:start(1.0)
end
if fields.stop then meta:set_int("output", 0) end
if fields.transfer then
local inv = player:get_inventory()
local data = { name = name, count = count, locked = locked }
local item = ItemStack(minetest.get_node(pos).name)
item:set_metadata(minetest.serialize(data))
update_description(item, name, count, capacity)
if inv:room_for_item("main", item) then
inv:add_item("main", item)
else
minetest.add_item(player:getpos(), item)
end
minetest.remove_node(pos)
local obj = find_visual(pos)
if obj then obj:remove() end
end
update_formspec(pos)
end)
-- putting stuff in place
local function on_rightclick(pos, node, clicker, itemstack, pointed_thing)
if can_access(pos, clicker) then
if itemstack and not itemstack:is_empty() then
if clicker:get_player_control().sneak then
if add_item(pos, ItemStack(itemstack:get_name())):is_empty() then
itemstack:take_item()
end
return itemstack
else
return add_item(pos, itemstack)
end
else
local meta = minetest.get_meta(pos)
local formspec = meta:get_string("showform")
local formname = "caches:cache"..minetest.pos_to_string(pos)
minetest.show_formspec(clicker:get_player_name(), formname, formspec)
end
end
return itemstack
end
-- restore proper function to core.item_place for my nodes
-- (so I can actually use the sneak key)
local old_item_place = core.item_place
local function caches_item_place(itemstack, placer, pointed_thing, param2)
if pointed_thing.type == "node" and placer then
local n = minetest.get_node(pointed_thing.under)
local nn = n.name
if minetest.get_item_group(nn, "caches") > 0 then
-- need to get the real name and not fake ones
local i = itemstack:get_name()
local d = minetest.registered_items[i]
if d and d.drop then
-- ignore default items and non-strings
if type(d.drop) == "string" and not string.match(i, "default:.+") then
itemstack:set_name(d.drop)
end
end
return on_rightclick(pointed_thing.under, n,
placer, itemstack, pointed_thing) or itemstack, false
end
end
return old_item_place(itemstack, placer, pointed_thing, param2)
end
core.item_place = caches_item_place
-- handle transfer of meta on crafted upgrades
minetest.register_on_craft(function(itemstack, player, old_craft_grid, craft_inv)
if minetest.get_item_group(itemstack:get_name(), "caches") > 0 then
local i = 1
local craft_size = player:get_inventory():get_size("craft")
while i <= craft_size do
local old = old_craft_grid[i]
i = i + 1
if minetest.get_item_group(old:get_name(), "caches") > 0 then
-- copy old cache meta to output stack
itemstack:set_metadata(old:get_metadata())
local data = minetest.deserialize(old:get_metadata())
if data then
local c = 0
local n = string.sub(itemstack:get_name(), 8)
for _, tier in pairs(tiers) do
if n == tier.name then c = tier.capacity end
end
update_description(itemstack, data.name, data.count, c)
end
return
end
end
end
end)
-- output a stack below the cache
local function do_output(pos)
local meta = minetest.get_meta(pos)
local name = meta:get_string("name")
local cache_count = meta:get_int("count")
if cache_count > 0 then
local count = ItemStack(name):get_stack_max()
if count > cache_count then count = cache_count end
local stack = ItemStack(name)
stack:set_count(count)
technic.tube_inject_item(pos, pos, vector.new(0, -1, 0), stack)
meta:set_int("count", cache_count - count)
if cache_count == count and locked == 0 then
meta:set_string("name", "air")
end
update_infotext(pos)
end
end
-- output mode = do an output once per second
local function cache_node_timer(pos, elapsed)
local meta = minetest.get_meta(pos)
local output = meta:get_int("output")
if output > 0 then
do_output(pos)
else
local timer = minetest.get_node_timer(pos)
timer:stop()
return false
end
return true
end
-- register item visual
minetest.register_entity("caches:visual", {
visual = "upright_sprite",
visual_size = {x=0.6, y=0.6},
collisionbox = {0},
physical = false,
textures = {default_texture},
})
-- register LBM to fix textures in visuals
minetest.register_lbm(
{
name = "caches:restore_visuals",
nodenames = {"group:caches"},
run_at_every_load = true,
action = function(pos, node)
update_infotext(pos)
end,
})
-- register caches
for _, tier in pairs(tiers) do
minetest.register_node("caches:"..tier.name, {
description = tier.description,
groups = { caches=1, tubedevice=1, tubedevice_receiver=1 },
tiles = { tier.texture },
paramtype2 = "facedir",
stack_max = 1,
tube = {
insert_object = function(pos, node, stack, direction)
return add_item(pos, stack)
end,
can_insert = function(pos, node, stack, direction)
return room_for_item(pos, stack)
end,
connect_sides = {left=1, right=1, back=1, top=1, bottom=1},
},
after_place_node = function(pos, placer, stack)
local meta = minetest.get_meta(pos)
local data = minetest.deserialize(stack:get_metadata())
local name = "air"
local count = 0
local locked = 0
if data then
name = data.name
count = data.count
locked = data.locked
end
meta:set_string("name", name)
meta:set_int("count", count)
meta:set_int("locked", locked)
meta:set_int("capacity", tier.capacity)
update_formspec(pos)
update_infotext(pos)
pipeworks.scan_for_tube_objects(pos)
end,
after_destruct = function(pos, oldnode)
pipeworks.scan_for_tube_objects(pos)
end,
on_punch = function(pos, node, puncher, pointed_thing)
if can_access(pos, puncher) then
local ctrl = puncher:get_player_control()
local inv = puncher:get_inventory()
if inv then
remove_item(pos, inv, "main", not ctrl.sneak)
end
end
end,
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
if itemstack and not itemstack:is_empty() then
local left = on_rightclick(pos, node, clicker, itemstack, pointed_thing)
if left:get_count() ~= itemstack:get_count() then
-- if we're here, this is some custom on_place thing
-- and this is in the twilight zone
minetest.after(0.1, function(clicker, left)
clicker:set_wielded_item(left)
end, clicker, left)
end
return left -- this value is pointless
end
end,
on_timer = cache_node_timer,
on_rotate = screwdriver.disallow,
mesecons = {effector = {action_on = do_output}},
diggable = false,
can_dig = function() return false end,
on_blast = function() end,
})
minetest.register_craft({
output = "caches:"..tier.name,
recipe = {
{"", tier.material, ""},
{tier.material, tier.base, tier.material},
{"", tier.material, ""},
}
})
end