This repository has been archived by the owner on Aug 20, 2020. It is now read-only.
forked from TeTpaAka/quests
-
Notifications
You must be signed in to change notification settings - Fork 3
/
hud.lua
314 lines (299 loc) · 9.88 KB
/
hud.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
--- Quests HUD.
-- @module hud
-- Boilerplate to support localized strings if intllib mod is installed.
local S = minetest.get_translator("quests")
local show_max = 10 -- the maximum visible quests.
local hud_config = { position = {x = 1, y = 0.2},
offset = { x = -200, y = 0},
number = quests.colors.new }
--- Set the HUD position (not offset).
-- Supplied positions may be `nil` and will be skipped.
-- @note Calling this function while quests are already displayed will result
-- in undefined behaviour. Call it beforehand.
function quests.set_hud_position(x, y)
hud_config.position.x = x or hud_config.position.x
hud_config.position.y = y or hud_config.position.y
end
--- Set the HUD offset (not position).
-- Supplied positions may be `nil` and will be skipped.
-- @note Calling this function while quests are already displayed will result
-- in undefined behaviour. Call it beforehand.
function quests.set_hud_offset(x, y)
hud_config.offset.x = x or hud_config.offset.x
hud_config.offset.y = y or hud_config.offset.y
end
--- Show quests HUD to player.
-- The HUD can only show up to `show_max` quests
-- @param playername Player whose quests HUD must be shown
-- @param autohide Whether to automatically hide the HUD once it's empty
function quests.show_hud(playername, autohide)
if quests.hud[playername] == nil then
quests.hud[playername] = { autohide = autohide }
end
if quests.hud[playername].list ~= nil then
return
end
local player = minetest.get_player_by_name(playername)
if player == nil then
return false
end
quests.hud[playername].header = player:hud_add({
hud_elem_type = "text",
alignment = {x=1, y=1},
position = {x = hud_config.position.x, y = hud_config.position.y},
offset = {x = hud_config.offset.x, y = hud_config.offset.y - 20},
number = hud_config.number,
text = S("Quests") .. ":"
})
quests.hud[playername].list = {}
quests.update_hud(playername)
end
--- Hide quests HUD to player.
-- @param playername Player whose quests HUD must be hidden
function quests.hide_hud(playername)
local player = minetest.get_player_by_name(playername)
if player == nil or quests.hud[playername] == nil or quests.hud[playername].list == nil then
return
end
for _,quest in pairs(quests.hud[playername].list) do
if quest.text and quest.text.id then
player:hud_remove(quest.text.id)
end
if quest.background and quest.background.id then
player:hud_remove(quest.background.id)
end
if quest.bar and quest.bar.id then
player:hud_remove(quest.bar.id)
end
end
player:hud_remove(quests.hud[playername].header)
quests.hud[playername].list = nil
end
local function get_quest_hud_string(title, value, max)
return title .. "\n ("..quests.round(value, 2).."/"..max..")"
end
local function get_hud_list(playername)
local deftable = {}
local counter = 0
for questname, plr_quest in quests.sorted_pairs(quests.active_quests[playername]) do
local quest = quests.registered_quests[questname]
local hide_from_hud
if quests.info_quests[playername] and quests.info_quests[playername][questname] then
hide_from_hud = quests.info_quests[playername][questname].hide_from_hud
else
hide_from_hud = false
end
if quest and not hide_from_hud then -- Quest might have been deleted
local function get_table(name, value, max)
local def = {
text = {
hud_elem_type = "text",
alignment = { x=1, y= 1 },
position = {x = hud_config.position.x, y = hud_config.position.y},
offset = {x = hud_config.offset.x, y = hud_config.offset.y + counter * 40},
number = hud_config.number,
text = name
}
}
if plr_quest.finished then
if quests.failed_quests[playername] and quests.failed_quests[playername][questname] then
def.text.number = quests.colors.failed
else
def.text.number = quests.colors.success
end
else
def.text.number = hud_config.number
end
if value and max then
def.bar = {
hud_elem_type = "image",
scale = { x = math.floor(20 * value / max), y = 1 },
alignment = { x = 1, y = 1 },
position = { x = hud_config.position.x, y = hud_config.position.y },
offset = { x = hud_config.offset.x + 2, y = hud_config.offset.y + counter * 40 + 24 },
text = "quests_questbar.png"
}
def.background = {
hud_elem_type = "image",
scale = { x = 1, y = 1 },
size = { x = 2, y = 4 },
alignment = { x = 1, y = 1 },
position = { x = hud_config.position.x, y = hud_config.position.y },
offset = { x = hud_config.offset.x, y = hud_config.offset.y + counter * 40 + 22 },
text = "quests_questbar_background.png"
}
end
return def
end
if quest.simple then
deftable[questname] = get_table(get_quest_hud_string(quest.title, plr_quest.value, quest.max), plr_quest.value, quest.max)
counter = counter + 1
else
deftable[questname] = get_table(quest.title)
counter = counter + 0.5
for taskname, task in pairs(quest.tasks) do
local plr_task = quests.active_quests[playername][questname][taskname]
if plr_task.visible and not plr_task.disabled and not plr_task.finished then
deftable[questname .. "#" .. taskname] = get_table("- " .. get_quest_hud_string(task.title, plr_task.value, task.max), plr_task.value, task.max)
counter = counter + 1
if counter >= show_max + 1 then
break
end
end
end
end
if counter >= show_max + 1 then
break
end
end
end
return deftable
end
local DELETED = {}
-- only for internal use
-- updates the hud
function quests.update_hud(playername)
if quests.hud[playername] == nil or quests.active_quests[playername] == nil then
return
end
if quests.hud[playername].list == nil then
if quests.hud[playername].autohide and next(quests.active_quests[playername]) ~= nil then
quests.show_hud(playername)
end
return
end
local player = minetest.get_player_by_name(playername)
if player == nil then
return
end
if quests.hud[playername].autohide then
if next(quests.active_quests[playername]) == nil then
player:hud_change(quests.hud[playername].header, "text", S("No more Quests"))
minetest.after(3, function(playername)
if next(quests.active_quests[playername]) ~= nil then
player:hud_change(quests.hud[playername].header, "text", S("Quests")..":")
quests.update_hud(playername)
else
quests.hide_hud(playername)
end
end, playername)
end
end
-- Check for changes in the hud
local function table_diff(tab1, tab2)
local result_tab
for k, v in pairs(tab2) do
if not tab1[k] or tab1[k] ~= v then
if type(tab1[k]) == "table" and type(v) == "table" then
local diff = table_diff(tab1[k], v)
if diff ~= nil then
if not result_tab then
result_tab = {}
end
result_tab[k] = diff
end
else
if not result_tab then
result_tab = {}
end
result_tab[k] = v
end
end
end
for k, _ in pairs(tab1) do
if tab2[k] == nil then
if not result_tab then
result_tab = {}
end
result_tab[k] = DELETED
end
end
return result_tab
end
-- Merge `from` into table `into`
local function table_merge(from, into)
for k, v in pairs(from) do
if type(v) == "table" and type(into[k]) == "table" then
table_merge(v, into[k])
else
into[k] = v
end
end
end
local old_hud = quests.hud[playername].list
local new_hud = get_hud_list(playername)
local diff = table_diff(old_hud, new_hud)
-- Copy the HUD IDs from the old table to the new one, to avoid loosing them
for questname, hud_elms in pairs(old_hud) do
for elm_name, elm_def in pairs(hud_elms) do
if new_hud[questname] and new_hud[questname][elm_name] then
new_hud[questname][elm_name].id = elm_def.id
end
end
end
--[[ Disabled because it had issues with MT engine and too much quests. HUD elements sometimes won't update.
if diff ~= nil then
for questname, hud_elms in pairs(diff) do
if hud_elms == DELETED then
for elm_name, elm_def in pairs(old_hud[questname]) do
player:hud_remove(elm_def.id)
end
else
for elm_name, elm_def in pairs(hud_elms) do
if not old_hud[questname] or not old_hud[questname][elm_name] or not old_hud[questname][elm_name].id then
new_hud[questname][elm_name].id = player:hud_add(elm_def)
else
for elm_prop_name, elm_prop in pairs(elm_def) do
if elm_prop_name ~= "id" then
if type(elm_prop) == "table" then
-- For table-based properties, MT expects a full table to be specified,
-- so we must create a merged table. Just merge the changes with the old
-- HUD table, since it will disappear.
table_merge(elm_prop, old_hud[questname][elm_name][elm_prop_name])
else
old_hud[questname][elm_name][elm_prop_name] = elm_prop
end
player:hud_change(new_hud[questname][elm_name].id, elm_prop_name, old_hud[questname][elm_name][elm_prop_name])
end
end
end
end
end
end
end]]
for questname, hud_elms in pairs(old_hud) do
for elm_name, elm_def in pairs(hud_elms) do
player:hud_remove(elm_def.id)
end
end
for questname, hud_elms in pairs(new_hud) do
for elm_name, elm_def in pairs(hud_elms) do
elm_def.id = player:hud_add(elm_def)
end
end
quests.hud[playername].list = new_hud
end
minetest.register_on_joinplayer(function(player)
local playername = player:get_player_name()
if quests.hud[playername] ~= nil then
---if not quests.hud[playername].first then
--- return
---end
local list = quests.hud[playername].list
local autohide = quests.hud[playername].autohide
local central_message_enabled = quests.hud[playername].central_message_enabled
quests.hud[playername] = {
autohide = autohide,
central_message_enabled = central_message_enabled
}
else -- new player
quests.hud[playername] = {
autohide = true,
central_message_enabled = true
}
quests.active_quests[playername] = {}
end
minetest.after(1, function(playername)
quests.show_hud(playername)
end, playername)
end)