4 * Created on: Aug 5, 2012
8 #include "BattleState.h"
10 #include "PartyLayout.h"
11 #include "states/SelectMoveAction.h"
12 #include "states/PerformAttacks.h"
13 #include "../app/Application.h"
14 #include "../app/Input.h"
15 #include "../common/Ikari.h"
16 #include "../common/Inventory.h"
17 #include "../common/Item.h"
18 #include "../common/Spell.h"
19 #include "../geometry/operators.h"
20 #include "../graphics/Sprite.h"
25 using app::Application;
27 using common::Inventory;
30 using geometry::Point;
31 using geometry::Vector;
38 void BattleState::AddMonster(const Monster &m) {
39 if (monsters.size() >= monstersLayout->NumPositions()) {
40 throw std::overflow_error("too many monsters for layout");
42 monsters.push_back(m);
45 void BattleState::AddHero(const Hero &h) {
46 if (heroes.size() >= heroesLayout->NumPositions()) {
47 throw std::overflow_error("too many heroes for layout");
52 void BattleState::SwapHeroes(std::vector<Hero>::size_type lhs, std::vector<Hero>::size_type rhs) {
53 if (lhs < 0 || lhs >= heroes.size() || rhs < 0 || rhs >= heroes.size() || lhs == rhs) return;
54 std::swap(heroes[lhs], heroes[rhs]);
58 void BattleState::Resize(int w, int h) {
63 void BattleState::EnterState(Application &ctrl, SDL_Surface *screen) {
64 monstersLayout->CalculatePositions(background->w, background->h, monsterPositions);
65 heroesLayout->CalculatePositions(background->w, background->h, heroesPositions);
66 for (vector<Hero>::size_type i(0), end(heroes.size()); i < end; ++i) {
67 spellMenus.push_back(res->spellMenuPrototype);
69 ikariMenus.push_back(res->ikariMenuPrototype);
71 heroTags[i] = HeroTag(this, i);
74 int tagHeight(attackTypeMenu.Height());
75 int tagWidth(attackTypeMenu.Width() * 2 + attackTypeMenu.Width() / 2);
76 int xOffset((BackgroundWidth() - 2 * tagWidth) / 2);
77 heroTagPositions[0] = Point<int>(xOffset, BackgroundHeight() - 2 * tagHeight);
78 heroTagPositions[1] = Point<int>(xOffset + tagWidth, BackgroundHeight() - 2 * tagHeight);
79 heroTagPositions[2] = Point<int>(xOffset, BackgroundHeight() - tagHeight);
80 heroTagPositions[3] = Point<int>(xOffset + tagWidth, BackgroundHeight() - tagHeight);
82 itemMenu = res->itemMenuPrototype;
86 void BattleState::LoadSpellMenu(vector<Hero>::size_type index) {
87 spellMenus[index].Clear();
88 spellMenus[index].Reserve(HeroAt(index).Spells().size());
89 for (vector<const Spell *>::const_iterator i(HeroAt(index).Spells().begin()), end(HeroAt(index).Spells().end()); i != end; ++i) {
90 bool enabled((*i)->CanUseInBattle() && (*i)->Cost() <= HeroAt(index).Mana());
91 spellMenus[index].Add((*i)->Name(), *i, enabled, 0, (*i)->Cost());
95 void BattleState::LoadIkariMenu(vector<Hero>::size_type index) {
96 ikariMenus[index].Clear();
97 ikariMenus[index].Reserve(6);
99 if (HeroAt(index).HasWeapon()) {
100 ikariMenus[index].Add(
101 HeroAt(index).Weapon()->Name(),
102 HeroAt(index).Weapon(),
103 HeroAt(index).Weapon()->HasIkari() && HeroAt(index).Weapon()->GetIkari()->Cost() <= HeroAt(index).IP(),
106 HeroAt(index).Weapon()->HasIkari() ? HeroAt(index).Weapon()->GetIkari()->Name() : "");
108 ikariMenus[index].Add(res->noEquipmentText, 0, false, res->weaponMenuIcon);
111 if (HeroAt(index).HasArmor()) {
112 ikariMenus[index].Add(
113 HeroAt(index).Armor()->Name(),
114 HeroAt(index).Armor(),
115 HeroAt(index).Armor()->HasIkari() && HeroAt(index).Armor()->GetIkari()->Cost() <= HeroAt(index).IP(),
118 HeroAt(index).Armor()->HasIkari() ? HeroAt(index).Armor()->GetIkari()->Name() : "");
120 ikariMenus[index].Add(res->noEquipmentText, 0, false, res->armorMenuIcon);
123 if (HeroAt(index).HasShield()) {
124 ikariMenus[index].Add(
125 HeroAt(index).Shield()->Name(),
126 HeroAt(index).Shield(),
127 HeroAt(index).Shield()->HasIkari() && HeroAt(index).Shield()->GetIkari()->Cost() <= HeroAt(index).IP(),
130 HeroAt(index).Shield()->HasIkari() ? HeroAt(index).Shield()->GetIkari()->Name() : "");
132 ikariMenus[index].Add(res->noEquipmentText, 0, false, res->shieldMenuIcon);
135 if (HeroAt(index).HasHelmet()) {
136 ikariMenus[index].Add(
137 HeroAt(index).Helmet()->Name(),
138 HeroAt(index).Helmet(),
139 HeroAt(index).Helmet()->HasIkari() && HeroAt(index).Helmet()->GetIkari()->Cost() <= HeroAt(index).IP(),
142 HeroAt(index).Helmet()->HasIkari() ? HeroAt(index).Helmet()->GetIkari()->Name() : "");
144 ikariMenus[index].Add(res->noEquipmentText, 0, false, res->helmetMenuIcon);
147 if (HeroAt(index).HasRing()) {
148 ikariMenus[index].Add(
149 HeroAt(index).Ring()->Name(),
150 HeroAt(index).Ring(),
151 HeroAt(index).Ring()->HasIkari() && HeroAt(index).Ring()->GetIkari()->Cost() <= HeroAt(index).IP(),
154 HeroAt(index).Ring()->HasIkari() ? HeroAt(index).Ring()->GetIkari()->Name() : "");
156 ikariMenus[index].Add(res->noEquipmentText, 0, false, res->ringMenuIcon);
159 if (HeroAt(index).HasJewel()) {
160 ikariMenus[index].Add(
161 HeroAt(index).Jewel()->Name(),
162 HeroAt(index).Jewel(),
163 HeroAt(index).Jewel()->HasIkari() && HeroAt(index).Jewel()->GetIkari()->Cost() <= HeroAt(index).IP(),
166 HeroAt(index).Jewel()->HasIkari() ? HeroAt(index).Jewel()->GetIkari()->Name() : "");
168 ikariMenus[index].Add(res->noEquipmentText, 0, false, res->jewelMenuIcon);
172 void BattleState::LoadInventory() {
173 const Inventory &inv(*res->inventory);
175 itemMenu.Reserve(inv.MaxItems());
176 for (int i(0); i < inv.MaxItems(); ++i) {
177 const Item *item(inv.ItemAt(i));
179 itemMenu.Add(item->Name(), item, item->CanUseInBattle(), item->MenuIcon(), inv.ItemCountAt(i));
181 itemMenu.AddEmptyEntry();
187 void BattleState::ExitState(Application &ctrl, SDL_Surface *screen) {
191 void BattleState::ResumeState(Application &ctrl, SDL_Surface *screen) {
192 // TODO: check for victory or defeat
194 ctrl.PopState(); // quit the battle scene
197 if (AttackSelectionDone()) {
198 ctrl.PushState(new PerformAttacks(this));
200 ctrl.PushState(new SelectMoveAction(this));
204 void BattleState::PauseState(Application &ctrl, SDL_Surface *screen) {
209 void BattleState::ClearAllAttacks() {
211 for (vector<Hero>::size_type i(0), end(heroes.size()); i < end; ++i) {
212 attackChoices[i] = AttackChoice(this);
217 void BattleState::HandleEvents(const Input &input) {
221 void BattleState::UpdateWorld(float deltaT) {
225 void BattleState::Render(SDL_Surface *screen) {
226 Vector<int> offset(CalculateScreenOffset(screen));
228 RenderBackground(screen, offset);
229 RenderMonsters(screen, offset);
230 // RenderHeroes(screen, offset);
231 RenderHeroTags(screen, offset);
234 void BattleState::RenderBackground(SDL_Surface *screen, const Vector<int> &offset) {
236 SDL_FillRect(screen, 0, SDL_MapRGB(screen->format, 0, 0, 0));
238 destRect.x = offset.X();
239 destRect.y = offset.Y();
240 destRect.w = background->w;
241 destRect.h = background->h;
242 SDL_BlitSurface(background, 0, screen, &destRect);
245 void BattleState::RenderMonsters(SDL_Surface *screen, const Vector<int> &offset) {
246 for (vector<Monster>::size_type i(0), end(monsters.size()); i < end; ++i) {
247 monsters[i].Sprite()->DrawCenterBottom(screen, monsterPositions[i] + offset);
251 void BattleState::RenderHeroes(SDL_Surface *screen, const Vector<int> &offset) {
252 for (vector<Hero>::size_type i(0), end(heroes.size()); i < end; ++i) {
253 heroes[i].Sprite()->DrawCenterBottom(screen, heroesPositions[i] + offset, 0, 1);
257 void BattleState::RenderHeroTags(SDL_Surface *screen, const Vector<int> &offset) {
258 int tagHeight(attackTypeMenu.Height());
259 int tagWidth(attackTypeMenu.Width() * 2 + attackTypeMenu.Width() / 2);
261 for (vector<Hero>::size_type i(0), end(heroes.size()); i < end; ++i) {
262 heroTags[i].Render(screen, tagWidth, tagHeight, heroTagPositions[i] + offset, (int)i == activeHero);