1 ///////////////////////////////////////////////////////////////////////////////
2 //            Copyright (C) 2004-2010 by The Allacrost Project
3 //                         All Rights Reserved
4 //
5 // This code is licensed under the GNU GPL version 2. It is free software
6 // and you may modify it and/or redistribute it under the terms of this license.
7 // See http://www.gnu.org/copyleft/gpl.html for details.
8 ///////////////////////////////////////////////////////////////////////////////
9 
10 /** ****************************************************************************
11 *** \file    map_dialogue.h
12 *** \author  Tyler Olsen, roots@allacrost.org
13 *** \brief   Header file for map mode dialogue
14 ***
15 *** \todo There is A LOT of indexing and id referencing in this code and in the
16 *** MapSprite's dialogue-related code. Currently very little is done to warn of
17 *** bad references (a sprite referencing a dialogue via an invalid ID) or bad
18 *** indexing (indexing a line of dialogue that does not exist/out of bounds errors).
19 *** The reason why things are this way right now is because sprites and dialogues
20 *** can be created in any order (and can even be created after the map has been loaded
21 *** and is in play). Because of this, the code may be referencing things that are
22 *** not yet created but will be shortly, so we don't want to print warnings about
23 *** those types of circumstances. What I think we should do is write a "CheckWarnings"
24 *** function or something similar that can be called after it is determined that
25 *** everything *should* be created and referenced properly.
26 *** ***************************************************************************/
27 
28 #ifndef __MAP_DIALOGUE_HEADER__
29 #define __MAP_DIALOGUE_HEADER__
30 
31 // Allacrost utilities
32 #include "utils.h"
33 #include "defs.h"
34 
35 // Allacrost engines
36 #include "script.h"
37 #include "video.h"
38 #include "gui.h"
39 
40 // Local map mode headers
41 #include "map_utils.h"
42 
43 namespace hoa_battle {
44 class BattleMode;
45 }
46 
47 namespace hoa_map {
48 
49 namespace private_map {
50 
51 /** ****************************************************************************
52 *** \brief Represents dialogues between characters on a map
53 ***
54 *** Dialogues consist of multiple lines. Each line of a dialogue contains the
55 *** following information:
56 ***
57 *** -# The text of the line
58 *** -# An object ID that indicates who is currently speaking the line
59 *** -# A value that indicates the maximum time that the line should be displayed
60 *** -# A pointer to a script function to execute after the line is finished
61 ***
62 *** Dialogues may also have a set of options attached to it. Each set of options
63 *** in a dialogue are represented by an instance of the MapDialogueOptions class.
64 *** The options are stored in a vector of MapDialogueOptions object pointers. This
65 *** vector is indexed by the lines of dialogue, so options for line 3 would be stored
66 *** in _options[3]. A null value would mean there are no options for that line of
67 *** dialogue.
68 ***
69 *** Both the display time value and the script function pointer are optional and
70 *** do not need to be set for every line of dialogue. Dialogues may also be "blocked",
71 *** which means that they ignore the user's input while the dialogue is executing.
72 *** The map file retains the number of times each dialogue in the map has been
73 *** seen by the player so that subsequent visits to the map do not falsely display
74 *** sprites as having new dialogue.
75 ***
76 *** The standard order of lines in a dialogue begin with the first line and end
77 *** with the last (as stored in the lines container). However this need not be
78 *** the case and quite often is not. After reading a line, you may proceed to any
79 *** other line in a dialogue. The next line can be chosen either by selecting a
80 *** particular option presented on a line, or looking up the next line value in a
81 *** class container. It can also be explicity set when calling the ReadNextLine
82 *** method to finish reading the current line, although this is usually only done
83 *** by the dialogue manager when processing a selected dialogue option.
84 ***
85 *** When a dialogue is finished, usually the state of all speaker sprites is
86 *** restored (uch as the direction they were facing prior to the dialogue) so that
87 *** they can resume their prior activity. Also for dialogues which are "owned" by
88 *** a sprite (where owned simply means that the dialogue instance is retained in
89 *** the MapSprite#_dialogues container), the sprite is informed that the
90 *** dialogue has finished so that the sprite may re-check whether or not all
91 *** dialogues that it contains have been seen by the player.
92 ***
93 *** \todo MapDialogues need to be made more generic. They should not require a
94 *** speaker ID (ie we can have a "narrator" of sorts), they should not require
95 *** a portrait, and they should not be contained within the MapSprite class.
96 *** Dialogues should be retained by the DialogueWindow class and sprites should
97 *** reference these dialogues via a dialogue ID as appropriate.
98 *** ***************************************************************************/
99 class MapDialogue {
100 public:
101 	//! \param id The id number to represent the dialogue by (should be unique to other dialogue ids)
102 	MapDialogue(uint32 id);
103 
104 	~MapDialogue();
105 
106 	/** \brief Adds a new line of text and to the dialogue
107 	*** \param text The text to show on the screen
108 	*** \param speaker_id The object ID of the speaker of this line of text
109 	*** \param next_line The line of dialogue which should follow this one (a negative value indicates to end the dialogue)
110 	*** \param time The maximum time in milliseconds to show the line of dialogue (default == infinite)
111 	*** \param event The ID of an event to enact after selecting the option. A zero value indicates that no event is to occur.
112 	***
113 	*** \todo This should take a ustring instead of a std::string, but we need better support
114 	*** for ustring in scripts to do that first.
115 	**/
116 	void AddText(std::string text, uint32 speaker_id, int32 next_line, uint32 event = 0, bool display_timer = false);
117 
118 	/** \brief Adds an option to the most recently added line of text
119 	*** \param text The text for this particular option
120 	*** \param next_line The index value of the next line of dialogue to display should this option be selected
121 	*** (a negative value indicates to end the dialogue immediately after the option is selected)
122 	*** \param event The ID of an event to enact after selecting the option. A zero value indicates that no event is to occur.
123 	***
124 	*** \todo This should take a ustring instead of a std::string, but we need better support
125 	*** for ustring in scripts to do that first.
126 	**/
127 	void AddOption(std::string text, int32 next_line, uint32 event = 0);
128 
129 	/** \brief Proceeds the dialogue forward to display the next line
130 	*** \param line Index value of the next line of dialogue to read. A negative value indicates
131 	*** that there is no proceeding line and that the dialogue should finish.
132 	*** \return False if the dialogue is finished, true otherwise.
133 	**/
134 	bool ReadNextLine(int32 line);
135 
136 	/** \brief Returns the string of the dialogue's event name as it would be stored in the saved game file
137 	*** \return The event string in the standard format of "dialogue#ID", where ID is the dialogue ID value
138 	**/
GetEventName()139 	std::string GetEventName()
140 		{ return std::string("dialogue#" + hoa_utils::NumberToString(_dialogue_id)); }
141 
142 	//! \brief Return true if this dialogue is available to be viewed (_times_seen is still less than _max_views)
IsAvailable()143 	bool IsAvailable() const
144 		{ if (_max_views < 0) return true; else return (static_cast<int32>(_times_seen) < _max_views); }
145 
146 	//! \brief Resets the _times_seen counter to zero
ResetTimesSeen()147 	void ResetTimesSeen()
148 		{ _times_seen = 0; }
149 
150 	//! \brief Increments the number of times this dialogue has been seen by the player
IncrementTimesSeen()151 	void IncrementTimesSeen()
152 		{ _times_seen++; }
153 
154 	//! \brief Indicates if this dialogue has already been seen by the player.
HasAlreadySeen()155 	bool HasAlreadySeen() const
156 		{ return (_times_seen != 0); }
157 
158 	// ----- Methods: retrieval of properties of the current line
159 
160 	//! \brief Returns true if the current line contains options.
CurrentLineHasOptions()161 	bool CurrentLineHasOptions() const
162 		{ if (_options[_current_line] != NULL) return true; else return false; }
163 
164 	//! \brief Returns the set of options for the current line (will be NULL if no options exist for this line)
GetCurrentOptions()165 	MapDialogueOptions* GetCurrentOptions() const
166 		{ return _options[_current_line]; }
167 
168 	//! \brief Returns an integer value of the next line of dialogue to be displayed for the current line
GetCurrentNextLine()169 	int32 GetCurrentNextLine() const
170 		{ return _next_lines[_current_line]; }
171 
172 	//! \brief Returns a reference to the unicode text string of the current line of dialogue
GetCurrentText()173 	const hoa_utils::ustring& GetCurrentText() const
174 		{ return _text[_current_line]; }
175 
176 	//! \brief Returns the object ID of the speaker of the current line of dialogue
GetCurrentSpeaker()177 	uint32 GetCurrentSpeaker() const
178 		{ return _speakers[_current_line]; }
179 
180 	//! \brief Returns the display time of the current line of dialogue
GetCurrentTime()181 	int32 GetCurrentTime() const
182 		{ return _display_times[_current_line]; }
183 
184 	//! \brief Returns the integer ID of the event that will be invoked after the current line of dialogue completes
GetCurrentEvent()185 	uint32 GetCurrentEvent()
186 		{ return _events[_current_line]; }
187 
188 	// ----- Methods: retrieval of properties of a specific line
189 
190 	//! \brief Returns the text of a specific line
GetLineText(uint32 line)191 	hoa_utils::ustring GetLineText(uint32 line) const
192 		{ if (line > _text.size()) return hoa_utils::ustring(); else return _text[line]; }
193 
194 	//! \brief Returns the object id of the speaker of a specific line
GetLineSpeaker(uint32 line)195 	uint32 GetLineSpeaker(uint32 line) const
196 		{ if (line > _speakers.size()) return 0; else return _speakers[line]; }
197 
198 	//! \brief Returns the display time of a specific line
GetLineTime(uint32 line)199 	int32 GetLineTime(uint32 line) const
200 		{ if (line > _display_times.size()) return -1; else return _display_times[line]; }
201 
202 	//! \brief Returns the ID of the event to execute after a specific line
GetLineEvent(uint32 line)203 	uint32 GetLineEvent(uint32 line)
204 		{ if (line > _events.size()) return 0; else return _events[line]; }
205 
206 	//! \name Class Member Access Functions
207 	//@{
GetDialogueID()208 	uint32 GetDialogueID() const
209 		{ return _dialogue_id; }
210 
GetMaxViews()211 	int32 GetMaxViews() const
212 		{ return _max_views; }
213 
GetTimesSeen()214 	int32 GetTimesSeen() const
215 		{ return _times_seen; }
216 
GetLineCount()217 	uint32 GetLineCount() const
218 		{ return _line_count; }
219 
GetCurrentLine()220 	uint32 GetCurrentLine()
221 		{ return _current_line;}
222 
GetSaveState()223 	bool GetSaveState() const
224 		{ return _save_state; }
225 
IsBlocked()226 	bool IsBlocked() const
227 		{ return _blocked; }
228 
IsSaveState()229 	bool IsSaveState() const
230 		{ return _save_state; }
231 
SetTimesSeen(uint32 times)232 	void SetTimesSeen(uint32 times)
233 		{ _times_seen = times; }
234 
SetMaxViews(int32 views)235 	void SetMaxViews(int32 views)
236 		{ _max_views = views; }
237 
SetBlocked(bool block)238 	void SetBlocked(bool block)
239 		{ _blocked = block; }
240 
SetSaveState(bool state)241 	void SetSaveState(bool state)
242 		{ _save_state = state; }
243 	//@}
244 
245 private:
246 	//! \brief A unique identification number that represents this dialogue
247 	uint32 _dialogue_id;
248 
249 	//! \brief Counts the number of time a player has seen this dialogue.
250 	uint32 _times_seen;
251 
252 	//! \brief Declares the max number of times that this dialogue can be viewed (negative value indicates no limit)
253 	int32 _max_views;
254 
255 	//! \brief Stores the amount of lines in the dialogue.
256 	uint32 _line_count;
257 
258 	//! \brief An index to the current line to read.
259 	uint32 _current_line;
260 
261 	//! \brief If true, dialogue will ignore user input and instead execute independently
262 	bool _blocked;
263 
264 	//! \brief If true, the status of map sprites will be reset after the dialogue completes
265 	bool _save_state;
266 
267 	//! \brief The event name for this dialogue that is stored in the saved game file, of the form "dialogue#"
268 	std::string _event_name;
269 
270 	//! \brief The text of the conversation, split up into multiple lines
271 	std::vector<hoa_utils::ustring> _text;
272 
273 	//! \brief A list of object ID numbers that declare the speaker of each line
274 	std::vector<uint32> _speakers;
275 
276 	//! \brief The maximum display time for each line in the dialogue. A negative value indicates infinite time
277 	std::vector<int32> _display_times;
278 
279 	//! \brief Holds indeces pointing to which line should follow each line of text. A negative value indicates that the dialogue should end.
280 	std::vector<int32> _next_lines;
281 
282 	//! \brief A set of dialogue options indexed according to the line of dialogue that they belong to
283 	std::vector<MapDialogueOptions*> _options;
284 
285 	//! \brief An optional MapEvent that may occur after each line
286 	std::vector<uint32> _events;
287 }; // class MapDialogue
288 
289 
290 /** ***************************************************************************************
291 *** \brief A container class for option sets presented in dialogue
292 ***
293 *** When the player reads a dialogue he or she may be presented with a small number of options,
294 *** one of which the player must select. The selected option determines the path that the
295 *** dialogue will take, which may include an entire series of scripted events and sequences.
296 *** This class is responsible for containing all of the information necessary to make this
297 *** possible. It represents a set of options that the player must choose between.
298 ***
299 *** Instances of this class are populated as needed by the MapDialogue class. For each option,
300 *** the class contains an index to the next line of dialogue that should be read and an optional
301 *** pointer to a script function to execute, should that particular option be selected.
302 *** **************************************************************************************/
303 class MapDialogueOptions {
304 	friend class DialogueSupervisor;
305 
306 public:
MapDialogueOptions()307 	MapDialogueOptions()
308 		{}
309 
~MapDialogueOptions()310 	~MapDialogueOptions()
311 		{}
312 
313 	/** \brief Adds a new option to the OptionBox
314 	*** \param text The text for the new option
315 	*** \param next_line An integer index of the next line of dialogue should this option be selected.
316 	*** \param event The ID of an event to enact after selecting the option. Zero indicates that no event is to occur.
317 	***/
318 	void AddOption(hoa_utils::ustring text, int32 next_line, uint32 event = 0);
319 
320 private:
321 	//! \brief Contains the text of the dialogue, where each entry represents a single line
322 	std::vector<hoa_utils::ustring> _text;
323 
324 	/** \brief A index containing the next line of dialogue that should follow each option
325 	*** This is an index into the lines container for the MapDialogue object that is using this set of options.
326 	**/
327 	std::vector<int32> _next_lines;
328 
329 	//! \brief An optional MapEvent that may occur as a result of selecting each option
330 	std::vector<uint32> _events;
331 }; // class MapDialogueOptions
332 
333 
334 /** ****************************************************************************
335 *** \brief A display window for all GUI controls and graphics necessary to execute a dialogue
336 ***
337 *** This class, inheriting from the MenuWindow class, handles all visual control
338 *** and placement of a dialgoue. It serves primarily as a container class for
339 *** dialogue graphics.
340 *** ***************************************************************************/
341 class DialogueWindow : public hoa_gui::MenuWindow {
342 	friend class DialogueSupervisor;
343 
344 public:
345 	DialogueWindow();
346 
347 	~DialogueWindow();
348 
349 	//! \brief Unhides the display window and prepares to begin a new dialogue display
350 	void Initialize();
351 
352 	//! \brief Clears all GUI structures and hides the display window
353 	void Reset();
354 
355 	/** \brief Draws the dialogue window and all other visuals
356 	*** \param name A pointer to the name of the current speaker
357 	*** \param portrait A pointer to the portrait image of the current speaker
358 	***
359 	*** It is valid for either function argument to be NULL. This indicates
360 	*** that the window should omit drawing this information.
361 	**/
362 	void Draw(hoa_utils::ustring* name, hoa_video::StillImage* portrait);
363 
364 private:
365 	//! \brief A parchment paper image embedded within the dialogue window
366 	hoa_video::StillImage _parchment_image;
367 
368 	//! \brief The nameplate image used along with the dialogue box image
369 	hoa_video::StillImage _nameplate_image;
370 
371 	//! \brief The textbox used for rendering the dialogue text
372 	hoa_gui::TextBox _display_textbox;
373 
374 	//! \brief The option box used for rendering dialogue options where applicable
375 	hoa_gui::OptionBox _display_options;
376 }; // class DialogueWindow : public hoa_video::MenuWindow
377 
378 
379 /** ****************************************************************************
380 *** \brief Manages dialogue execution on maps
381 ***
382 *** The MapMode class creates an instance of this class to handle all dialogue
383 *** processing that occurs on maps. This includes containing the dialogue objects,
384 *** handling user input, processing of script events, and display timing of the
385 *** dialogue.
386 ***
387 *** \todo Add support so that the player may backtrack through lines in a
388 *** dialogue (without re-processing selected options or previous script events).
389 *** ***************************************************************************/
390 class DialogueSupervisor {
391 public:
392 	DialogueSupervisor();
393 
394 	~DialogueSupervisor();
395 
396 	//! \brief Updates the state of visual elements such as scrolling text
397 	void Update();
398 
399 	//! \brief Draws the dialogue window, text, portraits, and other related visuals to the screen
400 	void Draw();
401 
402 	/** \brief Adds a new dialogue to be managed by the supervisor
403 	*** \param dialogue Pointer to a MapDialogue object that was created with the new operator
404 	***
405 	*** The dialogue to add must have a unique dialogue ID so that it can be added to the map.
406 	*** If a dialogue with the same ID is already found within the map, then the dialogue will
407 	*** not be added. All dialogues that are successfully added will be later deleted when this
408 	*** class' destructor is invoked, so make sure you only pass in MapDialogue's that were
409 	*** created with the "new" operator.
410 	**/
411 	void AddDialogue(MapDialogue* dialogue);
412 
413 	/** \brief Adds a reference of a sprite to a dialogue
414 	*** \param dialogue_id The ID number of the dialogue that the sprite wishes to reference
415 	*** \param sprite_id The ID number of the sprite requesting to be referenced
416 	***
417 	*** Sprites reference a dialogue so that when the dialogue's status is updated (view count incremented, etc),
418 	*** the sprite will be informed that the dialogue has changed.
419 	**/
420 	void AddSpriteReference(uint32 dialogue_id, uint32 sprite_id);
421 
422 	/** \brief Prepares the dialogue manager to begin processing a new dialogue
423 	*** \param dialogue_id The id number of the dialogue to begin
424 	**/
425 	void BeginDialogue(uint32 dialogue_id);
426 
427 	/** \brief Prepares the dialogue manager to begin processing a new dialogue
428 	*** \param sprite A pointer to the map sprite that references the dialogue to begin processing
429 	***
430 	*** This function operates the same as the other BeginDialogue function with one exception. It also
431 	*** handles the calls necessary to update the map sprite. Specifically, making sure the sprite references a
432 	*** valid dialogue and increments its next dialogue pointer.
433 	**/
434 	void BeginDialogue(MapSprite* sprite);
435 
436 	//! \brief Immediately ends any dialogue that is taking place
437 	void EndDialogue();
438 
439 	/** \brief Returns a pointer to the MapDialogue with the requested ID value
440 	*** \param dialogue_id The identification number of the dialogue to retrieve
441 	*** \return A pointer to the dialogue requested, or NULL if no such dialogue was found
442 	**/
443 	MapDialogue* GetDialogue(uint32 dialogue_id);
444 
445 	/** \brief Called whenever a map dialogue object's status is updated
446 	*** \param dialogue_id The ID number of the dialogue which was updated
447 	***
448 	*** The purpose of this function is to inform all map sprites which reference this dialogue
449 	*** that it has been updated, and that they should update their associated data accordingly. For example,
450 	*** it allows the sprite to re-examine whether or not it references any dialogue that has not been read by the player.
451 	*** This function is called automatically by the class every time that this class ends a dialogue that is taking place.
452 	**/
453 	void AnnounceDialogueUpdate(uint32 dialogue_id);
454 
455 	//! \name Class member access functions
456 	//@{
GetDialogueState()457 	DIALOGUE_STATE GetDialogueState() const
458 		{ return _state; }
459 
GetCurrentDialogue()460 	MapDialogue* GetCurrentDialogue() const
461 		{ return _current_dialogue; }
462 
GetCurrentOptions()463 	MapDialogueOptions* GetCurrentOptions() const
464 		{ return _current_options; }
465 
GetLineTimer()466 	int32 GetLineTimer() const
467 		{ return _line_timer; }
468 	//@}
469 
470 private:
471 	//! \brief Contains all dialogues used in the map in a std::map structure. The dialogue ID is the map key
472 	std::map<uint32, MapDialogue*> _all_dialogues;
473 
474 	/** \brief A container that stores map sprite IDs that are referenced with map dialogues
475 	*** The map key is the MapDialogue ID and the vector of unsigned integers is each sprite that references the dialogue.
476 	***
477 	*** \note The reason why these references are stored in this class rather than in the MapDialogue class is because
478 	*** it would require that a MapDialogue object exist before a sprite could create a reference to it. This would require
479 	*** an unnecessary dependency about which class objects are created first in the map script which should be avoided.
480 	**/
481 	std::map<uint32, std::vector<uint32> > _sprite_references;
482 
483 	//! \brief Retains the current state of the dialogue
484 	DIALOGUE_STATE _state;
485 
486 	//! \brief A pointer to the current piece of dialogue that is active
487 	MapDialogue* _current_dialogue;
488 
489 	//! \brief A pointer to the current set of options for the active dialogue line
490 	MapDialogueOptions* _current_options;
491 
492 	//! \brief A timer that is employed for dialogues which have a display time limit
493 	int32 _line_timer;
494 
495 	//! \brief The window and associated GUI controls where the dialogue text and graphics should be displayed
496 	DialogueWindow _dialogue_window;
497 
498 	// ---------- Private methods ----------
499 
500 	//! \brief Updates the state of the dialogue when it is in the line state
501 	void _UpdateLine();
502 
503 	//! \brief Updates the state of the dialogue when it is in the option state
504 	void _UpdateOptions();
505 
506 	//! \brief Populates the dialogue window's option box with the current line option text
507 	void _ConstructOptions();
508 
509 	/** \brief Finishes the current dialogue line and moves the dialogue forward to the next line
510 	*** \param next_line The index of the next line to read in the dialogue
511 	*** This function will automatically end the dialogue if no line follows the current line
512 	**/
513 	void _FinishLine(int32 next_line);
514 
515 	//! \brief Restores sprites to their states before this dialogue started
516 	void _RestoreSprites();
517 }; // class DialogueSupervisor
518 
519 } // namespace private_map
520 
521 } // namespace hoa_map
522 
523 #endif // __MAP_DIALOGUE_HEADER__
524