1 -- Internal player state
2 local mcl_playerplus_internal
= {}
4 local armor_mod
= minetest
.get_modpath("3d_armor")
8 minetest
.register_globalstep(function(dtime
)
12 -- Update jump status immediately since we need this info in real time.
13 -- WARNING: This section is HACKY as hell since it is all just based on heuristics.
14 for _
,player
in pairs(minetest
.get_connected_players()) do
15 local name
= player
:get_player_name()
16 if mcl_playerplus_internal
[name
].jump_cooldown
> 0 then
17 mcl_playerplus_internal
[name
].jump_cooldown
= mcl_playerplus_internal
[name
].jump_cooldown
- dtime
19 if player
:get_player_control().jump
and mcl_playerplus_internal
[name
].jump_cooldown
<= 0 then
21 local pos
= player
:get_pos()
23 local node_stand
= mcl_playerinfo
[name
].node_stand
24 local node_stand_below
= mcl_playerinfo
[name
].node_stand_below
25 local node_head
= mcl_playerinfo
[name
].node_head
26 local node_feet
= mcl_playerinfo
[name
].node_feet
27 if not node_stand
or not node_stand_below
or not node_head
or not node_feet
then
31 -- Cause buggy exhaustion for jumping
33 --[[ Checklist we check to know the player *actually* jumped:
35 * Not on or at climbable
38 FIXME: This code is pretty hacky and it is possible to miss some jumps or detect false
39 jumps because of delays, rounding errors, etc.
40 What this code *really* needs is some kind of jumping “callback” which this engine lacks
44 if minetest
.get_item_group(node_feet
, "liquid") == 0 and
45 minetest
.get_item_group(node_stand
, "liquid") == 0 and
46 not minetest
.registered_nodes
[node_feet
].climbable
and
47 not minetest
.registered_nodes
[node_stand
].climbable
and
48 (minetest
.registered_nodes
[node_stand
].walkable
or minetest
.registered_nodes
[node_stand_below
].walkable
)
49 and minetest
.get_item_group(node_stand
, "disable_jump") == 0
50 and minetest
.get_item_group(node_stand_below
, "disable_jump") == 0 then
51 -- Cause exhaustion for jumping
52 if mcl_sprint
.is_sprinting(name
) then
53 mcl_hunger
.exhaust(name
, mcl_hunger
.EXHAUST_SPRINT_JUMP
)
55 mcl_hunger
.exhaust(name
, mcl_hunger
.EXHAUST_JUMP
)
58 -- Reset cooldown timer
59 mcl_playerplus_internal
[name
].jump_cooldown
= 0.45
64 -- Run the rest of the code every 0.5 seconds
69 -- reset time for next check
70 -- FIXME: Make sure a regular check interval applies
74 for _
,player
in pairs(minetest
.get_connected_players()) do
76 local name
= player
:get_player_name()
79 local pos
= player
:get_pos()
82 local node_stand
= mcl_playerinfo
[name
].node_stand
83 local node_stand_below
= mcl_playerinfo
[name
].node_stand_below
84 local node_head
= mcl_playerinfo
[name
].node_head
85 local node_feet
= mcl_playerinfo
[name
].node_feet
86 if not node_stand
or not node_stand_below
or not node_head
or not node_feet
then
93 -- Standing on soul sand? If so, walk slower
94 if node_stand
== "mcl_nether:soul_sand" then
95 -- TODO: Tweak walk speed
96 -- TODO: Also slow down mobs
97 -- Slow down even more when soul sand is above certain block
98 if node_stand_below
== "mcl_core:ice" or node_stand_below
== "mcl_core:packed_ice" or node_stand_below
== "mcl_core:slimeblock" or node_stand_below
== "mcl_core:water_source" then
99 playerphysics
.add_physics_factor(player
, "speed", "mcl_playerplus:surface", 0.1)
101 playerphysics
.add_physics_factor(player
, "speed", "mcl_playerplus:surface", 0.4)
104 -- Reset speed decrease
105 playerphysics
.remove_physics_factor(player
, "speed", "mcl_playerplus:surface")
108 -- Is player suffocating inside node? (Only for solid full opaque cube type nodes
109 -- without group disable_suffocation=1)
110 local ndef
= minetest
.registered_nodes
[node_head
]
112 if (ndef
.walkable
== nil or ndef
.walkable
== true)
113 and (ndef
.collision_box
== nil or ndef
.collision_box
.type == "regular")
114 and (ndef
.node_box
== nil or ndef
.node_box
.type == "regular")
115 and (ndef
.groups
.disable_suffocation
~= 1)
116 and (ndef
.groups
.opaque
== 1)
117 and (node_head
~= "ignore")
118 -- Check privilege, too
119 and (not minetest
.check_player_privs(name
, {noclip
= true})) then
120 if player
:get_hp() > 0 then
121 mcl_death_messages
.player_damage(player
, string.format("%s suffocated to death.", name
))
122 player
:set_hp(player
:get_hp() - 1)
126 -- Am I near a cactus?
127 local near
= minetest
.find_node_near(pos
, 1, "mcl_core:cactus")
129 near
= minetest
.find_node_near({x
=pos
.x
, y
=pos
.y
-1, z
=pos
.z
}, 1, "mcl_core:cactus")
132 -- Am I touching the cactus? If so, it hurts
133 local dist
= vector
.distance(pos
, near
)
134 local dist_feet
= vector
.distance({x
=pos
.x
, y
=pos
.y
-1, z
=pos
.z
}, near
)
135 if dist
< 1.1 or dist_feet
< 1.1 then
136 if player
:get_hp() > 0 then
137 mcl_death_messages
.player_damage(player
, string.format("%s was prickled by a cactus.", name
))
138 mcl_hunger
.exhaust(name
, mcl_hunger
.EXHAUST_DAMAGE
)
139 player
:set_hp(player
:get_hp() - 1)
144 --[[ Swimming: Cause exhaustion.
145 NOTE: As of 0.4.15, it only counts as swimming when you are with the feet inside the liquid!
146 Head alone does not count. We respect that for now. ]]
147 if minetest
.get_item_group(node_feet
, "liquid") ~= 0 or
148 minetest
.get_item_group(node_stand
, "liquid") ~= 0 then
149 local lastPos
= mcl_playerplus_internal
[name
].lastPos
151 local dist
= vector
.distance(lastPos
, pos
)
152 mcl_playerplus_internal
[name
].swimDistance
= mcl_playerplus_internal
[name
].swimDistance
+ dist
153 if mcl_playerplus_internal
[name
].swimDistance
>= 1 then
154 local superficial
= math
.floor(mcl_playerplus_internal
[name
].swimDistance
)
155 mcl_hunger
.exhaust(name
, mcl_hunger
.EXHAUST_SWIM
* superficial
)
156 mcl_playerplus_internal
[name
].swimDistance
= mcl_playerplus_internal
[name
].swimDistance
- superficial
162 -- Underwater: Spawn bubble particles
163 if minetest
.get_item_group(node_head
, "water") ~= 0 then
165 minetest
.add_particlespawner({
168 minpos
= { x
= -0.25, y
= 0.3, z
= -0.25 },
169 maxpos
= { x
= 0.25, y
= 0.7, z
= 0.75 },
171 minvel
= {x
= -0.2, y
= 0, z
= -0.2},
172 maxvel
= {x
= 0.5, y
= 0, z
= 0.5},
173 minacc
= {x
= -0.4, y
= 4, z
= -0.4},
174 maxacc
= {x
= 0.5, y
= 1, z
= 0.5},
179 texture
= "mcl_particles_bubble.png"
183 -- Show positions of barriers when player is wielding a barrier
184 local wi
= player
:get_wielded_item():get_name()
185 if wi
== "mcl_core:barrier" or wi
== "mcl_core:realm_barrier" then
186 local pos
= vector
.round(player
:get_pos())
188 local vm
= minetest
.get_voxel_manip()
189 local emin
, emax
= vm
:read_from_map({x
=pos
.x
-r
, y
=pos
.y
-r
, z
=pos
.z
-r
}, {x
=pos
.x
+r
, y
=pos
.y
+r
, z
=pos
.z
+r
})
190 local area
= VoxelArea
:new
{
194 local data
= vm
:get_data()
195 for x
=pos
.x
-r
, pos
.x
+r
do
196 for y
=pos
.y
-r
, pos
.y
+r
do
197 for z
=pos
.z
-r
, pos
.z
+r
do
198 local vi
= area
:indexp({x
=x
, y
=y
, z
=z
})
199 local nodename
= minetest
.get_name_from_content_id(data
[vi
])
201 if nodename
== "mcl_core:barrier" then
202 tex
= "mcl_core_barrier.png"
203 elseif nodename
== "mcl_core:realm_barrier" then
204 tex
= "mcl_core_barrier.png^[colorize:#FF00FF:127^[transformFX"
207 minetest
.add_particle({
208 pos
= {x
=x
, y
=y
, z
=z
},
220 -- Update internal values
221 mcl_playerplus_internal
[name
].lastPos
= pos
227 -- set to blank on join (for 3rd party mods)
228 minetest
.register_on_joinplayer(function(player
)
229 local name
= player
:get_player_name()
231 mcl_playerplus_internal
[name
] = {
234 jump_cooldown
= -1, -- Cooldown timer for jumping, we need this to prevent the jump exhaustion to increase rapidly
238 -- clear when player leaves
239 minetest
.register_on_leaveplayer(function(player
)
240 local name
= player
:get_player_name()
242 mcl_playerplus_internal
[name
] = nil