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
:getpos()
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
:getpos()
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 mcl_playerphysics
.add_physics_factor(player
, "speed", "mcl_playerplus:surface", 0.1)
101 mcl_playerphysics
.add_physics_factor(player
, "speed", "mcl_playerplus:surface", 0.4)
104 -- Reset speed decrease
105 mcl_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)
145 local void
, void_deadly
= mcl_worlds
.is_in_void(pos
)
147 -- Player is deep into the void, deal void damage
148 if minetest
.settings
:get_bool("enable_damage") then
149 if player
:get_hp() > 0 then
150 mcl_death_messages
.player_damage(player
, string.format("%s fell into the endless void.", name
))
151 player
:set_hp(player
:get_hp() - 4)
154 -- If damge is disabled, we can't kill the player.
155 -- So we just teleport the player back to spawn.
156 local spawn
= mcl_spawn
.get_spawn_pos(player
)
157 player
:set_pos(spawn
)
158 mcl_worlds
.dimension_change(player
, mcl_worlds
.pos_to_dimension(spawn
))
159 minetest
.chat_send_player(name
, "The void is off-limits to you!")
163 --[[ Swimming: Cause exhaustion.
164 NOTE: As of 0.4.15, it only counts as swimming when you are with the feet inside the liquid!
165 Head alone does not count. We respect that for now. ]]
166 if minetest
.get_item_group(node_feet
, "liquid") ~= 0 or
167 minetest
.get_item_group(node_stand
, "liquid") ~= 0 then
168 local lastPos
= mcl_playerplus_internal
[name
].lastPos
170 local dist
= vector
.distance(lastPos
, pos
)
171 mcl_playerplus_internal
[name
].swimDistance
= mcl_playerplus_internal
[name
].swimDistance
+ dist
172 if mcl_playerplus_internal
[name
].swimDistance
>= 1 then
173 local superficial
= math
.floor(mcl_playerplus_internal
[name
].swimDistance
)
174 mcl_hunger
.exhaust(name
, mcl_hunger
.EXHAUST_SWIM
* superficial
)
175 mcl_playerplus_internal
[name
].swimDistance
= mcl_playerplus_internal
[name
].swimDistance
- superficial
181 -- Underwater: Spawn bubble particles
182 if minetest
.get_item_group(node_head
, "water") ~= 0 then
184 minetest
.add_particlespawner({
187 minpos
= { x
= -0.25, y
= 0.3, z
= -0.25 },
188 maxpos
= { x
= 0.25, y
= 0.7, z
= 0.75 },
190 minvel
= {x
= -0.2, y
= 0, z
= -0.2},
191 maxvel
= {x
= 0.5, y
= 0, z
= 0.5},
192 minacc
= {x
= -0.4, y
= 4, z
= -0.4},
193 maxacc
= {x
= 0.5, y
= 1, z
= 0.5},
198 texture
= "mcl_particles_bubble.png"
202 -- Show positions of barriers when player is wielding a barrier
203 local wi
= player
:get_wielded_item():get_name()
204 if wi
== "mcl_core:barrier" or wi
== "mcl_core:realm_barrier" then
205 local pos
= vector
.round(player
:getpos())
207 local vm
= minetest
.get_voxel_manip()
208 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
})
209 local area
= VoxelArea
:new
{
213 local data
= vm
:get_data()
214 for x
=pos
.x
-r
, pos
.x
+r
do
215 for y
=pos
.y
-r
, pos
.y
+r
do
216 for z
=pos
.z
-r
, pos
.z
+r
do
217 local vi
= area
:indexp({x
=x
, y
=y
, z
=z
})
218 local nodename
= minetest
.get_name_from_content_id(data
[vi
])
220 if nodename
== "mcl_core:barrier" then
221 tex
= "mcl_core_barrier.png"
222 elseif nodename
== "mcl_core:realm_barrier" then
223 tex
= "mcl_core_barrier.png^[colorize:#FF00FF:127^[transformFX"
226 minetest
.add_particle({
227 pos
= {x
=x
, y
=y
, z
=z
},
239 -- Update internal values
240 mcl_playerplus_internal
[name
].lastPos
= pos
246 -- set to blank on join (for 3rd party mods)
247 minetest
.register_on_joinplayer(function(player
)
248 local name
= player
:get_player_name()
250 mcl_playerplus_internal
[name
] = {
253 jump_cooldown
= -1, -- Cooldown timer for jumping, we need this to prevent the jump exhaustion to increase rapidly
257 -- clear when player leaves
258 minetest
.register_on_leaveplayer(function(player
)
259 local name
= player
:get_player_name()
261 mcl_playerplus_internal
[name
] = nil