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 // Headers
19 #include "sprite_character.h"
20 #include "cache.h"
21 #include "game_map.h"
22 #include "bitmap.h"
23
Sprite_Character(Game_Character * character,CloneType type)24 Sprite_Character::Sprite_Character(Game_Character* character, CloneType type) :
25 character(character),
26 tile_id(-1),
27 character_index(0),
28 chara_width(0),
29 chara_height(0) {
30
31 x_shift = ((type & XClone) == XClone);
32 y_shift = ((type & YClone) == YClone);
33
34 Update();
35 }
36
Update()37 void Sprite_Character::Update() {
38 if (tile_id != character->GetTileId() ||
39 character_name != character->GetSpriteName() ||
40 character_index != character->GetSpriteIndex() ||
41 refresh_bitmap
42 ) {
43 tile_id = character->GetTileId();
44 character_name = character->GetSpriteName();
45 character_index = character->GetSpriteIndex();
46 refresh_bitmap = false;
47
48 if (UsesCharset()) {
49 FileRequestAsync* char_request = AsyncHandler::RequestFile("CharSet", character_name);
50 char_request->SetGraphicFile(true);
51 request_id = char_request->Bind(&Sprite_Character::OnCharSpriteReady, this);
52 char_request->Start();
53 } else {
54 FileRequestAsync* tile_request = AsyncHandler::RequestFile("ChipSet", Game_Map::GetChipsetName());
55 tile_request->SetGraphicFile(true);
56 request_id = tile_request->Bind(&Sprite_Character::OnTileSpriteReady, this);
57 tile_request->Start();
58 }
59 }
60
61 if (UsesCharset()) {
62 int row = character->GetFacing();
63 auto frame = character->GetAnimFrame();
64 if (frame >= lcf::rpg::EventPage::Frame_middle2) frame = lcf::rpg::EventPage::Frame_middle;
65 SetSrcRect({frame * chara_width, row * chara_height, chara_width, chara_height});
66 }
67
68 SetFlashEffect(character->GetFlashColor());
69
70 SetOpacity(character->GetOpacity());
71 SetVisible(character->IsVisible());
72
73 SetX(character->GetScreenX(x_shift));
74 SetY(character->GetScreenY(y_shift));
75 // y_shift because Z is calculated via the screen Y position
76 SetZ(character->GetScreenZ(y_shift));
77
78 int bush_split = 4 - character->GetBushDepth();
79 SetBushDepth(bush_split > 3 ? 0 : GetHeight() / bush_split);
80 }
81
GetCharacter()82 Game_Character* Sprite_Character::GetCharacter() {
83 return character;
84 }
SetCharacter(Game_Character * new_character)85 void Sprite_Character::SetCharacter(Game_Character* new_character) {
86 character = new_character;
87 }
88
UsesCharset() const89 bool Sprite_Character::UsesCharset() const {
90 return !character_name.empty();
91 }
92
OnTileSpriteReady(FileRequestResult *)93 void Sprite_Character::OnTileSpriteReady(FileRequestResult*) {
94 const auto chipset = Game_Map::GetChipsetName();
95
96 BitmapRef tile;
97 if (!chipset.empty()) {
98 tile = Cache::Tile(Game_Map::GetChipsetName(), tile_id);
99 }
100 else {
101 tile = Bitmap::Create(16, 16, true);
102 }
103
104 SetBitmap(tile);
105
106 SetSrcRect({ 0, 0, TILE_SIZE, TILE_SIZE });
107 SetOx(8);
108 SetOy(16);
109
110 Update();
111 }
112
ChipsetUpdated()113 void Sprite_Character::ChipsetUpdated() {
114 if (UsesCharset()) {
115 return;
116 }
117 refresh_bitmap = true;
118 }
119
GetCharacterRect(StringView name,int index,const Rect bitmap_rect)120 Rect Sprite_Character::GetCharacterRect(StringView name, int index, const Rect bitmap_rect) {
121 Rect rect;
122 // Allow large 4x2 spriteset of 3x4 sprites
123 // when the character name starts with a $ sign.
124 // This is not exactly the VX Ace way because
125 // VX Ace uses a single 1x1 spriteset of 3x4 sprites.
126 if (!name.empty() && name.front() == '$') {
127 rect.width = bitmap_rect.width * (TILE_SIZE / 16) / 4;
128 rect.height = bitmap_rect.height * (TILE_SIZE / 16) / 2;
129 } else {
130 rect.width = 24 * (TILE_SIZE / 16) * 3;;
131 rect.height = 32 * (TILE_SIZE / 16) * 4;
132 }
133 rect.x = (index % 4) * rect.width;
134 rect.y = (index / 4) * rect.height;
135 return rect;
136 }
137
OnCharSpriteReady(FileRequestResult *)138 void Sprite_Character::OnCharSpriteReady(FileRequestResult*) {
139 SetBitmap(Cache::Charset(character_name));
140 auto rect = GetCharacterRect(character_name, character_index, GetBitmap()->GetRect());
141 chara_width = rect.width / 3;
142 chara_height = rect.height / 4;
143 SetOx(chara_width / 2);
144 SetOy(chara_height);
145 SetSpriteRect(rect);
146
147 Update();
148 }
149