summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/input_system.cpp8
-rw-r--r--src/message_system.cpp82
-rw-r--r--src/message_system.h26
-rw-r--r--src/renderer.cpp28
-rw-r--r--src/script_system.cpp4
5 files changed, 110 insertions, 38 deletions
diff --git a/src/input_system.cpp b/src/input_system.cpp index 5158724..6ee442a 100644 --- a/src/input_system.cpp +++ b/src/input_system.cpp
@@ -73,6 +73,14 @@ void InputSystem::tick(double dt) {
73 game_.getSystem<ScriptSystem>().runScript("default"); 73 game_.getSystem<ScriptSystem>().runScript("default");
74 } 74 }
75 } 75 }
76 } else if (e.key.keysym.sym == SDLK_LEFT) {
77 if (game_.getSystem<MessageSystem>().isChoiceActive()) {
78 game_.getSystem<MessageSystem>().selectFirstChoice();
79 }
80 } else if (e.key.keysym.sym == SDLK_RIGHT) {
81 if (game_.getSystem<MessageSystem>().isChoiceActive()) {
82 game_.getSystem<MessageSystem>().selectSecondChoice();
83 }
76 } 84 }
77 } else if (e.type == SDL_KEYUP && (e.key.keysym.sym == SDLK_LSHIFT || e.key.keysym.sym == SDLK_RSHIFT)) { 85 } else if (e.type == SDL_KEYUP && (e.key.keysym.sym == SDLK_LSHIFT || e.key.keysym.sym == SDLK_RSHIFT)) {
78 for (int spriteId : game_.getSprites()) { 86 for (int spriteId : game_.getSprites()) {
diff --git a/src/message_system.cpp b/src/message_system.cpp index a200abc..a969427 100644 --- a/src/message_system.cpp +++ b/src/message_system.cpp
@@ -39,10 +39,16 @@ void MessageSystem::tick(double dt) {
39 } 39 }
40 } 40 }
41 41
42 line.charsRevealed += CHARS_TO_REVEAL; 42 if (line.isChoice) {
43 if (line.charsRevealed > line.text.size()) {
44 line.charsRevealed = line.text.size(); 43 line.charsRevealed = line.text.size();
44 choiceSelection_ = 0;
45 } else {
46 line.charsRevealed += CHARS_TO_REVEAL;
47 if (line.charsRevealed > line.text.size()) {
48 line.charsRevealed = line.text.size();
49 }
45 } 50 }
51
46 advancedChars = true; 52 advancedChars = true;
47 break; 53 break;
48 } 54 }
@@ -50,14 +56,14 @@ void MessageSystem::tick(double dt) {
50 56
51 if (!advancedChars) { 57 if (!advancedChars) {
52 // If both lines are totally revealed, see if we can scroll up a line. 58 // If both lines are totally revealed, see if we can scroll up a line.
53 // This is doable as long as the next line isn't the sentinel value that 59 // This is doable as long as the last currently visible line doesn't
54 // means an A press is required. 60 // have the flag that means an A press is required.
55 if (!lines_.empty() && lines_.front() != "\f") { 61 if (!lines_.empty() && !linesToShow_.back().pause) {
56 if (linesToShow_.size() == 2) { 62 if (linesToShow_.size() == 2) {
57 linesToShow_.pop_front(); 63 linesToShow_.pop_front();
58 } 64 }
59 65
60 linesToShow_.push_back(MessageLine { .text = lines_.front() }); 66 linesToShow_.push_back(lines_.front());
61 lines_.pop_front(); 67 lines_.pop_front();
62 } else { 68 } else {
63 showNextArrow_ = true; 69 showNextArrow_ = true;
@@ -113,8 +119,8 @@ void MessageSystem::displayMessage(std::string_view msg, std::string speakerName
113 text.erase(0, 1); 119 text.erase(0, 1);
114 shouldAddBlank = false; 120 shouldAddBlank = false;
115 121
116 if (lines_.empty() || lines_.back() != "\f") { 122 if (!lines_.empty()) {
117 lines_.push_back("\f"); 123 lines_.back().pause = true;
118 } 124 }
119 } 125 }
120 126
@@ -139,13 +145,13 @@ void MessageSystem::displayMessage(std::string_view msg, std::string speakerName
139 } 145 }
140 146
141 if (nextWidth > MESSAGE_TEXT_WIDTH) { 147 if (nextWidth > MESSAGE_TEXT_WIDTH) {
142 lines_.push_back(curLine); 148 lines_.push_back({.text = curLine});
143 curLine = word; 149 curLine = word;
144 curWidth = wordWidth + game_.getFont().getCharacterWidth(' '); 150 curWidth = wordWidth + game_.getFont().getCharacterWidth(' ');
145 151
146 if (shouldAddBlank) { 152 if (shouldAddBlank) {
147 shouldAddBlank = false; 153 shouldAddBlank = false;
148 lines_.push_back("\f"); 154 lines_.back().pause = true;
149 } else { 155 } else {
150 shouldAddBlank = true; 156 shouldAddBlank = true;
151 } 157 }
@@ -160,52 +166,66 @@ void MessageSystem::displayMessage(std::string_view msg, std::string speakerName
160 firstWord = false; 166 firstWord = false;
161 } 167 }
162 168
163 lines_.push_back(curLine); 169 lines_.push_back({.text = curLine});
164 170
165 if (shouldAddBlank) { 171 if (shouldAddBlank) {
166 shouldAddBlank = false; 172 shouldAddBlank = false;
167 lines_.push_back("\f"); 173 lines_.back().pause = true;
168 } else { 174 } else {
169 shouldAddBlank = true; 175 shouldAddBlank = true;
170 } 176 }
171 } 177 }
172 178
173 if (lines_.empty() || lines_.back() != "\f") { 179 if (!lines_.empty()) {
174 lines_.push_back("\f"); 180 lines_.back().pause = true;
175 } 181 }
176 182
177 if (linesToShow_.empty()) { 183 if (linesToShow_.empty()) {
178 linesToShow_.push_back(MessageLine { .text = lines_.front() }); 184 linesToShow_.push_back(lines_.front());
179 lines_.pop_front(); 185 lines_.pop_front();
180 186
181 if (lines_.front() != "\f") { 187 if (!linesToShow_.back().pause) {
182 linesToShow_.push_back(MessageLine { .text = lines_.front() }); 188 linesToShow_.push_back(lines_.front());
183 lines_.pop_front(); 189 lines_.pop_front();
184 } 190 }
185 } 191 }
186} 192}
187 193
194void MessageSystem::showChoice(std::string choice1, std::string choice2) {
195 MessageLine line;
196 line.text = std::string(8, ' ') + choice1 + std::string(11, ' ') + choice2;
197 line.pause = true;
198 line.isChoice = true;
199 line.choicePos[0] = 8;
200 line.choicePos[1] = 8 + 11 + choice1.size();
201
202 lines_.push_back(line);
203}
204
188void MessageSystem::advanceText() { 205void MessageSystem::advanceText() {
206 // Cutscene must be active.
189 if (barsState_ != BarsState::Open) { 207 if (barsState_ != BarsState::Open) {
190 return; 208 return;
191 } 209 }
210 if (linesToShow_.empty()) {
211 return;
212 }
192 213
214 // We can only advance if all visible lines are fully revealed.
193 for (const MessageLine& line : linesToShow_) { 215 for (const MessageLine& line : linesToShow_) {
194 if (line.charsRevealed != line.text.size()) { 216 if (line.charsRevealed != line.text.size()) {
195 return; 217 return;
196 } 218 }
197 } 219 }
198 220
199 if (lines_.empty()) { 221 // If the last visible line doesn't have a pause, then the cutscene
200 linesToShow_.clear(); 222 // will automatically progress without us doing anything.
223 if (!linesToShow_.back().pause) {
201 return; 224 return;
202 } 225 }
203 226
204 if (lines_.front() != "\f") { 227 // Clear the current pause.
205 return; 228 linesToShow_.back().pause = false;
206 }
207
208 lines_.pop_front();
209 showNextArrow_ = false; 229 showNextArrow_ = false;
210 230
211 if (lines_.empty()) { 231 if (lines_.empty()) {
@@ -215,6 +235,20 @@ void MessageSystem::advanceText() {
215 } 235 }
216} 236}
217 237
238void MessageSystem::selectFirstChoice() {
239 if (isChoiceActive() && choiceSelection_ != 0) {
240 choiceSelection_ = 0;
241 game_.getMixer().playSound("../res/sfx/horizontal_menu.wav");
242 }
243}
244
245void MessageSystem::selectSecondChoice() {
246 if (isChoiceActive() && choiceSelection_ != 1) {
247 choiceSelection_ = 1;
248 game_.getMixer().playSound("../res/sfx/horizontal_menu.wav");
249 }
250}
251
218double MessageSystem::getCutsceneBarsProgress() const { 252double MessageSystem::getCutsceneBarsProgress() const {
219 switch (barsState_) { 253 switch (barsState_) {
220 case BarsState::Closed: return 0.0; 254 case BarsState::Closed: return 0.0;
diff --git a/src/message_system.h b/src/message_system.h index 155f9c6..ea27f14 100644 --- a/src/message_system.h +++ b/src/message_system.h
@@ -18,6 +18,14 @@ enum class SpeakerType {
18 Nonhuman 18 Nonhuman
19}; 19};
20 20
21struct MessageLine {
22 std::string text;
23 int charsRevealed = 0;
24 bool pause = false;
25 bool isChoice = false;
26 int choicePos[2] = {-1, -1};
27};
28
21class MessageSystem : public System { 29class MessageSystem : public System {
22public: 30public:
23 31
@@ -41,17 +49,18 @@ public:
41 std::string speakerName = "", 49 std::string speakerName = "",
42 SpeakerType speakerType = SpeakerType::None); 50 SpeakerType speakerType = SpeakerType::None);
43 51
52 void showChoice(std::string choice1, std::string choice2);
53
44 void advanceText(); 54 void advanceText();
45 55
56 void selectFirstChoice();
57
58 void selectSecondChoice();
59
46 // Info 60 // Info
47 61
48 double getCutsceneBarsProgress() const; 62 double getCutsceneBarsProgress() const;
49 63
50 struct MessageLine {
51 std::string text;
52 int charsRevealed = 0;
53 };
54
55 const std::list<MessageLine>& getLines() const { return linesToShow_; } 64 const std::list<MessageLine>& getLines() const { return linesToShow_; }
56 65
57 bool isMessageActive() const { return !linesToShow_.empty(); } 66 bool isMessageActive() const { return !linesToShow_.empty(); }
@@ -62,6 +71,10 @@ public:
62 71
63 int getNextArrowBob() const { return nextArrowBobPos_; } 72 int getNextArrowBob() const { return nextArrowBobPos_; }
64 73
74 bool isChoiceActive() const { return isMessageActive() && linesToShow_.back().isChoice; }
75
76 int getChoiceSelection() const { return choiceSelection_; }
77
65private: 78private:
66 79
67 enum class BarsState { 80 enum class BarsState {
@@ -77,13 +90,14 @@ private:
77 double length_ = 1000.0/8; 90 double length_ = 1000.0/8;
78 SpeakerType speaker_ = SpeakerType::None; 91 SpeakerType speaker_ = SpeakerType::None;
79 std::string speakerName_; 92 std::string speakerName_;
80 std::list<std::string> lines_; 93 std::list<MessageLine> lines_;
81 std::list<MessageLine> linesToShow_; 94 std::list<MessageLine> linesToShow_;
82 Timer textAdvTimer_ { 15 }; 95 Timer textAdvTimer_ { 15 };
83 bool showNextArrow_ = false; 96 bool showNextArrow_ = false;
84 int nextArrowBobPos_ = 0; 97 int nextArrowBobPos_ = 0;
85 bool nextArrowBobDown_ = true; 98 bool nextArrowBobDown_ = true;
86 Timer nextArrowBobTimer_ { 125 }; 99 Timer nextArrowBobTimer_ { 125 };
100 int choiceSelection_ = 0;
87}; 101};
88 102
89#endif /* end of include guard: MESSAGE_SYSTEM_H_DE10D011 */ 103#endif /* end of include guard: MESSAGE_SYSTEM_H_DE10D011 */
diff --git a/src/renderer.cpp b/src/renderer.cpp index db5daed..0c70ef5 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp
@@ -194,7 +194,7 @@ void Renderer::render(Game& game) {
194 } 194 }
195 195
196 int lineIndex = 0; 196 int lineIndex = 0;
197 for (const MessageSystem::MessageLine& line : game.getSystem<MessageSystem>().getLines()) { 197 for (const MessageLine& line : game.getSystem<MessageSystem>().getLines()) {
198 if (messageLines_[lineIndex].line != line.text) { 198 if (messageLines_[lineIndex].line != line.text) {
199 renderMessageLine(messageLines_[lineIndex], line.text, game); 199 renderMessageLine(messageLines_[lineIndex], line.text, game);
200 } 200 }
@@ -223,13 +223,27 @@ void Renderer::render(Game& game) {
223 advMsgArrowTex_ = loadImageFromFile("../res/advance_text_arrow.png"); 223 advMsgArrowTex_ = loadImageFromFile("../res/advance_text_arrow.png");
224 } 224 }
225 225
226 SDL_Rect destRect { 226 if (game.getSystem<MessageSystem>().isChoiceActive()) {
227 216, 227 int selection = game.getSystem<MessageSystem>().getChoiceSelection();
228 138 + game.getSystem<MessageSystem>().getNextArrowBob(), 228 int charIndex = game.getSystem<MessageSystem>().getLines().back().choicePos[selection];
229 16, 229 int baseX = messageLines_[1].charIndexToWidth[charIndex];
230 16 };
231 230
232 SDL_RenderCopy(ren_.get(), textures_.at(advMsgArrowTex_).get(), nullptr, &destRect); 231 SDL_Rect destRect {
232 18 + baseX - game.getSystem<MessageSystem>().getNextArrowBob()-16+3,
233 141,
234 16,
235 16};
236
237 SDL_RenderCopyEx(ren_.get(), textures_.at(advMsgArrowTex_).get(), nullptr, &destRect, -90, nullptr, SDL_FLIP_NONE);
238 } else {
239 SDL_Rect destRect {
240 216,
241 138 + game.getSystem<MessageSystem>().getNextArrowBob(),
242 16,
243 16 };
244
245 SDL_RenderCopy(ren_.get(), textures_.at(advMsgArrowTex_).get(), nullptr, &destRect);
246 }
233 } 247 }
234 } 248 }
235 } 249 }
diff --git a/src/script_system.cpp b/src/script_system.cpp index 0fa0c1b..21d4090 100644 --- a/src/script_system.cpp +++ b/src/script_system.cpp
@@ -21,8 +21,10 @@ ScriptSystem::ScriptSystem(Game& game) : game_(game) {
21 engine_.new_usertype<MessageSystem>( 21 engine_.new_usertype<MessageSystem>(
22 "message", 22 "message",
23 "displayMessage", &MessageSystem::displayMessage, 23 "displayMessage", &MessageSystem::displayMessage,
24 "showChoice", &MessageSystem::showChoice,
24 "hideCutsceneBars", &MessageSystem::hideCutsceneBars, 25 "hideCutsceneBars", &MessageSystem::hideCutsceneBars,
25 "isMessageActive", sol::property(&MessageSystem::isMessageActive)); 26 "isMessageActive", sol::property(&MessageSystem::isMessageActive),
27 "getChoiceSelection", &MessageSystem::getChoiceSelection);
26 28
27 engine_.new_usertype<AnimationSystem>( 29 engine_.new_usertype<AnimationSystem>(
28 "animation", 30 "animation",