Fix comeback bonus

This commit is contained in:
Joey Yakimowich-Payne 2026-01-19 13:10:07 -07:00
commit 99977bc8e6
No known key found for this signature in database
GPG key ID: DDF6AF5B21B407D4
4 changed files with 44 additions and 3 deletions

View file

@ -46,6 +46,7 @@ interface PointsCalculationParams {
playerRank: number; playerRank: number;
isFirstCorrect: boolean; isFirstCorrect: boolean;
config: GameConfig; config: GameConfig;
currentQuestionIndex?: number;
} }
export const calculatePointsWithBreakdown = (params: PointsCalculationParams): PointsBreakdown => { export const calculatePointsWithBreakdown = (params: PointsCalculationParams): PointsBreakdown => {
@ -78,7 +79,8 @@ export const calculatePointsWithBreakdown = (params: PointsCalculationParams): P
breakdown.streakBonus = pointsAfterStreak - breakdown.basePoints; breakdown.streakBonus = pointsAfterStreak - breakdown.basePoints;
} }
if (config.comebackBonusEnabled && playerRank > 3) { const isFirstQuestion = params.currentQuestionIndex === 0 || params.currentQuestionIndex === undefined;
if (config.comebackBonusEnabled && playerRank > 3 && !isFirstQuestion) {
breakdown.comebackBonus = config.comebackBonusPoints; breakdown.comebackBonus = config.comebackBonusPoints;
} }

View file

@ -915,6 +915,7 @@ export const useGame = () => {
playerRank, playerRank,
isFirstCorrect, isFirstCorrect,
config: gameConfigRef.current, config: gameConfigRef.current,
currentQuestionIndex: currentQuestionIndexRef.current,
}); });
const newScore = Math.max(0, currentPlayer.score + breakdown.total); const newScore = Math.max(0, currentPlayer.score + breakdown.total);
@ -1055,6 +1056,7 @@ export const useGame = () => {
playerRank, playerRank,
isFirstCorrect: false, isFirstCorrect: false,
config: gameConfigRef.current, config: gameConfigRef.current,
currentQuestionIndex: currentQuestionIndexRef.current,
}); });
const newScore = Math.max(0, p.score + breakdown.total); const newScore = Math.max(0, p.score + breakdown.total);
@ -1436,6 +1438,7 @@ export const useGame = () => {
playerRank, playerRank,
isFirstCorrect, isFirstCorrect,
config: gameConfigRef.current, config: gameConfigRef.current,
currentQuestionIndex: currentQuestionIndexRef.current,
}); });
setLastPointsEarned(breakdown.total); setLastPointsEarned(breakdown.total);

View file

@ -246,6 +246,7 @@ if [ -n "$TURN_IP" ]; then
# Coturn TURN Server Configuration # Coturn TURN Server Configuration
# Generated by setup-prod.sh on $(date) # Generated by setup-prod.sh on $(date)
listening-ip=0.0.0.0
listening-port=3478 listening-port=3478
tls-listening-port=5349 tls-listening-port=5349
external-ip=${TURN_IP} external-ip=${TURN_IP}
@ -342,9 +343,18 @@ echo -e " ${AUTH_DOMAIN} → ${BLUE}<your-server-ip>${NC}"
echo "" echo ""
if [ -n "$TURN_IP" ]; then if [ -n "$TURN_IP" ]; then
echo " 2. Open firewall ports for TURN server:" echo " 2. Open firewall ports for TURN server:"
echo ""
echo " For Ubuntu/ufw:"
echo -e " ${YELLOW}sudo ufw allow 3478/tcp && sudo ufw allow 3478/udp${NC}" echo -e " ${YELLOW}sudo ufw allow 3478/tcp && sudo ufw allow 3478/udp${NC}"
echo -e " ${YELLOW}sudo ufw allow 5349/tcp && sudo ufw allow 49152:65535/udp${NC}" echo -e " ${YELLOW}sudo ufw allow 5349/tcp && sudo ufw allow 49152:65535/udp${NC}"
echo "" echo ""
echo " For Oracle Cloud (firewalld):"
echo -e " ${YELLOW}sudo firewall-cmd --permanent --add-port=3478/tcp${NC}"
echo -e " ${YELLOW}sudo firewall-cmd --permanent --add-port=3478/udp${NC}"
echo -e " ${YELLOW}sudo firewall-cmd --permanent --add-port=5349/tcp${NC}"
echo -e " ${YELLOW}sudo firewall-cmd --permanent --add-port=49152-65535/udp${NC}"
echo -e " ${YELLOW}sudo firewall-cmd --reload${NC}"
echo ""
echo " 3. Start the TURN server:" echo " 3. Start the TURN server:"
echo -e " ${YELLOW}docker compose -f docker-compose.turn.yml up -d${NC}" echo -e " ${YELLOW}docker compose -f docker-compose.turn.yml up -d${NC}"
echo "" echo ""

