1// SuperTux
2// Copyright (C) 2018 Nir <goproducti@gmail.com>
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17#include "object/text_array_object.hpp"
18#include "control/input_manager.hpp"
19
20TextArrayObject::TextArrayObject(const std::string& name) :
21 ExposedObject<TextArrayObject, scripting::TextArray>(this),
22 m_isDone(false),
23 m_isAuto(false),
24 m_keepVisible(false),
25 m_fadeTransition(true),
26 m_fadetime(1.0),
27 m_texts(),
28 m_curTextIndex(0),
29 m_lastTextIndex(0),
30 m_waiting()
31{
32 m_name = name;
33}
34
35TextArrayObject::TextArrayObject(const ReaderMapping& reader) :
36 GameObject(reader),
37 ExposedObject<TextArrayObject, scripting::TextArray>(this),
38 m_isDone(false),
39 m_isAuto(false),
40 m_keepVisible(false),
41 m_fadeTransition(true),
42 m_fadetime(1.0),
43 m_texts(),
44 m_curTextIndex(0),
45 m_lastTextIndex(0),
46 m_waiting()
47{
48}
49
50void
51TextArrayObject::clear()
52{
53 m_texts.clear();
54 reset_automation();
55}
56
57void
58TextArrayObject::add_text(const std::string& text, float duration)
59{
60 auto pText = std::make_unique<TextArrayItem>();
61 assert(pText);
62
63 pText->duration = duration;
64 pText->text_object.set_text(text);
65
66 m_texts.push_back(std::move(pText));
67}
68
69void TextArrayObject::set_text_index(ta_index index)
70{
71 if (index < m_texts.size())
72 m_curTextIndex = index;
73}
74
75void
76TextArrayObject::set_fade_time(float fadetime)
77{
78 m_fadetime = fadetime;
79}
80
81void
82TextArrayObject::next_text()
83{
84 if (m_isDone)
85 return;
86
87 if (m_curTextIndex+1 >= m_texts.size()) {
88 m_isDone = true;
89 return;
90 }
91
92 m_lastTextIndex = m_curTextIndex++;
93
94 override_properties();
95 reset_automation();
96}
97
98void
99TextArrayObject::prev_text()
100{
101 if (m_isDone)
102 return;
103
104 if (m_curTextIndex == 0)
105 return;
106
107 m_lastTextIndex = m_curTextIndex--;
108
109 override_properties();
110 reset_automation();
111}
112
113void
114TextArrayObject::set_keep_visible(bool keep_visible)
115{
116 m_keepVisible = keep_visible;
117}
118
119void
120TextArrayObject::set_fade_transition(bool fade_transition)
121{
122 m_fadeTransition = fade_transition;
123}
124
125TextArrayItem*
126TextArrayObject::get_text_item(ta_index index)
127{
128 auto vecSize = m_texts.size();
129
130 if (vecSize == 0 || index >= vecSize)
131 return nullptr;
132
133 return m_texts.at(index).get();
134}
135
136TextArrayItem*
137TextArrayObject::get_current_text_item()
138{
139 return get_text_item(m_curTextIndex);
140}
141
142TextArrayItem*
143TextArrayObject::get_last_text_item()
144{
145 return get_text_item(m_lastTextIndex);
146}
147
148void
149TextArrayObject::set_done(bool done)
150{
151 m_isDone = done;
152}
153
154void
155TextArrayObject::set_auto(bool is_auto)
156{
157 m_isAuto = is_auto;
158 reset_automation();
159}
160
161void
162TextArrayObject::update(float dt_sec)
163{
164 if (m_isDone)
165 return;
166
167 // make sure there's anything to update
168 if (m_texts.size() == 0)
169 return;
170
171 // detect change request
172 handle_input_requests();
173
174 // check if if should update auto narration
175 if (m_isAuto && m_waiting.check()) {
176 next_text();
177 }
178
179 // update current
180 auto* curTextItem = get_current_text_item();
181 if (curTextItem)
182 curTextItem->text_object.update(dt_sec);
183
184 // update last (if transition is enabled)
185
186 if (should_fade()) {
187 auto* lastTextItem = get_last_text_item();
188 if (lastTextItem)
189 lastTextItem->text_object.update(dt_sec);
190 }
191}
192
193void
194TextArrayObject::draw(DrawingContext& context)
195{
196 if (m_isDone)
197 return;
198
199 auto* curTextItem = get_current_text_item();
200 if (!curTextItem)
201 return;
202
203 // draw last if transition enabled
204 if (should_fade()) {
205 auto* lastTextItem = get_last_text_item();
206 if (lastTextItem)
207 lastTextItem->text_object.draw(context);
208 }
209
210 // draw current
211 curTextItem->text_object.draw(context);
212}
213
214void
215TextArrayObject::override_properties()
216{
217 if (!(should_fade() || m_keepVisible))
218 return;
219
220 auto* curTextItem = get_current_text_item();
221 if (!curTextItem)
222 return;
223
224 // apply overrides
225 if (should_fade()) { // make fade transition
226 auto* lastTextItem = get_last_text_item();
227 if (lastTextItem) {
228 lastTextItem->text_object.fade_out(m_fadetime);
229 curTextItem->text_object.fade_in(m_fadetime);
230 }
231 } else if (m_keepVisible) { // keep visible
232 curTextItem->text_object.set_visible(true);
233 }
234}
235
236void
237TextArrayObject::reset_automation()
238{
239 m_waiting.stop();
240
241 if (m_isAuto) {
242 auto* text = get_current_text_item();
243 if (text)
244 m_waiting.start(text->duration);
245 }
246}
247
248void
249TextArrayObject::handle_input_requests()
250{
251 const Controller& controller = InputManager::current()->get_controller();
252
253 if (controller.pressed(Control::MENU_SELECT)) {
254 m_isAuto = false;
255 next_text();
256 } else if (controller.pressed(Control::REMOVE)) {
257 m_isAuto = false;
258 prev_text();
259 }
260
261}
262
263bool
264TextArrayObject::should_fade()
265{
266 return m_fadeTransition && (m_curTextIndex != m_lastTextIndex);
267}
268
269/* EOF */
270