File: ConversationPanel.h

package info (click to toggle)
endless-sky 0.10.16-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 414,608 kB
  • sloc: cpp: 73,435; python: 893; xml: 666; sh: 271; makefile: 28
file content (166 lines) | stat: -rw-r--r-- 5,423 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
/* ConversationPanel.h
Copyright (c) 2014 by Michael Zahniser

Endless Sky is free software: you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later version.

Endless Sky is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with
this program. If not, see <https://www.gnu.org/licenses/>.
*/

#pragma once

#include "Panel.h"

#include "text/WrappedText.h"

#include <functional>
#include <list>
#include <map>
#include <memory>
#include <string>
#include <vector>

class Color;
class Conversation;
class Mission;
class PlayerInfo;
class Point;
class Ship;
class Sprite;
class System;



// User interface panel that displays a conversation, allowing you to make
// choices. If a callback function is given, that function will be called when
// the panel closes, to report the outcome of the conversation.
class ConversationPanel : public Panel {
public:
	ConversationPanel(PlayerInfo &player, const Conversation &conversation,
		const Mission *caller = nullptr, const System *system = nullptr,
		const std::shared_ptr<Ship> &ship = nullptr, bool useTransactions = false);

	virtual ~ConversationPanel() override;

	template<class T>
	void SetCallback(T *t, void (T::*fun)(int));
	void SetCallback(std::function<void(int)> fun);

	// Draw this panel.
	virtual void Draw() override;


protected:
	// Event handlers.
	virtual bool KeyDown(SDL_Keycode key, Uint16 mod, const Command &command, bool isNewPress) override;
	virtual bool Drag(double dx, double dy) override;
	virtual bool Scroll(double dx, double dy) override;
	virtual bool Hover(int x, int y) override;


private:
	// Go to the given conversation node. If a choice index is given, include
	// the text of that choice in the conversation history.
	void Goto(int index, int selectedChoice = -1);
	// Exit this panel and do whatever needs to happen next, which includes
	// possibly activating a callback function and, if docked with an NPC,
	// destroying it or showing the BoardingPanel (if it is hostile).
	void Exit();
	// Handle mouse click on the "ok," "done," or a conversation choice.
	void ClickName(int side);
	void ClickChoice(int index);
	// Given an index into the list of displayed choices (i.e. not including
	// conditionally-skipped choices), return its "raw index" in the
	// conversation (i.e. including conditionally-skipped choices)
	int MapChoice(int n) const;


private:
	// Text to be displayed is broken up into chunks (paragraphs). Paragraphs
	// may also include "scene" images.
	class Paragraph {
	public:
		explicit Paragraph(const std::string &text, const Sprite *scene = nullptr, bool isFirst = false);

		// Get the height of this paragraph.
		int Height() const;
		// Get the "center point" of this paragraph. This is for drawing a
		// highlight under paragraphs that represent choices.
		Point Center() const;
		// Draw this paragraph at the given point, and return the point that the
		// next paragraph below this one should be drawn at.
		Point Draw(Point point, const Color &color) const;

	private:
		const Sprite *scene = nullptr;
		WrappedText wrap;
		// Special case: if this is the very first paragraph and it begins with
		// a "scene" image, there is no need for padding above the image.
		bool isFirst = false;
	};


private:
	// Reference to the player, to apply any changes to them.
	PlayerInfo &player;

	// A pointer to the mission that called this conversation.
	const Mission *caller = nullptr;

	// Should we use a PlayerInfo transaction to prevent save-load glitches?
	bool useTransactions = false;

	// The conversation we are displaying.
	const Conversation &conversation;
	// All conversations start with node 0.
	int node = 0;
	// This function should be called with the conversation outcome.
	std::function<void(int)> callback = nullptr;

	// Current scroll position.
	double scroll = 0.;

	// The "history" of the conversation up to this point:
	std::list<Paragraph> text;
	// The current choices being presented to you, and their indices:
	std::list<std::pair<Paragraph, int>> choices;
	int choice = 0;
	// Flicker time, set if the player enters invalid input for a pilot's name.
	int flickerTime = 0;

	// Text entry fields for changing the player's name.
	std::string firstName;
	std::string lastName;
	// Text substitutions (player's name, and ship name).
	std::map<std::string, std::string> subs;

	// Maximum scroll amount.
	double maxScroll = 0.;

	// If specified, this is a star system to display with a special big pointer
	// when the player brings up the map. (Typically a mission destination.)
	const System *system;
	// If specified, this is a pointer to the ship that this conversation
	// acts upon (e.g. the ship failing a "flight check", or the NPC you
	// have boarded).
	std::shared_ptr<Ship> ship;

	// Whether the mouse moved in the current frame.
	bool isHovering = false;
	Point hoverPoint;
};



// Allow the callback function to be a member of any class.
template<class T>
void ConversationPanel::SetCallback(T *t, void (T::*fun)(int))
{
	callback = std::bind(fun, t, std::placeholders::_1);
}