NXEngine v1.0.0.6
[NXEngine.git] / TextBox / SaveSelect.cpp
blobad5cc5f21e6c3f24383815e4ef716da2d674fde3
2 /*
3 The save select box (for multiple save files).
4 */
6 #include "../nx.h"
7 #include "../profile.h"
8 #include "../inventory.h"
9 #include "../replay.h"
10 #include "TextBox.h" // for textbox coordinates; MSG_W etc
11 #include "SaveSelect.h"
12 #include "SaveSelect.fdh"
14 // moved here as static data so that the compiler will shut up about a circular dependency
15 // that happens if you try to include profile.h from SaveSelect.h.
16 static Profile fProfiles[MAX_SAVE_SLOTS];
17 static bool fHaveProfile[MAX_SAVE_SLOTS];
18 int fPicXOffset;
20 TB_SaveSelect::TB_SaveSelect()
25 void c------------------------------() {}
28 void TB_SaveSelect::ResetState()
30 fVisible = false;
33 void TB_SaveSelect::SetVisible(bool enable, bool saving)
35 fVisible = enable;
36 if (!enable) return;
37 game.showmapnametime = 0;
39 fCoords.x = 38;
40 fCoords.y = 8;
41 fCoords.w = 244;
42 fCoords.h = 152;
43 fNumFiles = MAX_SAVE_SLOTS;
44 fSaving = saving;
46 fCurSel = settings->last_save_slot;
47 fPicXOffset = -24;
49 // load all profiles
50 memset(fHaveProfile, 0, sizeof(fHaveProfile));
51 for(int i=0;i<fNumFiles;i++)
53 if (!profile_load(GetProfileName(i), &fProfiles[i]))
54 fHaveProfile[i] = true;
57 textbox.ClearText();
60 bool TB_SaveSelect::IsVisible()
62 return fVisible;
66 void c------------------------------() {}
69 void TB_SaveSelect::Run_Input()
71 int start;
73 if (justpushed(DOWNKEY))
75 start = fCurSel;
76 for(;;)
78 fCurSel++;
79 if (fCurSel >= fNumFiles) fCurSel = 0;
81 if (fSaving) break;
82 if (fHaveProfile[fCurSel]) break;
83 if (fCurSel == start) break;
86 sound(SND_MENU_MOVE);
87 fPicXOffset = -24;
90 if (justpushed(UPKEY))
92 start = fCurSel;
93 for(;;)
95 fCurSel--;
96 if (fCurSel < 0) fCurSel = fNumFiles - 1;
98 if (fSaving) break;
99 if (fHaveProfile[fCurSel]) break;
100 if (fCurSel == start) break;
103 sound(SND_MENU_MOVE);
104 fPicXOffset = -24;
107 if (buttonjustpushed())
109 // when shown in a replay, the box is shown and everything just like what was done
110 // originally, but we won't actually overwrite any save files.
111 if (!Replay::IsPlaying())
113 if (fSaving)
114 game_save(fCurSel);
116 settings->last_save_slot = fCurSel;
117 settings_save(); // record new save/load slot
120 SetVisible(false);
122 // when the script hit the <SVP, it froze itself in an artifical <WAI9999
123 // waiting for us to complete. Now unfreeze it so can say "Game saved.",
124 // or for loading, just end.
125 ScriptInstance *s = GetCurrentScriptInstance();
126 if (s) s->delaytimer = 0;
131 void TB_SaveSelect::DrawProfile(int x, int y, int index)
133 Profile *p = &fProfiles[index];
134 const int w = fCoords.w - 33;
136 int sidewd = sprites[SPR_SAVESELECTOR_SIDES].w;
137 int repeatwd = w - (sidewd * 2);
138 int frame = (index == fCurSel) ? 0 : 1;
140 draw_sprite(x, y, SPR_SAVESELECTOR_SIDES, frame, LEFT);
141 draw_sprite_repeating_x(x+sidewd, y, SPR_SAVESELECTOR_MIDDLE, frame, repeatwd);
142 draw_sprite(x+sidewd+repeatwd, y, SPR_SAVESELECTOR_SIDES, frame, RIGHT);
144 y += 4;
145 const int FONT_SPACING = 5;
147 if (fHaveProfile[index])
149 const char *stage = map_get_stage_name(p->stage);
150 font_draw(x+8, y-1, stage, FONT_SPACING);
152 // draw health.
153 DrawHealth(x+w, y, p);
155 else if (fCurSel == index)
157 const char *str = "available";
158 int fx = (w / 2) - (GetFontWidth(str, FONT_SPACING) / 2);
159 font_draw(x+fx, y-1, str, FONT_SPACING);
164 void TB_SaveSelect::DrawExtendedInfo()
166 Profile *p = &fProfiles[fCurSel];
167 int x, y, s;
169 if (fPicXOffset < 0)
171 fPicXOffset += 8;
172 set_clip_rect(MSG_X+4, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
175 // player pic
176 draw_sprite((MSG_X+8) + fPicXOffset, MSG_NORMAL_Y+8, SPR_SELECTOR_ARMS);
178 x = (MSG_X + 12) + fPicXOffset;
179 y = MSG_NORMAL_Y + 12;
180 s = (p->equipmask & EQUIP_MIMIGA_MASK) ? SPR_MYCHAR_MIMIGA : SPR_MYCHAR;
182 draw_sprite(x, y, s, 0, RIGHT);
184 // player gun
185 if (p->curWeapon != WPN_NONE && p->curWeapon != WPN_BLADE)
187 int spr, frame;
188 GetSpriteForGun(p->curWeapon, 0, &spr, &frame);
190 draw_sprite_at_dp(x + sprites[s].frame[0].dir[RIGHT].actionpoint.x, \
191 y + sprites[s].frame[0].dir[RIGHT].actionpoint.y, \
192 spr, frame, RIGHT);
195 clear_clip_rect();
197 // whimsical stars
198 if (p->equipmask & EQUIP_WHIMSTAR)
200 x = MSG_X + 12;
202 for(int i=0;i<3;i++)
204 static int frames[] = { 1, 0, 2 };
205 draw_sprite(x, y+20, SPR_WHIMSICAL_STAR, frames[i]);
206 x += 10;
210 // WEAPONS:
211 x = MSG_X + 64;
212 y = MSG_NORMAL_Y + 8;
214 // weapon list
215 for(int i=0;i<WPN_COUNT;i++)
217 if (p->weapons[i].hasWeapon)
219 draw_sprite(x, y, SPR_ARMSICONS, i);
220 x += 20;
224 // xp of current weapon
225 if (p->curWeapon != WPN_NONE)
227 int xb = MSG_X + 64;
228 int yb = MSG_NORMAL_Y + 26;
230 int level = p->weapons[p->curWeapon].level;
231 int curxp = p->weapons[p->curWeapon].xp;
232 int maxxp = player->weapons[p->curWeapon].max_xp[level];
234 draw_sprite(xb, yb, SPR_XPLEVELICON); xb += 16;
235 draw_sprite(xb, yb, SPR_WHITENUMBERS, level+1); xb += 8;
236 draw_sprite(xb, yb, SPR_XPBAR);
238 if ((curxp == maxxp) && level == 2)
239 draw_sprite(xb, yb, SPR_XPBAR, 3); // MAX
240 else
241 DrawPercentage(xb, yb, SPR_XPBAR, 1, curxp, maxxp, sprites[SPR_XPBAR].w);
244 // ITEMS:
245 x = (MSG_X + 64) - 10;
246 y = MSG_NORMAL_Y + 40;
248 // Booster
249 // items list. I generally tried to put the ones that are temporary and indicate a
250 // quantity of stage completion at the front so they'll be more likely to be visible.
251 static int items[] = {
252 ITEM_BOOSTER08,
253 ITEM_BOOSTER20,
254 ITEM_LIFE_POT,
255 ITEM_PUPPY,
256 ITEM_JELLYFISH_JUICE,
257 ITEM_CHARCOAL,
258 ITEM_GUM_BASE,
259 ITEM_EXPLOSIVE,
260 ITEM_SPRINKLER,
261 ITEM_CONTROLLER,
262 ITEM_MA_PIGNON,
263 ITEM_LITTLE_MAN,
266 for(int i=0;items[i] != -1;i++)
268 if (CheckInventoryList(items[i], p->inventory, p->ninventory) != -1)
270 draw_sprite(x, y, SPR_ITEMIMAGE, items[i]);
271 x += 28;
273 if (x + sprites[SPR_ITEMIMAGE].w > (MSG_X + MSG_W) - 8)
274 break;
278 // health
279 DrawHealth((MSG_X+MSG_W) - 4, MSG_NORMAL_Y+8, p);
284 // I don't think it's possible to get 3-digit max life
285 // without hacking, but I accounted for it anyway.
286 static void DrawHealth(int xright, int y, Profile *p)
288 int hx, len;
290 hx = xright - 28 - 24;
291 if (p->maxhp > 99) { hx -= 8; }
292 len = (p->hp > 99) ? 8 : 0;
293 draw_sprite(hx-len, y-1, SPR_SS_HEALTH_ICON, 0, 0);
294 DrawNumberRAlign(hx+24, y, SPR_WHITENUMBERS, p->hp);
296 hx = xright - 4;
297 len = (p->maxhp > 99) ? 32 : 24;
298 draw_sprite(hx-len, y, SPR_WHITENUMBERS, 11); // '/' character
299 DrawNumberRAlign(hx, y, SPR_WHITENUMBERS, p->maxhp);
304 void TB_SaveSelect::Draw(void)
306 if (!fVisible)
307 return;
309 // handle user input
310 Run_Input();
312 // draw frame
313 TextBox::DrawFrame(fCoords.x, fCoords.y, fCoords.w, fCoords.h);
315 // draw selectors/options
316 int x = fCoords.x + 16;
317 int y = fCoords.y + 15;
319 for(int i=0;i<fNumFiles;i++)
321 DrawProfile(x, y, i);
322 y += (sprites[SPR_SAVESELECTOR_MIDDLE].h + 10);
325 // draw extended info for current selection
326 if (fHaveProfile[fCurSel])
327 DrawExtendedInfo();