fix: passengers now board/disembark based on their car position, not locomotive

Previously, passengers would board/disembark when the locomotive reached their
station, which was incorrect. Now:

**Boarding:**
- Passengers board when an EMPTY train car reaches their origin station
- Each passenger is assigned to the first available empty car (0-4)
- Car position calculated as: trainPosition - (carIndex + 1) * 7%

**Disembarking:**
- Passengers disembark when THEIR specific car reaches their destination
- Uses the passenger's position in the boardedPassengers array to find car index
- Each passenger's car position is independently checked against their destination

This creates more realistic train behavior where passengers interact with
individual train cars rather than just the locomotive.

Removed unused imports: findBoardablePassengers, findDeliverablePassengers

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Thomas Hallock 2025-10-01 09:07:31 -05:00
parent 01766944f0
commit 96782b0e7a
1 changed files with 49 additions and 24 deletions

View File

@ -1,6 +1,6 @@
import { useEffect, useRef } from 'react'
import { useComplementRace } from '../context/ComplementRaceContext'
import { generatePassengers, findBoardablePassengers, findDeliverablePassengers } from '../lib/passengerGenerator'
import { generatePassengers } from '../lib/passengerGenerator'
import { useSoundEffects } from './useSoundEffects'
/**
@ -101,34 +101,59 @@ export function useSteamJourney() {
})
// Check for passengers that should board
const boardable = findBoardablePassengers(
state.passengers,
state.stations,
trainPosition
)
// Passengers board when an EMPTY car reaches their station
const CAR_SPACING = 7 // Must match SteamTrainJourney component
const MAX_CARS = 5
const currentBoardedPassengers = state.passengers.filter(p => p.isBoarded && !p.isDelivered)
// Board passengers at their origin station
boardable.forEach(passenger => {
dispatch({
type: 'BOARD_PASSENGER',
passengerId: passenger.id
})
// Find waiting passengers whose origin station has an empty car nearby
state.passengers.forEach(passenger => {
if (passenger.isBoarded || passenger.isDelivered) return
const station = state.stations.find(s => s.id === passenger.originStationId)
if (!station) return
// Check if any empty car is at this station
// Cars are at positions: trainPosition - 7, trainPosition - 14, etc.
for (let carIndex = 0; carIndex < MAX_CARS; carIndex++) {
// Skip if this car already has a passenger
if (currentBoardedPassengers[carIndex]) continue
const carPosition = Math.max(0, trainPosition - (carIndex + 1) * CAR_SPACING)
const distance = Math.abs(carPosition - station.position)
// If car is at station (within 3% tolerance), board this passenger
if (distance < 3) {
dispatch({
type: 'BOARD_PASSENGER',
passengerId: passenger.id
})
return // Board this passenger and move on
}
}
})
// Check for deliverable passengers
const deliverable = findDeliverablePassengers(
state.passengers,
state.stations,
trainPosition
)
// Passengers disembark when THEIR car reaches their destination
currentBoardedPassengers.forEach((passenger, carIndex) => {
if (!passenger || passenger.isDelivered) return
// Deliver passengers at stations
deliverable.forEach(({ passenger, points }) => {
dispatch({
type: 'DELIVER_PASSENGER',
passengerId: passenger.id,
points
})
const station = state.stations.find(s => s.id === passenger.destinationStationId)
if (!station) return
// Calculate this passenger's car position
const carPosition = Math.max(0, trainPosition - (carIndex + 1) * CAR_SPACING)
const distance = Math.abs(carPosition - station.position)
// If this car is at the destination station (within 3% tolerance), deliver
if (distance < 3) {
const points = passenger.isUrgent ? 20 : 10
dispatch({
type: 'DELIVER_PASSENGER',
passengerId: passenger.id,
points
})
}
})
// Check for route completion (entire train exits tunnel)