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_CHARACTER_H
19 #define EP_GAME_CHARACTER_H
20 
21 // Headers
22 #include <string>
23 #include "color.h"
24 #include "flash.h"
25 #include <lcf/rpg/moveroute.h>
26 #include <lcf/rpg/eventpage.h>
27 #include <lcf/rpg/savemapeventbase.h>
28 #include "utils.h"
29 
30 /**
31  * Game_Character class.
32  */
33 class Game_Character {
34 public:
35 	using AnimType = lcf::rpg::EventPage::AnimType;
36 
37 	enum Type {
38 		Event,
39 		Player,
40 		Vehicle
41 	};
42 
43 	static StringView TypeToStr(Type t);
44 
45 	/**
46 	 * Destructor.
47 	 */
48 	virtual ~Game_Character();
49 
50 	/** @return the type of character this is */
51 	Type GetType() const;
52 
53 	/**
54 	 * Gets x position in tiles.
55 	 *
56 	 * @return x position.
57 	 */
58 	int GetX() const;
59 
60 	/**
61 	 * Sets x position in tiles.
62 	 *
63 	 * @param new_x new x position.
64 	 */
65 	void SetX(int new_x);
66 
67 	/**
68 	 * Gets y position in tiles.
69 	 *
70 	 * @return y position.
71 	 */
72 	int GetY() const;
73 
74 	/**
75 	 * Sets y position in tiles.
76 	 *
77 	 * @param new_y new y position.
78 	 */
79 	void SetY(int new_y);
80 
81 	/**
82 	 * Gets the map id the character was inititialy on.
83 	 *
84 	 * @return map id.
85 	 */
86 	int GetMapId() const;
87 
88 	/**
89 	 * Sets the map id the character was inititialy on.
90 	 *
91 	 * @param new_map_id New map id of character.
92 	 */
93 	void SetMapId(int new_map_id);
94 
95 	/**
96 	 * Gets character's movement direction.
97 	 *
98 	 * @return current front direction.
99 	 */
100 	int GetDirection() const;
101 
102 	/**
103 	 * Sets character's movement direction.
104 	 *
105 	 * @param new_direction New current front direction.
106 	 */
107 	void SetDirection(int new_direction);
108 
109 	/**
110 	 * Gets character's visible facing direction.
111 	 *
112 	 * @return direction of the sprite.
113 	 */
114 	int GetFacing() const;
115 
116 	/**
117 	 * Sets character's visible facing direction.
118 	 *
119 	 * @param new_direction New facing direction.
120 	 */
121 	void SetFacing(int new_direction);
122 
123 	/**
124 	 * Gets whether facing is locked.
125 	 *
126 	 * @return facing locked
127 	 */
128 	bool IsFacingLocked() const;
129 
130 	/**
131 	 * Enables or disables locked facing direction.
132 	 *
133 	 * @param locked true: locked, false: unlocked.
134 	 */
135 	void SetFacingLocked(bool locked);
136 
137 	/**
138 	 * Gets the event layer (top, same, below).
139 	 *
140 	 * @return event layer
141 	 */
142 	int GetLayer() const;
143 
144 	/**
145 	 * Sets the event layer (top, same, below).
146 	 *
147 	 * @param new_layer New event layer
148 	 */
149 	void SetLayer(int new_layer);
150 
151 	/**
152 	 * Gets whether other events can be in the same tile.
153 	 *
154 	 * @return whether event overlap is forbidden.
155 	 */
156 	bool IsOverlapForbidden() const;
157 
158 	/**
159 	 * Gets character movement speed.
160 	 *
161 	 * @return character movement speed
162 	 */
163 	int GetMoveSpeed() const;
164 
165 	/**
166 	 * Sets character movement speed.
167 	 *
168 	 * @param speed new movement speed
169 	 */
170 	void SetMoveSpeed(int speed);
171 
172 	/**
173 	 * Gets character movement frequency.
174 	 *
175 	 * @return character movement frequency
176 	 */
177 	int GetMoveFrequency() const;
178 
179 	/**
180 	 * Sets character movement frequency.
181 	 *
182 	 * @param frequency new character movement frequency
183 	 */
184 	void SetMoveFrequency(int frequency);
185 
186 	/**
187 	 * Returns the custom move route assigned via a MoveEvent.
188 	 *
189 	 * @return custom move route
190 	 */
191 	const lcf::rpg::MoveRoute& GetMoveRoute() const;
192 
193 	/**
194 	 * Sets a new custom move route. Used to assign a new MoveEvent.
195 	 *
196 	 * @param move_route new custom move route
197 	 */
198 	void SetMoveRoute(const lcf::rpg::MoveRoute& move_route);
199 
200 	/**
201 	 * Returns current index of the route assigned via a MoveEvent.
202 	 *
203 	 * @return current move route index
204 	 */
205 	int GetMoveRouteIndex() const;
206 
207 	/**
208 	 * Sets current index of a MoveEvent move route.
209 	 *
210 	 * @param new_index New custom move route index
211 	 */
212 	void SetMoveRouteIndex(int new_index);
213 
214 	/**
215 	 * Gets whether move route is overwritten by event.
216 	 *
217 	 * @return move route overwritten
218 	 */
219 	bool IsMoveRouteOverwritten() const;
220 
221 	/**
222 	 * Enables/Disables overwriting of move routes.
223 	 *
224 	 * @param force true: Use default move scheme, false: Use custom move route
225 	 */
226 	void SetMoveRouteOverwritten(bool force);
227 
228 	/**
229 	 * Checks if the forced move route has been repeating itself.
230 	 *
231 	 * @return whether forced move route has been repeating itself
232 	 */
233 	bool IsMoveRouteRepeated() const;
234 
235 	/**
236 	 * Makes current forced move route repeated/non-repeated.
237 	 *
238 	 * @param repeat true: Repeated move route, false: Non-repeated move route
239 	 */
240 	void SetMoveRouteRepeated(bool repeat);
241 
242 	/**
243 	 * Gets sprite name. Usually the name of the graphic file.
244 	 *
245 	 * @return sprite name
246 	 */
247 	const std::string& GetSpriteName() const;
248 
249 	/** @return true if this has a tile sprite */
250 	bool HasTileSprite() const;
251 
252 	/**
253 	 * Sets sprite name. Usually the name of the graphic file.
254 	 *
255 	 * @param sprite_name new sprite name
256 	 * @param index the index of the new sprite.
257 	 */
258 	void SetSpriteGraphic(std::string sprite_name, int index);
259 
260 	/**
261 	 * Sets sprite name from a move route command. Usually the name of the graphic file.
262 	 * This can be overridden to change behavior by child classes.
263 	 *
264 	 * @param sprite_name new sprite name
265 	 * @param index the index of the new sprite.
266 	 */
267 	virtual void MoveRouteSetSpriteGraphic(std::string sprite_name, int index);
268 
269 	/**
270 	 * Gets sprite index of character.
271 	 *
272 	 * @return sprite index
273 	 */
274 	int GetSpriteIndex() const;
275 
276 	/**
277 	 * Gets animation frame of character.
278 	 *
279 	 * @return anim_frame
280 	 */
281 	int GetAnimFrame() const;
282 
283 	/**
284 	 * Sets animation frame of character.
285 	 *
286 	 * @param frame new anim_frame
287 	 */
288 	void SetAnimFrame(int frame);
289 
290 	/**
291 	 * @return true if animation is paused.
292 	 */
293 	bool IsAnimPaused() const;
294 
295 	/**
296 	 * Sets whether animation is paused.
297 	 *
298 	 * @param value whether to pause the animation.
299 	 */
300 	void SetAnimPaused(bool value);
301 
302 	/**
303 	 * Updates the sprite facing direction based on current direction
304 	 */
305 	void UpdateFacing();
306 
307 	/**
308 	 * Begins a flash.
309 	 *
310 	 * @param r red color
311 	 * @param g blue color
312 	 * @param b green color
313 	 * @param power power of the flash
314 	 * @param frames Duration of the flash in frames
315 	 */
316 	void Flash(int r, int g, int b, int power, int frames);
317 
318 	/**
319 	 * Gets flash effect color.
320 	 *
321 	 * @return flash color
322 	 */
323 	Color GetFlashColor() const;
324 
325 	/**
326 	 * Returns intensity of flash effect.
327 	 *
328 	 * @return flash intensity
329 	 */
330 	double GetFlashLevel() const;
331 
332 	/**
333 	 * Sets intensity of flash effect.
334 	 *
335 	 * @param flash_level new flash intensity
336 	 */
337 	void SetFlashLevel(double flash_level);
338 
339 	/**
340 	 * Returns how many flash effect time is left.
341 	 *
342 	 * @return time left
343 	 */
344 	int GetFlashTimeLeft() const;
345 
346 	/**
347 	 * Set how long the flash effect will take.
348 	 *
349 	 * @param time_left flash duration
350 	 */
351 	void SetFlashTimeLeft(int time_left);
352 
353 	/**
354 	 * Gets the through flag (walk through everything)
355 	 *
356 	 * @return through flag
357 	 */
358 	bool GetThrough() const;
359 
360 	/**
361 	 * Sets the through flag (walk through everything)
362 	 *
363 	 * @param through through flag
364 	 */
365 	void SetThrough(bool through);
366 
367 	/** Resets the through flag to the route_through flag */
368 	void ResetThrough();
369 
370 	/**
371 	 * @return stop_count
372 	 */
373 	int GetStopCount() const;
374 
375 	/**
376 	 * Sets the stop_count
377 	 *
378 	 * @param sc the new stop count
379 	 */
380 	void SetStopCount(int sc);
381 
382 	/**
383 	 * @return max_stop_count
384 	 */
385 	int GetMaxStopCount() const;
386 
387 	/**
388 	 * @return stepping max_stop_count for the given frequency
389 	 * @param freq input movement frequency
390 	 */
391 	static constexpr int GetMaxStopCountForStep(int freq);
392 
393 	/**
394 	 * @return turning max_stop_count for the given frequency
395 	 * @param freq input movement frequency
396 	 */
397 	static constexpr int GetMaxStopCountForTurn(int freq);
398 
399 	/**
400 	 * @return waiting max_stop_count for the given frequency
401 	 * @param freq input movement frequency
402 	 */
403 	static constexpr int GetMaxStopCountForWait(int freq);
404 
405 	/**
406 	 * @return the number of frames for animating steps while not moving
407 	 * @param speed the movement speed.
408 	 */
409 	static constexpr int GetStationaryAnimFrames(int speed);
410 
411 	/**
412 	 * @return the number of frames for animating steps while moving or continuous.
413 	 * @param speed the movement speed.
414 	 */
415 	static constexpr int GetContinuousAnimFrames(int speed);
416 
417 	/**
418 	 * @return the number of frames for animating steps while spinning.
419 	 * @param speed the movement speed.
420 	 */
421 	static constexpr int GetSpinAnimFrames(int speed);
422 
423 	/**
424 	 * Sets the max_stop_count
425 	 *
426 	 * @param sc the new max stop count
427 	 */
428 	void SetMaxStopCount(int sc);
429 
430 	/** @return true if waiting for stop count in movement to complete */
431 	bool IsStopCountActive() const;
432 
433 	/**
434 	 * @return anim_count
435 	 */
436 	int GetAnimCount() const;
437 
438 	/**
439 	 * Sets the stop_count
440 	 *
441 	 * @param ac the new anim count.
442 	 */
443 	void SetAnimCount(int ac);
444 
445 	/** Resets the stepping animation */
446 	void ResetAnimation();
447 
448 	/**
449 	 * Gets if character is moving.
450 	 *
451 	 * @return whether the character is moving.
452 	 */
453 	bool IsMoving() const;
454 
455 	/**
456 	 * @return whether the character is jumping.
457 	 */
458 	bool IsJumping() const;
459 
460 	/**
461 	 * Set whether the character is jumping.
462 	 *
463 	 * @param val flag indicating jumping status
464 	 */
465 	void SetJumping(bool val);
466 
467 	/**
468 	 * @return X position where jump began.
469 	 */
470 	int GetBeginJumpX() const;
471 
472 	/**
473 	 * Set X position where jump began.
474 	 *
475 	 * @param x x position where jump began
476 	 */
477 	void SetBeginJumpX(int x);
478 
479 	/**
480 	 * @return Y position where jump began.
481 	 *
482 	 * @param y y position where jump began
483 	 */
484 	int GetBeginJumpY() const;
485 
486 	/**
487 	 * Set Y position where jump began.
488 	 */
489 	void SetBeginJumpY(int y);
490 
491 	/**
492 	 * @return whether the character is flying.
493 	 */
494 	bool IsFlying() const;
495 
496 	/**
497 	 * Set whether the character is flying.
498 	 *
499 	 * @param val whether or not character is flying.
500 	 */
501 	void SetFlying(bool val);
502 
503 	/**
504 	 * @return whether the RPG_RT processed flag is set.
505 	 */
506 	bool IsProcessed() const;
507 
508 	/**
509 	 * Set the RPG_RT processed flag
510 	 */
511 	void SetProcessed(bool val);
512 
513 	/**
514 	 * @return whether the event is paused.
515 	 */
516 	bool IsPaused() const;
517 
518 	/**
519 	 * Set the paused flag
520 	 */
521 	void SetPaused(bool val);
522 
523 	/**
524 	 * Activates or deactivates the event.
525 	 *
526 	 * @param active enables or disables the event.
527 	 */
528 	void SetActive(bool active);
529 
530 	/**
531 	 * Gets if the event is active.
532 	 *
533 	 * @return if the event is active (or inactive via EraseEvent-EventCommand).
534 	 */
535 	bool IsActive() const;
536 
537 	/**
538 	 * Checks if the character is stopping.
539 	 *
540 	 * @return whether the character is stopping.
541 	 */
542 	bool IsStopping() const;
543 
544 	/**
545 	 * Moves the character to a new location.
546 	 *
547 	 * @param map_id map id
548 	 * @param x tile x.
549 	 * @param y tile y.
550 	 */
551 	virtual void MoveTo(int map_id, int x, int y);
552 
553 	/**
554 	 * Move in the direction dir.
555 	 *
556 	 * @param dir the direction to move to.
557 	 *
558 	 * @return Whether move was successful or a move or jump is already in progress.
559 	 * @post If successful, IsStopping() == false.
560 	 */
561 	virtual bool Move(int dir);
562 
563 	/**
564 	 * Jump to (x, y)
565 	 *
566 	 * @param x the x position to jump to.
567 	 * @param y the y position to jump to.
568 	 *
569 	 * @return Whether jump was successful or a move or jump is already in progress.
570 	 * @post If successful, IsStopping() == false.
571 	 */
572 	bool Jump(int x, int y);
573 
574 	/**
575 	 * Check if this can move to the given tile.
576 	 *
577 	 * @param from_x Moving from x position
578 	 * @param from_y Moving from y position
579 	 * @param to_x Moving from x position
580 	 * @param to_y Moving from y position
581 	 *
582 	 * @return true if this can occupy (to_x, to_y) from (from_x, from_y)
583 	 */
584 	virtual bool MakeWay(int from_x, int from_y, int to_x, int to_y);
585 
586 	/**
587 	 * Turns the character 90 Degree to the left.
588 	 */
589 	void Turn90DegreeLeft();
590 
591 	/**
592 	 * Turns the character 90 Degree to the right.
593 	 */
594 	void Turn90DegreeRight();
595 
596 	/**
597 	 * Turns the character by 180 degree
598 	 */
599 	void Turn180Degree();
600 
601 	/**
602 	 * Turns the character 90 Degree to the left or right
603 	 * by using a random number.
604 	 */
605 	void Turn90DegreeLeftOrRight();
606 
607 	/** @return the direction we would need to face the hero. */
608 	int GetDirectionToHero();
609 
610 	/** @return the direction we would need to face away from hero. */
611 	int GetDirectionAwayHero();
612 
613 	/**
614 	 * @param dir input direction
615 	 *
616 	 * @return the direction 90 degrees to the left of dir
617 	 */
618 	static constexpr int GetDirection90DegreeLeft(int dir);
619 
620 	/**
621 	 * @param dir input direction
622 	 *
623 	 * @return the direction 90 degrees to the right of dir
624 	 */
625 	static constexpr int GetDirection90DegreeRight(int dir);
626 
627 	/**
628 	 * @param dir input direction
629 	 *
630 	 * @return the direction 180 degrees to the of dir
631 	 */
632 	static constexpr int GetDirection180Degree(int dir);
633 
634 	/**
635 	 * Character looks in a random direction
636 	 */
637 	void TurnRandom();
638 
639 	/**
640 	 * Character looks towards the hero.
641 	 */
642 	void TurnTowardHero();
643 
644 	/**
645 	 * Character looks away from the hero.
646 	 */
647 	void TurnAwayFromHero();
648 
649 	/**
650 	 * Character waits for 20 frames more.
651 	 */
652 	void Wait();
653 
654 	/**
655 	 * Forces a new, temporary, move route.
656 	 *
657 	 * @param new_route new move route.
658 	 * @param frequency frequency.
659 	 */
660 	void ForceMoveRoute(const lcf::rpg::MoveRoute& new_route, int frequency);
661 
662 	/**
663 	 * Cancels a previous forced move route.
664 	 */
665 	void CancelMoveRoute();
666 
667 	/** @return height of active jump in pixels */
668 	int GetJumpHeight() const;
669 
670 	/**
671 	 * Gets sprite x coordinate transformed to screen coordinate in pixels.
672 	 *
673 	 * @param apply_shift When true the coordinate is shifted by the map width (for looping maps)
674 	 * @return screen x coordinate in pixels.
675 	 */
676 	virtual int GetScreenX(bool apply_shift = false) const;
677 
678 	/**
679 	 * Gets sprite y coordinate transformed to screen coordinate in pixels.
680 	 *
681 	 * @param apply_shift When true the coordinate is shifted by the map height (for looping maps)
682 	 * @param apply_jump Apply jump height modifier if character is jumping
683 	 * @return screen y coordinate in pixels.
684 	 */
685 	virtual int GetScreenY(bool apply_shift = false, bool apply_jump = true) const;
686 
687 	/**
688 	 * Gets screen z coordinate in pixels.
689 	 *
690 	 * @param apply_shift Forwarded to GetScreenY
691 	 * @return screen z coordinate in pixels.
692 	 */
693 	virtual int GetScreenZ(bool apply_shift = false) const;
694 
695 	/**
696 	 * Gets tile graphic ID.
697 	 *
698 	 * @return tile graphic ID.
699 	 */
700 	int GetTileId() const;
701 
702 	/**
703 	 * Gets sprite x position in pixels.
704 	 *
705 	 * @return real x.
706 	 */
707 	int GetSpriteX() const;
708 
709 	/**
710 	 * Gets sprite y position in pixels.
711 	 *
712 	 * @return real y.
713 	 */
714 	int GetSpriteY() const;
715 
716 	/**
717 	 * Gets remaining step
718 	 *
719 	 * @return remaining step
720 	 */
721 	int GetRemainingStep() const;
722 
723 	/**
724 	 * Sets remaining step
725 	 *
726 	 * @param step new remaining step count
727 	 */
728 	void SetRemainingStep(int step);
729 
730 	/**
731 	 * Gets animation type.
732 	 *
733 	 * @return animation type.
734 	 */
735 	AnimType GetAnimationType() const;
736 
737 	/**
738 	 * Sets animation type.
739 	 *
740 	 * @param anim_type new animation type.
741 	 */
742 	void SetAnimationType(AnimType anim_type);
743 
744 	int DistanceXfromPlayer() const;
745 	int DistanceYfromPlayer() const;
746 
747 	/**
748 	 * Tests if the character is currently on the tile at x/y or moving
749 	 * towards it.
750 	 *
751 	 * @param x X tile position
752 	 * @param y Y tile position
753 	 * @return If on tile or moving towards
754 	 */
755 	virtual bool IsInPosition(int x, int y) const;
756 
757 	/**
758 	 * Gets current opacity of character.
759 	 *
760 	 * @return opacity (0 = Invisible, 255 = opaque)
761 	 */
762 	int GetOpacity() const;
763 
764 	/**
765 	 * @return RPG_RT transparency
766 	 */
767 	int GetTransparency() const;
768 
769 	/**
770 	 * Sets transparency of the character.
771 	 *
772 	 * @param value New transparency (0 = Opaque, 7 = mostly transparent)
773 	 */
774 	void SetTransparency(int value);
775 
776 	/**
777 	 * Gets if the character is visible.
778 	 *
779 	 * @return if visible, when true Opaque value is used
780 	 */
781 	virtual bool IsVisible() const;
782 
783 	/**
784 	 * Makes character visible/not visible.
785 	 * This has a higher priority then the Opacity setting.
786 	 * Needed for the "SetHeroTransparency" command because this can't be
787 	 * altered via the "Increase Transparency" move command.
788 	 *
789 	 * @param hidden true: invisible, false: visible
790 	 */
791 	void SetSpriteHidden(bool hidden);
792 
793 	/** @return true if sprite is hidden */
794 	bool IsSpriteHidden() const;
795 
796 	/**
797 	 * Tests if animation type is any fixed state.
798 	 *
799 	 * @return Whether direction is fixed
800 	 */
801 	static constexpr bool IsDirectionFixedAnimationType(AnimType);
802 
803 	/**
804 	 * Tests if the step animation is enabled.
805 	 * The animation is enabled when the animation type is not "fixed_graphic" and when
806 	 * the animation was not disabled through the move command "stop animation".
807 	 *
808 	 * @return Wheter animations are enabled.
809 	 */
810 	bool IsAnimated() const;
811 
812 	/**
813 	 * Tests if animation type is any continuous state.
814 	 *
815 	 * @return Whether animation is continuous
816 	 */
817 	bool IsContinuous() const;
818 
819 	/**
820 	 * Tests if animation is of the type spin.
821 	 *
822 	 * @return Whether animation is spin type
823 	 */
824 	bool IsSpinning() const;
825 
826 	/**
827 	 * Gets the bush depth of the tile where this character is standing
828 	 *
829 	 * @return Bush depth at this character's position
830 	 */
831 	int GetBushDepth() const;
832 
833 	enum CharsID {
834 		CharPlayer		= 10001,
835 		CharBoat		= 10002,
836 		CharShip		= 10003,
837 		CharAirship		= 10004,
838 		CharThisEvent	= 10005
839 	};
840 
841 	enum Direction {
842 		Up = 0,
843 		Right,
844 		Down,
845 		Left,
846 		UpRight,
847 		DownRight,
848 		DownLeft,
849 		UpLeft
850 	};
851 
852 	static bool IsDirectionDiagonal(int d);
853 
854 	/** Reverses a direction, ex: ReverseDir(Up) == Down. */
855 	static int ReverseDir(int dir);
856 
857 	static Game_Character* GetCharacter(int character_id, int event_id);
858 
859 	static constexpr int GetDxFromDirection(int dir);
860 	static constexpr int GetDyFromDirection(int dir);
861 
862 protected:
863 	explicit Game_Character(Type type, lcf::rpg::SaveMapEventBase* d);
864 	/** Check for and fix incorrect data after loading save game */
865 	void SanitizeData(StringView name);
866 	/** Check for and fix incorrect move route data after loading save game */
867 	void SanitizeMoveRoute(StringView name, const lcf::rpg::MoveRoute& mr, int32_t& idx, StringView chunk_name);
868 	void Update();
869 	virtual void UpdateAnimation();
870 	virtual void UpdateNextMovementAction() = 0;
871 	virtual void UpdateMovement(int amount);
872 
873 	void SetMaxStopCountForStep();
874 	void SetMaxStopCountForTurn();
875 	void SetMaxStopCountForWait();
876 	void UpdateMoveRoute(int32_t& current_index, const lcf::rpg::MoveRoute& current_route, bool is_overwrite);
877 	void IncAnimCount();
878 	void IncAnimFrame();
879 	void UpdateFlash();
880 	bool BeginMoveRouteJump(int32_t& current_index, const lcf::rpg::MoveRoute& current_route);
881 
882 	lcf::rpg::SaveMapEventBase* data();
883 	const lcf::rpg::SaveMapEventBase* data() const;
884 
885 	int original_move_frequency = 2;
886 	// contains if any movement (<= step_forward) of a forced move route was successful
887 
888 	Type _type = {};
889 	lcf::rpg::SaveMapEventBase* _data = nullptr;
890 };
891 
892 template <typename T>
893 class Game_CharacterDataStorage : public Game_Character
894 {
895 	public:
896 		using Type = Game_Character::Type;
897 		Game_CharacterDataStorage(Type typ);
898 
899 		Game_CharacterDataStorage(const Game_CharacterDataStorage&) = delete;
900 		Game_CharacterDataStorage& operator=(const Game_CharacterDataStorage&) = delete;
901 
902 		Game_CharacterDataStorage(Game_CharacterDataStorage&&) noexcept;
903 		Game_CharacterDataStorage& operator=(Game_CharacterDataStorage&&) noexcept;
904 
905 		~Game_CharacterDataStorage() = default;
906 
907 		T* data();
908 		const T* data() const;
909 	private:
910 		T _data = {};
911 };
912 
IsDirectionFixedAnimationType(AnimType at)913 constexpr bool Game_Character::IsDirectionFixedAnimationType(AnimType at) {
914 	return
915 		at == lcf::rpg::EventPage::AnimType_fixed_continuous ||
916 		at == lcf::rpg::EventPage::AnimType_fixed_graphic ||
917 		at == lcf::rpg::EventPage::AnimType_fixed_non_continuous;
918 }
919 
data()920 inline lcf::rpg::SaveMapEventBase* Game_Character::data() {
921 	return _data;
922 }
923 
data()924 inline const lcf::rpg::SaveMapEventBase* Game_Character::data() const {
925 	return _data;
926 }
927 
GetType()928 inline Game_Character::Type Game_Character::GetType() const {
929 	return _type;
930 }
931 
GetX()932 inline int Game_Character::GetX() const {
933 	return data()->position_x;
934 }
935 
SetX(int new_x)936 inline void Game_Character::SetX(int new_x) {
937 	data()->position_x = new_x;
938 }
939 
GetY()940 inline int Game_Character::GetY() const {
941 	return data()->position_y;
942 }
943 
SetY(int new_y)944 inline void Game_Character::SetY(int new_y) {
945 	data()->position_y = new_y;
946 }
947 
GetMapId()948 inline int Game_Character::GetMapId() const {
949 	return data()->map_id;
950 }
951 
SetMapId(int new_map_id)952 inline void Game_Character::SetMapId(int new_map_id) {
953 	data()->map_id = new_map_id;
954 }
955 
GetDirection()956 inline int Game_Character::GetDirection() const {
957 	return data()->direction;
958 }
959 
SetDirection(int new_direction)960 inline void Game_Character::SetDirection(int new_direction) {
961 	data()->direction = new_direction;
962 }
963 
GetFacing()964 inline int Game_Character::GetFacing() const {
965 	return data()->sprite_direction;
966 }
967 
SetFacing(int new_direction)968 inline void Game_Character::SetFacing(int new_direction) {
969 	data()->sprite_direction = new_direction;
970 }
971 
IsFacingLocked()972 inline bool Game_Character::IsFacingLocked() const {
973 	return data()->lock_facing;
974 }
975 
SetFacingLocked(bool locked)976 inline void Game_Character::SetFacingLocked(bool locked) {
977 	data()->lock_facing = locked || IsDirectionFixedAnimationType(GetAnimationType());
978 }
979 
GetLayer()980 inline int Game_Character::GetLayer() const {
981 	return data()->layer;
982 }
983 
SetLayer(int new_layer)984 inline void Game_Character::SetLayer(int new_layer) {
985 	data()->layer = new_layer;
986 }
987 
IsOverlapForbidden()988 inline bool Game_Character::IsOverlapForbidden() const {
989 	return data()->overlap_forbidden;
990 }
991 
GetMoveSpeed()992 inline int Game_Character::GetMoveSpeed() const {
993 	return data()->move_speed;
994 }
995 
SetMoveSpeed(int speed)996 inline void Game_Character::SetMoveSpeed(int speed) {
997 	data()->move_speed = speed;
998 }
999 
GetMoveFrequency()1000 inline int Game_Character::GetMoveFrequency() const {
1001 	return data()->move_frequency;
1002 }
1003 
SetMoveFrequency(int frequency)1004 inline void Game_Character::SetMoveFrequency(int frequency) {
1005 	data()->move_frequency = frequency;
1006 }
1007 
GetMoveRoute()1008 inline const lcf::rpg::MoveRoute& Game_Character::GetMoveRoute() const {
1009 	return data()->move_route;
1010 }
1011 
SetMoveRoute(const lcf::rpg::MoveRoute & move_route)1012 inline void Game_Character::SetMoveRoute(const lcf::rpg::MoveRoute& move_route) {
1013 	data()->move_route = move_route;
1014 }
1015 
GetMoveRouteIndex()1016 inline int Game_Character::GetMoveRouteIndex() const {
1017 	return data()->move_route_index;
1018 }
1019 
SetMoveRouteIndex(int new_index)1020 inline void Game_Character::SetMoveRouteIndex(int new_index) {
1021 	data()->move_route_index = new_index;
1022 }
1023 
IsMoveRouteOverwritten()1024 inline bool Game_Character::IsMoveRouteOverwritten() const {
1025 	return data()->move_route_overwrite;
1026 }
1027 
SetMoveRouteOverwritten(bool force)1028 inline void Game_Character::SetMoveRouteOverwritten(bool force) {
1029 	data()->move_route_overwrite = force;
1030 }
1031 
IsMoveRouteRepeated()1032 inline bool Game_Character::IsMoveRouteRepeated() const {
1033 	return data()->move_route_repeated;
1034 }
1035 
SetMoveRouteRepeated(bool force)1036 inline void Game_Character::SetMoveRouteRepeated(bool force) {
1037 	data()->move_route_repeated = force;
1038 }
1039 
GetSpriteName()1040 inline const std::string& Game_Character::GetSpriteName() const {
1041 	return data()->sprite_name;
1042 }
1043 
SetSpriteGraphic(std::string sprite_name,int index)1044 inline void Game_Character::SetSpriteGraphic(std::string sprite_name, int index) {
1045 	data()->sprite_name = std::move(sprite_name);
1046 	data()->sprite_id = index;
1047 }
1048 
MoveRouteSetSpriteGraphic(std::string sprite_name,int index)1049 inline void Game_Character::MoveRouteSetSpriteGraphic(std::string sprite_name, int index) {
1050 	SetSpriteGraphic(std::move(sprite_name), index);
1051 }
1052 
GetSpriteIndex()1053 inline int Game_Character::GetSpriteIndex() const {
1054 	return data()->sprite_id;
1055 }
1056 
GetAnimFrame()1057 inline int Game_Character::GetAnimFrame() const {
1058 	return data()->anim_frame;
1059 }
1060 
SetAnimFrame(int frame)1061 inline void Game_Character::SetAnimFrame(int frame) {
1062 	data()->anim_frame = frame;
1063 }
1064 
IsAnimPaused()1065 inline bool Game_Character::IsAnimPaused() const {
1066 	return data()->anim_paused;
1067 }
1068 
SetAnimPaused(bool value)1069 inline void Game_Character::SetAnimPaused(bool value) {
1070 	data()->anim_paused = value;
1071 }
1072 
GetFlashColor()1073 inline Color Game_Character::GetFlashColor() const {
1074 	return Flash::MakeColor(data()->flash_red, data()->flash_green, data()->flash_blue, data()->flash_current_level);
1075 }
1076 
GetFlashLevel()1077 inline double Game_Character::GetFlashLevel() const {
1078 	return data()->flash_current_level;
1079 }
1080 
SetFlashLevel(double flash_level)1081 inline void Game_Character::SetFlashLevel(double flash_level) {
1082 	data()->flash_current_level = flash_level;
1083 }
1084 
GetFlashTimeLeft()1085 inline int Game_Character::GetFlashTimeLeft() const {
1086 	return data()->flash_time_left;
1087 }
1088 
SetFlashTimeLeft(int time_left)1089 inline void Game_Character::SetFlashTimeLeft(int time_left) {
1090 	data()->flash_time_left = time_left;
1091 }
1092 
GetThrough()1093 inline bool Game_Character::GetThrough() const {
1094 	return data()->through;
1095 }
1096 
SetThrough(bool through)1097 inline void Game_Character::SetThrough(bool through) {
1098 	data()->through = through;
1099 }
1100 
ResetThrough()1101 inline void Game_Character::ResetThrough() {
1102 	data()->through = data()->route_through;
1103 }
1104 
GetAnimationType()1105 inline Game_Character::AnimType Game_Character::GetAnimationType() const {
1106 	return AnimType(data()->animation_type);
1107 }
1108 
SetAnimationType(Game_Character::AnimType anim_type)1109 inline void Game_Character::SetAnimationType(Game_Character::AnimType anim_type) {
1110 	data()->animation_type = int(anim_type);
1111 	SetFacingLocked(IsDirectionFixedAnimationType(anim_type));
1112 }
1113 
GetStopCount()1114 inline int Game_Character::GetStopCount() const {
1115 	return data()->stop_count;
1116 }
1117 
SetStopCount(int sc)1118 inline void Game_Character::SetStopCount(int sc) {
1119 	data()->stop_count = sc;
1120 }
1121 
GetMaxStopCount()1122 inline int Game_Character::GetMaxStopCount() const {
1123 	return data()->max_stop_count;
1124 }
1125 
SetMaxStopCount(int sc)1126 inline void Game_Character::SetMaxStopCount(int sc) {
1127 	data()->max_stop_count = sc;
1128 }
1129 
IsStopCountActive()1130 inline bool Game_Character::IsStopCountActive() const {
1131 	return GetStopCount() < GetMaxStopCount();
1132 }
1133 
GetAnimCount()1134 inline int Game_Character::GetAnimCount() const {
1135 	return data()->anim_count;
1136 }
1137 
SetAnimCount(int ac)1138 inline void Game_Character::SetAnimCount(int ac) {
1139 	data()->anim_count = ac;
1140 }
1141 
IncAnimCount()1142 inline void Game_Character::IncAnimCount() {
1143 	++data()->anim_count;
1144 }
1145 
IncAnimFrame()1146 inline void Game_Character::IncAnimFrame() {
1147 	data()->anim_frame = (data()->anim_frame + 1) % 4;
1148 	SetAnimCount(0);
1149 }
1150 
ResetAnimation()1151 inline void Game_Character::ResetAnimation() {
1152 	SetAnimCount(0);
1153 	if (GetAnimationType() != lcf::rpg::EventPage::AnimType_fixed_graphic) {
1154 		SetAnimFrame(lcf::rpg::EventPage::Frame_middle);
1155 	}
1156 }
1157 
GetRemainingStep()1158 inline int Game_Character::GetRemainingStep() const {
1159 	return data()->remaining_step;
1160 }
1161 
SetRemainingStep(int step)1162 inline void Game_Character::SetRemainingStep(int step) {
1163 	data()->remaining_step = step;
1164 }
1165 
IsJumping()1166 inline bool Game_Character::IsJumping() const {
1167 	return data()->jumping;
1168 }
1169 
SetJumping(bool val)1170 inline void Game_Character::SetJumping(bool val) {
1171 	data()->jumping = val;
1172 }
1173 
IsMoving()1174 inline bool Game_Character::IsMoving() const {
1175 	return !IsJumping() && GetRemainingStep() > 0;
1176 }
1177 
IsStopping()1178 inline bool Game_Character::IsStopping() const {
1179 	return !(IsMoving() || IsJumping());
1180 }
1181 
GetBeginJumpX()1182 inline int Game_Character::GetBeginJumpX() const {
1183 	return data()->begin_jump_x;
1184 }
1185 
SetBeginJumpX(int x)1186 inline void Game_Character::SetBeginJumpX(int x) {
1187 	data()->begin_jump_x = x;
1188 }
1189 
GetBeginJumpY()1190 inline int Game_Character::GetBeginJumpY() const {
1191 	return data()->begin_jump_y;
1192 }
1193 
SetBeginJumpY(int y)1194 inline void Game_Character::SetBeginJumpY(int y) {
1195 	data()->begin_jump_y = y;
1196 }
1197 
IsFlying()1198 inline bool Game_Character::IsFlying() const {
1199 	return data()->flying;
1200 }
1201 
SetFlying(bool val)1202 inline void Game_Character::SetFlying(bool val) {
1203 	data()->flying = val;
1204 }
1205 
GetTransparency()1206 inline int Game_Character::GetTransparency() const {
1207 	return data()->transparency;
1208 }
1209 
SetTransparency(int value)1210 inline void Game_Character::SetTransparency(int value) {
1211 	data()->transparency = Utils::Clamp(value, 0, 7);
1212 }
1213 
IsProcessed()1214 inline bool Game_Character::IsProcessed() const {
1215 	return data()->processed;
1216 }
1217 
SetProcessed(bool val)1218 inline void Game_Character::SetProcessed(bool val) {
1219 	data()->processed = val;
1220 }
1221 
IsPaused()1222 inline bool Game_Character::IsPaused() const {
1223 	return data()->pause;
1224 }
1225 
SetPaused(bool val)1226 inline void Game_Character::SetPaused(bool val) {
1227 	data()->pause = val;
1228 }
1229 
IsActive()1230 inline bool Game_Character::IsActive() const {
1231 	return data()->active;
1232 }
1233 
SetActive(bool active)1234 inline void Game_Character::SetActive(bool active) {
1235 	data()->active = active;
1236 }
1237 
HasTileSprite()1238 inline bool Game_Character::HasTileSprite() const {
1239 	return GetSpriteName().empty();
1240 }
1241 
GetTileId()1242 inline int Game_Character::GetTileId() const {
1243 	return HasTileSprite() ? GetSpriteIndex() : 0;
1244 }
1245 
SetSpriteHidden(bool hidden)1246 inline void Game_Character::SetSpriteHidden(bool hidden) {
1247 	data()->sprite_transparent = hidden;
1248 }
1249 
IsSpriteHidden()1250 inline bool Game_Character::IsSpriteHidden() const {
1251 	return data()->sprite_transparent;
1252 }
1253 
GetDirection90DegreeLeft(int dir)1254 constexpr int Game_Character::GetDirection90DegreeLeft(int dir) {
1255 	return (dir + 3) % 4;
1256 }
1257 
GetDirection90DegreeRight(int dir)1258 constexpr int Game_Character::GetDirection90DegreeRight(int dir) {
1259 	return (dir + 1) % 4;
1260 }
1261 
GetDirection180Degree(int dir)1262 constexpr int Game_Character::GetDirection180Degree(int dir) {
1263 	return (dir + 2) % 4;
1264 }
1265 
GetMaxStopCountForStep(int freq)1266 constexpr int Game_Character::GetMaxStopCountForStep(int freq) {
1267 	return freq >= 8 ? 0 : 1 << (9 - freq);
1268 }
1269 
GetMaxStopCountForTurn(int freq)1270 constexpr int Game_Character::GetMaxStopCountForTurn(int freq) {
1271 	return freq >= 8 ? 0 : 1 << (8 - freq);
1272 }
1273 
GetMaxStopCountForWait(int freq)1274 constexpr int Game_Character::GetMaxStopCountForWait(int freq) {
1275 	return 20 + GetMaxStopCountForTurn(freq);
1276 }
1277 
GetDxFromDirection(int dir)1278 constexpr int Game_Character::GetDxFromDirection(int dir) {
1279 	return (dir == Game_Character::Right || dir == Game_Character::UpRight || dir == Game_Character::DownRight)
1280 		- (dir == Game_Character::Left || dir == Game_Character::DownLeft || dir == Game_Character::UpLeft);
1281 }
1282 
GetDyFromDirection(int dir)1283 constexpr int Game_Character::GetDyFromDirection(int dir) {
1284 	return (dir == Game_Character::Down || dir == Game_Character::DownRight || dir == Game_Character::DownLeft)
1285 		- (dir == Game_Character::Up || dir == Game_Character::UpRight || dir == Game_Character::UpLeft);
1286 }
1287 
GetStationaryAnimFrames(int speed)1288 constexpr int Game_Character::GetStationaryAnimFrames(int speed) {
1289 	constexpr int limits[] = { 12, 10, 8, 6, 5, 4 };
1290 	return limits[speed - 1];
1291 }
1292 
GetContinuousAnimFrames(int speed)1293 constexpr int Game_Character::GetContinuousAnimFrames(int speed) {
1294 	constexpr int limits[] = { 16, 12, 10, 8, 7, 6 };
1295 	return limits[speed - 1];
1296 }
1297 
GetSpinAnimFrames(int speed)1298 constexpr int Game_Character::GetSpinAnimFrames(int speed) {
1299 	constexpr int limits[] = { 24, 16, 12, 8, 6, 4 };
1300 	return limits[speed - 1];
1301 }
1302 
IsVisible()1303 inline bool Game_Character::IsVisible() const {
1304 	return IsActive() && !IsSpriteHidden() && GetOpacity() > 0;
1305 }
1306 
1307 template <typename T>
Game_CharacterDataStorage(Type typ)1308 inline Game_CharacterDataStorage<T>::Game_CharacterDataStorage(Type typ)
1309 	: Game_Character(typ, nullptr)
1310 {
1311 	Game_Character::_data = &this->_data;
1312 }
1313 
1314 template <typename T>
Game_CharacterDataStorage(Game_CharacterDataStorage && o)1315 inline Game_CharacterDataStorage<T>::Game_CharacterDataStorage(Game_CharacterDataStorage&& o) noexcept
1316 : Game_Character(std::move(o)), _data(std::move(o._data))
1317 {
1318 	Game_Character::_data = &this->_data;
1319 }
1320 
1321 template <typename T>
1322 inline Game_CharacterDataStorage<T>& Game_CharacterDataStorage<T>::operator=(Game_CharacterDataStorage&& o) noexcept
1323 {
1324 	static_cast<Game_Character*>(this) = std::move(o);
1325 	if (this != &o) {
1326 		_data = std::move(o._data);
1327 		Game_Character::_data = &this->_data;
1328 	}
1329 	return *this;
1330 }
1331 
1332 template <typename T>
data()1333 inline T* Game_CharacterDataStorage<T>::data() {
1334 	return static_cast<T*>(Game_Character::data());
1335 }
1336 
1337 template <typename T>
data()1338 inline const T* Game_CharacterDataStorage<T>::data() const {
1339 	return static_cast<const T*>(Game_Character::data());
1340 }
1341 
IsDirectionDiagonal(int d)1342 inline bool Game_Character::IsDirectionDiagonal(int d) {
1343 	return d >= UpRight;
1344 }
1345 
TypeToStr(Game_Character::Type type)1346 inline StringView Game_Character::TypeToStr(Game_Character::Type type) {
1347 	switch (type) {
1348 		case Player: return "Player";
1349 		case Vehicle: return "Vehicle";
1350 		case Event: return "Event";
1351 	}
1352 	return "UnknownCharacter";
1353 }
1354 
1355 #endif
1356