~jadedctrl/gem-xwx-moe

~jadedctrl/gem-xwx-moe/gemujo_ludo/mods.niaj/fasado/subtitles/Agent.lua
 ..
0 --[[
1 Subtitles — adds subtitles to Minetest.
2
3 Copyright © 2022‒2023, Silver Sandstone <@SilverSandstone@craftodon.social>
4
5 Permission is hereby granted, free of charge, to any person obtaining a
6 copy of this software and associated documentation files (the "Software"),
7 to deal in the Software without restriction, including without limitation
8 the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 and/or sell copies of the Software, and to permit persons to whom the
10 Software is furnished to do so, subject to the following conditions:
11
12 The above copyright notice and this permission notice shall be included
13 in all copies or substantial portions of the Software.
14
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 DEALINGS IN THE SOFTWARE.
22 ]]
23
24
25 --- Provides the Agent class, which represents a player.
26
27
28 local S = subtitles.S;
29
30
31 local function toboolean(value)
32 if value then
33 return true;
34 else
35 return false;
36 end;
37 end;
38
39
40 --- Represents a player.
41 -- Each player gets one Agent object.
42 -- @type Agent
43 subtitles.Agent = subtitles.Object:extend();
44
45 --- Constructor.
46 -- @param username The name of the player.
47 function subtitles.Agent:new(username)
48 self.username = username;
49
50 self.display = nil;
51
52 self:load_settings();
53 end;
54
55 --- Loads settings from the player's metadata.
56 function subtitles.Agent:load_settings()
57 local player = self:get_player();
58 if not player then
59 return;
60 end;
61 local meta = player:get_meta();
62
63 self._enabled = subtitles.util.get_meta_bool(meta, 'subtitles:enabled', subtitles.settings.default_enable);
64 self._footsteps = subtitles.util.get_meta_bool(meta, 'subtitles:footsteps', true);
65 self._display_name = meta:get('subtitles:display');
66 end;
67
68 --- Returns the player's ObjectRef, or nil if the player has disconnected.
69 -- @return An ObjectRef or nil.
70 function subtitles.Agent:get_player()
71 return minetest.get_player_by_name(self.username);
72 end;
73
74 --- Returns the user's currently active display object.
75 -- This creates the display if necessary.
76 -- @return A SubtitleDisplay object.
77 function subtitles.Agent:get_display()
78 if not self.display then
79 self.display = self:create_display();
80 end;
81 return self.display;
82 end;
83
84 --- Creates a display object according to the user's current preferences.
85 -- @return A SubtitleDisplay object.
86 function subtitles.Agent:create_display()
87 local display_name = self:get_display_name();
88 local display_type = subtitles.SubtitleDisplay.get_by_name(display_name) or subtitles.CornerSubtitleDisplay;
89 return display_type(self.username);
90 end;
91
92 --- Checks if the player has subtitles enabled.
93 -- @return true if subtitles are enabled.
94 function subtitles.Agent:get_enabled()
95 return self._enabled;
96 end;
97
98 --- Enables or disables subtitles for the player.
99 -- @param enabled true to enable, or false to disable.
100 function subtitles.Agent:set_enabled(enabled)
101 enabled = toboolean(enabled);
102 self._enabled = enabled;
103
104 local player = self:get_player();
105 if not player then
106 return;
107 end;
108
109 local meta = player:get_meta();
110 subtitles.util.set_meta_bool(meta, 'subtitles:enabled', enabled);
111
112 if not enabled then
113 if self.display then
114 self.display:destroy();
115 self.display = nil;
116 end;
117 end;
118 end;
119
120 --- Toggles subtitles on/off.
121 function subtitles.Agent:toggle_enabled()
122 self:set_enabled(not self:get_enabled());
123 end;
124
125
126 --- Checks if footsteps are enabled for this player.
127 -- @return true if footsteps are enabled.
128 function subtitles.Agent:get_footsteps_enabled()
129 return self._footsteps;
130 end;
131
132
133 --- Enables or disables footsteps for the player.
134 -- @param enabled true to enable, or false to disable.
135 function subtitles.Agent:set_footsteps_enabled(enabled)
136 enabled = toboolean(enabled);
137 self._footsteps = enabled;
138
139 local player = self:get_player();
140 if not player then
141 return;
142 end;
143
144 local meta = player:get_meta();
145 subtitles.util.set_meta_bool(meta, 'subtitles:footsteps', enabled);
146 end;
147
148
149 --- Toggles the footsteps enabled state on/off.
150 function subtitles.Agent:toggle_footsteps_enabled()
151 self:set_footsteps_enabled(not self:get_footsteps_enabled());
152 end;
153
154
155 --- Returns the player's selected display name.
156 -- @return A display name string.
157 function subtitles.Agent:get_display_name()
158 return self._display_name or subtitles.DEFAULT_DISPLAY_NAME;
159 end;
160
161 --- Sets the player's display type.
162 -- This recreates the display if necessary.
163 -- @param name A display name string.
164 function subtitles.Agent:set_display_name(name)
165 assert(subtitles.SubtitleDisplay.get_by_name(name), ('Invalid display mode: ‘%s’.'):format(name));
166
167 self._display_name = name;
168
169 if self.display and self.display.NAME ~= name then
170 self.display:destroy();
171 self.display = nil;
172 end;
173
174 local player = self:get_player();
175 if player then
176 local meta = player:get_meta();
177 meta:set_string('subtitles:display', name);
178 end;
179 end;
180
181 --- Detects footsteps around the player and simulates sound effects.
182 function subtitles.Agent:handle_footsteps()
183 if not (self:get_enabled() and self:get_footsteps_enabled()) then
184 return;
185 end;
186
187 local player = self:get_player();
188 if not player then
189 return;
190 end;
191
192 local display = self:get_display();
193 local player_pos = player:get_pos();
194 local objects = minetest.get_objects_inside_radius(player_pos, subtitles.FOOTSTEP_HEAR_DISTANCE);
195 for __, object in ipairs(objects) do
196 if subtitles.util.object_is_walking(object) and object:get_properties().makes_footstep_sound then
197 local feet_pos = subtitles.util.get_feet_pos(object);
198 local under = minetest.get_node(vector.add(feet_pos, vector.new(0, -0.25, 0)));
199 local above = minetest.get_node(vector.add(feet_pos, vector.new(0, 0.25, 0)));
200 local spec = subtitles.util.get_node_sound(above.name, 'footstep')
201 or subtitles.util.get_node_sound(under.name, 'footstep');
202 if spec then
203 local params =
204 {
205 to_player = player;
206 max_hear_distance = subtitles.FOOTSTEP_HEAR_DISTANCE;
207 duration = subtitles.FOOTSTEP_DURATION;
208 pos = feet_pos;
209 };
210 local sound = subtitles.Sound(spec, params, nil);
211 display:handle_sound_play(sound);
212 end;
213 end;
214 end;
215 end;
216
217 --- Called every game tick.
218 -- @param dtime Seconds since this method was last called.
219 function subtitles.Agent:step(dtime)
220 if self.display then
221 self.display:step(dtime);
222 end;
223 end;
224
225 --- Shows an introduction message to the player.
226 function subtitles.Agent:show_intro()
227 local command = minetest.colorize('#FFFFBF', '/subtitles');
228 local message = S('Subtitles are available on this server. Type ‘@1’ to manage your preferences.', command);
229 minetest.chat_send_player(self.username, message);
230 end;
231
232 --- Called when the player first joins.
233 function subtitles.Agent:on_first_join()
234 if subtitles.settings.show_introduction and not minetest.is_singleplayer() then
235 self:show_intro();
236 end;
237 end;
238
239 --- Called when the player leaves the game.
240 function subtitles.Agent:on_leave()
241 if self.display then
242 self.display:destroy();
243 end;
244 end;