1 /*
2 * This file is part of EasyRPG Player.
3 *
4 * EasyRPG Player 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 * EasyRPG Player 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 EasyRPG Player. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #ifndef EP_GAME_SYSTEM_H
19 #define EP_GAME_SYSTEM_H
20
21 // Headers
22 #include <string>
23 #include <map>
24 #include <lcf/rpg/animation.h>
25 #include <lcf/rpg/music.h>
26 #include <lcf/rpg/sound.h>
27 #include <lcf/rpg/system.h>
28 #include <lcf/rpg/savesystem.h>
29 #include "color.h"
30 #include "transition.h"
31 #include "string_view.h"
32 #include "async_handler.h"
33 #include "filesystem_stream.h"
34
35 struct FileRequestResult;
36
37 /**
38 * Game System namespace.
39 */
40 class Game_System {
41 public:
42 enum sys_bgm {
43 BGM_Battle,
44 BGM_Victory,
45 BGM_Inn,
46 BGM_Boat,
47 BGM_Ship,
48 BGM_Airship,
49 BGM_GameOver,
50
51 BGM_Count
52 };
53
54 enum sys_sfx {
55 SFX_Cursor,
56 SFX_Decision,
57 SFX_Cancel,
58 SFX_Buzzer,
59 SFX_BeginBattle,
60 SFX_Escape,
61 SFX_EnemyAttacks,
62 SFX_EnemyDamage,
63 SFX_AllyDamage,
64 SFX_Evasion,
65 SFX_EnemyKill,
66 SFX_UseItem,
67
68 SFX_Count
69 };
70
71 enum sys_transition {
72 Transition_TeleportErase,
73 Transition_TeleportShow,
74 Transition_BeginBattleErase,
75 Transition_BeginBattleShow,
76 Transition_EndBattleErase,
77 Transition_EndBattleShow,
78 Transition_Count
79 };
80
81 using AtbMode = lcf::rpg::SaveSystem::AtbMode;
82
83 class Target {
84 public:
85 int map_id;
86 int x;
87 int y;
88 int switch_id;
Target()89 Target()
90 : map_id(0),
91 x(0),
92 y(0),
93 switch_id(0)
94 {}
Target(int map_id,int x,int y,int switch_id)95 Target(int map_id, int x, int y, int switch_id)
96 : map_id(map_id),
97 x(x),
98 y(y),
99 switch_id(switch_id)
100 {}
101 };
102
103 /**
104 * Initializes Game System.
105 */
106 Game_System();
107
108 /** Initialize from save game */
109 void SetupFromSave(lcf::rpg::SaveSystem save);
110
111 /** @return save game data */
112 const lcf::rpg::SaveSystem& GetSaveData() const;
113
114 /**
115 * Plays a Music.
116 *
117 * @param bgm music data.
118 */
119 void BgmPlay(lcf::rpg::Music const& bgm);
120
121 /**
122 * Stops playing music.
123 */
124 void BgmStop();
125
126 /**
127 * Fades out the current BGM
128 *
129 * @param duration Duration in ms
130 * @param clear_current_music If true then current_music is set to (OFF). Only needed on starting a new game.
131 */
132 void BgmFade(int duration, bool clear_current_music = false);
133
134 /**
135 * Plays a Sound.
136 *
137 * @param se sound data.
138 * @param stop_sounds If true stops all SEs when playing (OFF)/(...). Only used by the interpreter.
139 */
140 void SePlay(const lcf::rpg::Sound& se, bool stop_sounds = false);
141
142 /**
143 * Plays the first valid sound in the animation.
144 *
145 * @param animation animation data.
146 */
147 void SePlay(const lcf::rpg::Animation& animation);
148
149 /** @return system graphic filename. */
150 StringView GetSystemName();
151
152 /** @return message stretch style */
153 lcf::rpg::System::Stretch GetMessageStretch();
154
155 /** @return system font */
156 lcf::rpg::System::Font GetFontId();
157
158 /**
159 * Sets the system graphic.
160 *
161 * @param system_name new system name.
162 * @param message_stretch message stretch style
163 * @param font_id The system font to use.
164 */
165 void SetSystemGraphic(const std::string& system_name,
166 lcf::rpg::System::Stretch stretch,
167 lcf::rpg::System::Font font);
168
169 /** Resets the system graphic to the default value. */
170 void ResetSystemGraphic();
171
172 /** @return the system2 graphic name */
173 StringView GetSystem2Name();
174
175 /** @return true if the game has a configured system graphic */
176 bool HasSystemGraphic();
177
178 /** @return true if the game has a configured system2 graphic */
179 bool HasSystem2Graphic();
180
181 /**
182 * Gets the system music.
183 *
184 * @param which which "context" to set the music for.
185 * @return the music.
186 */
187 const lcf::rpg::Music& GetSystemBGM(int which);
188
189 /**
190 * Sets the system music.
191 *
192 * @param which which "context" to set the music for.
193 * @param bgm the music.
194 */
195 void SetSystemBGM(int which, lcf::rpg::Music bgm);
196
197 /**
198 * Gets the system sound effects.
199 *
200 * @param which which "context" to set the music for.
201 * @return the sound.
202 */
203 const lcf::rpg::Sound& GetSystemSE(int which);
204
205 /**
206 * Sets a system sound effect.
207 *
208 * @param which which "context" to set the effect for.
209 * @param sfx the sound effect.
210 */
211 void SetSystemSE(int which, lcf::rpg::Sound sfx);
212
213 /**
214 * Gets the system transitions.
215 *
216 * @param which which "context" to get the transition for.
217 * @return the transition.
218 */
219 Transition::Type GetTransition(int which);
220
221 /**
222 * Sets the system transitions.
223 *
224 * @param which which "context" to set the transition for.
225 * @param transition the transition.
226 */
227 void SetTransition(int which, int transition);
228
229 /**
230 * Sets a teleport target.
231 *
232 * @param map_id the destination map.
233 * @param x the destination X coordinate.
234 * @param y the destination Y coordinate.
235 * @param switch_id the switch ID.
236 */
237 void AddTeleportTarget(int map_id, int x, int y, int switch_id);
238
239 /**
240 * Removes a teleport target.
241 *
242 * @param map_id the map for which the target was used.
243 */
244 void RemoveTeleportTarget(int map_id);
245
246 /**
247 * Finds a teleport target.
248 *
249 * @param map_id the map for which to obtain the target.
250 * @return: pointer to a Target structure, or NULL.
251 */
252 Target* GetTeleportTarget(int map_id);
253
254 /**
255 * Sets an escape target.
256 *
257 * @param map_id the destination map.
258 * @param x the destination X coordinate.
259 * @param y the destination Y coordinate.
260 * @param switch_id the switch ID.
261 */
262 void SetEscapeTarget(int map_id, int x, int y, int switch_id);
263
264 /**
265 * Finds an escape target.
266 *
267 * @return pointer to a Target structure, or NULL.
268 */
269 Target* GetEscapeTarget();
270
271 bool GetAllowTeleport();
272 void SetAllowTeleport(bool allow);
273 bool GetAllowEscape();
274 void SetAllowEscape(bool allow);
275 bool GetAllowSave();
276 void SetAllowSave(bool allow);
277 bool GetAllowMenu();
278 void SetAllowMenu(bool allow);
279
280 int GetSaveCount();
281 void IncSaveCount();
282
283 const lcf::rpg::Music& GetCurrentBGM();
284 void MemorizeBGM();
285 void PlayMemorizedBGM();
286
287 void ReloadSystemGraphic();
288
289 /**
290 * Determines if the requested file is supposed to Stop BGM/SE play.
291 * For empty string and (OFF) this is always the case.
292 * Many RPG Maker translation overtranslated the (OFF) reserved string,
293 * e.g. (Brak) and (Kein Sound).
294 * A file is detected as "Stop BGM/SE" when the file is missing in the
295 * filesystem and the name is wrapped in (), otherwise it is a regular
296 * file.
297 *
298 * @param name File to find
299 * @param find_func Find function to use (OpenSound or OpenMusic)
300 * @param found_stream Handle to the file to play
301 * @return true when the file is supposed to Stop playback.
302 * false otherwise and a handle to the file is returned in found_stream
303 */
304 static bool IsStopFilename(StringView name, Filesystem_Stream::InputStream (*find_func) (StringView), Filesystem_Stream::InputStream& found_stream);
305
306 static bool IsStopMusicFilename(StringView name, Filesystem_Stream::InputStream& found_stream);
307 static bool IsStopMusicFilename(StringView name);
308 static bool IsStopSoundFilename(StringView name, Filesystem_Stream::InputStream& found_stream);
309 static bool IsStopSoundFilename(StringView name);
310
311 /** @return current atb mode */
312 AtbMode GetAtbMode();
313
314 /** Set the atb mode */
315 void SetAtbMode(AtbMode m);
316
317 /** Flip the atb mode to the opposite */
318 void ToggleAtbMode();
319
320 /** @return Music playing before battle started */
321 const lcf::rpg::Music& GetBeforeBattleMusic();
322
323 /**
324 * Set before battle music
325 *
326 * @param music music to set
327 */
328 void SetBeforeBattleMusic(lcf::rpg::Music music);
329
330 /** @return Music playing before boarded vehicle */
331 const lcf::rpg::Music& GetBeforeVehicleMusic();
332
333 /**
334 * Set before vehicle music
335 *
336 * @param name name of music to set
337 */
338 void SetBeforeVehicleMusic(lcf::rpg::Music music);
339
340 /** @return save slot used for last save game */
341 int GetSaveSlot();
342
343 /**
344 * Set the save slot used when saving the game
345 *
346 * @param slot the slot number
347 */
348 void SetSaveSlot(int slot);
349
350 /** @return RPG_RT compatible frame counter */
351 int GetFrameCounter();
352
353 /** Reset the RPG_RT compatible frame counter to 0 */
354 void ResetFrameCounter();
355
356 /** Increment the RPG_RT compatible frame counter */
357 void IncFrameCounter();
358
359 /** Get the system background color */
360 Color GetBackgroundColor();
361
362 /** @return true if battle animations are flipped if attacked from behind */
363 bool GetInvertAnimations();
364
365 /** Reset the face graphic. */
366 void ClearMessageFace();
367
368 /** @return name of file that contains the face. */
369 StringView GetMessageFaceName();
370
371 /**
372 * Set FaceSet graphic file containing the face.
373 *
374 * @param face FaceSet file
375 */
376 void SetMessageFaceName(const std::string& face);
377
378 /**
379 * Gets index of the face to display.
380 *
381 * @return face index
382 */
383 int GetMessageFaceIndex();
384
385 /**
386 * Sets index of the face to display
387 *
388 * @param index face index
389 */
390 void SetMessageFaceIndex(int index);
391
392 /**
393 * Whether to mirror the face.
394 *
395 * @return true: flipped, false: normal
396 */
397 bool IsMessageFaceFlipped();
398
399 /**
400 * Sets whether to mirror the face.
401 *
402 * @param flipped Enable/Disable mirroring
403 */
404 void SetMessageFaceFlipped(bool flipped);
405
406 /**
407 * If the face shall be placed right.
408 *
409 * @return true: right side, false: left side
410 */
411 bool IsMessageFaceRightPosition();
412
413 /**
414 * Sets the face position.
415 *
416 * @param right true: right side, false: left side
417 */
418 void SetMessageFaceRightPosition(bool right);
419
420 /**
421 * Gets if the message background is transparent.
422 *
423 * @return message transparent
424 */
425 bool IsMessageTransparent();
426
427 /**
428 * Sets message box background state
429 *
430 * @param transparent true: transparent, false: opaque
431 */
432 void SetMessageTransparent(bool transparent);
433
434 /**
435 * Gets the message box position.
436 *
437 * @return 0: top, 1: middle, 2: bottom
438 */
439 int GetMessagePosition();
440
441 /**
442 * Sets the message box position.
443 * Depending on the player position this value is ignored to prevent overlap.
444 * (see SetPositionFixed)
445 *
446 * @param new_position 0: top, 1: middle, 2: bottom
447 */
448 void SetMessagePosition(int new_position);
449
450 /**
451 * Gets whether message box position is fixed.
452 * In that case the hero can be obstructed.
453 *
454 * @return fixed
455 */
456 bool IsMessagePositionFixed();
457
458 /**
459 * Sets if message box is moved to avoid obscuring the player.
460 *
461 * @param fixed position fixed
462 */
463 void SetMessagePositionFixed(bool fixed);
464
465 /**
466 * Gets if parallel events continue while message box is displayed.
467 *
468 * @return whether events continue
469 */
470 bool GetMessageContinueEvents();
471
472 /**
473 * Sets if parallel events continue while message box is displayed.
474 *
475 * @param continue_events continue events
476 */
477 void SetMessageContinueEvents(bool continue_events);
478
479 /**
480 * Sets the RpgRt event message active flag.
481 *
482 * @param value what to set the flag to
483 */
484 void SetMessageEventMessageActive(bool value);
485
486 /** @return the RpgRt event message active flag */
487 bool GetMessageEventMessageActive();
488 private:
489 void OnBgmReady(FileRequestResult* result);
490 void OnBgmInelukiReady(FileRequestResult* result);
491 void OnSeReady(FileRequestResult* result, lcf::rpg::Sound se, bool stop_sounds);
492 void OnChangeSystemGraphicReady(FileRequestResult* result);
493 private:
494 lcf::rpg::SaveSystem data;
495 const lcf::rpg::System* dbsys;
496 FileRequestBinding music_request_id;
497 FileRequestBinding system_request_id;
498 std::map<std::string, FileRequestBinding> se_request_ids;
499 Color bg_color = Color{ 0, 0, 0, 255 };
500 bool bgm_pending = false;
501 };
502
HasSystemGraphic()503 inline bool Game_System::HasSystemGraphic() {
504 return !GetSystemName().empty();
505 }
506
HasSystem2Graphic()507 inline bool Game_System::HasSystem2Graphic() {
508 return !GetSystem2Name().empty();
509 }
510
IsStopMusicFilename(StringView name)511 inline bool Game_System::IsStopMusicFilename(StringView name) {
512 Filesystem_Stream::InputStream s;
513 return IsStopMusicFilename(name, s);
514 }
515
IsStopSoundFilename(StringView name)516 inline bool Game_System::IsStopSoundFilename(StringView name) {
517 Filesystem_Stream::InputStream s;
518 return IsStopSoundFilename(name, s);
519 }
520
ClearMessageFace()521 inline void Game_System::ClearMessageFace() {
522 SetMessageFaceName("");
523 SetMessageFaceIndex(0);
524 }
525
GetMessageFaceName()526 inline StringView Game_System::GetMessageFaceName() {
527 return data.face_name;
528 }
529
SetMessageFaceName(const std::string & face)530 inline void Game_System::SetMessageFaceName(const std::string& face) {
531 data.face_name = face;
532 }
533
GetMessageFaceIndex()534 inline int Game_System::GetMessageFaceIndex() {
535 return data.face_id;
536 }
537
SetMessageFaceIndex(int index)538 inline void Game_System::SetMessageFaceIndex(int index) {
539 data.face_id = index;
540 }
541
IsMessageFaceFlipped()542 inline bool Game_System::IsMessageFaceFlipped() {
543 return data.face_flip;
544 }
545
SetMessageFaceFlipped(bool flipped)546 inline void Game_System::SetMessageFaceFlipped(bool flipped) {
547 data.face_flip = flipped;
548 }
549
IsMessageFaceRightPosition()550 inline bool Game_System::IsMessageFaceRightPosition() {
551 return data.face_right;
552 }
553
SetMessageFaceRightPosition(bool right)554 inline void Game_System::SetMessageFaceRightPosition(bool right) {
555 data.face_right = right;
556 }
557
SetMessageTransparent(bool transparent)558 inline void Game_System::SetMessageTransparent(bool transparent) {
559 data.message_transparent = transparent;
560 }
561
GetMessagePosition()562 inline int Game_System::GetMessagePosition() {
563 return data.message_position;
564 }
565
SetMessagePosition(int new_position)566 inline void Game_System::SetMessagePosition(int new_position) {
567 data.message_position = new_position;
568 }
569
IsMessagePositionFixed()570 inline bool Game_System::IsMessagePositionFixed() {
571 return !data.message_prevent_overlap;
572 }
573
SetMessagePositionFixed(bool fixed)574 inline void Game_System::SetMessagePositionFixed(bool fixed) {
575 data.message_prevent_overlap = !fixed;
576 }
577
GetMessageContinueEvents()578 inline bool Game_System::GetMessageContinueEvents() {
579 return data.message_continue_events;
580 }
581
SetMessageContinueEvents(bool continue_events)582 inline void Game_System::SetMessageContinueEvents(bool continue_events) {
583 data.message_continue_events = continue_events;
584 }
585
SetMessageEventMessageActive(bool value)586 inline void Game_System::SetMessageEventMessageActive(bool value) {
587 data.event_message_active = value;
588 }
589
GetMessageEventMessageActive()590 inline bool Game_System::GetMessageEventMessageActive() {
591 return data.event_message_active;
592 }
593
GetAtbMode()594 inline Game_System::AtbMode Game_System::GetAtbMode() {
595 return static_cast<Game_System::AtbMode>(data.atb_mode);
596 }
597
SetAtbMode(AtbMode m)598 inline void Game_System::SetAtbMode(AtbMode m) {
599 data.atb_mode = m;
600 }
601
ToggleAtbMode()602 inline void Game_System::ToggleAtbMode() {
603 data.atb_mode = !data.atb_mode;
604 }
605
GetBeforeBattleMusic()606 inline const lcf::rpg::Music& Game_System::GetBeforeBattleMusic() {
607 return data.before_battle_music;
608 }
609
SetBeforeBattleMusic(lcf::rpg::Music music)610 inline void Game_System::SetBeforeBattleMusic(lcf::rpg::Music music) {
611 data.before_battle_music = std::move(music);
612 }
613
GetBeforeVehicleMusic()614 inline const lcf::rpg::Music& Game_System::GetBeforeVehicleMusic() {
615 return data.before_vehicle_music;
616 }
617
SetBeforeVehicleMusic(lcf::rpg::Music music)618 inline void Game_System::SetBeforeVehicleMusic(lcf::rpg::Music music) {
619 data.before_vehicle_music = std::move(music);
620 }
621
GetSaveSlot()622 inline int Game_System::GetSaveSlot() {
623 return data.save_slot;
624 }
625
SetSaveSlot(int slot)626 inline void Game_System::SetSaveSlot(int slot) {
627 data.save_slot = slot;
628 }
629
GetFrameCounter()630 inline int Game_System::GetFrameCounter() {
631 return data.frame_count;
632 }
633
ResetFrameCounter()634 inline void Game_System::ResetFrameCounter() {
635 data.frame_count = 0;
636 }
637
IncFrameCounter()638 inline void Game_System::IncFrameCounter() {
639 ++data.frame_count;
640 }
641
GetBackgroundColor()642 inline Color Game_System::GetBackgroundColor() {
643 return bg_color;
644 }
645
GetInvertAnimations()646 inline bool Game_System::GetInvertAnimations() {
647 return dbsys->invert_animations;
648 }
649
GetSaveCount()650 inline int Game_System::GetSaveCount() {
651 return data.save_count;
652 }
653
IncSaveCount()654 inline void Game_System::IncSaveCount() {
655 ++data.save_count;
656 }
657
GetSystem2Name()658 inline StringView Game_System::GetSystem2Name() {
659 return dbsys->system2_name;
660 }
661
GetCurrentBGM()662 inline const lcf::rpg::Music& Game_System::GetCurrentBGM() {
663 return data.current_music;
664 }
665
MemorizeBGM()666 inline void Game_System::MemorizeBGM() {
667 data.stored_music = data.current_music;
668 }
669
PlayMemorizedBGM()670 inline void Game_System::PlayMemorizedBGM() {
671 BgmPlay(data.stored_music);
672 }
673
SetAllowTeleport(bool allow)674 inline void Game_System::SetAllowTeleport(bool allow) {
675 data.teleport_allowed = allow;
676 }
677
GetAllowTeleport()678 inline bool Game_System::GetAllowTeleport() {
679 return data.teleport_allowed;
680 }
681
SetAllowEscape(bool allow)682 inline void Game_System::SetAllowEscape(bool allow) {
683 data.escape_allowed = allow;
684 }
685
GetAllowEscape()686 inline bool Game_System::GetAllowEscape() {
687 return data.escape_allowed;
688 }
689
SetAllowSave(bool allow)690 inline void Game_System::SetAllowSave(bool allow) {
691 data.save_allowed = allow;
692 }
693
GetAllowSave()694 inline bool Game_System::GetAllowSave() {
695 return data.save_allowed;
696 }
697
SetAllowMenu(bool allow)698 inline void Game_System::SetAllowMenu(bool allow) {
699 data.menu_allowed = allow;
700 }
701
GetAllowMenu()702 inline bool Game_System::GetAllowMenu() {
703 return data.menu_allowed;
704 }
705
706
707 #endif
708