4 * Created on: Aug 5, 2012
8 #include "BattleState.h"
10 #include "PartyLayout.h"
11 #include "states/SelectMoveAction.h"
12 #include "../app/Application.h"
13 #include "../app/Input.h"
14 #include "../common/Ikari.h"
15 #include "../common/Inventory.h"
16 #include "../common/Item.h"
17 #include "../common/Spell.h"
18 #include "../geometry/operators.h"
19 #include "../graphics/Sprite.h"
23 using app::Application;
25 using common::Inventory;
28 using geometry::Point;
29 using geometry::Vector;
36 void BattleState::AddMonster(const Monster &m) {
37 if (monsters.size() >= monstersLayout->NumPositions()) {
38 throw std::overflow_error("too many monsters for layout");
40 monsters.push_back(m);
43 void BattleState::AddHero(const Hero &h) {
44 if (heroes.size() >= heroesLayout->NumPositions()) {
45 throw std::overflow_error("too many heroes for layout");
51 void BattleState::Resize(int w, int h) {
56 void BattleState::EnterState(Application &ctrl, SDL_Surface *screen) {
57 monstersLayout->CalculatePositions(background->w, background->h, monsterPositions);
58 heroesLayout->CalculatePositions(background->w, background->h, heroesPositions);
59 for (vector<Hero>::size_type i(0), end(heroes.size()); i < end; ++i) {
60 spellMenus.push_back(res->spellMenuPrototype);
62 ikariMenus.push_back(res->ikariMenuPrototype);
64 heroTags[i] = HeroTag(&heroes[i], attackChoices + i, res, HeroTag::Alignment((i + 1) % 2));
67 int tagHeight(attackTypeMenu.Height());
68 int tagWidth(attackTypeMenu.Width() * 2 + attackTypeMenu.Width() / 2);
69 int xOffset((BackgroundWidth() - 2 * tagWidth) / 2);
70 heroTagPositions[0] = Point<int>(xOffset, BackgroundHeight() - 2 * tagHeight);
71 heroTagPositions[1] = Point<int>(xOffset + tagWidth, BackgroundHeight() - 2 * tagHeight);
72 heroTagPositions[2] = Point<int>(xOffset, BackgroundHeight() - tagHeight);
73 heroTagPositions[3] = Point<int>(xOffset + tagWidth, BackgroundHeight() - tagHeight);
75 itemMenu = res->itemMenuPrototype;
79 void BattleState::LoadSpellMenu(vector<Hero>::size_type index) {
80 spellMenus[index].Clear();
81 spellMenus[index].Reserve(HeroAt(index).Spells().size());
82 for (vector<const Spell *>::const_iterator i(HeroAt(index).Spells().begin()), end(HeroAt(index).Spells().end()); i != end; ++i) {
83 bool enabled((*i)->CanUseInBattle() && (*i)->Cost() <= HeroAt(index).Mana());
84 spellMenus[index].Add((*i)->Name(), *i, enabled, 0, (*i)->Cost());
88 void BattleState::LoadIkariMenu(vector<Hero>::size_type index) {
89 ikariMenus[index].Clear();
90 ikariMenus[index].Reserve(6);
92 if (HeroAt(index).HasWeapon()) {
93 ikariMenus[index].Add(
94 HeroAt(index).Weapon()->Name(),
95 HeroAt(index).Weapon(),
96 HeroAt(index).Weapon()->HasIkari() && HeroAt(index).Weapon()->GetIkari()->Cost() <= HeroAt(index).IP(),
99 HeroAt(index).Weapon()->HasIkari() ? HeroAt(index).Weapon()->GetIkari()->Name() : "");
101 ikariMenus[index].Add(res->noEquipmentText, 0, false, res->weaponMenuIcon);
104 if (HeroAt(index).HasArmor()) {
105 ikariMenus[index].Add(
106 HeroAt(index).Armor()->Name(),
107 HeroAt(index).Armor(),
108 HeroAt(index).Armor()->HasIkari() && HeroAt(index).Armor()->GetIkari()->Cost() <= HeroAt(index).IP(),
111 HeroAt(index).Armor()->HasIkari() ? HeroAt(index).Armor()->GetIkari()->Name() : "");
113 ikariMenus[index].Add(res->noEquipmentText, 0, false, res->armorMenuIcon);
116 if (HeroAt(index).HasShield()) {
117 ikariMenus[index].Add(
118 HeroAt(index).Shield()->Name(),
119 HeroAt(index).Shield(),
120 HeroAt(index).Shield()->HasIkari() && HeroAt(index).Shield()->GetIkari()->Cost() <= HeroAt(index).IP(),
123 HeroAt(index).Shield()->HasIkari() ? HeroAt(index).Shield()->GetIkari()->Name() : "");
125 ikariMenus[index].Add(res->noEquipmentText, 0, false, res->shieldMenuIcon);
128 if (HeroAt(index).HasHelmet()) {
129 ikariMenus[index].Add(
130 HeroAt(index).Helmet()->Name(),
131 HeroAt(index).Helmet(),
132 HeroAt(index).Helmet()->HasIkari() && HeroAt(index).Helmet()->GetIkari()->Cost() <= HeroAt(index).IP(),
135 HeroAt(index).Helmet()->HasIkari() ? HeroAt(index).Helmet()->GetIkari()->Name() : "");
137 ikariMenus[index].Add(res->noEquipmentText, 0, false, res->helmetMenuIcon);
140 if (HeroAt(index).HasRing()) {
141 ikariMenus[index].Add(
142 HeroAt(index).Ring()->Name(),
143 HeroAt(index).Ring(),
144 HeroAt(index).Ring()->HasIkari() && HeroAt(index).Ring()->GetIkari()->Cost() <= HeroAt(index).IP(),
147 HeroAt(index).Ring()->HasIkari() ? HeroAt(index).Ring()->GetIkari()->Name() : "");
149 ikariMenus[index].Add(res->noEquipmentText, 0, false, res->ringMenuIcon);
152 if (HeroAt(index).HasJewel()) {
153 ikariMenus[index].Add(
154 HeroAt(index).Jewel()->Name(),
155 HeroAt(index).Jewel(),
156 HeroAt(index).Jewel()->HasIkari() && HeroAt(index).Jewel()->GetIkari()->Cost() <= HeroAt(index).IP(),
159 HeroAt(index).Jewel()->HasIkari() ? HeroAt(index).Jewel()->GetIkari()->Name() : "");
161 ikariMenus[index].Add(res->noEquipmentText, 0, false, res->jewelMenuIcon);
165 void BattleState::LoadInventory() {
166 const Inventory &inv(*res->inventory);
168 itemMenu.Reserve(inv.MaxItems());
169 for (int i(0); i < inv.MaxItems(); ++i) {
170 const Item *item(inv.ItemAt(i));
172 itemMenu.Add(item->Name(), item, item->CanUseInBattle(), item->MenuIcon(), inv.ItemCountAt(i));
174 itemMenu.AddEmptyEntry();
179 void BattleState::ExitState(Application &ctrl, SDL_Surface *screen) {
183 void BattleState::ResumeState(Application &ctrl, SDL_Surface *screen) {
184 // TODO: check for victory, defeat or run
185 // reset attack choices
187 for (vector<Hero>::size_type i(0), end(heroes.size()); i < end; ++i) {
188 attackChoices[i] = AttackChoice(this);
190 ctrl.PushState(new SelectMoveAction(this));
193 void BattleState::PauseState(Application &ctrl, SDL_Surface *screen) {
198 void BattleState::HandleInput(const Input &input) {
202 void BattleState::UpdateWorld(float deltaT) {
206 void BattleState::Render(SDL_Surface *screen) {
207 Vector<int> offset(CalculateScreenOffset(screen));
209 RenderBackground(screen, offset);
210 RenderMonsters(screen, offset);
211 // RenderHeroes(screen, offset);
212 RenderHeroTags(screen, offset);
215 void BattleState::RenderBackground(SDL_Surface *screen, const Vector<int> &offset) {
217 SDL_FillRect(screen, 0, SDL_MapRGB(screen->format, 0, 0, 0));
219 destRect.x = offset.X();
220 destRect.y = offset.Y();
221 destRect.w = background->w;
222 destRect.h = background->h;
223 SDL_BlitSurface(background, 0, screen, &destRect);
226 void BattleState::RenderMonsters(SDL_Surface *screen, const Vector<int> &offset) {
227 for (vector<Monster>::size_type i(0), end(monsters.size()); i < end; ++i) {
228 monsters[i].Sprite()->DrawCenterBottom(screen, monsterPositions[i] + offset);
232 void BattleState::RenderHeroes(SDL_Surface *screen, const Vector<int> &offset) {
233 for (vector<Hero>::size_type i(0), end(heroes.size()); i < end; ++i) {
234 heroes[i].Sprite()->DrawCenterBottom(screen, heroesPositions[i] + offset);
238 void BattleState::RenderHeroTags(SDL_Surface *screen, const Vector<int> &offset) {
239 int tagHeight(attackTypeMenu.Height());
240 int tagWidth(attackTypeMenu.Width() * 2 + attackTypeMenu.Width() / 2);
242 for (vector<Hero>::size_type i(0), end(heroes.size()); i < end; ++i) {
243 heroTags[i].Render(screen, tagWidth, tagHeight, heroTagPositions[i] + offset, (int)i == activeHero);