]> git.localhorst.tv Git - l2e.git/blob - src/battle/BattleState.cpp
0f3fad94838f56e88a16bda2b6efbce8a788b624
[l2e.git] / src / battle / BattleState.cpp
1 /*
2  * BattleState.cpp
3  *
4  *  Created on: Aug 5, 2012
5  *      Author: holy
6  */
7
8 #include "BattleState.h"
9
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"
21
22 #include <algorithm>
23 #include <stdexcept>
24
25 using app::Application;
26 using app::Input;
27 using common::Inventory;
28 using common::Item;
29 using common::Spell;
30 using geometry::Point;
31 using geometry::Vector;
32 using graphics::Menu;
33
34 using std::vector;
35
36 namespace battle {
37
38 void BattleState::AddMonster(const Monster &m) {
39         if (monsters.size() >= monstersLayout->NumPositions()) {
40                 throw std::overflow_error("too many monsters for layout");
41         }
42         monsters.push_back(m);
43 }
44
45 void BattleState::AddHero(const Hero &h) {
46         if (numHeroes >= 4 || numHeroes >= (int)heroesLayout->NumPositions()) {
47                 throw std::overflow_error("too many heroes for layout");
48         }
49         heroes[numHeroes] = h;
50         ++numHeroes;
51 }
52
53 void BattleState::SwapHeroes(int lhs, int rhs) {
54         if (lhs < 0 || lhs >= numHeroes || rhs < 0 || rhs >= numHeroes || lhs == rhs) return;
55         std::swap(heroes[lhs], heroes[rhs]);
56 }
57
58
59 void BattleState::Resize(int w, int h) {
60
61 }
62
63
64 void BattleState::EnterState(Application &ctrl, SDL_Surface *screen) {
65         monstersLayout->CalculatePositions(background->w, background->h, monsterPositions);
66         heroesLayout->CalculatePositions(background->w, background->h, heroesPositions);
67         for (int i(0); i < 4; ++i) {
68                 spellMenus[i] = res->spellMenuPrototype;
69                 LoadSpellMenu(i);
70                 ikariMenus[i] = res->ikariMenuPrototype;
71                 LoadIkariMenu(i);
72                 heroTags[i] = HeroTag(this, i);
73         }
74
75         int tagHeight(attackTypeMenu.Height());
76         int tagWidth(attackTypeMenu.Width() * 2 + attackTypeMenu.Width() / 2);
77         int xOffset((BackgroundWidth() - 2 * tagWidth) / 2);
78         heroTagPositions[0] = Point<int>(xOffset, BackgroundHeight() - 2 * tagHeight);
79         heroTagPositions[1] = Point<int>(xOffset + tagWidth, BackgroundHeight() - 2 * tagHeight);
80         heroTagPositions[2] = Point<int>(xOffset, BackgroundHeight() - tagHeight);
81         heroTagPositions[3] = Point<int>(xOffset + tagWidth, BackgroundHeight() - tagHeight);
82
83         itemMenu = res->itemMenuPrototype;
84         LoadInventory();
85 }
86
87 void BattleState::LoadSpellMenu(vector<Hero>::size_type index) {
88         spellMenus[index].Clear();
89         spellMenus[index].Reserve(HeroAt(index).Spells().size());
90         for (vector<const Spell *>::const_iterator i(HeroAt(index).Spells().begin()), end(HeroAt(index).Spells().end()); i != end; ++i) {
91                 bool enabled((*i)->CanUseInBattle() && (*i)->Cost() <= HeroAt(index).Mana());
92                 spellMenus[index].Add((*i)->Name(), *i, enabled, 0, (*i)->Cost());
93         }
94 }
95
96 void BattleState::LoadIkariMenu(vector<Hero>::size_type index) {
97         ikariMenus[index].Clear();
98         ikariMenus[index].Reserve(6);
99
100         if (HeroAt(index).HasWeapon()) {
101                 ikariMenus[index].Add(
102                                 HeroAt(index).Weapon()->Name(),
103                                 HeroAt(index).Weapon(),
104                                 HeroAt(index).Weapon()->HasIkari() && HeroAt(index).Weapon()->GetIkari()->Cost() <= HeroAt(index).IP(),
105                                 res->weaponMenuIcon,
106                                 0,
107                                 HeroAt(index).Weapon()->HasIkari() ? HeroAt(index).Weapon()->GetIkari()->Name() : "");
108         } else {
109                 ikariMenus[index].Add(res->noEquipmentText, 0, false, res->weaponMenuIcon);
110         }
111
112         if (HeroAt(index).HasArmor()) {
113                 ikariMenus[index].Add(
114                                 HeroAt(index).Armor()->Name(),
115                                 HeroAt(index).Armor(),
116                                 HeroAt(index).Armor()->HasIkari() && HeroAt(index).Armor()->GetIkari()->Cost() <= HeroAt(index).IP(),
117                                 res->armorMenuIcon,
118                                 0,
119                                 HeroAt(index).Armor()->HasIkari() ? HeroAt(index).Armor()->GetIkari()->Name() : "");
120         } else {
121                 ikariMenus[index].Add(res->noEquipmentText, 0, false, res->armorMenuIcon);
122         }
123
124         if (HeroAt(index).HasShield()) {
125                 ikariMenus[index].Add(
126                                 HeroAt(index).Shield()->Name(),
127                                 HeroAt(index).Shield(),
128                                 HeroAt(index).Shield()->HasIkari() && HeroAt(index).Shield()->GetIkari()->Cost() <= HeroAt(index).IP(),
129                                 res->shieldMenuIcon,
130                                 0,
131                                 HeroAt(index).Shield()->HasIkari() ? HeroAt(index).Shield()->GetIkari()->Name() : "");
132         } else {
133                 ikariMenus[index].Add(res->noEquipmentText, 0, false, res->shieldMenuIcon);
134         }
135
136         if (HeroAt(index).HasHelmet()) {
137                 ikariMenus[index].Add(
138                                 HeroAt(index).Helmet()->Name(),
139                                 HeroAt(index).Helmet(),
140                                 HeroAt(index).Helmet()->HasIkari() && HeroAt(index).Helmet()->GetIkari()->Cost() <= HeroAt(index).IP(),
141                                 res->helmetMenuIcon,
142                                 0,
143                                 HeroAt(index).Helmet()->HasIkari() ? HeroAt(index).Helmet()->GetIkari()->Name() : "");
144         } else {
145                 ikariMenus[index].Add(res->noEquipmentText, 0, false, res->helmetMenuIcon);
146         }
147
148         if (HeroAt(index).HasRing()) {
149                 ikariMenus[index].Add(
150                                 HeroAt(index).Ring()->Name(),
151                                 HeroAt(index).Ring(),
152                                 HeroAt(index).Ring()->HasIkari() && HeroAt(index).Ring()->GetIkari()->Cost() <= HeroAt(index).IP(),
153                                 res->ringMenuIcon,
154                                 0,
155                                 HeroAt(index).Ring()->HasIkari() ? HeroAt(index).Ring()->GetIkari()->Name() : "");
156         } else {
157                 ikariMenus[index].Add(res->noEquipmentText, 0, false, res->ringMenuIcon);
158         }
159
160         if (HeroAt(index).HasJewel()) {
161                 ikariMenus[index].Add(
162                                 HeroAt(index).Jewel()->Name(),
163                                 HeroAt(index).Jewel(),
164                                 HeroAt(index).Jewel()->HasIkari() && HeroAt(index).Jewel()->GetIkari()->Cost() <= HeroAt(index).IP(),
165                                 res->jewelMenuIcon,
166                                 0,
167                                 HeroAt(index).Jewel()->HasIkari() ? HeroAt(index).Jewel()->GetIkari()->Name() : "");
168         } else {
169                 ikariMenus[index].Add(res->noEquipmentText, 0, false, res->jewelMenuIcon);
170         }
171 }
172
173 void BattleState::LoadInventory() {
174         const Inventory &inv(*res->inventory);
175         itemMenu.Clear();
176         itemMenu.Reserve(inv.MaxItems());
177         for (int i(0); i < inv.MaxItems(); ++i) {
178                 const Item *item(inv.ItemAt(i));
179                 if (item) {
180                         itemMenu.Add(item->Name(), item, item->CanUseInBattle(), item->MenuIcon(), inv.ItemCountAt(i));
181                 } else {
182                         itemMenu.AddEmptyEntry();
183                 }
184         }
185         ClearAllAttacks();
186 }
187
188 void BattleState::ExitState(Application &ctrl, SDL_Surface *screen) {
189
190 }
191
192 void BattleState::ResumeState(Application &ctrl, SDL_Surface *screen) {
193         // TODO: check for victory or defeat
194         if (ranAway) {
195                 ctrl.PopState(); // quit the battle scene
196                 return;
197         }
198         if (AttackSelectionDone()) {
199                 ctrl.PushState(new PerformAttacks(this));
200         } else {
201                 ctrl.PushState(new SelectMoveAction(this));
202         }
203 }
204
205 void BattleState::PauseState(Application &ctrl, SDL_Surface *screen) {
206
207 }
208
209
210 void BattleState::ClearAllAttacks() {
211         activeHero = -1;
212         for (int i(0); i < numHeroes; ++i) {
213                 attackChoices[i] = AttackChoice(this);
214         }
215 }
216
217
218 void BattleState::HandleEvents(const Input &input) {
219
220 }
221
222 void BattleState::UpdateWorld(float deltaT) {
223
224 }
225
226 void BattleState::Render(SDL_Surface *screen) {
227         Vector<int> offset(CalculateScreenOffset(screen));
228
229         RenderBackground(screen, offset);
230         RenderMonsters(screen, offset);
231 //      RenderHeroes(screen, offset);
232         RenderHeroTags(screen, offset);
233 }
234
235 void BattleState::RenderBackground(SDL_Surface *screen, const Vector<int> &offset) {
236         // black for now
237         SDL_FillRect(screen, 0, SDL_MapRGB(screen->format, 0, 0, 0));
238         SDL_Rect destRect;
239         destRect.x = offset.X();
240         destRect.y = offset.Y();
241         destRect.w = background->w;
242         destRect.h = background->h;
243         SDL_BlitSurface(background, 0, screen, &destRect);
244 }
245
246 void BattleState::RenderMonsters(SDL_Surface *screen, const Vector<int> &offset) {
247         for (vector<Monster>::size_type i(0), end(monsters.size()); i < end; ++i) {
248                 monsters[i].Sprite()->DrawCenterBottom(screen, monsterPositions[i] + offset);
249         }
250 }
251
252 void BattleState::RenderHeroes(SDL_Surface *screen, const Vector<int> &offset) {
253         for (int i(0); i < numHeroes; ++i) {
254                 heroes[i].Sprite()->DrawCenterBottom(screen, heroesPositions[i] + offset, 0, 1);
255         }
256 }
257
258 void BattleState::RenderHeroTags(SDL_Surface *screen, const Vector<int> &offset) {
259         int tagHeight(attackTypeMenu.Height());
260         int tagWidth(attackTypeMenu.Width() * 2 + attackTypeMenu.Width() / 2);
261
262         for (int i(0); i < numHeroes; ++i) {
263                 heroTags[i].Render(screen, tagWidth, tagHeight, heroTagPositions[i] + offset, (int)i == activeHero);
264         }
265 }
266
267 }