4 #include "statusbar.fdh"
14 #define HEALTH_X (STATUS_X+0)
15 #define HEALTH_Y (STATUS_Y+24)
16 #define HEALTHFILL_X (HEALTH_X+24)
17 #define HEALTHFILL_Y (HEALTH_Y+1)
18 #define HEALTHFILL_MAXLEN 39
20 #define WEAPONBAR_Y (STATUS_Y+1)
21 #define CURWEAPON_X (STATUS_X+1)
23 #define XPBAR_Y (STATUS_Y+16) // Y coordinate of "XP" area
24 #define XPBAR_X (STATUS_X+24) // X of yellow XP bar
26 #define AMMO_X (STATUS_X+32)
27 #define AMMO_Y (STATUS_Y+0)
29 #define NIKU_X STATUS_X
32 #define FRAME_XP_BAR 0 // empty bar frame
33 #define FRAME_XP_FILL 1 // sprite to fill bar with
34 #define FRAME_XP_FLASH 2 // white flashing when XP is gained
35 #define FRAME_XP_MAX 3 // "MAX" when XP is at max on L3
37 //int displayed_health = 0;
38 //int healthdectimer = 0;
40 static PercentBar PHealthBar
;
42 // the "slide" effect when changing weapons
45 int lv_offset
; // offset of XP bar
46 int wpn_offset
; // offset of weapon bar
47 int ammo_offset
; // offset of ammo, in addition to wpn_offset
50 int firstWeapon
; // weapon to show as current weapon
52 #define SLIDE_LV_OFFSET 16
53 #define SLIDE_TIMER_START 5
56 bool statusbar_init(void)
58 InitPercentBar(&PHealthBar
, player
->hp
);
60 memset(&slide
, 0, sizeof(slide
));
61 slide
.firstWeapon
= player
->curWeapon
;
66 void DrawStatusBar(void)
68 int level
, curxp
, maxxp
;
72 //debug("%08x", game.bossbar.object);
73 //debug("%s", game.bossbar.defeated ? "true" : "false");
75 // handle animations etc
79 if (game
.bossbar
.object
&& !game
.bossbar
.defeated
)
82 // BOSS_X = 32 at normal resolution
83 #define BOSS_X ((SCREEN_WIDTH / 2) - (BOSSBAR_W / 2) - 29)
84 #define BOSS_Y (SCREEN_HEIGHT-20)
85 draw_sprite(BOSS_X
, BOSS_Y
, SPR_TEXTBOX
, 0, 0);
86 draw_sprite(BOSS_X
, BOSS_Y
+8, SPR_TEXTBOX
, 2, 0);
87 draw_sprite(BOSS_X
+8, BOSS_Y
+4, SPR_BOSSHPICON
, 0, 0);
89 // e.g. bosses w/ multiple forms (Ballos)
90 if (game
.bossbar
.object
->hp
> game
.bossbar
.starting_hp
)
91 game
.bossbar
.starting_hp
= game
.bossbar
.object
->hp
;
93 RunPercentBar(&game
.bossbar
.bar
, game
.bossbar
.object
->hp
);
94 DrawPercentBar(&game
.bossbar
.bar
, BOSS_X
+40, BOSS_Y
+5, game
.bossbar
.object
->hp
, game
.bossbar
.starting_hp
, BOSSBAR_W
);
97 if (game
.frozen
|| player
->inputs_locked
) return;
98 if (fade
.getstate() != FS_NO_FADE
) return;
102 if (!player
->hurt_flash_state
)
106 // -- draw the health bar -----------------------------
107 draw_sprite(HEALTH_X
, HEALTH_Y
, SPR_HEALTHBAR
, 0, 0);
109 DrawPercentBar(&PHealthBar
, HEALTHFILL_X
, HEALTHFILL_Y
, player
->hp
, player
->maxHealth
, HEALTHFILL_MAXLEN
);
111 // draw the health in numbers
112 DrawNumberRAlign(HEALTH_X
+24, HEALTH_Y
, SPR_WHITENUMBERS
, PHealthBar
.displayed_value
);
115 // -- draw the XP bar ---------------------------------
116 level
= player
->weapons
[player
->curWeapon
].level
;
117 curxp
= player
->weapons
[player
->curWeapon
].xp
;
118 maxxp
= player
->weapons
[player
->curWeapon
].max_xp
[level
];
120 if (player
->curWeapon
== WPN_NONE
)
126 // draw XP bar and fill it
127 draw_sprite(XPBAR_X
+slide
.lv_offset
, XPBAR_Y
, SPR_XPBAR
, FRAME_XP_BAR
, 0);
129 maxed_out
= ((curxp
== maxxp
) && level
== 2);
131 DrawPercentage(XPBAR_X
+slide
.lv_offset
, XPBAR_Y
, SPR_XPBAR
, FRAME_XP_FILL
, curxp
, maxxp
, sprites
[SPR_XPBAR
].w
);
133 // draw the white flashing if we just got more XP
134 // the time-left and flash-state are in separate variables--
135 // otherwise the Spur will not flash XP bar
136 if (statusbar
.xpflashcount
)
138 if (++statusbar
.xpflashstate
& 2)
140 draw_sprite(XPBAR_X
+slide
.lv_offset
, XPBAR_Y
, SPR_XPBAR
, FRAME_XP_FLASH
, 0);
143 statusbar
.xpflashcount
--;
145 else statusbar
.xpflashstate
= 0;
149 draw_sprite(XPBAR_X
+slide
.lv_offset
, XPBAR_Y
, SPR_XPBAR
, FRAME_XP_MAX
, 0);
152 DrawWeaponLevel(HEALTH_X
+ slide
.lv_offset
, XPBAR_Y
, player
->curWeapon
);
155 // -- draw the weapon bar -----------------------------
156 // draw current weapon
157 if (player
->curWeapon
!= WPN_NONE
)
158 draw_sprite(CURWEAPON_X
+ slide
.wpn_offset
, WEAPONBAR_Y
, SPR_ARMSICONS
, slide
.firstWeapon
, 0);
160 // draw ammo, note we draw ammo of firstweapon NOT current weapon, for slide effect
161 DrawWeaponAmmo((AMMO_X
+ slide
.wpn_offset
+ slide
.ammo_offset
), AMMO_Y
, slide
.firstWeapon
);
163 // draw other weapons
164 w
= slide
.firstWeapon
;
165 x
= STATUS_X
+ 64 + slide
.wpn_offset
+ 1;
168 if (++w
>= WPN_COUNT
) w
= 0;
169 if (w
==slide
.firstWeapon
) break;
171 if (player
->weapons
[w
].hasWeapon
)
173 draw_sprite(x
, WEAPONBAR_Y
, SPR_ARMSICONS
, w
, RIGHT
);
178 DrawAirLeft((SCREEN_WIDTH
/2) - (5*8), ((SCREEN_HEIGHT
)/2)-16);
182 void DrawAirLeft(int x
, int y
)
184 if (player
->airshowtimer
)
186 draw_sprite(x
, y
, SPR_AIR
, (player
->airleft
%30 > 10) ? 0:1, RIGHT
);
188 if (player
->airshowtimer
%6 < 4)
189 DrawNumber(x
+32, y
, player
->airleft
/10);
193 void DrawWeaponAmmo(int x
, int y
, int wpn
)
196 if (!player
->hurt_flash_state
|| game
.mode
!= GM_NORMAL
)
198 draw_sprite(x
, y
+8, SPR_WHITENUMBERS
, 11, 0);
201 if (!player
->weapons
[wpn
].maxammo
)
202 { // ammo is "not applicable"
204 draw_sprite(x
, y
, SPR_NAAMMO
, 0, 0);
205 draw_sprite(x
, y
+8, SPR_NAAMMO
, 0, 0);
209 DrawNumber(x
, y
, player
->weapons
[wpn
].ammo
);
210 DrawNumber(x
, y
+8, player
->weapons
[wpn
].maxammo
);
214 void DrawWeaponLevel(int x
, int y
, int wpn
)
216 int level
= (player
->weapons
[wpn
].level
+ 1);
217 if (wpn
== WPN_NONE
) level
= 0;
219 draw_sprite(x
, y
, SPR_XPLEVELICON
, 0, 0);
220 draw_sprite(x
+16, y
, SPR_WHITENUMBERS
, level
, 0);
224 static void RunStatusBar(void)
226 // handle slowly decreasing the health when player is hurt
227 // note how it only decrements while it's actually visible--i thought that was a nice touch
228 if (!player
->hurt_flash_state
)
230 RunPercentBar(&PHealthBar
, player
->hp
);
233 if (game
.frozen
|| player
->inputs_locked
) return;
234 if (fade
.getstate() != FS_NO_FADE
) return;
236 // sliding effect when changing weapons
239 slide
.lv_offset
+= slide
.move_dir
;
240 if (--slide
.timer
> 0)
242 slide
.wpn_offset
+= slide
.move_dir
;
246 if (!slide
.timer
) slide
.firstWeapon
= player
->curWeapon
;
247 slide
.wpn_offset
= slide
.lv_offset
;
248 slide
.ammo_offset
= 0;
253 slide
.firstWeapon
= player
->curWeapon
;
258 // start the slide effect. if dir = LEFT, slides left (next weapon), if RIGHT does "prev weapon"
259 // newwpn = the weapon to change to
260 void weapon_slide(int dir
, int newwpn
)
263 if (slide
.lv_offset
) slide
.firstWeapon
= player
->curWeapon
; // if already sliding change immediately
264 if (dir
==RIGHT
) sign
= -1; else sign
= 1;
266 slide
.lv_offset
= SLIDE_LV_OFFSET
* sign
;
267 slide
.timer
= SLIDE_TIMER_START
;
268 slide
.ammo_offset
= 16 * sign
;
269 slide
.move_dir
= -2 * sign
;
270 player
->curWeapon
= newwpn
;
273 // the opening slide effect on load/new game
274 void weapon_introslide()
276 if (player
->curWeapon
== WPN_NONE
)
278 weapon_slide(LEFT
, player
->curWeapon
);
282 stat_PrevWeapon(true);
284 stat_NextWeapon(true);
287 // switches to the next weapon in inventory
288 void stat_NextWeapon(bool quiet
)
292 w
= player
->curWeapon
;
293 if (w
== WPN_NONE
) return;
297 if (++w
>= WPN_COUNT
) w
= 0;
299 if (player
->weapons
[w
].hasWeapon
|| w
== player
->curWeapon
)
301 if (!quiet
) sound(SND_SWITCH_WEAPON
);
302 weapon_slide(LEFT
, w
);
305 } while(w
!= player
->curWeapon
);
308 // switches to the previous weapon in inventory
309 void stat_PrevWeapon(bool quiet
)
313 w
= player
->curWeapon
;
314 if (w
== WPN_NONE
) return;
318 if (--w
< 0) w
= WPN_COUNT
-1;
320 if (player
->weapons
[w
].hasWeapon
|| w
== player
->curWeapon
)
322 if (!quiet
) sound(SND_SWITCH_WEAPON
);
323 weapon_slide(RIGHT
, w
);
330 void InitPercentBar(PercentBar
*bar
, int starting_value
)
332 PHealthBar
.displayed_value
= starting_value
;
333 PHealthBar
.dectimer
= 0;
336 void RunPercentBar(PercentBar
*bar
, int current_value
)
338 if (current_value
!= bar
->displayed_value
)
340 if (current_value
> bar
->displayed_value
)
342 bar
->displayed_value
= current_value
;
346 if (++bar
->dectimer
> 0x1e)
348 bar
->displayed_value
--;
352 else bar
->dectimer
= 0;
355 void DrawPercentBar(PercentBar
*bar
, int x
, int y
, int curvalue
, int maxvalue
, int width
)
357 if (bar
->displayed_value
!= curvalue
)
358 DrawPercentage(x
, y
, SPR_HEALTHFILL
, 1, bar
->displayed_value
, maxvalue
, width
);
360 DrawPercentage(x
, y
, SPR_HEALTHFILL
, 0, curvalue
, maxvalue
, width
);
364 void c------------------------------() {}
367 // draws number "num" at x,y.
368 // leading zeroes are omitted, however, the space for them is still
369 // skipped over (left blank). thus it always leaves space for 3 digits.
370 void DrawNumber(int x
, int y
, int num
)
372 static const int numtable
[3] = { 1000, 100, 10 };
373 int place
, digit
, total
;
375 if (num
> 9999) num
= 9999;
381 while(num
>= numtable
[place
])
383 num
-= numtable
[place
];
390 draw_sprite(x
+(place
*8), y
, SPR_WHITENUMBERS
, digit
);
395 draw_sprite(x
+(3*8), y
, SPR_WHITENUMBERS
, num
);
399 void DrawPercentage(int x
, int y
, int fill_sprite
, int fsframe
, int curvalue
, int maxvalue
, int width_at_max
)
401 if (curvalue
< 0) curvalue
= 0;
402 if (curvalue
> 0 || maxvalue
==0)
406 if (curvalue
>= maxvalue
)
408 fillwidth
= width_at_max
;
412 fillwidth
= (int)(((float)width_at_max
/ (float)maxvalue
) * (float)curvalue
);
413 if (!fillwidth
) return;
416 draw_sprite_clip_width(x
, y
, fill_sprite
, fsframe
, fillwidth
);
420 // draws a given number using sprite 's' as the font
421 // the numbers are drawn right-aligned to "x".
422 void DrawNumberRAlign(int x
, int y
, int s
, int num
)
426 int fontwidth
= sprites
[s
].w
;
428 sprintf(str
, "%d", num
);
429 x
-= strlen(str
) * fontwidth
;
434 draw_sprite(x
, y
, s
, str
[i
] - '0');
439 void DrawTwoDigitNumber(int x
, int y
, int num
)
441 DrawDigit(x
+0, y
, num
/10);
442 DrawDigit(x
+8, y
, num
%10);
445 void DrawDigit(int x
, int y
, int digit
)
447 draw_sprite(x
, y
, SPR_WHITENUMBERS
, digit
);
451 void c------------------------------() {}
457 if (player
->equipmask
& EQUIP_NIKUMARU
)
459 if (!game
.frozen
&& !player
->inputs_locked
)
461 if (game
.counter
< 300000) // 100'00"0
471 void niku_draw(int value
, bool force_white
)
473 int clkframe
= (game
.counter
% 30) <= 10;
474 if (game
.frozen
|| player
->inputs_locked
|| force_white
) clkframe
= 0;
476 draw_sprite(NIKU_X
, NIKU_Y
, SPR_NIKU_CLOCK
, clkframe
);
478 int mins
= (value
/ 3000); // the game runs at 50 fps
479 int secs
= (value
/ 50) % 60;
480 int tens
= (value
/ 5) % 10;
482 DrawNumber(NIKU_X
, NIKU_Y
, mins
);
483 DrawTwoDigitNumber(NIKU_X
+36, NIKU_Y
, secs
);
484 DrawDigit(NIKU_X
+56, NIKU_Y
, tens
);
486 draw_sprite(NIKU_X
+30, NIKU_Y
, SPR_NIKU_PUNC
);