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