1 ///////////////////////////////////////////////////////////////////////////////
2 // Copyright (C) 2004-2011 by The Allacrost Project
3 // Copyright (C) 2012-2016 by Bertram (Valyria Tear)
4 // All Rights Reserved
5 //
6 // This code is licensed under the GNU GPL version 2. It is free software
7 // and you may modify it and/or redistribute it under the terms of this license.
8 // See http://www.gnu.org/copyleft/gpl.html for details.
9 ///////////////////////////////////////////////////////////////////////////////
10
11 /** ****************************************************************************
12 *** \file dialogue.cpp
13 *** \author Tyler Olsen, roots@allacrost.org
14 *** \author Yohann Ferreira, yohann ferreira orange fr
15 *** \brief Source file for common dialogue code.
16 *** ***************************************************************************/
17
18 #include "dialogue.h"
19
20 #include "common/global/global.h"
21
22 #include "common.h"
23 #include "common/gui/gui.h"
24
25 #include "engine/video/video.h"
26 #include "engine/input.h"
27 #include "engine/mode_manager.h"
28
29 using namespace vt_system;
30 using namespace vt_utils;
31 using namespace vt_video;
32 using namespace vt_gui;
33
34 namespace vt_common
35 {
36
37 ///////////////////////////////////////////////////////////////////////////////
38 // Dialogue Class Functions
39 ///////////////////////////////////////////////////////////////////////////////
40
Dialogue(const std::string & dialogue_id)41 Dialogue::Dialogue(const std::string& dialogue_id) :
42 _dialogue_id(dialogue_id),
43 _line_count(0)
44 {}
45
~Dialogue()46 Dialogue::~Dialogue()
47 {
48 for(uint32_t i = 0; i < _options.size(); i++) {
49 if(_options[i] != nullptr) {
50 delete _options[i];
51 _options[i] = nullptr;
52 }
53 }
54 }
55
Create(DialogueSupervisor * dialogue_supervisor,const std::string & dialogue_id)56 Dialogue* Dialogue::Create(DialogueSupervisor* dialogue_supervisor, const std::string& dialogue_id)
57 {
58 Dialogue* dialogue = new Dialogue(dialogue_id);
59
60 // As the object is created through scripting, we register it
61 // to the common dialogue supervisor.
62 // NOTE: We don't do it in the constructor as SpriteDialogue are children
63 // of this class
64 dialogue_supervisor->AddDialogue(dialogue);
65
66 return dialogue;
67 }
68
AddLine(const std::string & text)69 void Dialogue::AddLine(const std::string& text)
70 {
71 AddLine(text, DIALOGUE_NEXT_LINE);
72 }
73
AddLine(const std::string & text,int32_t next_line)74 void Dialogue::AddLine(const std::string& text, int32_t next_line)
75 {
76 ++_line_count;
77 _text.push_back(MakeUnicodeString(text));
78 _next_lines.push_back(next_line);
79 _display_times.push_back(DIALOGUE_NO_TIMER);
80 _options.push_back(nullptr);
81 }
82
AddLine(const std::string & text,const std::string & speaker_id)83 void Dialogue::AddLine(const std::string& text, const std::string& speaker_id)
84 {
85 AddLineTimed(text, speaker_id, DIALOGUE_NEXT_LINE, DIALOGUE_NO_TIMER);
86 }
87
AddLine(const std::string & text,const std::string & speaker_id,int32_t next_line)88 void Dialogue::AddLine(const std::string& text, const std::string& speaker_id, int32_t next_line)
89 {
90 AddLineTimed(text, speaker_id, next_line, DIALOGUE_NO_TIMER);
91 }
92
AddLineTimed(const std::string & text,uint32_t display_time)93 void Dialogue::AddLineTimed(const std::string& text, uint32_t display_time)
94 {
95 AddLineTimed(text, DIALOGUE_NEXT_LINE, display_time);
96 }
97
AddLineTimed(const std::string & text,int32_t next_line,uint32_t display_time)98 void Dialogue::AddLineTimed(const std::string& text, int32_t next_line, uint32_t display_time)
99 {
100 ++_line_count;
101 _text.push_back(MakeUnicodeString(text));
102 _next_lines.push_back(next_line);
103 _display_times.push_back(display_time);
104 _options.push_back(nullptr);
105 }
106
AddLineTimed(const std::string & text,const std::string & speaker_id,uint32_t display_time)107 void Dialogue::AddLineTimed(const std::string& text, const std::string& speaker_id, uint32_t display_time)
108 {
109 AddLineTimed(text, speaker_id, DIALOGUE_NEXT_LINE, display_time);
110 }
111
AddLineTimed(const std::string & text,const std::string & speaker_id,int32_t next_line,uint32_t display_time)112 void Dialogue::AddLineTimed(const std::string &text, const std::string& speaker_id, int32_t next_line, uint32_t display_time)
113 {
114 AddLineTimed(text, next_line, display_time);
115 _speakers.push_back(speaker_id);
116 }
117
AddOption(const std::string & text)118 void Dialogue::AddOption(const std::string& text)
119 {
120 AddOption(text, DIALOGUE_NEXT_LINE);
121 }
122
AddOption(const std::string & text,int32_t next_line)123 void Dialogue::AddOption(const std::string& text, int32_t next_line)
124 {
125 if(_line_count == 0) {
126 IF_PRINT_WARNING(COMMON_DEBUG) << "Attempted to add an option to a dialogue with no lines" << std::endl;
127 return;
128 }
129
130 uint32_t current_line = _line_count - 1;
131
132 // If the line the options will be added to currently has no options, create a new instance of the CommonDialogueOptions class to store the options in.
133 if(_options[current_line] == nullptr) {
134 _options[current_line] = new DialogueOptions();
135 }
136 _options[current_line]->AddOption(text, next_line);
137 }
138
Validate()139 bool Dialogue::Validate()
140 {
141 // Valid dialogues need to have at least one line
142 if(_line_count == 0) {
143 IF_PRINT_WARNING(COMMON_DEBUG) << "Validation failed for dialogue #" << _dialogue_id << ": no lines" << std::endl;
144 return false;
145 }
146
147 // Check that all next lines with positive values point to valid indeces
148 for(uint32_t i = 0; i < _line_count; ++i) {
149 if((_next_lines[i] >= 0) && (static_cast<uint32_t>(_next_lines[i]) >= _line_count)) {
150 IF_PRINT_WARNING(COMMON_DEBUG) << "Validation failed for dialogue #" << _dialogue_id
151 << ": next line referred to an invalid line index: " << _next_lines[i] << std::endl;
152 return false;
153 }
154
155 // If this line has options, we have to examine the next line argument for each option as well
156 if(_options[i] != 0) {
157 if(_options[i]->GetNumberOptions() == 0) {
158 PRINT_WARNING << "Validation failed for dialogue #" << _dialogue_id
159 << ": line had options declared but no options defined" << std::endl;
160 return false;
161 }
162
163 for(uint32_t j = 0; j < _options[i]->GetNumberOptions(); ++j) {
164 int32_t option_next_line = _options[i]->GetOptionNextLine(j);
165 if((option_next_line >= 0) && (static_cast<uint32_t>(option_next_line) >= _line_count)) {
166 IF_PRINT_WARNING(COMMON_DEBUG) << "Validation failed for dialogue #" << _dialogue_id
167 << ": option's next line referred to an invalid line index: "
168 << option_next_line << std::endl;
169 return false;
170 }
171 }
172 }
173 }
174
175 // Construct containers that hold all unique sprite and event ids for this dialogue
176 std::set<std::string> speaker_ids;
177 for(uint32_t i = 0; i < _line_count; ++i) {
178 speaker_ids.insert(_speakers[i]);
179 }
180
181 // Check that all sprites and events referenced by the dialogue exist
182 // FIXME: Move the check into the dialogue supervisor
183 /*
184 for(std::set<uint32_t>::iterator i = speaker_ids.begin(); i != speaker_ids.end(); ++i) {
185 if(BattleMode::CurrentInstance()->GetDialogueSupervisor()->GetSpeaker(*i) == nullptr) {
186 PRINT_WARNING << "Validation failed for dialogue #" << _dialogue_id
187 << ": dialogue referenced invalid speaker with id: " << *i << std::endl;
188 return false;
189 }
190 }
191 */
192
193 return true;
194 }
195
196 ///////////////////////////////////////////////////////////////////////////////
197 // DialogueOptions Functions
198 ///////////////////////////////////////////////////////////////////////////////
199
AddOption(const std::string & text)200 void DialogueOptions::AddOption(const std::string& text)
201 {
202 AddOption(text, DIALOGUE_NEXT_LINE);
203 }
204
AddOption(const std::string & text,int32_t next_line)205 void DialogueOptions::AddOption(const std::string& text, int32_t next_line)
206 {
207 _text.push_back(MakeUnicodeString(text));
208 _next_lines.push_back(next_line);
209 }
210
211 ///////////////////////////////////////////////////////////////////////////////
212 // DialogueWindow class methods
213 ///////////////////////////////////////////////////////////////////////////////
214
DialogueWindow()215 DialogueWindow::DialogueWindow() :
216 _pos(512.0f, 512.0f),
217 _indicator_symbol(DIALOGUE_NO_INDICATOR),
218 _blink_time(0),
219 _blink_state(true),
220 _portrait_image(nullptr)
221 {
222 //TODO: Makes this part of the themes
223 if(_parchment_image.Load("data/gui/black_sleet_parch.png") == false)
224 PRINT_ERROR << "failed to load dialogue image: " << _parchment_image.GetFilename() << std::endl;
225
226 if(_nameplate_image.Load("data/gui/dialogue_nameplate.png") == false)
227 PRINT_ERROR << "failed to load dialogue image: " << _nameplate_image.GetFilename() << std::endl;
228
229 if(_next_line_image.Load("data/gui/dialogue_cont_arrow.png") == false)
230 PRINT_ERROR << "failed to load dialogue image: " << _next_line_image.GetFilename() << std::endl;
231
232 if(_last_line_image.Load("data/gui/dialogue_last_ind.png") == false)
233 PRINT_ERROR << "failed to load dialogue image: " << _last_line_image.GetFilename() << std::endl;
234
235 VideoManager->PushState();
236 VideoManager->SetStandardCoordSys();
237
238 _display_textbox.SetDisplaySpeed(SystemManager->GetMessageSpeed());
239 _display_textbox.SetPosition(260.0f, 596.0f);
240 _display_textbox.SetDimensions(640.0f, 126.0f);
241 _display_textbox.SetTextStyle(TextStyle("text20", Color::black, VIDEO_TEXT_SHADOW_LIGHT));
242 _display_textbox.SetDisplayMode(VIDEO_TEXT_FADECHAR);
243 _display_textbox.SetAlignment(VIDEO_X_CENTER, VIDEO_Y_CENTER);
244 _display_textbox.SetTextAlignment(VIDEO_X_LEFT, VIDEO_Y_TOP);
245
246 _display_optionbox.SetPosition(300.0f, 630.0f);
247 _display_optionbox.SetDimensions(640.0f, 90.0f, 1, 255, 1, 4);
248 _display_optionbox.SetOptionAlignment(VIDEO_X_LEFT, VIDEO_Y_CENTER);
249 _display_optionbox.SetTextStyle(TextStyle("title20", Color::black, VIDEO_TEXT_SHADOW_LIGHT));
250 _display_optionbox.SetSelectMode(VIDEO_SELECT_SINGLE);
251 _display_optionbox.SetCursorOffset(-55.0f, -25.0f);
252 _display_optionbox.SetVerticalWrapMode(VIDEO_WRAP_MODE_NONE);
253
254 _name_text.SetStyle(TextStyle("title22", Color::black, VIDEO_TEXT_SHADOW_LIGHT));
255
256 VideoManager->PopState();
257 }
258
SetPosition(float pos_x,float pos_y)259 void DialogueWindow::SetPosition(float pos_x, float pos_y)
260 {
261 _pos.x = pos_x;
262 _pos.y = pos_y;
263
264 _display_textbox.SetPosition(_pos.x + 80.0f, _pos.y - 110.0f);
265 _display_optionbox.SetPosition(_pos.x - 220.0f, _pos.y - 112.0f);
266 }
267
Clear()268 void DialogueWindow::Clear()
269 {
270 _display_textbox.ClearText();
271 _display_optionbox.ClearOptions();
272 _name_text.Clear();
273 _portrait_image = nullptr;
274 }
275
Draw()276 void DialogueWindow::Draw()
277 {
278 VideoManager->PushState();
279 VideoManager->SetStandardCoordSys();
280 VideoManager->SetDrawFlags(VIDEO_X_CENTER, VIDEO_Y_BOTTOM, VIDEO_BLEND, 0);
281
282 VideoManager->Move(_pos.x, _pos.y);
283 _parchment_image.Draw();
284
285 VideoManager->MoveRelative(-370.0f, -45.0f);
286 if(_portrait_image)
287 _portrait_image->Draw();
288
289 if (!_name_text.GetString().empty()) {
290 VideoManager->MoveRelative(0.0f, 30.0f);
291 _nameplate_image.Draw();
292
293 VideoManager->MoveRelative(0.0f, -6.0f);
294 _name_text.Draw();
295 }
296 else {
297 VideoManager->MoveRelative(0.0f, 24.0f);
298 }
299
300 VideoManager->MoveRelative(0.0f, 5.0f);
301 _blink_time += SystemManager->GetUpdateTime();
302 if(_blink_time > 500) {
303 _blink_time -= 500;
304 _blink_state = _blink_state ? false : true;
305 }
306
307 if(_indicator_symbol == DIALOGUE_NEXT_INDICATOR && _blink_state) {
308 VideoManager->MoveRelative(830.0f, 0.0f);
309 _next_line_image.Draw();
310 } else if(_indicator_symbol == DIALOGUE_LAST_INDICATOR && _blink_state) {
311 VideoManager->MoveRelative(830.0f, 0.0f);
312 _last_line_image.Draw();
313 }
314
315 _display_textbox.Draw();
316 _display_optionbox.Draw();
317
318 VideoManager->PopState();
319 }
320
321 ///////////////////////////////////////////////////////////////////////////////
322 // DialogueSupervisor class methods
323 ///////////////////////////////////////////////////////////////////////////////
324
DialogueSupervisor()325 DialogueSupervisor::DialogueSupervisor() :
326 _state(DIALOGUE_STATE_INACTIVE),
327 _current_dialogue(nullptr),
328 _current_options(nullptr),
329 _line_timer(),
330 _line_counter(0),
331 _dialogue_window()
332 {
333 _dialogue_window.SetPosition(512.0f, 170.0f);
334 }
335
~DialogueSupervisor()336 DialogueSupervisor::~DialogueSupervisor()
337 {
338 // Delete all dialogues
339 for(std::map<std::string, Dialogue *>::iterator it = _dialogues.begin(); it != _dialogues.end(); ++it) {
340 delete it->second;
341 }
342 _dialogues.clear();
343 _speakers.clear();
344 }
345
SetDialoguePosition(float x,float y)346 void DialogueSupervisor::SetDialoguePosition(float x, float y)
347 {
348 _dialogue_window.SetPosition(x, y);
349 }
350
Update()351 void DialogueSupervisor::Update()
352 {
353 if(_current_dialogue == nullptr)
354 return;
355
356 _line_timer.Update();
357
358 switch(_state) {
359 case DIALOGUE_STATE_LINE:
360 _UpdateLine();
361 break;
362 case DIALOGUE_STATE_OPTION:
363 _UpdateOptions();
364 break;
365 default:
366 PRINT_WARNING << "Dialogue supervisor was in an unknown state: " << _state << std::endl;
367 _state = DIALOGUE_STATE_LINE;
368 break;
369 }
370 }
371
Draw()372 void DialogueSupervisor::Draw()
373 {
374 _dialogue_window.Draw();
375 }
376
AddDialogue(Dialogue * dialogue)377 void DialogueSupervisor::AddDialogue(Dialogue* dialogue)
378 {
379 if(dialogue == nullptr) {
380 IF_PRINT_WARNING(COMMON_DEBUG) << "function received nullptr argument" << std::endl;
381 return;
382 }
383
384 if(GetDialogue(dialogue->GetDialogueID()) != nullptr) {
385 IF_PRINT_WARNING(COMMON_DEBUG) << "a dialogue was already registered with this ID: " << dialogue->GetDialogueID() << std::endl;
386 delete dialogue;
387 return;
388 }
389 _dialogues.insert(std::make_pair(dialogue->GetDialogueID(), dialogue));
390 }
391
AddSpeaker(const std::string & speaker_id,const std::string & name,const std::string & portrait)392 void DialogueSupervisor::AddSpeaker(const std::string& speaker_id, const std::string& name, const std::string& portrait)
393 {
394 if(_speakers.find(speaker_id) != _speakers.end()) {
395 PRINT_WARNING << "Speaker already existed with requested id: " << speaker_id << std::endl;
396 return;
397 }
398
399 Speaker new_speaker;
400 new_speaker.name = MakeUnicodeString(name);
401 if(!portrait.empty()) {
402 if(!new_speaker.portrait.Load(portrait)) {
403 IF_PRINT_WARNING(COMMON_DEBUG) << "invalid image filename for new portrait: " << portrait << std::endl;
404 }
405 // Make sure the portrait doesn't go over the screen edge.
406 if(new_speaker.portrait.GetHeight() > 130.0f)
407 new_speaker.portrait.SetHeightKeepRatio(130.0f);
408 }
409
410 _speakers[speaker_id] = new_speaker;
411 }
412
ChangeSpeakerName(const std::string & speaker_id,const std::string & name)413 void DialogueSupervisor::ChangeSpeakerName(const std::string& speaker_id, const std::string& name)
414 {
415 std::map<std::string, Speaker>::iterator it = _speakers.find(speaker_id);
416 if(it == _speakers.end()) {
417 PRINT_WARNING << "No speaker found with requested id: " << speaker_id << std::endl;
418 return;
419 }
420
421 it->second.name = MakeUnicodeString(name);
422
423 if(_current_dialogue != nullptr) {
424 if(_current_dialogue->GetLineSpeaker(_line_counter) == speaker_id) {
425 _dialogue_window.GetNameText().SetText(it->second.name);
426 }
427 }
428 }
429
ChangeSpeakerPortrait(const std::string & speaker_id,const std::string & portrait)430 void DialogueSupervisor::ChangeSpeakerPortrait(const std::string& speaker_id, const std::string& portrait)
431 {
432 if(portrait.empty())
433 return;
434
435 std::map<std::string, Speaker>::iterator it = _speakers.find(speaker_id);
436 if(it == _speakers.end()) {
437 PRINT_WARNING << "No speaker found with requested id: " << speaker_id << std::endl;
438 return;
439 }
440
441 // Note: we don't have to also check whether or not the active portrait on the dialogue window needs to be
442 // updated since the dialogue window simply retains a pointer to the image object. We only update the StillImage
443 // class object contents in this function, not its address.
444 if(!it->second.portrait.Load(portrait)) {
445 PRINT_WARNING << "Invalid image filename for new portrait: " << portrait << std::endl;
446 return;
447 }
448 }
449
StartDialogue(const std::string & dialogue_id)450 void DialogueSupervisor::StartDialogue(const std::string& dialogue_id)
451 {
452 Dialogue *dialogue = GetDialogue(dialogue_id);
453
454 if(dialogue == nullptr) {
455 PRINT_WARNING << "Could not begin dialogue because none existed for id: " << dialogue_id << std::endl;
456 return;
457 }
458
459 if(_current_dialogue != nullptr) {
460 PRINT_WARNING << "beginning a new dialogue while another dialogue is still active" << std::endl;
461 }
462
463 _line_counter = 0;
464 _current_dialogue = dialogue;
465 _current_options = _current_dialogue->GetLineOptions(_line_counter);
466
467 _BeginLine();
468 }
469
EndDialogue()470 void DialogueSupervisor::EndDialogue()
471 {
472 if(_current_dialogue == nullptr) {
473 IF_PRINT_WARNING(COMMON_DEBUG) << "Tried to end a dialogue when none was active" << std::endl;
474 return;
475 }
476
477 _current_dialogue = nullptr;
478 _current_options = nullptr;
479 _line_timer.Finish();
480 }
481
ForceNextLine()482 void DialogueSupervisor::ForceNextLine()
483 {
484 if(_current_dialogue == nullptr) {
485 IF_PRINT_WARNING(COMMON_DEBUG) << "function called when no dialogue was active" << std::endl;
486 return;
487 }
488
489 _EndLine();
490 }
491
GetDialogue(const std::string & dialogue_id)492 Dialogue* DialogueSupervisor::GetDialogue(const std::string& dialogue_id)
493 {
494 std::map<std::string, Dialogue *>::iterator it = _dialogues.find(dialogue_id);
495 if(it == _dialogues.end())
496 return nullptr;
497
498 return it->second;
499 }
500
GetSpeaker(const std::string & speaker_id)501 Speaker* DialogueSupervisor::GetSpeaker(const std::string& speaker_id)
502 {
503 std::map<std::string, Speaker>::iterator it = _speakers.find(speaker_id);
504 if(it != _speakers.end())
505 return &(it->second);
506
507 return nullptr;
508 }
509
_UpdateLine()510 void DialogueSupervisor::_UpdateLine()
511 {
512 _dialogue_window.GetDisplayTextBox().Update();
513
514 if(_current_options != nullptr) {
515 if(_dialogue_window.GetDisplayTextBox().IsFinished()) {
516 _state = DIALOGUE_STATE_OPTION;
517 return;
518 }
519 }
520
521 // If the line has a valid display time and the timer is finished, move on to the next line
522 if((_line_timer.GetDuration() > 0) && (_line_timer.IsFinished())) {
523 _EndLine();
524 return;
525 }
526
527 // Set the correct indicator
528 if(_current_options || !_dialogue_window.GetDisplayTextBox().IsFinished()) {
529 _dialogue_window.SetIndicator(DIALOGUE_NO_INDICATOR);
530 } else if(_line_counter == _current_dialogue->GetLineCount() - 1) {
531 if (_dialogue_window.SetIndicator(DIALOGUE_LAST_INDICATOR))
532 vt_global::GlobalManager->Media().PlaySound("line_complete");
533 } else {
534 if (_dialogue_window.SetIndicator(DIALOGUE_NEXT_INDICATOR))
535 vt_global::GlobalManager->Media().PlaySound("line_complete");
536 }
537
538 // If the current mode is accepting input, we can handle it.
539 if (!vt_mode_manager::ModeManager->GetTop()->AcceptUserInputInDialogues())
540 return;
541
542 if(vt_input::InputManager->ConfirmPress()) {
543 // If the line is not yet finished displaying, display the rest of the text
544 if(_dialogue_window.GetDisplayTextBox().IsFinished() == false) {
545 _dialogue_window.GetDisplayTextBox().ForceFinish();
546 }
547 // Proceed to option selection if the line has options
548 else if(_current_options != nullptr) {
549 _state = DIALOGUE_STATE_OPTION;
550 } else {
551 _EndLine();
552 }
553 }
554 }
555
_UpdateOptions()556 void DialogueSupervisor::_UpdateOptions()
557 {
558 _dialogue_window.GetDisplayOptionBox().Update();
559 vt_global::GlobalMedia& media = vt_global::GlobalManager->Media();
560
561 if(vt_input::InputManager->ConfirmPress()) {
562 _dialogue_window.GetDisplayOptionBox().InputConfirm();
563 media.PlaySound("confirm");
564 _EndLine();
565 }
566
567 else if(vt_input::InputManager->UpPress()) {
568 _dialogue_window.GetDisplayOptionBox().InputUp();
569 media.PlaySound("bump");
570 }
571
572 else if(vt_input::InputManager->DownPress()) {
573 _dialogue_window.GetDisplayOptionBox().InputDown();
574 media.PlaySound("bump");
575 }
576 }
577
_BeginLine()578 void DialogueSupervisor::_BeginLine()
579 {
580 _state = DIALOGUE_STATE_LINE;
581 _current_options = _current_dialogue->GetLineOptions(_line_counter);
582
583 // Initialize the line timer
584 if(_current_dialogue->GetLineDisplayTime(_line_counter) >= 0) {
585 _line_timer.Initialize(_current_dialogue->GetLineDisplayTime(_line_counter));
586 _line_timer.Run();
587 }
588 // If the line has no timer specified, set the line time to zero and put the timer in the finished state
589 else {
590 _line_timer.Initialize(0);
591 _line_timer.Finish();
592 }
593
594 // Setup the text and graphics for the dialogue window
595 _dialogue_window.Clear();
596 _dialogue_window.GetDisplayTextBox().SetDisplayText(_current_dialogue->GetLineText(_line_counter));
597 if(_current_options != nullptr) {
598 for(uint32_t i = 0; i < _current_options->GetNumberOptions(); ++i) {
599 _dialogue_window.GetDisplayOptionBox().AddOption(_current_options->GetOptionText(i));
600 }
601
602 _dialogue_window.GetDisplayOptionBox().SetSelection(0);
603 }
604
605 Speaker* line_speaker = GetSpeaker(_current_dialogue->GetLineSpeaker(_line_counter));
606 if(line_speaker == nullptr) {
607 IF_PRINT_WARNING(COMMON_DEBUG) << "dialogue #" << _current_dialogue->GetDialogueID()
608 << " referenced a speaker that did not exist with id: " << _current_dialogue->GetLineSpeaker(_line_counter) << std::endl;
609 _dialogue_window.GetNameText().SetText("");
610 _dialogue_window.SetPortraitImage(nullptr);
611 } else {
612 _dialogue_window.GetNameText().SetText(line_speaker->name);
613 _dialogue_window.SetPortraitImage(&(line_speaker->portrait));
614 }
615 }
616
_EndLine()617 void DialogueSupervisor::_EndLine()
618 {
619 // Determine the next line to read
620 int32_t next_line = _current_dialogue->GetLineNextLine(_line_counter);
621 // If this line had options, the selected option next line overrides the line's next line that we set above
622 if(_current_options != nullptr) {
623 uint32_t selected_option = _dialogue_window.GetDisplayOptionBox().GetSelection();
624 next_line = _current_options->GetOptionNextLine(selected_option);
625 }
626
627 // --- Case 1: Explicitly setting the next line. Warn and end the dialogue if the line to move to is invalid
628 if(next_line >= 0) {
629 if(static_cast<uint32_t>(next_line) >= _current_dialogue->GetLineCount()) {
630 IF_PRINT_WARNING(COMMON_DEBUG) << "dialogue #" << _current_dialogue->GetDialogueID()
631 << " tried to set dialogue to invalid line. Current/next line values: {" << _line_counter
632 << ", " << next_line << "}" << std::endl;
633 next_line = DIALOGUE_END;
634 }
635 }
636 // --- Case 2: Request to incrementing the current line. If we're incrementing past the last line, end the dialogue
637 else if(next_line == DIALOGUE_NEXT_LINE) {
638 next_line = _line_counter + 1;
639 if(static_cast<uint32_t>(next_line) >= _current_dialogue->GetLineCount())
640 next_line = DIALOGUE_END;
641 }
642 // --- Case 3: Request to end the current dialogue
643 else if(next_line == DIALOGUE_END) {
644 // Do nothing
645 }
646 // --- Case 4: Unknown negative value. Warn and end dialogue
647 else {
648 IF_PRINT_WARNING(COMMON_DEBUG) << "dialogue #" << _current_dialogue->GetDialogueID()
649 << " unknown next line control value: " << next_line << std::endl;
650 next_line = DIALOGUE_END;
651 }
652
653 // Now either end the dialogue or move on to the next line
654 if(next_line == DIALOGUE_END) {
655 EndDialogue();
656 } else {
657 _line_counter = next_line;
658 _BeginLine();
659 }
660 }
661
662 } // namespace vt_common
663