Files
triviathang/backend/services/game_service.py
2025-12-22 14:47:25 -05:00

286 lines
8.6 KiB
Python

from backend.models import db, Game, Score
from flask_socketio import emit
def get_game_state(game):
"""Get current game state with all necessary information"""
current_question = game.get_current_question()
state = {
'game_id': game.id,
'game_name': game.name,
'current_question_index': game.current_question_index,
'total_questions': len(game.game_questions),
'is_active': game.is_active,
'teams': [team.to_dict() for team in game.teams]
}
if current_question:
state['current_question'] = current_question.to_dict(include_answer=False)
return state
def get_admin_game_state(game):
"""Get game state with answer (for admin only)"""
state = get_game_state(game)
current_question = game.get_current_question()
if current_question:
state['current_question'] = current_question.to_dict(include_answer=True)
return state
def start_game(game, socketio_instance):
"""Start/activate a game"""
# Deactivate any other active games
active_games = Game.query.filter_by(is_active=True).all()
for g in active_games:
if g.id != game.id:
g.is_active = False
game.is_active = True
game.current_question_index = 0
db.session.commit()
# Emit game_started event
socketio_instance.emit('game_started', {
'game_id': game.id,
'game_name': game.name,
'total_questions': len(game.game_questions)
}, room=f'game_{game.id}_contestant')
socketio_instance.emit('game_started', {
'game_id': game.id,
'game_name': game.name,
'total_questions': len(game.game_questions)
}, room=f'game_{game.id}_admin')
# Emit first question
broadcast_question_change(game, socketio_instance)
def next_question(game, socketio_instance):
"""Move to next question"""
if game.current_question_index < len(game.game_questions) - 1:
game.current_question_index += 1
db.session.commit()
broadcast_question_change(game, socketio_instance)
return True
return False
def previous_question(game, socketio_instance):
"""Move to previous question"""
if game.current_question_index > 0:
game.current_question_index -= 1
db.session.commit()
broadcast_question_change(game, socketio_instance)
return True
return False
def broadcast_question_change(game, socketio_instance):
"""Broadcast question change to all connected clients"""
current_question = game.get_current_question()
if not current_question:
return
# Emit to contestant room (without answer)
socketio_instance.emit('question_changed', {
'question_index': game.current_question_index,
'question': current_question.to_dict(include_answer=False),
'total_questions': len(game.game_questions)
}, room=f'game_{game.id}_contestant')
# Emit to admin room (with answer)
socketio_instance.emit('question_with_answer', {
'question_index': game.current_question_index,
'question': current_question.to_dict(include_answer=True),
'total_questions': len(game.game_questions)
}, room=f'game_{game.id}_admin')
def award_points(game, team, points, socketio_instance):
"""Award points to a team for the current question"""
# Check if score already exists for this team and question
existing_score = Score.query.filter_by(
team_id=team.id,
question_index=game.current_question_index
).first()
if existing_score:
# Add to existing score
existing_score.points += points
else:
# Create new score
score = Score(
team_id=team.id,
game_id=game.id,
question_index=game.current_question_index,
points=points
)
db.session.add(score)
db.session.commit()
# Get all team scores with full data including lifelines
all_scores = [t.to_dict() for t in game.teams]
# Broadcast score update
score_data = {
'team_id': team.id,
'team_name': team.name,
'new_score': team.total_score,
'points_awarded': points,
'all_scores': all_scores
}
socketio_instance.emit('score_updated', score_data, room=f'game_{game.id}_contestant')
socketio_instance.emit('score_updated', score_data, room=f'game_{game.id}_admin')
def toggle_answer_visibility(game, show_answer, socketio_instance):
"""Toggle answer visibility on contestant screen"""
current_question = game.get_current_question()
if not current_question:
return
answer_data = {
'show_answer': show_answer
}
if show_answer:
answer_data['answer'] = current_question.answer
# Broadcast to contestant room only
socketio_instance.emit('answer_visibility_changed', answer_data, room=f'game_{game.id}_contestant')
def toggle_timer_pause(game, paused, socketio_instance):
"""Pause or resume the timer"""
# Broadcast timer pause state to both rooms
socketio_instance.emit('timer_paused', {
'paused': paused
}, room=f'game_{game.id}_contestant')
socketio_instance.emit('timer_paused', {
'paused': paused
}, room=f'game_{game.id}_admin')
def reset_timer(game, socketio_instance):
"""Reset the timer to 30 seconds"""
# Broadcast timer reset to both rooms
socketio_instance.emit('timer_reset', {
'seconds': 30
}, room=f'game_{game.id}_contestant')
socketio_instance.emit('timer_reset', {
'seconds': 30
}, room=f'game_{game.id}_admin')
def end_game(game, socketio_instance):
"""End/deactivate a game"""
game.is_active = False
db.session.commit()
# Emit game_ended event to all rooms
socketio_instance.emit('game_ended', {
'game_id': game.id,
'game_name': game.name
}, room=f'game_{game.id}_contestant')
socketio_instance.emit('game_ended', {
'game_id': game.id,
'game_name': game.name
}, room=f'game_{game.id}_admin')
def restart_game(game, socketio_instance):
"""Restart a game (clear scores and reset to waiting state)"""
# Clear all scores for this game
Score.query.filter_by(game_id=game.id).delete()
# Reset game state
game.is_active = False
game.current_question_index = 0
# Reset phone-a-friend lifelines for all teams
for team in game.teams:
team.phone_a_friend_count = 5
db.session.commit()
# Emit game_ended event to reset contestant view
socketio_instance.emit('game_ended', {
'game_id': game.id,
'game_name': game.name
}, room=f'game_{game.id}_contestant')
# Emit score update to show cleared scores and reset lifelines
socketio_instance.emit('score_updated', {
'team_id': None,
'team_name': None,
'new_score': 0,
'points_awarded': 0,
'all_scores': [t.to_dict() for t in game.teams]
}, room=f'game_{game.id}_contestant')
socketio_instance.emit('score_updated', {
'team_id': None,
'team_name': None,
'new_score': 0,
'points_awarded': 0,
'all_scores': [t.to_dict() for t in game.teams]
}, room=f'game_{game.id}_admin')
def broadcast_lifeline_update(game, team, socketio_instance):
"""Broadcast phone-a-friend lifeline update"""
# Get all team scores with updated lifeline counts
all_scores = [t.to_dict() for t in game.teams]
lifeline_data = {
'team_id': team.id,
'team_name': team.name,
'phone_a_friend_count': team.phone_a_friend_count,
'all_scores': all_scores
}
socketio_instance.emit('lifeline_updated', lifeline_data, room=f'game_{game.id}_contestant')
socketio_instance.emit('lifeline_updated', lifeline_data, room=f'game_{game.id}_admin')
def broadcast_audio_play(game, socketio_instance):
"""Broadcast audio play command to contestants"""
socketio_instance.emit('audio_play', {
'game_id': game.id
}, room=f'game_{game.id}_contestant')
def broadcast_audio_pause(game, socketio_instance):
"""Broadcast audio pause command to contestants"""
socketio_instance.emit('audio_pause', {
'game_id': game.id
}, room=f'game_{game.id}_contestant')
def broadcast_audio_stop(game, socketio_instance):
"""Broadcast audio stop command to contestants"""
socketio_instance.emit('audio_stop', {
'game_id': game.id
}, room=f'game_{game.id}_contestant')
def broadcast_audio_seek(game, position, socketio_instance):
"""Broadcast audio seek command to contestants"""
socketio_instance.emit('audio_seek', {
'game_id': game.id,
'position': position
}, room=f'game_{game.id}_contestant')