1 local S
= minetest
.get_translator("orienteering")
2 local mod_map
= minetest
.get_modpath("map") -- map mod from Minetest Game
4 local orienteering
= {}
5 orienteering
.playerhuds
= {}
6 orienteering
.settings
= {}
7 orienteering
.settings
.speed_unit
= S("m/s")
8 orienteering
.settings
.length_unit
= S("m")
9 orienteering
.settings
.hud_pos
= { x
= 0.5, y
= 0 }
10 orienteering
.settings
.hud_offset
= { x
= 0, y
= 15 }
11 orienteering
.settings
.hud_alignment
= { x
= 0, y
= 0 }
13 local set
= tonumber(minetest
.settings
:get("orienteering_hud_pos_x"))
14 if set
then orienteering
.settings
.hud_pos
.x
= set
end
15 set
= tonumber(minetest
.settings
:get("orienteering_hud_pos_y"))
16 if set
then orienteering
.settings
.hud_pos
.y
= set
end
17 set
= tonumber(minetest
.settings
:get("orienteering_hud_offset_x"))
18 if set
then orienteering
.settings
.hud_offset
.x
= set
end
19 set
= tonumber(minetest
.settings
:get("orienteering_hud_offset_y"))
20 if set
then orienteering
.settings
.hud_offset
.y
= set
end
21 set
= minetest
.settings
:get("orienteering_hud_alignment")
23 orienteering
.settings
.hud_alignment
.x
= 1
24 elseif set
== "center" then
25 orienteering
.settings
.hud_alignment
.x
= 0
26 elseif set
== "right" then
27 orienteering
.settings
.hud_alignment
.x
= -1
30 local o_lines
= 4 -- Number of lines in HUD
32 -- Helper function to switch between 12h and 24 mode for the time
33 function orienteering
.toggle_time_mode(itemstack
, user
, pointed_thing
)
34 --[[ Player attribute “orienteering:twelve”:
35 * "true": Use 12h mode for time
36 * "false" or unset: Use 24h mode for time ]]
37 if user
:get_meta():get_string("orienteering:twelve") == "true" then
38 user
:get_meta():set_string("orienteering:twelve", "false")
40 user
:get_meta():set_string("orienteering:twelve", "true")
42 orienteering
.update_hud_displays(user
)
45 local use
= S("Put this tool in your hotbar to see the data it provides.")
46 local use_time
= S("Put this tool in your hotbar to make use of its functionality. Punch to toggle between 24-hour and 12-hour display for the time feature.")
48 -- Displays height (Y)
49 minetest
.register_tool("orienteering:altimeter", {
50 description
= S("Altimeter"),
51 _tt_help
= S("Shows your elevation"),
52 _doc_items_longdesc
= S("It shows you your current elevation (Y)."),
53 _doc_items_usagehelp
= use
,
54 wield_image
= "orienteering_altimeter.png",
55 inventory_image
= "orienteering_altimeter.png",
56 groups
= { disable_repair
= 1 },
59 -- Displays X and Z coordinates
60 minetest
.register_tool("orienteering:triangulator", {
61 description
= S("Triangulator"),
62 _tt_help
= S("Shows your horizontal coordinates"),
63 _doc_items_longdesc
= S("It shows you the coordinates of your current position in the horizontal plane (X and Z)."),
64 _doc_items_usagehelp
= use
,
65 wield_image
= "orienteering_triangulator.png",
66 inventory_image
= "orienteering_triangulator.png",
67 groups
= { disable_repair
= 1 },
70 -- Displays player yaw
71 minetest
.register_tool("orienteering:compass", {
72 description
= S("Compass"),
73 _tt_help
= S("Shows your yaw"),
74 _doc_items_longdesc
= S("It shows you your yaw (horizontal viewing angle) in degrees."),
75 _doc_items_usagehelp
= use
,
76 wield_image
= "orienteering_compass_wield.png",
77 inventory_image
= "orienteering_compass_inv.png",
78 groups
= { disable_repair
= 1 },
81 -- Displays player pitch
82 minetest
.register_tool("orienteering:sextant", {
83 description
= S("Sextant"),
84 _tt_help
= S("Shows your pitch"),
85 _doc_items_longdesc
= S("It shows you your pitch (vertical viewing angle) in degrees."),
86 _doc_items_usagehelp
= use
,
87 wield_image
= "orienteering_sextant_wield.png",
88 inventory_image
= "orienteering_sextant_inv.png",
89 groups
= { disable_repair
= 1 },
92 -- Ultimate orienteering tool: Displays X,Y,Z, yaw, pitch, time, speed and enables the minimap
93 minetest
.register_tool("orienteering:quadcorder", {
94 description
= S("Quadcorder"),
95 _tt_help
= S("Shows your coordinates, yaw, pitch, time, speed and enables minimap"),
96 _doc_items_longdesc
= S("This is the ultimate orientieering tool. It shows you your coordinates (X, Y and Z), shows your yaw and pitch (horizontal and vertical viewing angles), the current time, your current speed and it enables you to access the minimap."),
97 wield_image
= "orienteering_quadcorder.png",
98 _doc_items_usagehelp
= use_time
,
99 wield_scale
= { x
=1, y
=1, z
=3.5 },
100 inventory_image
= "orienteering_quadcorder.png",
101 groups
= { disable_repair
= 1 },
102 on_use
= orienteering
.toggle_time_mode
,
105 -- Displays game time
106 minetest
.register_tool("orienteering:watch", {
107 description
= S("Watch"),
108 _tt_help
= S("Shows the time"),
109 _doc_items_longdesc
= S("It shows you the current time."),
110 _doc_items_usagehelp
= S("Put the watch in your hotbar to see the time. Punch to toggle between the 24-hour and 12-hour display."),
111 wield_image
= "orienteering_watch.png",
112 inventory_image
= "orienteering_watch.png",
113 groups
= { disable_repair
= 1 },
114 on_use
= orienteering
.toggle_time_mode
,
118 minetest
.register_tool("orienteering:speedometer", {
119 description
= S("Speedometer"),
120 _tt_help
= S("Shows your speed"),
121 _doc_items_longdesc
= S("It shows you your current horizontal (“hor.”) and vertical (“ver.”) speed in meters per second, where one meter is the side length of a single cube."),
122 _doc_items_usagehelp
= use
,
123 wield_image
= "orienteering_speedometer_wield.png",
124 inventory_image
= "orienteering_speedometer_inv.png",
125 groups
= { disable_repair
= 1 },
129 -- Enables minimap (surface)
130 minetest
.register_tool("orienteering:map", {
131 description
= S("Map"),
132 _tt_help
= S("Allows using the minimap"),
133 _doc_items_longdesc
= S("The map allows you to view a minimap of the area around you."),
134 _doc_items_usagehelp
= S("If you put a map in your hotbar, you will be able to access the minimap (only surface mode). Press the “minimap” key to view the minimap."),
135 wield_image
= "orienteering_map.png",
136 wield_scale
= { x
=1.5, y
=1.5, z
=0.15 },
137 inventory_image
= "orienteering_map.png",
138 groups
= { disable_repair
= 1 },
142 -- Enables minimap (radar)
143 minetest
.register_tool("orienteering:automapper", {
144 description
= S("Radar Mapper"),
145 _tt_help
= S("Allows using the minimap and radar"),
146 _doc_items_longdesc
= S("The radar mapper is a device that combines a map with a radar. It unlocks both the surface mode and radar mode of the minimap."),
147 _doc_items_usagehelp
= S("If you put a radar mapper in your hotbar, you will be able to access the minimap. Press the “minimap” key to view the minimap."),
148 wield_image
= "orienteering_automapper_wield.png",
149 wield_scale
= { x
=1, y
=1, z
=2 },
150 inventory_image
= "orienteering_automapper_inv.png",
151 groups
= { disable_repair
= 1 },
154 -- Displays X,Y,Z coordinates, yaw and game time
155 minetest
.register_tool("orienteering:gps", {
156 description
= S("GPS device"),
157 _tt_help
= S("Shows your coordinates, yaw and the time"),
158 _doc_items_longdesc
= S("The GPS device shows you your coordinates (X, Y and Z), your yaw (horizontal viewing angle) and the time."),
159 _doc_items_usagehelp
= use_time
,
160 wield_image
= "orienteering_gps_wield.png",
161 wield_scale
= { x
=1, y
=1, z
=2 },
162 inventory_image
= "orienteering_gps_inv.png",
163 groups
= { disable_repair
= 1 },
164 on_use
= orienteering
.toggle_time_mode
,
167 if minetest
.get_modpath("default") ~= nil then
169 minetest
.register_craft({
170 output
= "orienteering:altimeter",
173 {"default:steel_ingot"},
174 {"default:steel_ingot"},
177 minetest
.register_craft({
178 output
= "orienteering:triangulator",
180 {"", "default:bronze_ingot", ""},
181 {"default:bronze_ingot", "", "default:bronze_ingot"},
184 minetest
.register_craft({
185 output
= "orienteering:sextant",
187 {"", "default:gold_ingot", ""},
188 {"default:gold_ingot", "default:gold_ingot", "default:gold_ingot"},
191 minetest
.register_craft({
192 output
= "orienteering:compass",
194 {"", "default:tin_ingot", ""},
195 {"default:tin_ingot", "group:stick", "default:tin_ingot"},
196 {"", "default:tin_ingot", ""},
199 minetest
.register_craft({
200 output
= "orienteering:speedometer",
202 {"", "default:gold_ingot", ""},
203 {"default:steel_ingot", "group:stick", "default:steel_ingot"},
204 {"", "default:steel_ingot", ""},
207 minetest
.register_craft({
208 output
= "orienteering:automapper",
210 {"default:gold_ingot", "default:gold_ingot", "default:gold_ingot"},
211 {"default:mese_crystal", "default:obsidian_shard", "default:mese_crystal"},
212 {"default:gold_ingot", "default:gold_ingot", "default:gold_ingot"}
215 minetest
.register_craft({
216 output
= "orienteering:gps",
218 { "default:gold_ingot", "orienteering:triangulator", "default:gold_ingot" },
219 { "orienteering:compass", "default:bronze_ingot", "orienteering:watch" },
220 { "default:tin_ingot", "orienteering:altimeter", "default:tin_ingot" }
223 minetest
.register_craft({
224 output
= "orienteering:quadcorder",
226 { "default:gold_ingot", "default:gold_ingot", "default:gold_ingot" },
227 { "orienteering:speedometer", "default:diamond", "orienteering:automapper", },
228 { "orienteering:sextant", "default:diamond", "orienteering:gps" }
231 minetest
.register_craft({
232 output
= "orienteering:watch",
234 { "default:copper_ingot" },
236 { "default:copper_ingot" }
240 if (not mod_map
) and minetest
.get_modpath("dye") then
241 minetest
.register_craft({
242 output
= "orienteering:map",
244 { "default:paper", "default:paper", "default:paper" },
245 { "default:paper", "dye:black", "default:paper" },
246 { "default:paper", "default:paper", "default:paper" },
253 function orienteering
.update_automapper(player
)
254 if orienteering
.tool_active(player
, "orienteering:automapper") or orienteering
.tool_active(player
, "orienteering:quadcorder") or minetest
.is_creative_enabled(player
:get_player_name()) then
255 player
:hud_set_flags({minimap
= true, minimap_radar
= true})
256 elseif ((not mod_map
) and orienteering
.tool_active(player
, "orienteering:map")) or ((mod_map
) and orienteering
.tool_active(player
, "map:mapping_kit")) then
257 player
:hud_set_flags({minimap
= true, minimap_radar
= false})
259 player
:hud_set_flags({minimap
= false, minimap_radar
= false})
263 -- Checks whether a certain orienteering tool is “active” and ready for use
264 function orienteering
.tool_active(player
, item
)
265 -- Requirement: player carries the tool in the hotbar
266 local inv
= player
:get_inventory()
267 -- Exception: MTG's Mapping Kit can be anywhere
268 if item
== "map:mapping_kit" then
269 return inv
:contains_item("main", item
)
271 local hotbar
= player
:hud_get_hotbar_itemcount()
273 if inv
:get_stack("main", i
):get_name() == item
then
280 function orienteering
.init_hud(player
)
281 orienteering
.update_automapper(player
)
282 local name
= player
:get_player_name()
283 orienteering
.playerhuds
[name
] = {}
285 orienteering
.playerhuds
[name
]["o_line"..i
] = player
:hud_add({
286 hud_elem_type
= "text",
288 position
= orienteering
.settings
.hud_pos
,
289 offset
= { x
= orienteering
.settings
.hud_offset
.x
, y
= orienteering
.settings
.hud_offset
.y
+ 20*(i
-1) },
290 alignment
= orienteering
.settings
.hud_alignment
,
292 scale
= { x
= 100, y
= 20 },
298 function orienteering
.update_hud_displays(player
)
299 local toDegrees
=180/math
.pi
300 local name
= player
:get_player_name()
301 local gps
, altimeter
, triangulator
, compass
, sextant
, watch
, speedometer
, quadcorder
303 if orienteering
.tool_active(player
, "orienteering:gps") then
306 if orienteering
.tool_active(player
, "orienteering:altimeter") then
309 if orienteering
.tool_active(player
, "orienteering:triangulator") then
312 if orienteering
.tool_active(player
, "orienteering:compass") then
315 if orienteering
.tool_active(player
, "orienteering:sextant") then
318 if orienteering
.tool_active(player
, "orienteering:watch") then
321 if orienteering
.tool_active(player
, "orienteering:speedometer") then
324 if orienteering
.tool_active(player
, "orienteering:quadcorder") then
328 local str_pos
, str_angles
, str_time
, str_speed
329 local pos
= vector
.round(player
:get_pos())
330 if (altimeter
and triangulator
) or gps
or quadcorder
then
331 str_pos
= S("Coordinates: X=@1, Y=@2, Z=@3", pos
.x
, pos
.y
, pos
.z
)
332 elseif altimeter
then
333 str_pos
= S("Height: Y=@1", pos
.y
)
334 elseif triangulator
then
335 str_pos
= S("Coordinates: X=@1, Z=@2", pos
.x
, pos
.z
)
340 -- Yaw in Minetest goes counter-clockwise, which is opposite of how compasses work
341 local yaw
= 360-player
:get_look_horizontal()*toDegrees
342 local pitch
= player
:get_look_vertical()*toDegrees
343 if ((compass
or gps
) and sextant
) or quadcorder
then
344 str_angles
= S("Yaw: @1°, pitch: @2°", string.format("%.1f", yaw
), string.format("%.1f", pitch
))
345 elseif compass
or gps
then
346 str_angles
= S("Yaw: @1°", string.format("%.1f", yaw
))
348 str_angles
= S("Pitch: @1°", string.format("%.1f", pitch
))
353 local time
= minetest
.get_timeofday()
354 if watch
or gps
or quadcorder
then
355 local totalminutes
= time
* 1440
356 local minutes
= totalminutes
% 60
357 local hours
= math
.floor((totalminutes
- minutes
) / 60)
358 minutes
= math
.floor(minutes
)
359 local twelve
= player
:get_meta():get_string("orienteering:twelve") == "true"
361 if hours
== 12 and minutes
== 0 then
362 str_time
= S("Time: noon")
363 elseif hours
== 0 and minutes
== 0 then
364 str_time
= S("Time: midnight")
366 local hours12
= math
.fmod(hours
, 12)
367 if hours12
== 0 then hours12
= 12 end
369 str_time
= S("Time: @1:@2 p.m.", string.format("%i", hours12
), string.format("%02i", minutes
))
371 str_time
= S("Time: @1:@2 a.m.", string.format("%i", hours12
), string.format("%02i", minutes
))
375 str_time
= S("Time: @1:@2", string.format("%02i", hours
), string.format("%02i", minutes
))
381 if speedometer
or quadcorder
then
382 local speed_hor
, speed_ver
384 local attach
= player
:get_attach()
385 if attach
== nil then
386 v
= player
:get_player_velocity()
388 v
= attach
:get_velocity()
390 v
= player
:get_player_velocity()
395 speed_hor
= vector
.length(v
)
397 local u
= orienteering
.settings
.speed_unit
398 str_speed
= S("Speed: hor.: @1 @2, vert.: @3 @4", string.format("%.1f", speed_hor
), u
, string.format("%.1f", speed_ver
), u
)
403 local strs
= { str_pos
, str_angles
, str_time
, str_speed
}
406 if strs
[i
] ~= "" then
407 player
:hud_change(orienteering
.playerhuds
[name
]["o_line"..line
], "text", strs
[i
])
411 for l
=line
, o_lines
do
412 player
:hud_change(orienteering
.playerhuds
[name
]["o_line"..l
], "text", "")
417 -- Disable all HUD flag handling in map mod because we already handle it
419 map
.update_hud_flags
= function() end
422 minetest
.register_on_newplayer(orienteering
.init_hud
)
423 minetest
.register_on_joinplayer(orienteering
.init_hud
)
425 minetest
.register_on_leaveplayer(function(player
)
426 orienteering
.playerhuds
[player
:get_player_name()] = nil
429 local updatetimer
= 0
430 minetest
.register_globalstep(function(dtime
)
431 updatetimer
= updatetimer
+ dtime
432 if updatetimer
> 0.1 then
433 local players
= minetest
.get_connected_players()
435 orienteering
.update_automapper(players
[i
])
436 orienteering
.update_hud_displays(players
[i
])
438 updatetimer
= updatetimer
- dtime
442 if minetest
.get_modpath("awards") ~= nil and minetest
.get_modpath("default") ~= nil then
443 awards
.register_achievement("orienteering_quadcorder", {
444 title
= S("Master of Orienteering"),
445 description
= S("Craft a quadcorder."),
446 icon
= "orienteering_quadcorder.png",
449 item
= "orienteering:quadcorder",