3 The save select box (for multiple save files).
7 #include "../profile.h"
8 #include "../inventory.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
];
20 TB_SaveSelect::TB_SaveSelect()
25 void c------------------------------() {}
28 void TB_SaveSelect::ResetState()
33 void TB_SaveSelect::SetVisible(bool enable
, bool saving
)
37 game
.showmapnametime
= 0;
43 fNumFiles
= MAX_SAVE_SLOTS
;
46 fCurSel
= settings
->last_save_slot
;
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;
60 bool TB_SaveSelect::IsVisible()
66 void c------------------------------() {}
69 void TB_SaveSelect::Run_Input()
73 if (justpushed(DOWNKEY
))
79 if (fCurSel
>= fNumFiles
) fCurSel
= 0;
82 if (fHaveProfile
[fCurSel
]) break;
83 if (fCurSel
== start
) break;
90 if (justpushed(UPKEY
))
96 if (fCurSel
< 0) fCurSel
= fNumFiles
- 1;
99 if (fHaveProfile
[fCurSel
]) break;
100 if (fCurSel
== start
) break;
103 sound(SND_MENU_MOVE
);
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())
116 settings
->last_save_slot
= fCurSel
;
117 settings_save(); // record new save/load slot
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
);
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
);
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
];
172 set_clip_rect(MSG_X
+4, 0, SCREEN_WIDTH
, SCREEN_HEIGHT
);
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
);
185 if (p
->curWeapon
!= WPN_NONE
&& p
->curWeapon
!= WPN_BLADE
)
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
, \
198 if (p
->equipmask
& EQUIP_WHIMSTAR
)
204 static int frames
[] = { 1, 0, 2 };
205 draw_sprite(x
, y
+20, SPR_WHIMSICAL_STAR
, frames
[i
]);
212 y
= MSG_NORMAL_Y
+ 8;
215 for(int i
=0;i
<WPN_COUNT
;i
++)
217 if (p
->weapons
[i
].hasWeapon
)
219 draw_sprite(x
, y
, SPR_ARMSICONS
, i
);
224 // xp of current weapon
225 if (p
->curWeapon
!= WPN_NONE
)
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
241 DrawPercentage(xb
, yb
, SPR_XPBAR
, 1, curxp
, maxxp
, sprites
[SPR_XPBAR
].w
);
245 x
= (MSG_X
+ 64) - 10;
246 y
= MSG_NORMAL_Y
+ 40;
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
[] = {
256 ITEM_JELLYFISH_JUICE
,
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
]);
273 if (x
+ sprites
[SPR_ITEMIMAGE
].w
> (MSG_X
+ MSG_W
) - 8)
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
)
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
);
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)
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
])