~jadedctrl/gem-xwx-moe
~jadedctrl/gem-xwx-moe/gemujo_ludo/mods.niaj/fasado/subtitles/Agent.lua
~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; |