5 ARMOR_DROP
= minetest
.get_modpath("bones") ~= nil
7 ARMOR_LEVEL_MULTIPLIER
= 1
8 ARMOR_HEAL_MULTIPLIER
= 1
9 ARMOR_RADIATION_MULTIPLIER
= 1
12 cactus
= "mcl_core:cactus",
13 iron
= "mcl_core:iron_ingot",
14 bronze
= "mcl_core:bronze_ingot",
15 diamond
= "mcl_core:diamond",
16 gold
= "mcl_core:gold_ingot",
17 mithril
= "moreores:mithril_ingot",
18 crystal
= "ethereal:crystal_ingot",
20 ARMOR_FIRE_PROTECT
= minetest
.get_modpath("ethereal") ~= nil
22 {"mcl_core:lava_source", 5, 8},
23 {"mcl_core:lava_flowing", 5, 8},
24 {"fire:basic_flame", 3, 4},
25 {"fire:permanent_flame", 3, 4},
26 {"ethereal:crystal_spike", 2, 1},
27 {"ethereal:fire_flower", 2, 1},
28 {"mcl_torches:torch", 1, 1},
33 local modpath
= minetest
.get_modpath(minetest
.get_current_modname())
34 local worldpath
= minetest
.get_worldpath()
35 local input
= io
.open(modpath
.."/armor.conf", "r")
37 dofile(modpath
.."/armor.conf")
41 input
= io
.open(worldpath
.."/armor.conf", "r")
43 dofile(worldpath
.."/armor.conf")
47 if not minetest
.get_modpath("moreores") then
48 ARMOR_MATERIALS
.mithril
= nil
50 if not minetest
.get_modpath("ethereal") then
51 ARMOR_MATERIALS
.crystal
= nil
56 elements
= {"head", "torso", "legs", "feet"},
57 physics
= {"jump","speed","gravity"},
58 formspec
= "size[8,8.5]image[2,0.75;2,4;armor_preview]"
59 .."list[current_player;main;0,4.5;8,4;]"
60 .."list[current_player;craft;4,1;3,3;]"
61 .."list[current_player;craftpreview;7,2;1,1;]"
62 .."listring[current_player;main]"
63 .."listring[current_player;craft]",
65 default_skin
= "character",
69 if minetest
.get_modpath("skins") then
71 elseif minetest
.get_modpath("simple_skins") then
72 skin_mod
= "simple_skins"
73 elseif minetest
.get_modpath("u_skins") then
75 elseif minetest
.get_modpath("wardrobe") then
84 armor
.update_player_visuals
= function(self
, player
)
88 local name
= player
:get_player_name()
89 if self
.textures
[name
] then
90 mcl_player
.player_set_textures(player
, {
91 self
.textures
[name
].skin
,
92 self
.textures
[name
].armor
,
93 self
.textures
[name
].wielditem
,
98 armor
.set_player_armor
= function(self
, player
)
99 local name
, player_inv
= armor
:get_valid_player(player
, "[set_player_armor]")
103 local armor_texture
= "3d_armor_trans.png"
104 local armor_level
= 0
107 local armor_water
= 0
108 local armor_radiation
= 0
113 local physics_o
= {speed
=1,gravity
=1,jump
=1}
114 local material
= {type=nil, count
=1}
115 local preview
= armor
:get_preview(name
) or "character_preview.png"
116 for _
,v
in ipairs(self
.elements
) do
120 local stack
= player_inv
:get_stack("armor", i
)
121 local item
= stack
:get_name()
122 if stack
:get_count() == 1 then
123 local def
= stack
:get_definition()
124 for k
, v
in pairs(elements
) do
126 local level
= def
.groups
["armor_"..k
]
128 local texture
= def
.texture
or item
:gsub("%:", "_")
129 table.insert(textures
, texture
..".png")
130 preview
= preview
.."^"..texture
.."_preview.png"
131 armor_level
= armor_level
+ level
132 state
= state
+ stack
:get_wear()
134 armor_heal
= armor_heal
+ (def
.groups
["armor_heal"] or 0)
135 armor_fire
= armor_fire
+ (def
.groups
["armor_fire"] or 0)
136 armor_water
= armor_water
+ (def
.groups
["armor_water"] or 0)
137 armor_radiation
= armor_radiation
+ (def
.groups
["armor_radiation"] or 0)
138 for kk
,vv
in ipairs(self
.physics
) do
139 local o_value
= def
.groups
["physics_"..vv
]
141 physics_o
[vv
] = physics_o
[vv
] + o_value
144 local mat
= string.match(item
, "%:.+_(.+)$")
145 if material
.type then
146 if material
.type == mat
then
147 material
.count
= material
.count
+ 1
158 if minetest
.get_modpath("shields") then
159 armor_level
= armor_level
* 0.9
161 if material
.type and material
.count
== #self
.elements
then
162 armor_level
= armor_level
* 1.1
164 armor_level
= armor_level
* ARMOR_LEVEL_MULTIPLIER
165 armor_heal
= armor_heal
* ARMOR_HEAL_MULTIPLIER
166 armor_radiation
= armor_radiation
* ARMOR_RADIATION_MULTIPLIER
167 if #textures
> 0 then
168 armor_texture
= table.concat(textures
, "^")
170 local armor_groups
= {fleshy
=100}
171 if armor_level
> 0 then
172 armor_groups
.level
= math
.floor(armor_level
/ 20)
173 armor_groups
.fleshy
= 100 - armor_level
174 armor_groups
.radiation
= 100 - armor_radiation
176 player
:set_armor_groups(armor_groups
)
177 -- Physics override intentionally removed because of possible conflicts
178 self
.textures
[name
].armor
= armor_texture
179 self
.textures
[name
].preview
= preview
180 self
.def
[name
].state
= state
181 self
.def
[name
].count
= items
182 self
.def
[name
].level
= armor_level
183 self
.def
[name
].heal
= armor_heal
184 self
.def
[name
].jump
= physics_o
.jump
185 self
.def
[name
].speed
= physics_o
.speed
186 self
.def
[name
].gravity
= physics_o
.gravity
187 self
.def
[name
].fire
= armor_fire
188 self
.def
[name
].water
= armor_water
189 self
.def
[name
].radiation
= armor_radiation
190 self
:update_player_visuals(player
)
193 armor
.update_armor
= function(self
, player
)
194 -- Legacy support: Called when armor levels are changed
195 -- Other mods can hook on to this function, see hud mod for example
198 armor
.get_player_skin
= function(self
, name
)
200 if skin_mod
== "skins" or skin_mod
== "simple_skins" then
201 skin
= skins
.skins
[name
]
202 elseif skin_mod
== "u_skins" then
203 skin
= u_skins
.u_skins
[name
]
204 elseif skin_mod
== "wardrobe" then
205 skin
= string.gsub(wardrobe
.playerSkins
[name
], "%.png$","")
207 return skin
or armor
.default_skin
210 armor
.get_preview
= function(self
, name
)
211 if skin_mod
== "skins" then
212 return armor
:get_player_skin(name
).."_preview.png"
216 armor
.get_armor_formspec
= function(self
, name
)
217 if not armor
.textures
[name
] then
218 minetest
.log("error", "3d_armor: Player texture["..name
.."] is nil [get_armor_formspec]")
221 if not armor
.def
[name
] then
222 minetest
.log("error", "3d_armor: Armor def["..name
.."] is nil [get_armor_formspec]")
225 local formspec
= armor
.formspec
.."list[detached:"..name
.."_armor;armor;0,1;2,3;]"
226 formspec
= formspec
:gsub("armor_preview", armor
.textures
[name
].preview
)
227 formspec
= formspec
:gsub("armor_level", armor
.def
[name
].level
)
228 formspec
= formspec
:gsub("armor_heal", armor
.def
[name
].heal
)
229 formspec
= formspec
:gsub("armor_fire", armor
.def
[name
].fire
)
230 formspec
= formspec
:gsub("armor_radiation", armor
.def
[name
].radiation
)
234 armor
.update_inventory
= function(self
, player
)
237 armor
.get_valid_player
= function(self
, player
, msg
)
240 minetest
.log("error", "3d_armor: Player reference is nil "..msg
)
243 local name
= player
:get_player_name()
245 minetest
.log("error", "3d_armor: Player name is nil "..msg
)
248 local pos
= player
:get_pos()
249 local player_inv
= player
:get_inventory()
250 local armor_inv
= minetest
.get_inventory({type="detached", name
=name
.."_armor"})
252 minetest
.log("error", "3d_armor: Player position is nil "..msg
)
254 elseif not player_inv
then
255 minetest
.log("error", "3d_armor: Player inventory is nil "..msg
)
257 elseif not armor_inv
then
258 minetest
.log("error", "3d_armor: Detached armor inventory is nil "..msg
)
261 return name
, player_inv
, armor_inv
, pos
264 -- Register Player Model
266 mcl_player
.player_register_model("3d_armor_character.b3d", {
267 animation_speed
= 30,
269 armor
.default_skin
..".png",
270 "3d_armor_trans.png",
271 "3d_armor_trans.png",
275 lay
= {x
=162, y
=166},
276 walk
= {x
=168, y
=187},
277 mine
= {x
=189, y
=198},
278 walk_mine
= {x
=200, y
=219},
283 -- Register Callbacks
285 minetest
.register_on_player_receive_fields(function(player
, formname
, fields
)
286 local name
= armor
:get_valid_player(player
, "[on_player_receive_fields]")
293 for field
, _
in pairs(fields
) do
294 if string.find(field
, "skins_set") then
295 minetest
.after(0, function(name
)
296 local player
= minetest
.get_player_by_name(name
)
300 local skin
= armor
:get_player_skin(name
)
301 armor
.textures
[name
].skin
= skin
..".png"
302 armor
:set_player_armor(player
)
303 end, player
:get_player_name())
308 minetest
.register_on_joinplayer(function(player
)
309 mcl_player
.player_set_model(player
, "3d_armor_character.b3d")
310 local name
= player
:get_player_name()
311 local player_inv
= player
:get_inventory()
312 local armor_inv
= minetest
.create_detached_inventory(name
.."_armor", {
313 on_put
= function(inv
, listname
, index
, stack
, player
)
314 player
:get_inventory():set_stack(listname
, index
, stack
)
315 armor
:set_player_armor(player
)
316 armor
:update_inventory(player
)
318 on_take
= function(inv
, listname
, index
, stack
, player
)
319 player
:get_inventory():set_stack(listname
, index
, nil)
320 armor
:set_player_armor(player
)
321 armor
:update_inventory(player
)
323 on_move
= function(inv
, from_list
, from_index
, to_list
, to_index
, count
, player
)
324 local plaver_inv
= player
:get_inventory()
325 local stack
= inv
:get_stack(to_list
, to_index
)
326 player_inv
:set_stack(to_list
, to_index
, stack
)
327 player_inv
:set_stack(from_list
, from_index
, nil)
328 armor
:set_player_armor(player
)
329 armor
:update_inventory(player
)
331 allow_put
= function(inv
, listname
, index
, stack
, player
)
332 local iname
= stack
:get_name()
336 g
= minetest
.get_item_group(iname
, "armor_head")
337 elseif index
== 3 then
338 g
= minetest
.get_item_group(iname
, "armor_torso")
339 elseif index
== 4 then
340 g
= minetest
.get_item_group(iname
, "armor_legs")
341 elseif index
== 5 then
342 g
= minetest
.get_item_group(iname
, "armor_feet")
344 -- Minor FIXME: If player attempts to place stack into occupied slot, this is rejected.
345 -- It would be better if 1 item is placed in exchanged for the item in the slot.
346 if g
~= 0 and g
~= nil and (inv
:get_stack(listname
, index
):is_empty() or (inv
:get_stack(listname
, index
):get_name() ~= stack
:get_name()) and stack
:get_count() <= 1) then
352 allow_take
= function(inv
, listname
, index
, stack
, player
)
353 return stack
:get_count()
355 allow_move
= function(inv
, from_list
, from_index
, to_list
, to_index
, count
, player
)
359 armor_inv
:set_size("armor", 6)
360 player_inv
:set_size("armor", 6)
362 local stack
= player_inv
:get_stack("armor", i
)
363 armor_inv
:set_stack("armor", i
, stack
)
377 armor
.textures
[name
] = {
378 skin
= armor
.default_skin
..".png",
379 armor
= "3d_armor_trans.png",
380 wielditem
= "3d_armor_trans.png",
381 preview
= armor
.default_skin
.."_preview.png",
383 if skin_mod
== "skins" then
384 local skin
= skins
.skins
[name
]
385 if skin
and skins
.get_type(skin
) == skins
.type.MODEL
then
386 armor
.textures
[name
].skin
= skin
..".png"
388 elseif skin_mod
== "simple_skins" then
389 local skin
= skins
.skins
[name
]
391 armor
.textures
[name
].skin
= skin
..".png"
393 elseif skin_mod
== "u_skins" then
394 local skin
= u_skins
.u_skins
[name
]
395 if skin
and u_skins
.get_type(skin
) == u_skins
.type.MODEL
then
396 armor
.textures
[name
].skin
= skin
..".png"
398 elseif skin_mod
== "wardrobe" then
399 local skin
= wardrobe
.playerSkins
[name
]
401 armor
.textures
[name
].skin
= skin
404 if minetest
.get_modpath("player_textures") then
405 local filename
= minetest
.get_modpath("player_textures").."/textures/player_"..name
406 local f
= io
.open(filename
..".png")
409 armor
.textures
[name
].skin
= "player_"..name
..".png"
412 for i
=1, ARMOR_INIT_TIMES
do
413 minetest
.after(ARMOR_INIT_DELAY
* i
, function(name
)
414 local player
= minetest
.get_player_by_name(name
)
418 armor
:set_player_armor(player
)
419 end, player
:get_player_name())
423 if ARMOR_DROP
== true or ARMOR_DESTROY
== true then
424 armor
.drop_armor
= function(pos
, stack
)
425 local obj
= minetest
.add_item(pos
, stack
)
427 obj
:setvelocity({x
=math
.random(-1, 1), y
=5, z
=math
.random(-1, 1)})
430 minetest
.register_on_dieplayer(function(player
)
431 local name
, player_inv
, armor_inv
, pos
= armor
:get_valid_player(player
, "[on_dieplayer]")
436 for i
=1, player_inv
:get_size("armor") do
437 local stack
= armor_inv
:get_stack("armor", i
)
438 if stack
:get_count() > 0 then
439 table.insert(drop
, stack
)
440 armor_inv
:set_stack("armor", i
, nil)
441 player_inv
:set_stack("armor", i
, nil)
444 armor
:set_player_armor(player
)
445 if ARMOR_DESTROY
== false then
446 minetest
.after(ARMOR_BONES_DELAY
, function(pos
, drop
)
447 local node
= minetest
.get_node(vector
.round(pos
))
449 if node
.name
~= "bones:bones" then
451 node
= minetest
.get_node(vector
.round(pos
))
452 if node
.name
~= "bones:bones" then
453 minetest
.log("warning", "Failed to add armor to bones node.")
457 local meta
= minetest
.get_meta(vector
.round(pos
))
458 local owner
= meta
:get_string("owner")
459 local inv
= meta
:get_inventory()
460 for _
,stack
in ipairs(drop
) do
461 if name
== owner
and inv
:room_for_item("main", stack
) then
462 inv
:add_item("main", stack
)
464 armor
.drop_armor(pos
, stack
)
468 for _
,stack
in ipairs(drop
) do
469 armor
.drop_armor(pos
, stack
)
477 minetest
.register_on_player_hpchange(function(player
, hp_change
)
478 local name
, player_inv
, armor_inv
= armor
:get_valid_player(player
, "[on_hpchange]")
479 if name
and hp_change
< 0 then
481 -- used for insta kill tools/commands like /kill (doesnt damage armor)
482 if hp_change
< -100 then
490 local stack
= player_inv
:get_stack("armor", i
)
491 if stack
:get_count() > 0 then
492 local use
= stack
:get_definition().groups
["armor_use"] or 0
493 local heal
= stack
:get_definition().groups
["armor_heal"] or 0
494 local item
= stack
:get_name()
496 armor_inv
:set_stack("armor", i
, stack
)
497 player_inv
:set_stack("armor", i
, stack
)
498 state
= state
+ stack
:get_wear()
500 if stack
:get_count() == 0 then
501 local desc
= minetest
.registered_items
[item
].description
503 minetest
.chat_send_player(name
, "Your "..desc
.." got destroyed!")
505 armor
:set_player_armor(player
)
506 armor
:update_inventory(player
)
508 heal_max
= heal_max
+ heal
511 armor
.def
[name
].state
= state
512 armor
.def
[name
].count
= items
513 heal_max
= heal_max
* ARMOR_HEAL_MULTIPLIER
514 if heal_max
> math
.random(100) then
517 armor
:update_armor(player
)
522 -- Fire Protection and water breating, added by TenPlus1
524 if ARMOR_FIRE_PROTECT
== true then
525 -- override hot nodes so they do not hurt player anywhere but mod
526 for _
, row
in pairs(ARMOR_FIRE_NODES
) do
527 if minetest
.registered_nodes
[row
[1]]
then
528 minetest
.override_item(row
[1], {damage_per_second
= 0})
532 print ("[3d_armor] Fire Nodes disabled")
535 minetest
.register_globalstep(function(dtime
)
536 armor
.timer
= armor
.timer
+ dtime
537 if armor
.timer
< ARMOR_UPDATE_TIME
then
540 for _
,player
in pairs(minetest
.get_connected_players()) do
541 local name
= player
:get_player_name()
542 local pos
= player
:get_pos()
543 local hp
= player
:get_hp()
545 if name
and armor
.def
[name
].water
> 0 then
546 if player
:get_breath() < 10 then
547 player
:set_breath(10)
551 if ARMOR_FIRE_PROTECT
== true
552 and name
and pos
and hp
then
553 pos
.y
= pos
.y
+ 1.4 -- head level
554 local node_head
= minetest
.get_node(pos
).name
555 pos
.y
= pos
.y
- 1.2 -- feet level
556 local node_feet
= minetest
.get_node(pos
).name
557 -- is player inside a hot node?
558 for _
, row
in pairs(ARMOR_FIRE_NODES
) do
559 -- check fire protection, if not enough then get hurt
560 if row
[1] == node_head
or row
[1] == node_feet
then
561 if hp
> 0 and armor
.def
[name
].fire
< row
[2] then
562 hp
= hp
- row
[3] * ARMOR_UPDATE_TIME