View file

@ -231,6 +231,7 @@ describe('calculatePointsWithBreakdown', () => {
const result = calculatePointsWithBreakdown({ const result = calculatePointsWithBreakdown({
...baseParams, ...baseParams,
playerRank: 5, playerRank: 5,
currentQuestionIndex: 1,
config: { ...DEFAULT_GAME_CONFIG, comebackBonusEnabled: false }, config: { ...DEFAULT_GAME_CONFIG, comebackBonusEnabled: false },
}); });
@ -242,6 +243,7 @@ describe('calculatePointsWithBreakdown', () => {
const result = calculatePointsWithBreakdown({ const result = calculatePointsWithBreakdown({
...baseParams, ...baseParams,
playerRank: rank, playerRank: rank,
currentQuestionIndex: 1,
config: { ...DEFAULT_GAME_CONFIG, comebackBonusEnabled: true, comebackBonusPoints: 100 }, config: { ...DEFAULT_GAME_CONFIG, comebackBonusEnabled: true, comebackBonusPoints: 100 },
}); });
@ -253,6 +255,7 @@ describe('calculatePointsWithBreakdown', () => {
const result = calculatePointsWithBreakdown({ const result = calculatePointsWithBreakdown({
...baseParams, ...baseParams,
playerRank: 4, playerRank: 4,
currentQuestionIndex: 1,
config: { ...DEFAULT_GAME_CONFIG, comebackBonusEnabled: true, comebackBonusPoints: 100 }, config: { ...DEFAULT_GAME_CONFIG, comebackBonusEnabled: true, comebackBonusPoints: 100 },
}); });
@ -264,11 +267,33 @@ describe('calculatePointsWithBreakdown', () => {
const result = calculatePointsWithBreakdown({ const result = calculatePointsWithBreakdown({
...baseParams, ...baseParams,
playerRank: 10, playerRank: 10,
currentQuestionIndex: 2,
config: { ...DEFAULT_GAME_CONFIG, comebackBonusEnabled: true, comebackBonusPoints: 150 }, config: { ...DEFAULT_GAME_CONFIG, comebackBonusEnabled: true, comebackBonusPoints: 150 },
}); });
expect(result.comebackBonus).toBe(150); expect(result.comebackBonus).toBe(150);
}); });
it('applies no comeback bonus on first question (index 0)', () => {
const result = calculatePointsWithBreakdown({
...baseParams,
playerRank: 5,
currentQuestionIndex: 0,
config: { ...DEFAULT_GAME_CONFIG, comebackBonusEnabled: true, comebackBonusPoints: 100 },
});
expect(result.comebackBonus).toBe(0);
});
it('applies no comeback bonus when currentQuestionIndex is undefined', () => {
const result = calculatePointsWithBreakdown({
...baseParams,
playerRank: 5,
config: { ...DEFAULT_GAME_CONFIG, comebackBonusEnabled: true, comebackBonusPoints: 100 },
});
expect(result.comebackBonus).toBe(0);
});
}); });
describe('first correct bonus', () => { describe('first correct bonus', () => {
@ -319,9 +344,10 @@ describe('calculatePointsWithBreakdown', () => {
const result = calculatePointsWithBreakdown({ const result = calculatePointsWithBreakdown({
...baseParams, ...baseParams,
streak: 4, // Above threshold streak: 4,
playerRank: 5, // Qualifies for comeback playerRank: 5,
isFirstCorrect: true, isFirstCorrect: true,
currentQuestionIndex: 2,
config, config,
}); });