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