fix(game): restore the six-way effect target
Implement the flagged object-84 selector and initially inactive type-4 object 149. Choose a different effect from 1-6, render the enabled target from its original active-table rectangle, award its static 500 points, then apply the recovered bonus or cashout action and disable it until reselected. This replaces the final unimplemented help-screen target effect with its original dispatcher values. Test Plan: - `cargo test --all-targets` -- 49 passed - `cargo clippy --all-targets -- -D warnings` -- passed - `cargo build --profile production` -- passed - live object-84 probe activated record 149 and selected effect 3 - effect selection/consumption test -- passed - `git diff --cached --check` -- passed
This commit is contained in:
@@ -429,6 +429,20 @@ impl App {
|
||||
);
|
||||
}
|
||||
}
|
||||
if game.effect_target_active() {
|
||||
let region = Rect::new(60.0, 57.0, 18.0, 17.0);
|
||||
draw_texture_ex(
|
||||
&self.assets.active_table,
|
||||
region.x,
|
||||
region.y,
|
||||
WHITE,
|
||||
DrawTextureParams {
|
||||
dest_size: Some(vec2(region.w, region.h)),
|
||||
source: Some(region),
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
}
|
||||
if game.ball.in_launcher {
|
||||
draw_texture_ex(
|
||||
&self.assets.plunger,
|
||||
|
||||
+123
-3
@@ -4,7 +4,10 @@ use crate::{
|
||||
CollisionResponse, GRAVITY_MILLI_PER_STEP, MAXIMUM_SPEED_MILLI_PER_STEP, MilliVec,
|
||||
STEP_SECONDS, circle_collision_response, line_collision_response, path_intersects_circle,
|
||||
},
|
||||
table::{BUMPERS, LOCK_HOLES, PASSIVE_CIRCLES, TARGET_SENSORS, WALLS, WHEEL_RESET_SENSOR},
|
||||
table::{
|
||||
BUMPERS, EFFECT_SENSOR, LOCK_HOLES, PASSIVE_CIRCLES, TARGET_SENSORS, WALLS,
|
||||
WHEEL_RESET_SENSOR,
|
||||
},
|
||||
};
|
||||
use macroquad::prelude::{Rect, Vec2, vec2};
|
||||
|
||||
@@ -221,6 +224,7 @@ pub struct Game {
|
||||
pending_flipper_edges: [i8; 2],
|
||||
trigger_contacts: [bool; 176],
|
||||
object_active: [bool; 176],
|
||||
target_effect: u8,
|
||||
}
|
||||
|
||||
impl Game {
|
||||
@@ -258,6 +262,7 @@ impl Game {
|
||||
pending_flipper_edges: [0; 2],
|
||||
trigger_contacts: [false; 176],
|
||||
object_active: initial_object_activity(),
|
||||
target_effect: 0,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -568,6 +573,16 @@ impl Game {
|
||||
if wall.flags & 0x0400 != 0 {
|
||||
self.wheel_animation = 0.65;
|
||||
}
|
||||
if wall.flags & 0x0004 != 0 {
|
||||
let previous = self.target_effect;
|
||||
loop {
|
||||
self.target_effect = u8::try_from(self.next_random_value() % 6 + 1).unwrap_or(1);
|
||||
if self.target_effect != previous {
|
||||
break;
|
||||
}
|
||||
}
|
||||
self.object_active[usize::from(EFFECT_SENSOR.id)] = true;
|
||||
}
|
||||
}
|
||||
|
||||
fn check_media(&mut self, events: &mut Vec<Event>) {
|
||||
@@ -604,6 +619,22 @@ impl Game {
|
||||
}
|
||||
|
||||
let current_position = MilliVec::from_position(self.ball.position);
|
||||
if self.check_lock_holes(old_position, current_position, movement_velocity, events)
|
||||
|| self.check_wheel_reset(old_position, current_position, movement_velocity, events)
|
||||
{
|
||||
return;
|
||||
}
|
||||
self.check_effect_sensor(old_position, current_position, movement_velocity, events);
|
||||
self.check_target_sensors(old_position, current_position, movement_velocity, events);
|
||||
}
|
||||
|
||||
fn check_lock_holes(
|
||||
&mut self,
|
||||
old_position: MilliVec,
|
||||
current_position: MilliVec,
|
||||
movement_velocity: MilliVec,
|
||||
events: &mut Vec<Event>,
|
||||
) -> bool {
|
||||
for (index, sensor) in LOCK_HOLES.into_iter().enumerate() {
|
||||
let touched = path_intersects_circle(
|
||||
old_position,
|
||||
@@ -634,9 +665,18 @@ impl Game {
|
||||
}
|
||||
self.reset_ball_to_launcher();
|
||||
events.push(Event::Lock);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn check_wheel_reset(
|
||||
&mut self,
|
||||
old_position: MilliVec,
|
||||
current_position: MilliVec,
|
||||
movement_velocity: MilliVec,
|
||||
events: &mut Vec<Event>,
|
||||
) -> bool {
|
||||
let reset_touched = path_intersects_circle(
|
||||
old_position,
|
||||
movement_velocity,
|
||||
@@ -656,9 +696,61 @@ impl Game {
|
||||
self.wheel_animation = 0.65;
|
||||
self.reset_ball_to_launcher();
|
||||
events.push(Event::Wheel);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn check_effect_sensor(
|
||||
&mut self,
|
||||
old_position: MilliVec,
|
||||
current_position: MilliVec,
|
||||
movement_velocity: MilliVec,
|
||||
events: &mut Vec<Event>,
|
||||
) {
|
||||
let effect_index = usize::from(EFFECT_SENSOR.id);
|
||||
if self.object_active[effect_index] {
|
||||
let touched = path_intersects_circle(
|
||||
old_position,
|
||||
movement_velocity,
|
||||
EFFECT_SENSOR.center,
|
||||
EFFECT_SENSOR.radius,
|
||||
);
|
||||
let entered = touched && !self.trigger_contacts[effect_index];
|
||||
self.trigger_contacts[effect_index] = path_intersects_circle(
|
||||
current_position,
|
||||
MilliVec::default(),
|
||||
EFFECT_SENSOR.center,
|
||||
EFFECT_SENSOR.radius,
|
||||
);
|
||||
if entered && !self.tilted {
|
||||
self.add_score(EFFECT_SENSOR.score);
|
||||
match self.target_effect {
|
||||
1 => self.bonus = self.bonus.saturating_add(10_000),
|
||||
2 => self.bonus = self.bonus.saturating_add(20_000),
|
||||
3 => self.bonus = self.bonus.saturating_add(50_000),
|
||||
4 => self.bonus = self.bonus.saturating_add(100_000),
|
||||
5 => self.bonus = self.bonus.saturating_add(200_000),
|
||||
6 => {
|
||||
self.add_score(self.bonus);
|
||||
self.bonus = 0;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
self.target_effect = 0;
|
||||
self.object_active[effect_index] = false;
|
||||
events.push(Event::Target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_target_sensors(
|
||||
&mut self,
|
||||
old_position: MilliVec,
|
||||
current_position: MilliVec,
|
||||
movement_velocity: MilliVec,
|
||||
events: &mut Vec<Event>,
|
||||
) {
|
||||
for sensor in TARGET_SENSORS {
|
||||
let touched = path_intersects_circle(
|
||||
old_position,
|
||||
@@ -729,6 +821,10 @@ impl Game {
|
||||
self.object_active[object_id]
|
||||
}
|
||||
|
||||
pub fn effect_target_active(&self) -> bool {
|
||||
self.object_active[usize::from(EFFECT_SENSOR.id)]
|
||||
}
|
||||
|
||||
fn next_claw_terminal_frame(&mut self) -> u8 {
|
||||
let value = self.next_random_value();
|
||||
CLAW_TERMINAL_FRAMES[value as usize % CLAW_TERMINAL_FRAMES.len()]
|
||||
@@ -875,6 +971,7 @@ impl Game {
|
||||
self.claw = Claw::default();
|
||||
self.trigger_contacts.fill(false);
|
||||
self.object_active = initial_object_activity();
|
||||
self.target_effect = 0;
|
||||
self.nudge_shake = 0.0;
|
||||
self.launcher_charge = 0.0;
|
||||
self.launcher_was_down = false;
|
||||
@@ -1133,6 +1230,29 @@ mod tests {
|
||||
assert!(game.object_active[109..=120].iter().all(|active| *active));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn effect_selector_activates_and_consumes_record_149() {
|
||||
let mut game = Game::new_with_seed(1, 7);
|
||||
let mut events = Vec::new();
|
||||
game.apply_wall_rule(84, &mut events);
|
||||
|
||||
assert!((1..=6).contains(&game.target_effect));
|
||||
assert!(game.effect_target_active());
|
||||
game.target_effect = 3;
|
||||
game.ball.in_launcher = false;
|
||||
game.ball.position = EFFECT_SENSOR.center;
|
||||
game.check_sensor_objects(
|
||||
MilliVec::from_position(EFFECT_SENSOR.center),
|
||||
MilliVec::default(),
|
||||
&mut events,
|
||||
);
|
||||
|
||||
assert_eq!(game.bonus, 50_000);
|
||||
assert_eq!(game.player().score, 2_000);
|
||||
assert_eq!(game.target_effect, 0);
|
||||
assert!(!game.effect_target_active());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn center_drain_advances_to_a_fresh_ball() {
|
||||
let mut game = Game::new(1);
|
||||
|
||||
@@ -333,6 +333,8 @@ pub const LOCK_HOLES: [MechanismSensor; 5] = [
|
||||
pub const WHEEL_RESET_SENSOR: MechanismSensor =
|
||||
MechanismSensor::new(148, Vec2::new(17.0, 23.0), 19.0);
|
||||
|
||||
pub const EFFECT_SENSOR: TargetSensor = TargetSensor::new(149, Vec2::new(68.0, 65.0), 16.0, 500);
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
Reference in New Issue
Block a user