286 lines
8.6 KiB
Python
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')
|