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 "battle_animation.h"
20 #include "game_enemy.h"
21 #include "sprite_actor.h"
22 #include "game_battler.h"
23 #include "game_actor.h"
24 #include "game_screen.h"
25 #include "bitmap.h"
26 #include "cache.h"
27 #include "main_data.h"
28 #include "player.h"
29 #include <lcf/reader_util.h>
30 #include "output.h"
31 
Sprite_Actor(Game_Actor * actor)32 Sprite_Actor::Sprite_Actor(Game_Actor* actor)
33 	: Sprite_Battler(actor, actor->GetId())
34 {
35 	CreateSprite();
36 }
37 
~Sprite_Actor()38 Sprite_Actor::~Sprite_Actor() {
39 }
40 
GetBattler() const41 Game_Actor* Sprite_Actor::GetBattler() const {
42 	return static_cast<Game_Actor*>(Sprite_Battler::GetBattler());
43 }
44 
Update()45 void Sprite_Actor::Update() {
46 	auto* battler = GetBattler();
47 
48 	if (!battler->IsHidden() && old_hidden != battler->IsHidden()) {
49 		DoIdleAnimation();
50 	}
51 
52 	old_hidden = battler->IsHidden();
53 
54 	++cycle;
55 
56 	if (anim_state > 0) {
57 		// Animations for allies
58 		if (Player::IsRPG2k3()) {
59 			UpdatePosition();
60 
61 			if (animation) {
62 				// Is a battle animation
63 				animation->SetInvert(battler->IsDirectionFlipped());
64 				animation->Update();
65 
66 				if (animation->IsDone()) {
67 					if (loop_state == LoopState_DefaultAnimationAfterFinish) {
68 						DoIdleAnimation();
69 					} else if (loop_state == LoopState_LoopAnimation) {
70 						animation->SetFrame(0);
71 					} else if (loop_state == LoopState_WaitAfterFinish) {
72 						if (animation->GetFrames() > 0) {
73 							animation->SetFrame(animation->GetFrames() - 1);
74 						}
75 						idling = true;
76 					}
77 				}
78 
79 				return;
80 			}
81 			// Is a battle charset animation
82 			static const int frames[] = {0,1,2,1,0};
83 			int frame = (battler->IsDefending() ? 0 : (normal_attacking ? std::min(2, cycle / 10) : frames[cycle / 10]));
84 
85 			if (battler->IsDirectionFlipped()) {
86 				frame = 2 - frame;
87 			}
88 
89 			if (frame == sprite_frame)
90 				return;
91 
92 			const lcf::rpg::BattlerAnimation* anim = lcf::ReaderUtil::GetElement(lcf::Data::battleranimations, battler->GetBattleAnimationId());
93 			if (!anim) {
94 				Output::Warning("Invalid battler animation ID {}", battler->GetBattleAnimationId());
95 				return;
96 			}
97 
98 			const auto* ext = lcf::ReaderUtil::GetElement(anim->poses, anim_state);
99 			if (!ext) {
100 				Output::Warning("Animation {}: Invalid battler anim-extension state {}", anim->ID, anim_state);
101 				return;
102 			}
103 
104 			SetSrcRect(Rect(frame * 48, ext->battler_index * 48, 48, 48));
105 
106 			if (cycle == ((idling || normal_attacking || anim_state == AnimationState_WalkingLeft || anim_state == AnimationState_WalkingRight || anim_state == AnimationState_Victory) ? 40 : 30)) {
107 				switch (loop_state) {
108 					case LoopState_DefaultAnimationAfterFinish:
109 						DoIdleAnimation();
110 						break;
111 					case LoopState_WaitAfterFinish:
112 						--cycle; // incremented to last cycle next update
113 						idling = true;
114 						break;
115 					case LoopState_LoopAnimation:
116 						cycle = 0;
117 						break;
118 					default:
119 						assert(false && "Bad loop state");
120 				}
121 			}
122 		}
123 	}
124 
125 	if (animation) {
126 		animation->SetVisible(IsVisible());
127 	}
128 
129 	const bool flip = battler->IsDirectionFlipped();
130 	SetFlipX(flip);
131 }
132 
SetAnimationState(int state,LoopState loop,int animation_id)133 void Sprite_Actor::SetAnimationState(int state, LoopState loop, int animation_id) {
134 	// Default value is 100 (function called with val+1)
135 	// 100 maps all states to "Bad state" (7)
136 	if (state == 101) {
137 		state = 7;
138 	}
139 
140 	anim_state = state;
141 
142 	loop_state = loop;
143 
144 	cycle = 0;
145 
146 	idling = false;
147 
148 	auto* battler = GetBattler();
149 
150 	if (battler->GetBattleAnimationId() > 0) {
151 		const lcf::rpg::BattlerAnimation* anim = lcf::ReaderUtil::GetElement(lcf::Data::battleranimations, battler->GetBattleAnimationId());
152 		if (!anim) {
153 			Output::Warning("Invalid battler animation ID {}", battler->GetBattleAnimationId());
154 			return;
155 		}
156 
157 		const auto* ext = lcf::ReaderUtil::GetElement(anim->poses, anim_state);
158 		if (!ext) {
159 			Output::Warning("Animation {}: Invalid battler anim-extension state {}", anim->ID, anim_state);
160 			return;
161 		}
162 
163 		StringView sprite_file = ext->battler_name;
164 
165 		if (ext->animation_type == lcf::rpg::BattlerAnimationPose::AnimType_battle) {
166 			do_not_draw = false;
167 			SetBitmap(BitmapRef());
168 			if (animation_id == 0) {
169 				animation_id = ext->battle_animation_id;
170 			}
171 			lcf::rpg::Animation* battle_anim = lcf::ReaderUtil::GetElement(lcf::Data::animations, animation_id);
172 			if (!battle_anim) {
173 				Output::Warning("Invalid battle animation ID {}", animation_id);
174 				animation.reset();
175 			} else {
176 				animation.reset(new BattleAnimationBattler(*battle_anim, { battler }));
177 				animation->SetZ(GetZ());
178 			}
179 			animation->SetInvert(battler->IsDirectionFlipped());
180 		}
181 		else {
182 			do_not_draw = sprite_file.empty();
183 			animation.reset();
184 			if (!sprite_file.empty()) {
185 				FileRequestAsync* request = AsyncHandler::RequestFile("BattleCharSet", sprite_file);
186 				request->SetGraphicFile(true);
187 				request_id = request->Bind(&Sprite_Actor::OnBattlercharsetReady, this, ext->battler_index);
188 				request->Start();
189 			}
190 		}
191 	}
192 }
193 
SetAnimationLoop(LoopState loop)194 void Sprite_Actor::SetAnimationLoop(LoopState loop) {
195 	loop_state = loop;
196 }
197 
DetectStateChange()198 void Sprite_Actor::DetectStateChange() {
199 	if (idling) {
200 		DoIdleAnimation();
201 	}
202 }
203 
IsIdling()204 bool Sprite_Actor::IsIdling() {
205 	return idling;
206 }
207 
GetWidth() const208 int Sprite_Actor::GetWidth() const {
209 	if (animation) {
210 		return animation->GetAnimationCellWidth() / 2;
211 	}
212 	return Sprite::GetWidth();
213 }
214 
GetHeight() const215 int Sprite_Actor::GetHeight() const {
216 	if (animation) {
217 		return animation->GetAnimationCellHeight() / 2;
218 	}
219 	return Sprite::GetHeight();
220 }
221 
CreateSprite()222 void Sprite_Actor::CreateSprite() {
223 	auto* battler = GetBattler();
224 
225 	images = {{battler->GetDisplayX(), battler->GetDisplayY()}};
226 
227 	SetX(images.back().x);
228 	SetY(images.back().y);
229 
230 	// Not animated -> Monster
231 	SetOx(24);
232 	SetOy(24);
233 	ResetZ();
234 	SetAnimationState(anim_state);
235 	idling = true;
236 }
237 
DoIdleAnimation()238 void Sprite_Actor::DoIdleAnimation() {
239 	auto* battler = GetBattler();
240 	if (battler->IsDefending()) {
241 		SetAnimationState(AnimationState_Defending);
242 		idling = true;
243 		return;
244 	}
245 
246 	const lcf::rpg::State* state = battler->GetSignificantState();
247 	int idling_anim;
248 	if (battler->GetBattleAnimationId() <= 0) {
249 		// Monster
250 		// Only visually different state is Death
251 		if (state && state->ID == 1) {
252 			idling_anim = AnimationState_Dead;
253 		} else {
254 			idling_anim = AnimationState_Idle;
255 		}
256 	} else {
257 		idling_anim = state ? state->battler_animation_id + 1 : AnimationState_Idle;
258 	}
259 
260 	if (idling_anim == 101)
261 		idling_anim = 7;
262 
263 	if (idling_anim != anim_state || loop_state == LoopState_DefaultAnimationAfterFinish)
264 		SetAnimationState(idling_anim, idling_anim == AnimationState_Dead ? LoopState_WaitAfterFinish : LoopState_LoopAnimation);
265 
266 	idling = true;
267 }
268 
OnBattlercharsetReady(FileRequestResult * result,int32_t battler_index)269 void Sprite_Actor::OnBattlercharsetReady(FileRequestResult* result, int32_t battler_index) {
270 	SetBitmap(Cache::Battlecharset(result->file));
271 	SetSrcRect(Rect((battler->IsDirectionFlipped() ? 96 : 0), battler_index * 48, 48, 48));
272 }
273 
Draw(Bitmap & dst)274 void Sprite_Actor::Draw(Bitmap& dst) {
275 	auto* battler = GetBattler();
276 	// "do_not_draw" is set to true if the CBA battler name is empty, this
277 	// makes the sprite not being drawn. This fixes issue #1708.
278 	if (battler->IsHidden() || do_not_draw) {
279 		return;
280 	}
281 
282 	SetTone(Main_Data::game_screen->GetTone());
283 	SetFlashEffect(battler->GetFlashColor());
284 
285 	int steps = static_cast<int>(256 / images.size());
286 	int opacity = steps;
287 	for (auto it = images.crbegin(); it != images.crend(); ++it) {
288 		Sprite_Battler::SetX(it->x);
289 		Sprite_Battler::SetY(it->y);
290 		Sprite_Battler::SetOpacity(std::min(opacity, 255));
291 		Sprite_Battler::Draw(dst);
292 		opacity += steps;
293 	}
294 }
295 
UpdatePosition()296 void Sprite_Actor::UpdatePosition() {
297 	assert(!images.empty());
298 	images.pop_back();
299 	images.insert(images.begin(), {battler->GetDisplayX(), battler->GetDisplayY()});
300 
301 	if (afterimage_fade >= 0) {
302 		++afterimage_fade;
303 		if (afterimage_fade >= images.size()) {
304 			// CBA finished, remove afterimages
305 			images.resize(1);
306 			afterimage_fade = -1;
307 		}
308 	}
309 }
310 
ResetZ()311 void Sprite_Actor::ResetZ() {
312 	Sprite_Battler::ResetZ();
313 	if (animation) {
314 		animation->SetZ(GetZ());
315 	}
316 }
317 
SetNormalAttacking(bool nnormal_attacking)318 void Sprite_Actor::SetNormalAttacking(bool nnormal_attacking) {
319 	normal_attacking = nnormal_attacking;
320 }
321 
SetAfterimageAmount(unsigned amount)322 void Sprite_Actor::SetAfterimageAmount(unsigned amount) {
323 	images.resize(1 + amount);
324 	std::fill(images.begin() + 1, images.end(), images.front());
325 }
326 
DoAfterimageFade()327 void Sprite_Actor::DoAfterimageFade() {
328 	if (images.size() > 1) {
329 		afterimage_fade = 0;
330 	}
331 }
332