]> git.localhorst.tv Git - l2e.git/blob - src/menu/EquipMenu.cpp
removed lazy fwd headers
[l2e.git] / src / menu / EquipMenu.cpp
1 #include "EquipMenu.h"
2
3 #include "HeroStatus.h"
4 #include "PartyMenu.h"
5 #include "Resources.h"
6 #include "../app/Application.h"
7 #include "../app/Input.h"
8 #include "../common/GameConfig.h"
9 #include "../common/GameState.h"
10 #include "../common/Hero.h"
11 #include "../common/Inventory.h"
12 #include "../common/Item.h"
13 #include "../common/Stats.h"
14 #include "../graphics/Font.h"
15 #include "../graphics/Frame.h"
16 #include "../math/Vector.h"
17
18 using app::Input;
19 using common::Hero;
20 using common::Inventory;
21 using common::Item;
22 using common::Stats;
23 using math::Vector;
24 using graphics::Font;
25 using graphics::Frame;
26
27 namespace menu {
28
29 EquipMenu::EquipMenu(PartyMenu *parent, int cursor)
30 : parent(parent)
31 , cursor(cursor)
32 , actionMenu(*parent->Res().equipmentActionMenuProperties)
33 , equipmentMenu(*parent->Res().equipmentMenuProperties)
34 , inventoryMenu(*parent->Res().inventoryMenuProperties) {
35         actionMenu.Add(parent->Res().equipMenuEquipLabel, CHOICE_EQUIP);
36         actionMenu.Add(parent->Res().equipMenuStrongestLabel, CHOICE_STRONGEST);
37         actionMenu.Add(parent->Res().equipMenuRemoveLabel, CHOICE_REMOVE);
38         actionMenu.Add(parent->Res().equipMenuRemoveAllLabel, CHOICE_REMOVE_ALL);
39         actionMenu.Add(parent->Res().equipMenuDropLabel, CHOICE_DROP);
40
41         LoadEquipment();
42 }
43
44
45 void EquipMenu::OnEnterState(SDL_Surface *) {
46         equipmentMenu.SetInactive();
47         inventoryMenu.SetInactive();
48 }
49
50 void EquipMenu::OnExitState(SDL_Surface *) {
51
52 }
53
54 void EquipMenu::OnResumeState(SDL_Surface *) {
55
56 }
57
58 void EquipMenu::OnPauseState(SDL_Surface *) {
59
60 }
61
62
63 void EquipMenu::OnResize(int width, int height) {
64
65 }
66
67
68 void EquipMenu::HandleEvents(const Input &input) {
69         if (input.JustPressed(Input::SHOULDER_LEFT)) {
70                 PreviousHero();
71         }
72         if (input.JustPressed(Input::SHOULDER_RIGHT)) {
73                 NextHero();
74         }
75         if (actionMenu.IsActive()) {
76                 if (input.JustPressed(Input::PAD_UP)) {
77                         actionMenu.PreviousRow();
78                 }
79                 if (input.JustPressed(Input::PAD_DOWN)) {
80                         actionMenu.NextRow();
81                 }
82                 if (input.JustPressed(Input::ACTION_A)) {
83                         switch (actionMenu.Selected()) {
84                                 case CHOICE_EQUIP:
85                                         LoadEquipment();
86                                         actionMenu.SetSelected();
87                                         equipmentMenu.SetActive();
88                                         break;
89                                 case CHOICE_STRONGEST:
90                                         // TODO: implement "equip strongest" when items' stat effects are done
91                                         break;
92                                 case CHOICE_REMOVE:
93                                         actionMenu.SetSelected();
94                                         equipmentMenu.SetActive();
95                                         break;
96                                 case CHOICE_REMOVE_ALL:
97                                         RemoveAllEquipment();
98                                         break;
99                                 case CHOICE_DROP:
100                                         actionMenu.SetSelected();
101                                         equipmentMenu.SetActive();
102                                         break;
103                         }
104                 } else if (input.JustPressed(Input::ACTION_B)) {
105                         Ctrl().PopState();
106                 }
107         } else if (equipmentMenu.IsActive()) {
108                 if (input.JustPressed(Input::PAD_UP)) {
109                         equipmentMenu.PreviousRow();
110                         if (InventoryVisible()) {
111                                 LoadInventory();
112                         }
113                 }
114                 if (input.JustPressed(Input::PAD_DOWN)) {
115                         equipmentMenu.NextRow();
116                         if (InventoryVisible()) {
117                                 LoadInventory();
118                         }
119                 }
120                 if (input.JustPressed(Input::ACTION_B)) {
121                         equipmentMenu.SetInactive();
122                         actionMenu.SetActive();
123                 } else if (input.JustPressed(Input::ACTION_A)) {
124                         switch (actionMenu.Selected()) {
125                                 case CHOICE_EQUIP:
126                                         equipmentMenu.SetSelected();
127                                         inventoryMenu.SetActive();
128                                         break;
129                                 case CHOICE_STRONGEST:
130                                 case CHOICE_REMOVE_ALL:
131                                         // invalid state, recover
132                                         equipmentMenu.SetInactive();
133                                         actionMenu.SetActive();
134                                         break;
135                                 case CHOICE_REMOVE:
136                                         RemoveItem();
137                                         break;
138                                 case CHOICE_DROP:
139                                         DropItem();
140                                         break;
141                         }
142                 }
143         } else {
144                 if (input.JustPressed(Input::PAD_UP)) {
145                         inventoryMenu.PreviousRow();
146                 }
147                 if (input.JustPressed(Input::PAD_DOWN)) {
148                         inventoryMenu.NextRow();
149                 }
150                 if (input.JustPressed(Input::ACTION_A)) {
151                         EquipSelected();
152                         inventoryMenu.SetInactive();
153                         equipmentMenu.SetActive();
154                 } else if (input.JustPressed(Input::ACTION_B)) {
155                         inventoryMenu.SetInactive();
156                         equipmentMenu.SetActive();
157                 }
158         }
159 }
160
161 void EquipMenu::UpdateWorld(Uint32 deltaT) {
162
163 }
164
165 void EquipMenu::Render(SDL_Surface *screen) {
166         Vector<int> offset((screen->w - Width()) / 2, (screen->h - Height()) / 2);
167         Vector<int> shoulderNavOffset(
168                         5 * parent->Res().statusFont->CharWidth(),
169                         parent->Res().statusFont->CharHeight());
170         Vector<int> statsOffset(
171                         4 * parent->Res().statusFont->CharWidth(),
172                         8 * parent->Res().statusFont->CharHeight() - parent->Res().statusFont->CharHeight() / 8);
173         Vector<int> equipOffset(
174                         17 * parent->Res().statusFont->CharWidth(),
175                         4 * parent->Res().statusFont->CharHeight() - parent->Res().statusFont->CharHeight() / 8);
176
177         parent->RenderBackground(screen);
178         parent->Res().shoulderNav->Draw(screen, offset + shoulderNavOffset);
179         RenderStatus(screen, offset + parent->StatusOffset(0));
180         RenderStats(screen, offset + statsOffset);
181         RenderEquipmentMenu(screen, offset + equipOffset);
182         if (InventoryVisible()) {
183                 Vector<int> inventoryOffset(
184                                 parent->Res().statusFont->CharWidth(),
185                                 17 * parent->Res().statusFont->CharHeight() - parent->Res().statusFont->CharHeight() / 8);
186                 RenderInventoryMenu(screen, offset + inventoryOffset);
187         } else {
188                 Vector<int> menuOffset(
189                                 15 * parent->Res().statusFont->CharWidth(),
190                                 17 * parent->Res().statusFont->CharHeight() - parent->Res().statusFont->CharHeight() / 8);
191                 RenderActionMenu(screen, offset + menuOffset);
192         }
193 }
194
195 int EquipMenu::Width() const {
196         return parent->Width();
197 }
198
199 int EquipMenu::Height() const {
200         return parent->Height();
201 }
202
203 void EquipMenu::RenderStatus(SDL_Surface *screen, const Vector<int> &offset) const {
204         parent->GetHeroStatus(cursor).Render(screen, offset);
205 }
206
207 void EquipMenu::RenderStats(SDL_Surface *screen, const Vector<int> &offset) const {
208         const Stats &stats(GetHero().GetStats());
209         Vector<int> lineBreak(0, parent->Res().statusFont->CharHeight());
210
211         Vector<int> position(offset);
212         RenderStatsLine(parent->Res().atpLabel, stats.Attack(), screen, position);
213
214         position += lineBreak;
215         RenderStatsLine(parent->Res().dfpLabel, stats.Defense(), screen, position);
216
217         position += lineBreak;
218         RenderStatsLine(parent->Res().strLabel, stats.Strength(), screen, position);
219
220         position += lineBreak;
221         RenderStatsLine(parent->Res().aglLabel, stats.Agility(), screen, position);
222
223         position += lineBreak;
224         RenderStatsLine(parent->Res().intLabel, stats.Intelligence(), screen, position);
225
226         position += lineBreak;
227         RenderStatsLine(parent->Res().gutLabel, stats.Gut(), screen, position);
228
229         position += lineBreak;
230         RenderStatsLine(parent->Res().mgrLabel, stats.MagicResistance(), screen, position);
231 }
232
233 void EquipMenu::RenderStatsLine(const char *label, int number, SDL_Surface *screen, const Vector<int> &position) const {
234         const Font &font(*parent->Res().statusFont);
235         const Vector<int> numberOffset(4 * font.CharWidth(), 0);
236
237         font.DrawString(label, screen, position, 3);
238         font.DrawNumber(number, screen, position + numberOffset, 3);
239 }
240
241 void EquipMenu::RenderEquipmentMenu(SDL_Surface *screen, const Vector<int> &offset) const {
242         equipmentMenu.Draw(screen, offset);
243 }
244
245 void EquipMenu::RenderActionMenu(SDL_Surface *screen, const Vector<int> &offset) const {
246         const Font &font(*parent->Res().statusFont);
247         const Frame &frame(*parent->Res().statusFrame);
248         const Vector<int> menuOffset(3 * font.CharWidth(), font.CharHeight() + font.CharHeight() / 2);
249
250         frame.Draw(screen, offset, 15 * font.CharWidth(), 10 * font.CharHeight());
251         actionMenu.Draw(screen, offset + menuOffset);
252 }
253
254 void EquipMenu::RenderInventoryMenu(SDL_Surface *screen, const Vector<int> &offset) const {
255         const Font &font(*parent->Res().normalFont);
256         const Frame &frame(*parent->Res().statusFrame);
257         const Vector<int> menuOffset(3 * font.CharWidth(), font.CharHeight() + font.CharHeight() / 4);
258
259         frame.Draw(screen, offset, 30 * font.CharWidth(), 11 * font.CharHeight());
260         inventoryMenu.Draw(screen, offset + menuOffset);
261 }
262
263
264 void EquipMenu::NextHero() {
265         cursor = (cursor + 1) % parent->Game().state->partySize;
266         LoadEquipment();
267         if (InventoryVisible()) {
268                 LoadInventory();
269         }
270 }
271
272 void EquipMenu::PreviousHero() {
273         cursor = (cursor + parent->Game().state->partySize - 1) % parent->Game().state->partySize;
274         LoadEquipment();
275         if (InventoryVisible()) {
276                 LoadInventory();
277         }
278 }
279
280 Hero &EquipMenu::GetHero() {
281         return *parent->Game().state->party[cursor];
282 }
283
284 const Hero &EquipMenu::GetHero() const {
285         return *parent->Game().state->party[cursor];
286 }
287
288
289 void EquipMenu::LoadEquipment() {
290         equipmentMenu.Clear();
291         for (int i = 0; i < Hero::EQUIP_COUNT; ++i) {
292                 if (GetHero().Equipped(Hero::EquipSlot(i))) {
293                         const Item *item(GetHero().Equipment(Hero::EquipSlot(i)));
294                         equipmentMenu.Add(item->Name(), item, true, item->MenuIcon());
295                 } else {
296                         equipmentMenu.Add(parent->Res().noEquipmentText, 0);
297                 }
298         }
299 }
300
301 void EquipMenu::RemoveAllEquipment() {
302         Inventory &inv(parent->Game().state->inventory);
303         for (int i = 0; i < Hero::EQUIP_COUNT; ++i) {
304                 if (GetHero().Equipped(Hero::EquipSlot(i))
305                                 && inv.Add(GetHero().Equipment(Hero::EquipSlot(i)), 1)) {
306                         GetHero().RemoveEquipment(Hero::EquipSlot(i));
307                 }
308         }
309         LoadEquipment();
310 }
311
312 void EquipMenu::RemoveItem() {
313         Inventory &inv(parent->Game().state->inventory);
314         Hero::EquipSlot slot = Hero::EquipSlot(equipmentMenu.SelectedIndex());
315
316         if (GetHero().Equipped(slot) && inv.Add(GetHero().Equipment(slot), 1)) {
317                 GetHero().RemoveEquipment(slot);
318         }
319
320         LoadEquipment();
321 }
322
323 void EquipMenu::DropItem() {
324         GetHero().RemoveEquipment(Hero::EquipSlot(equipmentMenu.SelectedIndex()));
325         LoadEquipment();
326 }
327
328
329 bool EquipMenu::InventoryVisible() const {
330         return !actionMenu.IsActive() && actionMenu.Selected() == CHOICE_EQUIP;
331 }
332
333 void EquipMenu::LoadInventory() {
334         const Inventory &inv = parent->Game().state->inventory;
335         const Hero &hero = GetHero();
336         const Hero::EquipSlot slot = Hero::EquipSlot(equipmentMenu.SelectedIndex());
337
338         inventoryMenu.Clear();
339         for (int i = 0; i < inv.MaxItems(); ++i) {
340                 const Item *item = inv.ItemAt(i);
341                 if (item && item->EquipableAt(slot)) {
342                         inventoryMenu.Add(item->Name(), item, hero.CanEquip(*item),
343                                         item->MenuIcon(), inv.ItemCountAt(i));
344                 }
345         }
346 }
347
348 void EquipMenu::EquipSelected() {
349         Inventory &inv = parent->Game().state->inventory;
350         Hero &hero = GetHero();
351         const Hero::EquipSlot slot = Hero::EquipSlot(equipmentMenu.SelectedIndex());
352
353         const Item *selected = inventoryMenu.Selected();
354         const Item *equipped = equipmentMenu.Selected();
355
356         if (!hero.CanEquip(*selected)) {
357                 // TODO: error noise and blur
358                 return;
359         }
360
361         inv.Remove(selected, 1);
362         if (!inv.Add(equipped, 1)) {
363                 // roll back
364                 inv.Add(selected, 1);
365                 // TODO: error noise, blur, message?
366                 return;
367         }
368
369         hero.SetEquipment(slot, selected);
370         LoadEquipment();
371         LoadInventory();
372 }
373
374 }