1 #include "PerformAttacks.h"
3 #include "../BattleState.h"
5 #include "../Monster.h"
6 #include "../TargetSelection.h"
7 #include "../../app/Application.h"
8 #include "../../app/Input.h"
9 #include "../../common/Ikari.h"
10 #include "../../common/Item.h"
11 #include "../../common/Spell.h"
12 #include "../../graphics/Animation.h"
13 #include "../../graphics/Font.h"
14 #include "../../graphics/Frame.h"
18 using app::Application;
21 using graphics::AnimationRunner;
26 PerformAttacks::PerformAttacks(Battle *battle, BattleState *parent)
37 void PerformAttacks::OnEnterState(SDL_Surface *screen) {
38 battle->CalculateAttackOrder();
39 numberAnimation.reserve(battle->MaxMonsters() > battle->NumHeroes() + 1
40 ? battle->MaxMonsters()
41 : battle->NumHeroes() + 1);
42 numberPosition.reserve(numberAnimation.size());
43 OnResize(screen->w, screen->h);
46 void PerformAttacks::OnExitState(SDL_Surface *screen) {
47 battle->ClearAllAttacks();
50 void PerformAttacks::OnResumeState(SDL_Surface *screen) {
54 void PerformAttacks::OnPauseState(SDL_Surface *screen) {
59 void PerformAttacks::OnResize(int width, int height) {
60 const Resources &res = parent->Res();
61 framePosition = parent->ScreenOffset();
62 frameSize = Vector<int>(
64 res.titleFrame->BorderHeight() * 2 + res.titleFont->CharHeight());
68 void PerformAttacks::HandleEvents(const Input &input) {
70 if (HasAnimationsRunning()) return;
72 battle->ApplyDamage();
74 if (battle->AttacksFinished()) {
79 battle->CalculateDamage();
81 if (battle->CurrentAttack().IsMonster()) {
82 Monster &monster(battle->MonsterAt(battle->CurrentAttack().index));
83 titleBarText = monster.Name();
84 targetAnimation = AnimationRunner(monster.MeleeAnimation());
85 moveAnimation = AnimationRunner(monster.AttackAnimation());
86 monster.SetAnimation(moveAnimation);
87 AddNumberAnimations(battle->MonsterAt(battle->CurrentAttack().index).GetAttackChoice().Selection());
88 } else if (battle->CurrentAttack().IsCapsule()) {
89 Capsule &capsule(battle->GetCapsule());
90 titleBarText = capsule.Name();
91 targetAnimation = AnimationRunner(capsule.MeleeAnimation());
92 moveAnimation = AnimationRunner(capsule.AttackAnimation());
93 capsule.SetAnimation(moveAnimation);
94 AddNumberAnimations(capsule.GetAttackChoice().Selection());
96 Hero &hero(battle->HeroAt(battle->CurrentAttack().index));
97 const AttackChoice &ac(battle->CurrentAttackAttackChoice());
99 switch (ac.GetType()) {
100 case AttackChoice::SWORD:
101 if (hero.HasWeapon()) {
102 titleBarText = hero.Weapon()->Name();
103 targetAnimation = AnimationRunner(hero.Weapon()->AttackAnimation());
105 titleBarText = "Melee attack!";
106 targetAnimation = AnimationRunner(hero.MeleeAnimation());
108 moveAnimation = AnimationRunner(hero.AttackAnimation());
109 AddNumberAnimations(ac.Selection());
111 case AttackChoice::MAGIC:
112 titleBarText = ac.GetSpell()->Name();
113 moveAnimation = AnimationRunner(hero.SpellAnimation());
115 case AttackChoice::DEFEND:
116 titleBarText = "Defends.";
117 moveAnimation.Clear();
119 case AttackChoice::IKARI:
120 if (ac.GetItem()->HasIkari()) {
121 titleBarText = ac.GetItem()->GetIkari()->Name();
122 if (ac.GetItem()->GetIkari()->IsMagical()) {
123 moveAnimation = AnimationRunner(hero.SpellAnimation());
125 moveAnimation = AnimationRunner(hero.AttackAnimation());
129 case AttackChoice::ITEM:
130 titleBarText = ac.GetItem()->Name();
131 moveAnimation.Clear();
133 case AttackChoice::UNDECIDED:
134 titleBarText = "UNDECIDED";
135 moveAnimation.Clear();
141 titleBarTimer = GraphicsTimers().StartCountdown(850);
142 textPosition = parent->ScreenOffset() + Vector<int>(
143 (parent->Width() - std::strlen(titleBarText) * parent->Res().titleFont->CharWidth()) / 2,
144 parent->Res().titleFrame->BorderHeight());
146 if (moveAnimation.Valid()) {
147 moveAnimation.Start(*this);
148 if (battle->CurrentAttack().IsMonster()) {
149 battle->MonsterAt(battle->CurrentAttack().index).SetAnimation(moveAnimation);
150 } else if (battle->CurrentAttack().IsHero()) {
151 battle->HeroAt(battle->CurrentAttack().index).SetAnimation(moveAnimation);
153 battle->GetCapsule().SetAnimation(moveAnimation);
156 if (targetAnimation.Valid()) {
157 targetAnimationTimer = GraphicsTimers().StartCountdown(150);
159 targetAnimationTimer.Clear();
163 void PerformAttacks::AddNumberAnimations(const TargetSelection &ts) {
164 if (ts.TargetsMonsters()) {
165 for (int i(0); i < battle->MaxMonsters(); ++i) {
167 numberAnimation.push_back(NumberAnimation(ts.GetAmount(i), parent->Res().numberAnimationPrototype, parent->Res().bigNumberSprite));
168 numberPosition.push_back(
169 battle->MonsterAt(i).Position() + parent->ScreenOffset());
170 } else if (ts.IsGood(i)) {
171 numberAnimation.push_back(NumberAnimation(ts.GetAmount(i), parent->Res().numberAnimationPrototype, parent->Res().greenNumberSprite));
172 numberPosition.push_back(
173 battle->MonsterAt(i).Position() + parent->ScreenOffset());
177 for (int i(0); i < battle->NumHeroes(); ++i) {
179 numberAnimation.push_back(NumberAnimation(ts.GetAmount(i), parent->Res().numberAnimationPrototype, parent->Res().bigNumberSprite));
180 numberPosition.push_back(
181 battle->HeroAt(i).Position() + parent->ScreenOffset());
182 } else if (ts.IsGood(i)) {
183 numberAnimation.push_back(NumberAnimation(ts.GetAmount(i), parent->Res().numberAnimationPrototype, parent->Res().greenNumberSprite));
184 numberPosition.push_back(
185 battle->HeroAt(i).Position() + parent->ScreenOffset());
191 void PerformAttacks::CheckAnimations() {
192 if (targetAnimation.Valid() && targetAnimationTimer.JustHit()) {
193 targetAnimation.Start(*this);
195 if (moveAnimation.Valid() && !moveAnimation.Finished()) return;
196 if (targetAnimation.Valid() && !targetAnimation.Finished()) return;
197 if (moveAnimation.Valid() || targetAnimation.Valid()) {
198 moveAnimation.Clear();
199 targetAnimation.Clear();
200 for (vector<NumberAnimation>::iterator i(numberAnimation.begin()), end(numberAnimation.end()); i != end; ++i) {
204 for (vector<NumberAnimation>::iterator i(numberAnimation.begin()), end(numberAnimation.end()); i != end; ++i) {
205 i->CheckTimers(*this);
210 bool PerformAttacks::HasAnimationsRunning() const {
211 if (titleBarTimer.Running()) return true;
212 if (moveAnimation.Valid() && moveAnimation.Running()) return true;
213 if (targetAnimation.Valid() && targetAnimation.Running()) return true;
214 for (vector<NumberAnimation>::const_iterator i(numberAnimation.begin()), end(numberAnimation.end()); i != end; ++i) {
215 if (i->Running()) return true;
220 void PerformAttacks::ResetAnimation() {
221 if (moveAnimation.Valid()) {
222 moveAnimation.Clear();
223 if (!battle->CurrentAttack().IsMonster()) {
224 battle->HeroAt(battle->CurrentAttack().index).GetAnimation().Clear();
227 if (targetAnimation.Valid()) {
228 targetAnimation.Clear();
230 titleBarTimer.Clear();
231 numberAnimation.clear();
232 numberPosition.clear();
236 void PerformAttacks::UpdateWorld(Uint32 deltaT) {
240 void PerformAttacks::Render(SDL_Surface *screen) {
241 parent->RenderBackground(screen);
242 parent->RenderMonsters(screen);
243 parent->RenderHeroes(screen);
244 parent->RenderCapsule(screen);
245 parent->RenderSmallHeroTags(screen);
246 RenderTitleBar(screen);
247 RenderNumbers(screen);
248 RenderTargetAnimation(screen);
251 void PerformAttacks::RenderTitleBar(SDL_Surface *screen) const {
252 if (!titleBarText || !titleBarTimer.Running()) return;
254 parent->Res().titleFrame->Draw(screen, framePosition, frameSize.X(), frameSize.Y());
256 parent->Res().titleFont->DrawString(titleBarText, screen, textPosition);
259 void PerformAttacks::RenderNumbers(SDL_Surface *screen) const {
260 for (vector<NumberAnimation>::size_type i(0), end(numberAnimation.size()); i < end; ++i) {
261 if (numberAnimation[i].Running()) {
262 Vector<int> align(numberAnimation[i].Width() / -2, numberAnimation[i].Height() * -3 / 4);
263 numberAnimation[i].Draw(screen, numberPosition[i] + align);
268 void PerformAttacks::RenderTargetAnimation(SDL_Surface *screen) const {
269 if (!targetAnimation.Valid() || !targetAnimation.Running()) return;
270 const TargetSelection &ts(battle->CurrentAttackAttackChoice().Selection());
271 if (ts.TargetsHeroes()) {
272 for (vector<Vector<int> >::size_type i(0), end(battle->NumHeroes()); i < end; ++i) {
273 if (ts.IsSelected(i)) {
274 targetAnimation.DrawCenter(screen, battle->HeroAt(i).Position() + parent->ScreenOffset());
278 for (vector<Vector<int> >::size_type i(0), end(battle->MaxMonsters()); i < end; ++i) {
279 if (ts.IsSelected(i)) {
280 targetAnimation.DrawCenter(screen, battle->MonsterAt(i).Position() + parent->ScreenOffset());