|
|
from flask import Flask, render_template, session, redirect, url_for, request
|
|
|
import time
|
|
|
from pathlib import Path
|
|
|
import random
|
|
|
|
|
|
app = Flask(__name__)
|
|
|
|
|
|
app.secret_key = 'your_super_secret_key_for_flask_session_security'
|
|
|
|
|
|
|
|
|
|
|
|
videos = [
|
|
|
"static/videos/Animated_Drought_Relief_Video_Creation.mp4",
|
|
|
"static/videos/Animated_Rainwater_Harvesting_Video.mp4",
|
|
|
"static/videos/Animated_Water_Filtration_Process_Video.mp4",
|
|
|
"static/videos/Water_Filtration_Animation_Ready.mp4",
|
|
|
"static/videos/Animated_Rainwater_Usage_Video.mp4",
|
|
|
"static/videos/Water_Hero_Video_Generation_Complete.mp4"
|
|
|
]
|
|
|
|
|
|
|
|
|
video_descriptions = [
|
|
|
"🌍 Water Crisis Alert",
|
|
|
"🏠 Collection Master",
|
|
|
"💧 Purification Expert",
|
|
|
"🗃️ Storage Specialist",
|
|
|
"♻️ Usage Strategist",
|
|
|
"🌱 Environmental Champion"
|
|
|
]
|
|
|
|
|
|
|
|
|
task_scenarios = [
|
|
|
|
|
|
{
|
|
|
"question": "🌍 After watching the video, what is the FIRST step to address water scarcity at your home?",
|
|
|
"choices": [
|
|
|
{
|
|
|
"action": "🌧️ Start collecting rainwater immediately",
|
|
|
"description": "Begin harvesting nature's free water supply",
|
|
|
"consequence": "✅ SMART START! You're taking the first step toward water independence! +100 XP",
|
|
|
"xp_reward": 100,
|
|
|
"icon": "🏆"
|
|
|
},
|
|
|
{
|
|
|
"action": "🚿 Take longer showers to enjoy water while it lasts",
|
|
|
"description": "Use more water before it runs out",
|
|
|
"consequence": "❌ WRONG APPROACH! This worsens the problem. Conservation is key! -20 Health",
|
|
|
"xp_reward": 0,
|
|
|
"icon": "💸"
|
|
|
},
|
|
|
{
|
|
|
"action": "⏳ Wait for government to solve the problem",
|
|
|
"description": "Rely on authorities to fix water issues",
|
|
|
"consequence": "❌ MISSED OPPORTUNITY! Individual action is crucial. Start now! -20 Health",
|
|
|
"xp_reward": 0,
|
|
|
"icon": "⏰"
|
|
|
}
|
|
|
]
|
|
|
},
|
|
|
|
|
|
{
|
|
|
"question": "🌧️ It's raining heavily! Your house has a metal roof. What's your FIRST action as a Water Conservation Hero?",
|
|
|
"choices": [
|
|
|
{
|
|
|
"action": "🏠 Install gutters and downspouts on your roof",
|
|
|
"description": "Channel rainwater efficiently into collection system",
|
|
|
"consequence": "✅ SMART MOVE! You capture 80% of the rainfall from your roof area. +100 XP",
|
|
|
"xp_reward": 100,
|
|
|
"icon": "🏆"
|
|
|
},
|
|
|
{
|
|
|
"action": "🛣️ Let the water flow down the streets",
|
|
|
"description": "Allow natural drainage to carry water away",
|
|
|
"consequence": "❌ MISSED OPPORTUNITY! Thousands of liters wasted into storm drains. -20 Health",
|
|
|
"xp_reward": 0,
|
|
|
"icon": "💸"
|
|
|
},
|
|
|
{
|
|
|
"action": "🛍️ Place plastic bags under the roof edge",
|
|
|
"description": "Use bags to catch dripping water",
|
|
|
"consequence": "❌ INEFFICIENT! Bags tear easily and collect very little water. Try a proper system! -20 Health",
|
|
|
"xp_reward": 0,
|
|
|
"icon": "🗑️"
|
|
|
}
|
|
|
]
|
|
|
},
|
|
|
|
|
|
{
|
|
|
"question": "💧 Your collection tank is filling up with rainwater, but you notice leaves and debris floating in it. What's your next critical step?",
|
|
|
"choices": [
|
|
|
{
|
|
|
"action": "🔍 Install a first-flush diverter and filtration system",
|
|
|
"description": "Remove initial dirty water and filter the rest",
|
|
|
"consequence": "✅ EXCELLENT CHOICE! Clean, safe water ready for storage. Your filtration efficiency: 95%! +100 XP",
|
|
|
"xp_reward": 100,
|
|
|
"icon": "🧪"
|
|
|
},
|
|
|
{
|
|
|
"action": "⚠️ Use the dirty water directly without treatment",
|
|
|
"description": "Proceed with unfiltered rainwater",
|
|
|
"consequence": "❌ HEALTH HAZARD! Contaminated water can cause serious illness. Always filter first! -20 Health",
|
|
|
"xp_reward": 0,
|
|
|
"icon": "☠️"
|
|
|
},
|
|
|
{
|
|
|
"action": "🧪 Add household bleach to kill germs",
|
|
|
"description": "Chemical treatment of collected water",
|
|
|
"consequence": "❌ WRONG CHEMICAL! Bleach is not safe for water treatment. Use proper filtration! -20 Health",
|
|
|
"xp_reward": 0,
|
|
|
"icon": "⚗️"
|
|
|
}
|
|
|
]
|
|
|
},
|
|
|
|
|
|
{
|
|
|
"question": "🏺 You have 500 liters of clean, filtered rainwater. The monsoon season is ending soon. Where should you store this precious resource?",
|
|
|
"choices": [
|
|
|
{
|
|
|
"action": "🏺 Install an underground concrete tank with cover",
|
|
|
"description": "Professional storage solution with temperature control",
|
|
|
"consequence": "✅ MASTER STRATEGY! Water stays cool, clean, and safe for months. Storage efficiency: 100%! +100 XP",
|
|
|
"xp_reward": 100,
|
|
|
"icon": "🏛️"
|
|
|
},
|
|
|
{
|
|
|
"action": "🪣 Store in open buckets around your yard",
|
|
|
"description": "Multiple container approach for easy access",
|
|
|
"consequence": "❌ BREEDING GROUND! Open water attracts mosquitoes and gets contaminated. -20 Health",
|
|
|
"xp_reward": 0,
|
|
|
"icon": "🦟"
|
|
|
},
|
|
|
{
|
|
|
"action": "🌍 Dig a pit and let water sit directly in ground",
|
|
|
"description": "Natural ground storage method",
|
|
|
"consequence": "❌ CONTAMINATION RISK! Soil bacteria and insects will pollute your water. -20 Health",
|
|
|
"xp_reward": 0,
|
|
|
"icon": "🕳️"
|
|
|
}
|
|
|
]
|
|
|
},
|
|
|
|
|
|
{
|
|
|
"question": "♻️ Dry season has arrived! You have 200 liters of stored rainwater left. Your neighbor is asking for help with their garden. How do you maximize the impact?",
|
|
|
"choices": [
|
|
|
{
|
|
|
"action": "🌿 Use for drip irrigation and toilet flushing",
|
|
|
"description": "Strategic usage for maximum water conservation",
|
|
|
"consequence": "✅ WATER WISDOM! You save 300L of municipal water and help the environment! +100 XP",
|
|
|
"xp_reward": 100,
|
|
|
"icon": "🌱"
|
|
|
},
|
|
|
{
|
|
|
"action": "⏰ Save all water for potential emergencies later",
|
|
|
"description": "Conservative approach for future needs",
|
|
|
"consequence": "❌ MISSED IMPACT! Water can spoil if stored too long. Use it wisely now! -20 Health",
|
|
|
"xp_reward": 0,
|
|
|
"icon": "⏰"
|
|
|
},
|
|
|
{
|
|
|
"action": "🚽 Mix with sewage water for disposal",
|
|
|
"description": "Combine with waste water system",
|
|
|
"consequence": "❌ TERRIBLE WASTE! Never contaminate clean water with sewage! -20 Health",
|
|
|
"xp_reward": 0,
|
|
|
"icon": "🤮"
|
|
|
}
|
|
|
]
|
|
|
},
|
|
|
|
|
|
{
|
|
|
"question": "🌱 Now that you've mastered rainwater harvesting, how will you inspire your community to join the movement?",
|
|
|
"choices": [
|
|
|
{
|
|
|
"action": "👥 Organize community workshops and share your knowledge",
|
|
|
"description": "Teach others about water conservation benefits",
|
|
|
"consequence": "✅ COMMUNITY HERO! You inspire 50 families to start rainwater harvesting! +100 XP",
|
|
|
"xp_reward": 100,
|
|
|
"icon": "🌟"
|
|
|
},
|
|
|
{
|
|
|
"action": "🤐 Keep the knowledge to yourself for competitive advantage",
|
|
|
"description": "Maintain exclusive access to water conservation techniques",
|
|
|
"consequence": "❌ SELFISH APPROACH! Environmental problems need collective solutions! -20 Health",
|
|
|
"xp_reward": 0,
|
|
|
"icon": "🚫"
|
|
|
},
|
|
|
{
|
|
|
"action": "📱 Only post about it on social media occasionally",
|
|
|
"description": "Share water conservation tips online when convenient",
|
|
|
"consequence": "❌ MINIMAL IMPACT! Real change needs active community engagement! -20 Health",
|
|
|
"xp_reward": 0,
|
|
|
"icon": "📱"
|
|
|
}
|
|
|
]
|
|
|
}
|
|
|
]
|
|
|
|
|
|
|
|
|
achievements_list = [
|
|
|
{"name": "🌟 First Steps", "desc": "Started your water journey", "condition": "start"},
|
|
|
{"name": "💧 Drop Collector", "desc": "Learned about collection", "condition": "video_1"},
|
|
|
{"name": "🔬 Purification Pro", "desc": "Mastered filtration", "condition": "video_2"},
|
|
|
{"name": "🏺 Storage Sage", "desc": "Understood storage methods", "condition": "video_3"},
|
|
|
{"name": "♻️ Usage Expert", "desc": "Optimized water usage", "condition": "video_4"},
|
|
|
{"name": "🎯 Perfect Score", "desc": "100% accuracy achieved", "condition": "perfect"},
|
|
|
{"name": "🔥 On Fire", "desc": "3 correct answers in a row", "condition": "streak_3"},
|
|
|
{"name": "🌍 Water Hero", "desc": "Completed the full quest", "condition": "complete"}
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
def calculate_level() -> int:
|
|
|
return min(10, 1 + session.get('xp_points', 0) // 100)
|
|
|
|
|
|
|
|
|
def add_xp(amount: int):
|
|
|
old_level = session.get('player_level', 1)
|
|
|
session['xp_points'] = session.get('xp_points', 0) + amount
|
|
|
session['player_level'] = calculate_level()
|
|
|
if session['player_level'] > old_level:
|
|
|
session['message'] = f"🎉 LEVEL UP! You reached Level {session['player_level']}!"
|
|
|
|
|
|
|
|
|
def unlock_achievement(condition: str):
|
|
|
for achievement in achievements_list:
|
|
|
if achievement["condition"] == condition and achievement not in session.get('achievements', []):
|
|
|
session['achievements'] = session.get('achievements', []) + [achievement]
|
|
|
session['message'] = f"🏆 Achievement Unlocked: {achievement['name']} - {achievement['desc']}"
|
|
|
add_xp(50)
|
|
|
|
|
|
|
|
|
def initialize_game_state():
|
|
|
session.setdefault("video_index", 0)
|
|
|
session.setdefault("feedback", "")
|
|
|
session.setdefault("quiz_correct_count", 0)
|
|
|
session.setdefault("quiz_attempts", 0)
|
|
|
session.setdefault("player_level", 1)
|
|
|
session.setdefault("xp_points", 0)
|
|
|
session.setdefault("achievements", [])
|
|
|
session.setdefault("streak", 0)
|
|
|
session.setdefault("health", 100)
|
|
|
session.setdefault("video_watched", False)
|
|
|
session.setdefault("question_answered", False)
|
|
|
session.setdefault("message", "")
|
|
|
|
|
|
|
|
|
def next_video_logic():
|
|
|
if session['video_index'] < len(videos) - 1:
|
|
|
session['video_index'] += 1
|
|
|
session['feedback'] = ""
|
|
|
session['video_watched'] = False
|
|
|
session['question_answered'] = False
|
|
|
session['message'] = ""
|
|
|
if session['video_index'] > 0:
|
|
|
unlock_achievement(f"video_{session['video_index']}")
|
|
|
return redirect(url_for('main_app'))
|
|
|
else:
|
|
|
unlock_achievement("complete")
|
|
|
return redirect(url_for('summary_page'))
|
|
|
|
|
|
|
|
|
def mark_video_watched_logic():
|
|
|
session['video_watched'] = True
|
|
|
session['message'] = ""
|
|
|
|
|
|
|
|
|
def replay_video_logic():
|
|
|
session['feedback'] = ""
|
|
|
session['video_watched'] = False
|
|
|
session['question_answered'] = False
|
|
|
session['message'] = "🔄 Video ready for replay! Click play to watch again."
|
|
|
|
|
|
|
|
|
def reset_quest_logic():
|
|
|
session.clear()
|
|
|
initialize_game_state()
|
|
|
|
|
|
|
|
|
def select_card_logic(choice_index: int):
|
|
|
current_scenario = task_scenarios[session['video_index']]
|
|
|
choice = current_scenario["choices"][choice_index]
|
|
|
|
|
|
session['quiz_attempts'] = session.get('quiz_attempts', 0) + 1
|
|
|
session['question_answered'] = True
|
|
|
|
|
|
session['feedback'] = choice["consequence"]
|
|
|
session['message'] = ""
|
|
|
|
|
|
if choice["xp_reward"] > 0:
|
|
|
session['quiz_correct_count'] = session.get('quiz_correct_count', 0) + 1
|
|
|
session['streak'] = session.get('streak', 0) + 1
|
|
|
add_xp(choice["xp_reward"])
|
|
|
if session['streak'] >= 3:
|
|
|
unlock_achievement("streak_3")
|
|
|
else:
|
|
|
session['streak'] = 0
|
|
|
session['health'] = max(0, session.get('health', 100) - 20)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@app.route('/')
|
|
|
def welcome_page():
|
|
|
if 'player_level' not in session:
|
|
|
initialize_game_state()
|
|
|
return render_template('welcome.html')
|
|
|
|
|
|
|
|
|
@app.route('/begin_quest', methods=['POST'])
|
|
|
def begin_quest():
|
|
|
unlock_achievement("start")
|
|
|
return redirect(url_for('main_app'))
|
|
|
|
|
|
|
|
|
@app.route('/main', methods=['GET', 'POST'])
|
|
|
def main_app():
|
|
|
if 'player_level' not in session:
|
|
|
return redirect(url_for('welcome_page'))
|
|
|
|
|
|
|
|
|
if request.method == 'POST':
|
|
|
if 'mark_watched' in request.form:
|
|
|
mark_video_watched_logic()
|
|
|
elif 'select_choice' in request.form:
|
|
|
choice_index = int(request.form['select_choice'])
|
|
|
select_card_logic(choice_index)
|
|
|
elif 'next_level' in request.form or 'continue_quest' in request.form:
|
|
|
return next_video_logic()
|
|
|
elif 'replay_video' in request.form:
|
|
|
replay_video_logic()
|
|
|
return redirect(url_for('main_app'))
|
|
|
elif 'main_menu' in request.form:
|
|
|
return redirect(url_for('welcome_page'))
|
|
|
|
|
|
return redirect(url_for('main_app'))
|
|
|
|
|
|
current_video_index = session.get('video_index', 0)
|
|
|
current_video_path = videos[current_video_index]
|
|
|
|
|
|
|
|
|
is_local_video = current_video_path.startswith('videos/')
|
|
|
if is_local_video:
|
|
|
video_src = url_for('static', filename=current_video_path)
|
|
|
else:
|
|
|
video_src = current_video_path
|
|
|
|
|
|
|
|
|
local_file_exists = True
|
|
|
if is_local_video:
|
|
|
full_path = Path(app.static_folder) / current_video_path
|
|
|
if not full_path.exists():
|
|
|
local_file_exists = False
|
|
|
|
|
|
context = {
|
|
|
'current_video_index': current_video_index,
|
|
|
'total_videos': len(videos),
|
|
|
'video_src': video_src,
|
|
|
'is_local_video': is_local_video,
|
|
|
'local_file_exists': local_file_exists,
|
|
|
'video_description': video_descriptions[current_video_index],
|
|
|
'current_scenario': task_scenarios[current_video_index],
|
|
|
'player_level': session.get('player_level', 1),
|
|
|
'xp_points': session.get('xp_points', 0),
|
|
|
'health': session.get('health', 100),
|
|
|
'streak': session.get('streak', 0),
|
|
|
'quiz_correct_count': session.get('quiz_correct_count', 0),
|
|
|
'quiz_attempts': session.get('quiz_attempts', 0),
|
|
|
'video_watched': session.get('video_watched', False),
|
|
|
'question_answered': session.get('question_answered', False),
|
|
|
'feedback': session.get('feedback', ''),
|
|
|
'achievements': session.get('achievements', []),
|
|
|
'message': session.pop('message', '')
|
|
|
}
|
|
|
return render_template('main.html', **context)
|
|
|
|
|
|
|
|
|
@app.route('/summary')
|
|
|
def summary_page():
|
|
|
if 'player_level' not in session:
|
|
|
return redirect(url_for('welcome_page'))
|
|
|
|
|
|
total_quizzes = len([s for s in task_scenarios if s.get("choices")])
|
|
|
score = session.get('quiz_correct_count', 0)
|
|
|
|
|
|
if score == total_quizzes and total_quizzes > 0:
|
|
|
unlock_achievement("perfect")
|
|
|
|
|
|
context = {
|
|
|
'player_level': session.get('player_level', 1),
|
|
|
'xp_points': session.get('xp_points', 0),
|
|
|
'quiz_score': score,
|
|
|
'total_quizzes': total_quizzes,
|
|
|
'accuracy': (score / max(1, total_quizzes)) * 100,
|
|
|
'streak': session.get('streak', 0),
|
|
|
'achievements': session.get('achievements', []),
|
|
|
'current_date': time.strftime("%B %d, %Y"),
|
|
|
'message': session.pop('message', '')
|
|
|
}
|
|
|
return render_template('summary.html', **context)
|
|
|
|
|
|
|
|
|
@app.route('/restart_quest', methods=['POST'])
|
|
|
def restart_quest():
|
|
|
reset_quest_logic()
|
|
|
return redirect(url_for('welcome_page'))
|
|
|
|
|
|
|
|
|
@app.route('/view_stats', methods=['POST'])
|
|
|
def view_stats():
|
|
|
session['message'] = "Detailed stats coming soon!"
|
|
|
return redirect(url_for('summary_page'))
|
|
|
|
|
|
|
|
|
@app.route('/share_impact', methods=['POST'])
|
|
|
def share_impact():
|
|
|
session['message'] = "🌟 Your impact is shared!"
|
|
|
return redirect(url_for('summary_page'))
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
app.run(debug=True) |