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