Better number popup behavior (fixes #163)

This commit is contained in:
periwinkle 2023-06-16 23:35:28 -04:00 committed by Laura K
parent 7caff84e04
commit b3007c10e3
7 changed files with 57 additions and 67 deletions

View File

@ -13,20 +13,15 @@ pub struct NumberPopup {
pub prev_x: i32,
pub prev_y: i32,
counter: u16,
throttle: u16,
value_display: i16,
}
impl NumberPopup {
pub fn new() -> NumberPopup {
NumberPopup { value: 0, x: 0, y: 0, prev_x: 0, prev_y: 0, counter: 0, throttle: 0, value_display: 0 }
NumberPopup { value: 0, x: 0, y: 0, prev_x: 0, prev_y: 0, counter: 0, value_display: 0 }
}
pub fn set_value(&mut self, value: i16) {
if self.counter > 32 {
self.counter = 32;
}
self.value = value;
}
@ -34,32 +29,24 @@ impl NumberPopup {
self.set_value(self.value + value);
}
pub fn set_value_throttled(&mut self, value: i16) {
self.throttle = 16;
self.set_value(value);
}
pub fn add_value_throttled(&mut self, value: i16) {
self.set_value_throttled(self.value + value);
pub fn update_displayed_value(&mut self) {
if self.counter > 32 {
self.counter = 32;
}
self.value_display += self.value;
self.value = 0;
}
}
impl GameEntity<()> for NumberPopup {
fn tick(&mut self, _state: &mut SharedGameState, _custom: ()) -> GameResult<()> {
if self.throttle > 0 {
self.throttle = self.throttle.saturating_sub(1);
}
if self.value == 0 || self.throttle > 0 {
if self.value_display == 0 {
return Ok(());
}
self.value_display = self.value;
self.counter += 1;
if self.counter == 80 {
self.counter = 0;
self.value = 0;
self.value_display = 0;
}
@ -81,7 +68,8 @@ impl GameEntity<()> for NumberPopup {
let (frame_x, frame_y) = frame.xy_interpolated(state.frame_time);
let x = interpolate_fix9_scale(self.prev_x, self.x, state.frame_time) - frame_x;
let y = interpolate_fix9_scale(self.prev_y, self.y, state.frame_time) - frame_y - y_offset;
let y = interpolate_fix9_scale(self.prev_y, self.y, state.frame_time) - frame_y - y_offset
- 3.0f32; // This is supposed to be -4, but for some reason -3 looks more accurate
let n = format!("{:+}", self.value_display);

View File

@ -100,6 +100,9 @@ impl GameEntity<([&mut Player; 2], &NPCList, &mut Stage, &BulletManager, &mut Fl
for part in &mut self.parts {
if part.shock > 0 {
part.shock -= 1;
} else if part.npc_flags.show_damage() && part.popup.value != 0 {
// I don't know where the best place to put this is, but let's try putting it here
part.popup.update_displayed_value();
}
part.popup.x = part.x;
part.popup.y = part.y;

View File

@ -625,6 +625,10 @@ impl GameEntity<([&mut Player; 2], &NPCList, &mut Stage, &mut BulletManager, &mu
_ => Ok(()),
}?;
// I don't know where the best place to put this is, but let's try putting it here
if self.shock == 0 && self.npc_flags.show_damage() && self.popup.value != 0 {
self.popup.update_displayed_value();
}
self.popup.x = self.x;
self.popup.y = self.y;
self.popup.tick(state, ())?;

View File

@ -332,6 +332,9 @@ impl NPCList {
state.set_flag(npc.flag_num as usize, true);
if npc.npc_flags.show_damage() {
if npc.popup.value != 0 {
npc.popup.update_displayed_value();
}
if vanish {
npc.vanish(state);
}

View File

@ -108,14 +108,13 @@ pub struct Player {
pub air: u16,
pub skin: Box<dyn PlayerSkin>,
pub controller: Box<dyn PlayerController>,
pub popup: NumberPopup,
pub damage_popup: NumberPopup,
pub exp_popup: NumberPopup,
strafe_up: bool,
weapon_offset_y: i8,
splash: bool,
tick: u8,
booster_switch: BoosterSwitch,
damage_counter: u16,
damage_taken: i16,
pub anim_num: u16,
anim_counter: u16,
anim_rect: Rect<u16>,
@ -167,10 +166,9 @@ impl Player {
air: 0,
skin,
controller: Box::new(DummyPlayerController::new()),
popup: NumberPopup::new(),
damage_popup: NumberPopup::new(),
exp_popup: NumberPopup::new(),
strafe_up: false,
damage_counter: 0,
damage_taken: 0,
anim_num: 0,
anim_counter: 0,
anim_rect: constants.player.frames_right[0],
@ -896,11 +894,8 @@ impl Player {
self.controller.set_rumble(rumble_intensity, rumble_intensity, 20);
self.damage = self.damage.saturating_add(final_hp as u16);
if self.popup.value > 0 {
self.popup.set_value(-(self.damage as i16));
} else {
self.popup.add_value(-(self.damage as i16));
}
self.damage_popup.add_value(-(self.damage as i16));
self.damage_popup.update_displayed_value();
if self.life == 0 {
state.sound_manager.play_sfx(17);
@ -937,9 +932,9 @@ impl GameEntity<&NPCList> for Player {
fn tick(&mut self, state: &mut SharedGameState, npc_list: &NPCList) -> GameResult {
if !self.cond.alive() {
if self.life == 0 {
self.popup.x = self.x;
self.popup.y = self.y - self.display_bounds.top as i32 + 0x1000;
self.popup.tick(state, ())?;
self.damage_popup.x = self.x;
self.damage_popup.y = self.y - self.display_bounds.top as i32 + 0x1000;
self.damage_popup.tick(state, ())?;
}
return Ok(());
@ -949,18 +944,14 @@ impl GameEntity<&NPCList> for Player {
self.shock_counter = 0;
}
if self.damage_counter != 0 {
self.damage_counter -= 1;
}
if self.xp_counter != 0 {
self.xp_counter -= 1;
}
if self.shock_counter != 0 {
self.shock_counter -= 1;
} else if self.damage_taken != 0 {
self.damage_taken = 0;
} else if self.exp_popup.value != 0 {
self.exp_popup.update_displayed_value();
}
match (self.control_mode, state.settings.noclip) {
@ -969,9 +960,12 @@ impl GameEntity<&NPCList> for Player {
(ControlMode::IronHead, _) => self.tick_ironhead(state)?,
}
self.popup.x = self.x;
self.popup.y = self.y - self.display_bounds.top as i32 + 0x1000;
self.popup.tick(state, ())?;
self.damage_popup.x = self.x;
self.damage_popup.y = self.y - self.display_bounds.top as i32 + 0x1000;
self.damage_popup.tick(state, ())?;
self.exp_popup.x = self.x;
self.exp_popup.y = self.y - self.display_bounds.top as i32 + 0x1000;
self.exp_popup.tick(state, ())?;
self.cond.set_increase_acceleration(false);
self.tick_animation(state);

View File

@ -287,16 +287,8 @@ impl Player {
inventory.add_xp(npc.exp, self, state);
if let Some(weapon) = inventory.get_current_weapon() {
if weapon.wtype == WeaponType::Spur {
npc.exp = 0;
} else {
if self.shock_counter == 0 {
if self.popup.value > 0 {
self.popup.add_value(npc.exp as i16);
} else {
self.popup.set_value(npc.exp as i16);
}
}
if weapon.wtype != WeaponType::Spur {
self.exp_popup.add_value(npc.exp as i16);
}
}

View File

@ -1197,7 +1197,7 @@ impl GameScene {
}
if npc.npc_flags.show_damage() {
npc.popup.add_value_throttled(-bullet.damage);
npc.popup.add_value(-bullet.damage);
}
}
} else if !bullet.weapon_flags.no_proj_dissipation()
@ -1261,6 +1261,7 @@ impl GameScene {
}
if npc.npc_flags.shootable() {
let shock = npc.shock;
if npc.cond.damage_boss() {
idx = 0;
npc = unsafe { self.boss.parts.get_unchecked_mut(0) };
@ -1268,10 +1269,6 @@ impl GameScene {
npc.life = (npc.life as i32).saturating_sub(bullet.damage as i32).clamp(0, u16::MAX as i32) as u16;
if npc.npc_flags.show_damage() {
npc.popup.add_value(-bullet.damage);
}
if npc.life == 0 {
npc.life = npc.id;
@ -1295,7 +1292,7 @@ impl GameScene {
npc.cond.set_alive(false);
}
} else {
if npc.shock < 14 {
if shock < 14 {
for _ in 0..3 {
state.create_caret(bullet.x, bullet.y, CaretType::HurtParticles, Direction::Left);
}
@ -1303,6 +1300,9 @@ impl GameScene {
}
npc.shock = 8;
if npc.npc_flags.show_damage() {
npc.popup.add_value(-bullet.damage);
}
npc = unsafe { self.boss.parts.get_unchecked_mut(i) };
npc.shock = 8;
@ -1919,12 +1919,16 @@ impl Scene for GameScene {
self.frame.prev_y = self.frame.y;
self.player1.prev_x = self.player1.x;
self.player1.prev_y = self.player1.y;
self.player1.popup.prev_x = self.player1.popup.x;
self.player1.popup.prev_y = self.player1.popup.y;
self.player1.damage_popup.prev_x = self.player1.damage_popup.x;
self.player1.damage_popup.prev_y = self.player1.damage_popup.y;
self.player1.exp_popup.prev_x = self.player1.exp_popup.x;
self.player1.exp_popup.prev_y = self.player1.exp_popup.y;
self.player2.prev_x = self.player2.x;
self.player2.prev_y = self.player2.y;
self.player2.popup.prev_x = self.player2.popup.x;
self.player2.popup.prev_y = self.player2.popup.y;
self.player2.damage_popup.prev_x = self.player2.damage_popup.x;
self.player2.damage_popup.prev_y = self.player2.damage_popup.y;
self.player2.exp_popup.prev_x = self.player2.exp_popup.x;
self.player2.exp_popup.prev_y = self.player2.exp_popup.y;
for npc in self.npc_list.iter_alive() {
npc.prev_x = npc.x;
@ -2010,8 +2014,10 @@ impl Scene for GameScene {
self.water_renderer.draw(state, ctx, &self.frame, WaterLayer::Front)?;
self.draw_carets(state, ctx)?;
self.player1.popup.draw(state, ctx, &self.frame)?;
self.player2.popup.draw(state, ctx, &self.frame)?;
self.player1.exp_popup.draw(state, ctx, &self.frame)?;
self.player1.damage_popup.draw(state, ctx, &self.frame)?;
self.player2.exp_popup.draw(state, ctx, &self.frame)?;
self.player2.damage_popup.draw(state, ctx, &self.frame)?;
self.draw_npc_popup(state, ctx)?;
self.draw_boss_popup(state, ctx)?;