diff --git a/Project2-draft/Main-Paige.html b/Project2-draft/Main-Paige.html new file mode 100644 index 0000000..a7d1fbd --- /dev/null +++ b/Project2-draft/Main-Paige.html @@ -0,0 +1,21 @@ + + + + + Main Page + + + + + + +

Main Page

+ + + + diff --git a/Project2-draft/background.jpg b/Project2-draft/background.jpg new file mode 100644 index 0000000..f03ebd0 Binary files /dev/null and b/Project2-draft/background.jpg differ diff --git a/Project2-draft/exit.html b/Project2-draft/exit.html new file mode 100644 index 0000000..6fbeaf6 --- /dev/null +++ b/Project2-draft/exit.html @@ -0,0 +1,10 @@ + + + + + Exit + + +

This is the Exit page

+ + \ No newline at end of file diff --git a/Project2-draft/explore-page.html b/Project2-draft/explore-page.html new file mode 100644 index 0000000..1f32e8b --- /dev/null +++ b/Project2-draft/explore-page.html @@ -0,0 +1,10 @@ + + + + + Explore + + + + + \ No newline at end of file diff --git a/Project2-draft/front-page.html b/Project2-draft/front-page.html new file mode 100644 index 0000000..49c854b --- /dev/null +++ b/Project2-draft/front-page.html @@ -0,0 +1,10 @@ + + + + + Front Page + + + + + \ No newline at end of file diff --git a/Project2-draft/manage.html b/Project2-draft/manage.html new file mode 100644 index 0000000..15d820e --- /dev/null +++ b/Project2-draft/manage.html @@ -0,0 +1,10 @@ + + + + + Manage + + + + + \ No newline at end of file diff --git a/Project2-draft/style.css b/Project2-draft/style.css new file mode 100644 index 0000000..381424a --- /dev/null +++ b/Project2-draft/style.css @@ -0,0 +1,39 @@ +@import url('https://fonts.googleapis.com/css2?family=Pixelify+Sans:wght@400..700&display=swap'); + +ul { + list-style: none; + padding: 0; + margin: 0; +} + +body { + font-family: "pixelify sans", sans-serif ; + text-align: center; + color: #8b4513; + background-image: url("background.jpg"); + font-size: 40px; + text-shadow: 0px 0px 10px rgba(0,0,0,0.3); /* adding shadow behind the text, to make it more visible*/ + +} + +button { + padding: 40px 300px; + margin: 4px; + width: 200px; + height: 60px; + background-color: #7ed957; + color: #8b4513; + border: none; + border-radius: 2px; + cursor: pointer; + font-family: "Pixelify Sans", sans-serif; + font-size: 22px; + text-align: center; + white-space: nowrap; + line-height: 10px; + text-indent: -40px; /* moving the text more to the center */ +} + +button:hover { + background-color: darkolivegreen; +} diff --git a/Project2-draft/view-journal.html b/Project2-draft/view-journal.html new file mode 100644 index 0000000..7392ece --- /dev/null +++ b/Project2-draft/view-journal.html @@ -0,0 +1,10 @@ + + + + + View Journal + + + + + \ No newline at end of file diff --git a/__pycache__/creature_game.cpython-312.pyc b/__pycache__/creature_game.cpython-312.pyc new file mode 100644 index 0000000..536e345 Binary files /dev/null and b/__pycache__/creature_game.cpython-312.pyc differ diff --git a/__pycache__/creature_game.cpython-39.pyc b/__pycache__/creature_game.cpython-39.pyc new file mode 100644 index 0000000..ed68726 Binary files /dev/null and b/__pycache__/creature_game.cpython-39.pyc differ diff --git a/creature_game.py b/creature_game.py index d147dad..91d4ea2 100644 --- a/creature_game.py +++ b/creature_game.py @@ -22,7 +22,7 @@ class Database: """Database connection handler""" - def __init__(self, host='localhost', user='root', password='', database='creature_catcher'): + def __init__(self, host='localhost', user='root', password='123456789', database='creature_catcher'): self.connection = pymysql.connect( host=host, user=user, @@ -659,7 +659,7 @@ def main_menu(self): db = Database( host='localhost', user='root', - password='Cde3xsw2', + password='123456789', database='creature_catcher' ) print("✅ Connected!\n") diff --git a/exitpage/exit.css b/exitpage/exit.css new file mode 100644 index 0000000..dc36f0c --- /dev/null +++ b/exitpage/exit.css @@ -0,0 +1,27 @@ +body{ + background:url("exitbackground.jpg"); + background-size:cover; + background-position:center; + background-repeat:no repeat; + font-family:pixelify sans,sans-serif; + color:#8b4513 ; + display:flex; + justify-content:center; + align-items:center; + height:100vh; + margin:0; +} +.exit-wrapper{ + text-align:center; +} + +.btn{ + padding:10px; + background:#7ed957; + border-radius:6px; + border:none; + font-size:16px; + font-weight:bold; + cursor:pointer; + +} diff --git a/exitpage/exit.html b/exitpage/exit.html new file mode 100644 index 0000000..e19a462 --- /dev/null +++ b/exitpage/exit.html @@ -0,0 +1,22 @@ + + + + + + + Creaturecatch exit + + + + + +
+

You have successfully logged out!

+

Thank you for playing creature catch!

+

Click play to play again!

+ + +
+ + + \ No newline at end of file diff --git a/exitpage/exit.js b/exitpage/exit.js new file mode 100644 index 0000000..29b28e4 --- /dev/null +++ b/exitpage/exit.js @@ -0,0 +1,4 @@ +const playBtn = document.getElementById(playBtn); +playBtn.addEventListener("click", () => { + window.location.href = "login.html"; +}); diff --git a/exitpage/exitbackground.jpg b/exitpage/exitbackground.jpg new file mode 100644 index 0000000..2ab48db Binary files /dev/null and b/exitpage/exitbackground.jpg differ diff --git a/game.py b/game.py new file mode 100644 index 0000000..91baf4e --- /dev/null +++ b/game.py @@ -0,0 +1,469 @@ +from flask import Flask, render_template, request, jsonify, send_from_directory +from flask_cors import CORS +import random + +from creature_game import Database, Game, Player, Creature, PlayerCreature, Habitat + +app = Flask(__name__) +CORS(app) + +# connect database + + +def get_db(): + return Database( + host='127.0.0.1', + user='root', + password='123456789', + database='creature_catcher' + ) + + +@app.route('/') +def login_page(): + return send_from_directory('loginpage', 'login.html') + + +@app.route('/journal_page/') +def journal_page_files(filename): + return send_from_directory('journal', filename) + + +@app.route('/images/') +def image_files(filename): + return send_from_directory('images', filename) + + +@app.route('/game') +def game_page(): + return render_template('index.html') + + +@app.route('/login', methods=['POST']) +def login(): + """Login or create player""" + data = request.json + username = data.get('username', '').strip() + + if not username: + return jsonify({'error': 'no username'}), 400 + + messages = [] + + try: + db = get_db() + game = Game(db) + + # Check if new player + existing_player = Player.get_by_username(db, username) + + if not existing_player: + messages.append(f"🌟 Creating new sanctuary for {username}...") + game.login_or_create(username) + starter = Creature.from_db(db, 1) + messages.append( + f"✨ You received your first creature: {starter.name} ({starter.type.name} type)!") + messages.append(f"📖 {starter.description}") + messages.append("") + messages.append(f"🏠 {starter.name} has been placed in Habitat 1") + messages.append("") + else: + game.login_or_create(username) + messages.append(f"👋 Welcome back to your sanctuary, {username}!") + messages.append("") + + return jsonify({ + 'success': True, + 'messages': messages, + 'player_id': game.player.id, + 'username': game.player.username + }) + + except Exception as e: + messages.append(f"❌ Error: {str(e)}") + return jsonify({'success': False, 'messages': messages}), 500 + +# explore + + +@app.route('/explore/start', methods=['GET']) +def explore_start(): + """Start exploration - show companions""" + player_id = request.args.get('player_id') + + if not player_id: + return jsonify({'error': 'Player ID required'}), 400 + + try: + db = get_db() + player = Player.from_db(db, int(player_id)) + unplaced = player.get_unplaced_creatures(db) + + messages = [] + + # unplaced creatures + if unplaced: + messages.append("") + messages.append( + "⚠️ You have unplaced creatures! Place all creatures in habitats before exploring.") + messages.append(f"📦 {len(unplaced)} creature(s) need placement.") + messages.append("") + return jsonify({'success': False, 'messages': messages, 'error': 'unplaced'}) + + if not player.are_all_happy(db): + messages.append("") + messages.append( + "⚠️ Some creatures are unhappy! You must fix happiness before exploring.") + messages.append( + "Rearrange creatures in habitats or release unhappy ones.") + messages.append("") + return jsonify({'success': False, 'messages': messages, 'error': 'unhappy'}) + + # companions + habitats = player.get_habitats(db) + all_creatures = [] + for habitat in habitats: + all_creatures.extend(habitat.creatures) + + if not all_creatures: + messages.append("") + messages.append("❌ You have no creatures to take as companions!") + messages.append("") + return jsonify({'success': False, 'messages': messages, 'error': 'no_creatures'}) + + messages.append("") + messages.append("🎒 Choose a companion for exploration:") + for i, pc in enumerate(all_creatures, 1): + messages.append( + f" [{i}] {pc.nickname} ({pc.creature.type.name}) - Happiness: {pc.happiness}%") + messages.append("") + messages.append("Select companion (number):") + + companions_data = [{'id': pc.id, 'nickname': pc.nickname, + 'type': pc.creature.type.name} for pc in all_creatures] + + return jsonify({ + 'success': True, + 'messages': messages, + 'companions': companions_data + }) + + except Exception as e: + return jsonify({'error': str(e)}), 500 + + +@app.route('/explore/encounter', methods=['POST']) +def explore_encounter(): + """Encounter wild creatures""" + data = request.json + player_id = data.get('player_id') + companion_id = data.get('companion_id') + + if not player_id or not companion_id: + return jsonify({'error': 'Player ID and companion ID required'}), 400 + + try: + db = get_db() + player = Player.from_db(db, int(player_id)) + companion = PlayerCreature.from_db(db, int(companion_id)) + + messages = [] + messages.append("") + messages.append(f"🌿 {companion.nickname} joins you for exploration!") + messages.append("") + + # Check if all discovered + all_species = Creature.get_all(db) + discovered = player.get_discovered_species(db) + + if len(discovered) >= 16: + messages.append( + "🎊 ═══════════════════════════════════════════════════ 🎊") + messages.append(" 🌟 CONGRATULATIONS! YOU'VE CAUGHT THEM ALL! 🌟") + messages.append( + "🎊 ═══════════════════════════════════════════════════ 🎊") + messages.append("") + messages.append(" You've discovered all 16 creature species!") + messages.append(" Your sanctuary is complete!") + messages.append("") + return jsonify({'success': True, 'messages': messages, 'complete': True}) + + # undiscovered creatures + undiscovered = [c for c in all_species if c.id not in discovered] + num_to_show = min(3, len(undiscovered)) + wild_choices = random.sample(undiscovered, num_to_show) + + if num_to_show == 1: + messages.append("🔍 You encounter a wild creature:") + else: + messages.append(f"🔍 You encounter {num_to_show} wild creatures:") + + wild_data = [] + for i, wild in enumerate(wild_choices, 1): + effectiveness = companion.creature.type.get_effectiveness( + db, wild.type.id) + status = "✅ Strong" if effectiveness >= 2.0 else "🟡 Normal" if effectiveness >= 1.0 else "❌ Weak" + messages.append( + f" [{i}] {wild.name} ({wild.type.name}) - {status} attraction - ✨ NEW!") + messages.append(f" {wild.description}") + + wild_data.append({ + 'id': wild.id, + 'name': wild.name, + 'type': wild.type.name, + 'description': wild.description, + 'effectiveness': effectiveness, + 'status': status + }) + + messages.append("") + choice_range = f"1-{num_to_show}" if num_to_show > 1 else "1" + messages.append( + f"Which creature to approach? ({choice_range} or 0 to leave):") + + return jsonify({ + 'success': True, + 'messages': messages, + 'wild_creatures': wild_data, + 'companion_id': companion.id + }) + + except Exception as e: + return jsonify({'error': str(e)}), 500 + + +@app.route('/explore/catch', methods=['POST']) +def explore_catch(): + """Attempt to catch a creature""" + data = request.json + player_id = data.get('player_id') + wild_creature_id = data.get('wild_creature_id') + effectiveness = data.get('effectiveness', 1.0) + + if not player_id or not wild_creature_id: + return jsonify({'error': 'error'}), 400 + + try: + db = get_db() + player = Player.from_db(db, int(player_id)) + target = Creature.from_db(db, int(wild_creature_id)) + base_chance = 0.3 + modified_chance = min(0.95, base_chance * effectiveness) + + messages = [] + messages.append("") + messages.append(f"🎯 Attempting to attract {target.name}...") + messages.append(f" Base chance: 30%") + messages.append(f" Type multiplier: {effectiveness}x") + messages.append(f" Final chance: {int(modified_chance * 100)}%") + messages.append("") + + success = random.random() < modified_chance + + if success: + messages.append( + f"🎉 Success! {target.name} trusts you and joins your sanctuary!") + messages.append("") + player.catch_creature(db, target) + messages.append( + f"✨ {target.name} has been added to your unplaced creatures.") + messages.append("") + else: + messages.append( + f"😞 {target.name} was not convinced and fled. Better luck next time!") + messages.append("") + + return jsonify({ + 'success': True, + 'messages': messages, + 'caught': success, + 'creature_id': target.id + }) + + except Exception as e: + return jsonify({'error': str(e)}), 500 + + +@app.route('/habitats', methods=['GET']) +def view_habitats(): + """View habitats""" + player_id = request.args.get('player_id') + + if not player_id: + return jsonify({'error': 'Player ID required'}), 400 + + try: + db = get_db() + player = Player.from_db(db, int(player_id)) + habitats = player.get_habitats(db) + unplaced = player.get_unplaced_creatures(db) + + messages = [] + messages.append("") + messages.append("🏠 === SANCTUARY HABITATS ===") + messages.append("") + + habitat_data = [] + for habitat in habitats: + messages.append( + f"Habitat {habitat.number} ({len(habitat.creatures)}/{Habitat.MAX_SLOTS} creatures):") + creatures_list = [] + if habitat.creatures: + for i, cre in enumerate(habitat.creatures, 1): + emoji = "😊" if cre.happiness >= 70 else "😐" if cre.happiness >= 30 else "😢" + messages.append( + f" [{i}] {emoji} {cre.nickname} ({cre.creature.type.name}) - {cre.happiness}% happy") + creatures_list.append({ + 'id': cre.id, + 'nickname': cre.nickname, + 'type': cre.creature.type.name, + 'happiness': cre.happiness + }) + else: + messages.append(" (empty)") + messages.append("") + + habitat_data.append({ + 'id': habitat.id, + 'number': habitat.number, + 'creatures': creatures_list, + 'is_full': habitat.is_full() + }) + + messages.append(f"📦 Unplaced Creatures ({len(unplaced)}):") + unplaced_data = [] + if unplaced: + for i, pc in enumerate(unplaced, 1): + messages.append( + f" [{i}] {pc.nickname} ({pc.creature.type.name})") + unplaced_data.append({ + 'id': pc.id, + 'nickname': pc.nickname, + 'type': pc.creature.type.name + }) + else: + messages.append(" (none)") + messages.append("") + + return jsonify({ + 'success': True, + 'messages': messages, + 'habitats': habitat_data, + 'unplaced': unplaced_data + }) + + except Exception as e: + return jsonify({'error': 'error'}), 500 + + +@app.route('/journal', methods=['GET']) +def view_journal(): + """View field journal""" + player_id = request.args.get('player_id') + + if not player_id: + return jsonify({'error': 'Player ID required'}), 400 + + try: + db = get_db() + player = Player.from_db(db, int(player_id)) + discovered = player.get_discovered_species(db) + all_species = Creature.get_all(db) + + creatures_data = [] + for creature in all_species: + is_discovered = creature.id in discovered + creatures_data.append({ + 'id': creature.id, + 'name': creature.name if is_discovered else "???", + 'type': creature.type.name if is_discovered else "???", + 'description': creature.description if is_discovered else "Not yet discovered", + 'image': creature.image_path if is_discovered else None, + 'discovered': is_discovered + }) + + return jsonify({ + 'success': True, + 'creatures': creatures_data, + 'discovered_count': len(discovered), + 'total_species': len(all_species) + }) + + except Exception as e: + return jsonify({'error': str(e)}), 500 + + +@app.route('/move', methods=['POST']) +def move_creature(): + """Move a creature between habitats""" + data = request.json + player_id = data.get('player_id') + creature_id = data.get('creature_id') + target_habitat_id = data.get('target_habitat_id') + + if not player_id or not creature_id: + return jsonify({'error': 'error'}), 400 + + try: + db = get_db() + player = Player.from_db(db, int(player_id)) + creature = PlayerCreature.from_db(db, creature_id) + + if not creature or creature.player_id != player.id: + return jsonify({'error': 'Invalid creature'}), 400 + + messages = [] + + if target_habitat_id is None: + # Move to unplaced + db.execute_commit( + "UPDATE player_creatures SET habitat_id = NULL, habitat_slot = NULL WHERE id = %s", + (creature_id,) + ) + messages.append("") + messages.append( + f"✅ Moved {creature.nickname} to unplaced creatures") + messages.append("") + return jsonify({'success': True, 'messages': messages}) + else: + # Move to habitat + habitats = player.get_habitats(db) + target_habitat = None + for h in habitats: + if h.id == target_habitat_id: + target_habitat = h + break + + if not target_habitat: + return jsonify({'error': 'Invalid habitat'}), 400 + + if target_habitat.is_full(): + messages.append("") + messages.append(f"❌ Habitat {target_habitat.number} is full!") + messages.append("") + return jsonify({'success': False, 'messages': messages}) + + new_slot = len(target_habitat.creatures) + 1 + db.execute_commit( + "UPDATE player_creatures SET habitat_id = %s, habitat_slot = %s WHERE id = %s", + (target_habitat_id, new_slot, creature_id) + ) + + target_habitat.creatures.append(creature) + target_habitat.update_happiness(db) + + messages.append("") + messages.append( + f"✅ Moved {creature.nickname} to Habitat {target_habitat.number}") + messages.append( + f"Updated happiness for Habitat {target_habitat.number}") + messages.append("") + + return jsonify({'success': True, 'messages': messages}) + + except Exception as e: + return jsonify({'error': str(e)}), 500 + + +if __name__ == '__main__': + app.run(debug=True, host='127.0.0.1', port=8080) diff --git a/h b/h new file mode 100644 index 0000000..c3849d4 --- /dev/null +++ b/h @@ -0,0 +1,48 @@ +1a437f7 (HEAD -> main_page, origin/main_page) Merge remote-tracking branch 'origin/main_page' into main_page +2ec38a8 updated menu page (main page) +0c5b4d3 Merge branch 'main' into main_page +c7e7c3e main page +96e4b9b Merge pull request #3 from Sorathor/exit +8caaa78 add exit.html +38c40c2 exit +e1c362c Merge pull request #2 from Sorathor/login +419abe5 (origin/login) Merge branch 'main' into login +90a8d28 change pwd +8bf7a6c login.c +b95a462 login.c +4269f30 login.html +b39b216 update .gitattributes to include SQL language detection +a43b85b remove .gitattributes file for CSS and JS language detection +57f38af change dir +e7afd5b Merge pull request #1 from Sorathor/explore +a41e01c (origin/explore) restore .gitattributes for CSS and JS file detection +72a2d65 update .gitattributes to enhance language detection for CSS and JS files +21f345e add .gitattributes for CSS and JS file detection +d4de2a1 add compiled bytecode +707971b core game logic and endpoint +398da4d add frontend +2ed39bf change the password +0276d7d first commit +5e2377f (main) Update README.md +5f3589c Update README.md +c40bd2b Update README.md +a16321e Add files via upload +b13bd9c Create borealynx.png +732236a Delete assets directory +4cc3764 Create setup-database.py +76927a6 Create creature_schema.sql +740f20f Create creature_game.py +3fa680c Delete game.py +36840be Delete story.py +f9b04da Update README.md +705f632 Update README.md +af57ab1 Update README.md +7a76fda Update README.md +c770379 Add files via upload +36b225f Create text.png +a6b6a2f Create example.pyc +fec64a0 Create story.py +e1d8957 Create game.py +25d5ba7 Rename gitignore.txt to .gitignore +e6442be Add files via upload +e14510e Initial commit diff --git a/journal/bg.png b/journal/bg.png new file mode 100644 index 0000000..e31ccdd Binary files /dev/null and b/journal/bg.png differ diff --git a/journal/server.py b/journal/server.py new file mode 100644 index 0000000..6957a00 --- /dev/null +++ b/journal/server.py @@ -0,0 +1,22 @@ +from flask import Flask, request, jsonify +from flask_cors import CORS + +app = Flask(__name__) +CORS(app) + +import mysql.connector +@app.route('/journal', methods=['GET']) +def get_journal(): + db = mysql.connector.connect( + host='127.0.0.1', + user='root', + password='123456789', + database='creature_catcher' + ) + cursor = db.cursor() + cursor.execute("""SELECT a.id AS SN, a.name AS name, b.name AS type FROM creatures a LEFT JOIN types b ON a.id = b.id""") + result=cursor.fetchall() + print(result) + return jsonify(result) +if __name__ == '__main__': + app.run(debug=True) \ No newline at end of file diff --git a/setup-database.py b/journal/setup-database.py similarity index 94% rename from setup-database.py rename to journal/setup-database.py index 8e5aec0..1f090a7 100644 --- a/setup-database.py +++ b/journal/setup-database.py @@ -12,7 +12,7 @@ def setup_database(): # Connection details - UPDATE THESE DB_HOST = 'localhost' DB_USER = 'root' - DB_PASSWORD = 'Cde3xsw2' # <-- UPDATE WITH YOUR PASSWORD + DB_PASSWORD = '123456789' # <-- UPDATE WITH YOUR PASSWORD DB_NAME = 'creature_catcher' try: @@ -22,7 +22,7 @@ def setup_database(): host=DB_HOST, user=DB_USER, password=DB_PASSWORD, - charset='utf8mb4' + database=DB_NAME ) with connection.cursor() as cursor: @@ -35,7 +35,7 @@ def setup_database(): # You can paste the SQL here or read from file # For now, let's read from the schema file try: - with open('creature_schema.sql', 'r') as f: + with open('Software2-Project\creature_schema.sql', 'r') as f: sql_content = f.read() # Split by semicolons and execute each statement diff --git a/journal/viewjournal.css b/journal/viewjournal.css new file mode 100644 index 0000000..2ee4613 --- /dev/null +++ b/journal/viewjournal.css @@ -0,0 +1,111 @@ +body { + margin: 0; + padding: 20px 0; + font-family: Arial, sans-serif; + background-image: url('bg.png'); + background-size: cover; + background-repeat: no-repeat; + background-attachment: fixed; + background-position: center; + display: flex; + flex-direction: column; + align-items: center; + gap: 20px; + min-height: 100vh; +} + + +#journal { + width: 60vw; + height: 60vw; + max-width: 800px; + max-height: 800px; + border-radius: 15px; + display: flex; + flex-direction: column; + align-items: center; + justify-content: flex-start; + padding: 15px; +} + +.journal-summary { + font-size: 18px; + font-weight: bold; + color: #000; + margin-bottom: 10px; + text-align: center; +} + +#journalList { + display: grid; + grid-template-columns: repeat(4, 1fr); + grid-auto-rows: 1fr; + gap: 70px; + width: 100%; + height: 100%; +} + + +.journal-item { + background: rgba(255, 255, 255, 0.3); + border-radius: 10px; + color: #000; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + aspect-ratio: 1 / 1; + box-shadow: 0 4px 8px rgba(0,0,0,0.3); + transition: transform 0.2s, box-shadow 0.2s; +} + +.journal-item:hover { + transform: scale(1.05); + box-shadow: 0 8px 20px rgba(0,0,0,0.5); +} + +.journal-item img { + width: 75%; + height: 80%; + object-fit: contain; +} + +.journal-item .placeholder { + width: 70%; + height: 70%; + background: rgba(255, 255, 255, 0.5); + display: flex; + align-items: center; + justify-content: center; + font-size: 32px; + font-weight: bold; + color: #000; + text-shadow: none; +} + +.journal-item p { + margin: 5px 0 0 0; + font-size: 12px; + text-align: center; + color: #000; +} + +#backBtn { + background: rgba(255, 255, 255, 0.4); + color: #000; + border: none; + border-radius: 8px; + padding: 8px 16px; + font-size: 14px; + font-weight: bold; + cursor: pointer; + transition: background 0.2s, transform 0.2s, box-shadow 0.2s; + margin-top: 20px; +} + +#backBtn:hover { + background: rgba(255, 255, 255, 0.6); + transform: translateY(-2px); + box-shadow: 0 4px 10px rgba(0,0,0,0.3); +} + diff --git a/journal/viewjournal.html b/journal/viewjournal.html new file mode 100644 index 0000000..96a0319 --- /dev/null +++ b/journal/viewjournal.html @@ -0,0 +1,21 @@ + + + + + + Creature Catcher + + + + + +

View Journal

+ +
+
+
+ + + + + diff --git a/journal/viewjournal.js b/journal/viewjournal.js new file mode 100644 index 0000000..7d4cd48 --- /dev/null +++ b/journal/viewjournal.js @@ -0,0 +1,75 @@ +const params = new URLSearchParams(window.location.search); +const playerId = params.get("player_id"); + +function goBack() { + window.location.href = `/game?player_id=${playerId}`; +} + +async function loadJournalPage(playerId) { + const journal = document.getElementById("journal"); + + const existingGrid = document.getElementById("journalList"); + if (existingGrid) existingGrid.remove(); + + try { + const response = await fetch(`/journal?player_id=${playerId}`); + const data = await response.json(); + + if (!data.success) { + throw new Error("Failed to fetch journal data"); + } + + const existingSummary = document.querySelector(".journal-summary"); + if (existingSummary) existingSummary.remove(); + + const summary = document.createElement("div"); + summary.className = "journal-summary"; + summary.textContent = `Discovered: ${data.discovered_count || 0} / ${ + data.total_species || 16 + }`; + journal.appendChild(summary); + + const grid = document.createElement("div"); + grid.id = "journalList"; + journal.appendChild(grid); + + data.creatures.forEach((creature) => { + const item = document.createElement("div"); + item.className = "journal-item"; + + if (creature.discovered) { + const img = document.createElement("img"); + img.src = `../${creature.image}`; + img.alt = creature.name; + + img.onerror = () => { + img.src = "https://placehold.co/600x400"; + }; + + item.appendChild(img); + + const info = document.createElement("p"); + info.innerHTML = `${creature.name}
${creature.type}`; + item.appendChild(info); + } else { + const placeholder = document.createElement("div"); + placeholder.className = "placeholder"; + placeholder.textContent = "???"; + item.appendChild(placeholder); + + const info = document.createElement("p"); + info.textContent = "???"; + item.appendChild(info); + } + + grid.appendChild(item); + }); + } catch (error) { + console.error("Error loading journal:", error); + journal.textContent = "Failed to load journal."; + } +} + +document.addEventListener("DOMContentLoaded", () => { + loadJournalPage(playerId); +}); diff --git a/loginpage/login.html b/loginpage/login.html new file mode 100644 index 0000000..ff12560 --- /dev/null +++ b/loginpage/login.html @@ -0,0 +1,26 @@ + + + + + + + Creaturecatch login + + + + +
+

Welcome to creature catch

+ + +
+ + + diff --git a/manage_page/app.py b/manage_page/app.py new file mode 100644 index 0000000..248a916 --- /dev/null +++ b/manage_page/app.py @@ -0,0 +1,42 @@ +from flask import Flask, jsonify, render_template + +app = Flask(__name__, template_folder='templates', static_folder='static') + +@app.route('/manage') +def manage_page(): + return render_template('manage.html') + +@app.route('/manage/data') +def display_data(): + data = { + "habitats": { + "h1s1": {"name": "Spriggle", "image": "/static/images/spriggle.png"}, + "h1s2": None, + "h1s3": None, + "h1s4": None, + + "h2s1": None, + "h2s2": None, + "h2s3": None, + "h2s4": None, + + "h3s1": None, + "h3s2": None, + "h3s3": None, + "h3s4": None, + + "h4s1": None, + "h4s2": None, + "h4s3": None, + "h4s4": None, + + "unplaced": [ + # empty for now + ] + } + } + return jsonify(data) + +if __name__ == "__main__": + app.run(debug=True) + diff --git a/manage_page/game.py b/manage_page/game.py new file mode 100644 index 0000000..a7846ea --- /dev/null +++ b/manage_page/game.py @@ -0,0 +1,21 @@ +import mysql.connector + +connection = mysql.connector.connect( + host='127.0.0.1', + port= 5000, + database='creature_catcher', + user='root', + password='123456789', + autocommit=True + ) + +cursor = connection.cursor() + +player_id = 1 + +cursor.execute("Insert ignore into players (id, username) values (1,'player1)") + +for i in range (1,5): + cursor.execute( + "Insert ignore into habitats (payer_id" + ) \ No newline at end of file diff --git a/manage_page/managepage.png b/manage_page/managepage.png new file mode 100644 index 0000000..834af03 Binary files /dev/null and b/manage_page/managepage.png differ diff --git a/manage_page/static/manage.css b/manage_page/static/manage.css new file mode 100644 index 0000000..2e27fa1 --- /dev/null +++ b/manage_page/static/manage.css @@ -0,0 +1,159 @@ +/* /* +body { + margin: 0; + padding: 0; + background: url("./Untitled\ design\ \(10\).png") no-repeat center center fixed; + background-size: cover; + +} + + +.container { + width: 80%; + max-width: 900px; + margin: 40px auto; + + + padding: 20px; + border-radius: 12px; + +} + + +#habitatTable { + width: 100%; + + + border-radius: 10px; + overflow: hidden; +} + + + + + +.btn { + + border: none; + padding: 12px 22px; + font-size: 16px; + border-radius: 8px; + + + font-weight: bold; + +} + +.btn:hover { + + transform: scale(1.05); +} + + */ + +/* body{ + background-image: url('../managepage.png'); + background-repeat: no-repeat; + background-attachment: fixed; + background-position: center; + background-size: cover; + } */ + + /* .habitat_table{ + border-collapse: collapse; + width: 75%; + margin: auto; + + } */ + + /* #habitatTable{ + width: 100%; + border: 1px solid; + + } + */ */ + + /* --- General body and page styling --- */ +body { + font-family: Arial, sans-serif; + background-color: #f5f5f5; + margin: 0; + padding: 0; +} + +.managepagemain { + max-width: 1000px; + margin: 30px auto; + padding: 20px; + background-color: #ffffff; + box-shadow: 0 4px 12px rgba(0,0,0,0.1); + border-radius: 10px; +} + +/* --- Table styling --- */ +.habitat_table table { + width: 100%; + border-collapse: collapse; + margin-bottom: 20px; +} +a +/* Table headers */ +.habitat_table th { + background-color: #4CAF50; + color: white; + padding: 12px; + text-align: left; + font-size: 16px; +} + +/* Table cells */ +.habitat_table td { + padding: 10px; + border: 1px solid #ddd; + vertical-align: middle; + text-align: center; + font-size: 14px; +} + +/* Alternating row colors for readability */ +.habitat_table tr:nth-child(even) { + background-color: #f9f9f9; +} + +/* Hover effect */ +.habitat_table tr:hover { + background-color: #e0f7fa; +} + +/* Creature images */ +.habitat_table td img { + width: 50px; + height: 50px; + object-fit: contain; + margin-right: 5px; + vertical-align: middle; + border-radius: 5px; +} + +/* --- Buttons --- */ +.buttons { + display: flex; + gap: 10px; + margin-top: 20px; +} + +.buttons button { + padding: 10px 20px; + border: none; + background-color: #4CAF50; + color: white; + font-size: 14px; + border-radius: 5px; + cursor: pointer; + transition: background-color 0.2s ease; +} + +.buttons button:hover { + background-color: #45a049; +} + diff --git a/manage_page/static/manage.js b/manage_page/static/manage.js new file mode 100644 index 0000000..e378151 --- /dev/null +++ b/manage_page/static/manage.js @@ -0,0 +1,238 @@ +const player_id = 2; +let value1 = ""; +let value2 = ""; + +const table = document.querySelector(".habitat_table"); +const cdiv = document.createElement("div"); + +let h4 = document.createElement("h4"); +h4.innerText = ""; + +const edit = document.getElementById("Editbtn"); +edit.addEventListener("click", async () => { + console.log("clicked successfully"); + + value1, value2 = await edit_btn(); + + let value3 = await move_creature(value1, value2); + console.log(value3, "this is value 3"); +}); + +async function edit_btn() { + let div = document.querySelector("#manage_btn"); + + h4.innerText = "select the image you want to move"; + + div.appendChild(h4); + + value1 = await after_click(); + + h4.innerText = `You Selected ${value1}`; + + h4.innerText = "select the you destination habitat"; + + value2 = await after_click(); + + h4.innerText = `You Selected ${value2}`; + // console.log(value1,value2) + return value1, value2; +} + +function after_click() { + return new Promise((resolve) => { + function handler(event) { + const target = event.target; + + //if an image is selected + if (target.tagName === "IMG") { + const src = target.src; + const fileName = src.substring(src.lastIndexOf("/") + 1); + const nameWithoutExt = fileName.split(".")[0]; + + console.log("User clicked image:", nameWithoutExt); + + table.removeEventListener("click", handler); + resolve(nameWithoutExt); + } + + //if habitat row is selectd + else if (target.tagName === "TD" && target.cellIndex === 0) { + const habitatName = target.innerText.trim(); + console.log("User clicked habitat:", habitatName); + + table.removeEventListener("click", handler); + resolve(habitatName); + } + } + + table.addEventListener("click", handler); + }); +} + +const data = document.querySelector(".habitat_table"); + +async function get_habitat(params) { + const url = `http://127.0.0.1:8080//habitats?player_id=${player_id}`; + const response = await fetch(url); + const result = await response.json(); + return result; +} + +async function move_habitat_API(creatureID, targetID) { + let url = `http://127.0.0.1:8080/move`; + try { + const response = await fetch(url, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + player_id: player_id, + creature_id: creatureID, + target_habitat_id: targetID, + }), + }); + const result = await response.json(); + return result; + } catch (error) { + return JSON.stringify({ status: "fail", message: str(error) }); + } +} + +async function put_habitat(params) { + //create a variable habitatbox that will be the main table + const habitatbox = document.querySelector(".habitat_table"); + habitatbox.innerHTML = ""; + const table = document.createElement("table"); + + table.id = "managetable"; + const thead = document.createElement("thead"); + thead.innerHTML = "HabitatCreature"; + + let r = await get_habitat(); + // console.log(r) + const tbody = document.createElement("tbody"); + table.appendChild(thead); + table.appendChild(tbody); + habitatbox.appendChild(table); + + //loop through result to fetch the habitat number + for (let i = 0; i < r["habitats"].length; i++) { + let tr = document.createElement("tr"); + let num = r["habitats"][i]; + // console.log(num, "index of habitat") + let td = document.createElement("td"); + let habitat_num = `Habitat ${num.number}`; + // console.log(habitat_num,"hab num") + td.innerText = `${habitat_num}`; + tr.appendChild(td); + + //loop to get the specific creature in specific habitat to get the name for the image + //append each image in the specific tr of the table + + for (let j = 0; j < r["habitats"][i]["creatures"].length; j++) { + let td2 = document.createElement("td"); + let crtr_name = r["habitats"][i]["creatures"][j]["nickname"]; + // console.log(crtr_name+"This is name") + let img_name = crtr_name.toLowerCase(); + let a = `/images/${img_name}.png`; + td2.innerHTML = ``; + // console.log(habitat_num+"number habitat") + tr.appendChild(td2); + } + //append the habitat name in the table + tbody.appendChild(tr); + } + // const t = document.querySelector("#managetable") + // console.log(t) +} + +async function move_creature(value1, value2) { + let result = await get_habitat(); + console.log(result, "this is the result of move") + let creature_id = result["habitats"][0]["creatures"][0]["id"]; + // console.log(creature_id,'this is creature id') + let target_habitat_id = result["habitats"][0]["id"]; + // console.log(target_habitat_id) + let creature_name = result["habitats"][0]["creatures"][0]["nickname"]; + // console.log(creature_name, 'crname') + let current_habitat = []; + for (let i = 0; i < result["habitats"].length; i++) { + let serial_num = i + 1; + let target_habitat_id = result["habitats"][i]["id"]; + // let creture_id = '' + // let trgt_id='' + // if ("value2"=="target_habitat_id"){ + // trgt_id = target_habitat_id + // } + let td = document.createElement("td"); + // let habitat_num = `Habitat ${serial_num.number}` + for (let j = 0; j < result["habitats"][i]["creatures"].length; j++) { + let crtr_name = result["habitats"][i]["creatures"][j]["nickname"]; + let crtr_id = result["habitats"][i]["creatures"][j]["id"]; + + response = { + id: `${serial_num}`, + creaturename: `${crtr_name}`, + creatureid: `${crtr_id}`, + habitat_id: `${target_habitat_id}`, + }; + current_habitat.push(response); + // if ("value1"==="crtr_name"){ + // creture_id = crtr_id + // } + } + + // const editbtn = document.querySelector("#Editbtn"); + + // const editBtn = document.getElementById("Editbtn"); + } + console.log(value1, value2, "crt name and habittat id in move fn"); + // {id: '3', creaturename: 'Obscurine', creatureid: '83', habitat_id: '7'} 'this is inside the 6 loop of current_habitat in move_crtr fn' + // return (current_habitat) + + let final_habitat_id + let final_creature_id + let hab_num = +(value2.split(" ")[1]) + for (let h of result.habitats){ + if (h.number === hab_num){ + final_habitat_id = +(h.id) + } + } + + + for (let i = 0; i < current_habitat.length; i++) { + console.log( + current_habitat[i], + `this is inside the ${i} loop of current_habitat in move_crtr fn` + ); + let crt = current_habitat[i].creaturename; + let hbt = current_habitat[i]; + + if (crt.toLowerCase() === value1.toLowerCase()) { + + final_creature_id = +(hbt.creatureid); + // console.log( + // hbt.habitat_id, + // final_habitat_id, + // hbt.creatureid, + // final_creature_id, + // "ckk habitat id check insd mv fn if condn" + // ); + } + } + + console.log(typeof final_creature_id, "type of crt id") + console.log(typeof final_habitat_id, "type of hab id") + + const move_result = await move_habitat_API(final_creature_id,final_habitat_id) + console.log(move_result, "response api") + if (move_result.success){ + await put_habitat() + } + + +} + +get_habitat(); + +put_habitat(); + diff --git a/manage_page/static/spriggle.png b/manage_page/static/spriggle.png new file mode 100644 index 0000000..b689e14 Binary files /dev/null and b/manage_page/static/spriggle.png differ diff --git a/manage_page/templates/manage.html b/manage_page/templates/manage.html new file mode 100644 index 0000000..bfe4304 --- /dev/null +++ b/manage_page/templates/manage.html @@ -0,0 +1,25 @@ + +> + + + Manage Habitat + + + + + +
+ +
+ +
+ +
+ + +
+
+ + + + \ No newline at end of file diff --git a/static/backgroundimg.jpg b/static/backgroundimg.jpg new file mode 100644 index 0000000..49a767d Binary files /dev/null and b/static/backgroundimg.jpg differ diff --git a/static/game.css b/static/game.css new file mode 100644 index 0000000..84e320b --- /dev/null +++ b/static/game.css @@ -0,0 +1,204 @@ +body { + padding: 20px; + line-height: 1.5; +} +.container { + max-width: 800px; + margin: 0 auto; +} +.page, +.hidden, +.popup.hidden { + display: none; +} +.page.active { + display: block; +} +.journal-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); + gap: 15px; +} +.habitats-grid { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 20px; + margin-bottom: 20px; +} +.popup { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 0.5); + display: flex; + justify-content: center; + align-items: center; + z-index: 200; +} +.btn, +input { + width: 100%; + padding: 10px; + border-radius: 6px; + border: 4px; + outline: none; + font-size: 16px; + margin-bottom: 10px; + display: block; + font-size: 16px; + text-decoration: none; + text-align: center; + box-sizing: border-box; +} + +.popup-content { + background-color: #795c34; + padding: 40px; + border-radius: 20px; + border: 3px solid #5a4222; + text-align: center; + box-shadow: 0 10px 25px rgba(0, 0, 0, 0.3); + max-width: 400px; + width: 90%; +} + +#popupMessage { + color: #fcd34d; + font-size: 1.5rem; + margin-bottom: 20px; + font-family: "Pixelify Sans", sans-serif; + text-shadow: 1px 1px 0px #5a4222; +} + +#popupOkBtn { + background-color: white; + color: #4ade80; + font-weight: bold; + font-size: 1.2rem; + padding: 10px 30px; + border-radius: 50px; + border: none; + cursor: pointer; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); + width: auto; + display: inline-block; +} + +.creature-item { + padding: 5px 0; + cursor: pointer; +} +.journal-item { + text-align: center; + padding: 10px; +} +.journal-item img { + width: 100%; + height: auto; + margin-bottom: 5px; +} +h1, +h3 { + margin-bottom: 15px; + font-weight: normal; +} +#exitPage.active { + background: black; + font-family: geometric, sans-serif; + color: white; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 100; +} +#exitPage .btn { + padding: 10px; + background: green; + border-radius: 6px; + border: none; + font-size: 16px; + font-weight: bold; + cursor: pointer; + width: auto; +} +#explorePage.active { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 50; + display: flex; + flex-direction: column; + align-items: center; + overflow-y: auto; + padding: 20px 0; + box-sizing: border-box; + background-color: #e3d5b0; + background-image: url("backgroundimg.jpg"); + background-size: cover; + background-position: center; +} + +.explore-modal { + background-color: #795c34; + padding: 40px 60px; + border-radius: 20px; + border: 3px solid #5a4222; + text-align: center; + max-width: 600px; + width: 90%; + margin: auto; +} + +.explore-modal h1 { + color: #fcd34d; + font-size: 3.5rem; + margin-bottom: 10px; + font-family: "Pixelify Sans", sans-serif; +} + +.explore-modal p { + color: #d1b06b; + font-size: 1.2rem; + margin-bottom: 30px; +} + +#companionList { + display: flex; + flex-direction: column; + gap: 15px; + align-items: center; +} + +#companionList .btn, +#wildList .btn { + background-color: white; + color: #4ade80; + font-weight: bold; + font-size: 1.2rem; + padding: 15px 40px; + border-radius: 50px; + border: none; + cursor: pointer; + width: auto; +} + +#wildBackBtn { + background-color: #ef4444; + color: white; + font-weight: bold; + padding: 10px 30px; + border-radius: 25px; + border: none; + cursor: pointer; + margin-top: 20px; +} diff --git a/static/game.js b/static/game.js new file mode 100644 index 0000000..12fc76c --- /dev/null +++ b/static/game.js @@ -0,0 +1,292 @@ +let playerId = null; +let playerUsername = null; +let currentCompanions = []; +let currentWildCreatures = []; +let currentCompanionId = null; +let currentHabitatsData = null; + +document.addEventListener("DOMContentLoaded", () => { + const params = new URLSearchParams(location.search); + playerId = params.get("player_id"); + playerUsername = params.get("username"); + + if (!playerId) { + location.href = "/"; + } else { + showPage("mainPage"); + } +}); + +function showPage(pageId) { + document.querySelectorAll(".page").forEach((page) => { + page.classList.remove("active"); + }); + document.getElementById(pageId).classList.add("active"); +} + +function showPopup(message) { + const popup = document.getElementById("popup"); + const popupMessage = document.getElementById("popupMessage"); + popupMessage.textContent = message; + popup.classList.remove("hidden"); +} + +function hidePopup() { + document.getElementById("popup").classList.add("hidden"); +} + +async function loadExplorePage() { + showPage("explorePage"); + + try { + const response = await fetch(`/explore/start?player_id=${playerId}`); + const data = await response.json(); + + if (data.success && data.companions) { + currentCompanions = data.companions; + const companionList = document.getElementById("companionList"); + companionList.innerHTML = ""; + + data.companions.forEach((comp) => { + const btn = document.createElement("button"); + btn.className = "btn"; + btn.textContent = `${comp.nickname} (${comp.type})`; + btn.onclick = () => selectCompanion(comp.id); + companionList.appendChild(btn); + }); + + document.getElementById("companionSelection").classList.remove("hidden"); + document.getElementById("wildSelection").classList.add("hidden"); + } else { + showPopup( + data.messages ? data.messages.join("\n") : "Cannot explore", + false + ); + showPage("mainPage"); + } + } catch (error) { + showPopup("Error: " + error, false); + showPage("mainPage"); + } finally { + } +} + +async function selectCompanion(companionId) { + currentCompanionId = companionId; + + try { + const response = await fetch("/explore/encounter", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + player_id: playerId, + companion_id: companionId, + }), + }); + + const data = await response.json(); + + if (data.complete) { + showPopup("Congratulations! You've caught them all!", true); + showPage("mainPage"); + return; + } + + if (data.success && data.wild_creatures) { + currentWildCreatures = data.wild_creatures; + const wildList = document.getElementById("wildList"); + wildList.innerHTML = ""; + + data.wild_creatures.forEach((wild) => { + const btn = document.createElement("button"); + btn.className = "btn"; + btn.textContent = `${wild.name} (${wild.type}) - ${wild.status}`; + btn.onclick = () => catchCreature(wild.id, wild.effectiveness); + wildList.appendChild(btn); + }); + + document.getElementById("companionSelection").classList.add("hidden"); + document.getElementById("wildSelection").classList.remove("hidden"); + } + } catch (error) { + showPopup("Error: " + error, false); + } finally { + } +} + +async function catchCreature(wildCreatureId, effectiveness) { + try { + const response = await fetch("/explore/catch", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + player_id: playerId, + wild_creature_id: wildCreatureId, + companion_id: currentCompanionId, + effectiveness: effectiveness, + }), + }); + + const data = await response.json(); + + if (data.success) { + const message = data.caught + ? "Success! Creature caught!" + : "Failed! Creature escaped."; + showPopup(message, data.caught); + + setTimeout(() => { + hidePopup(); + showPage("mainPage"); + }, 2000); + } + } catch (error) { + showPopup("Error: " + error, false); + } finally { + } +} + +async function loadManagePage() { + showPage("managePage"); + + try { + const response = await fetch(`/habitats?player_id=${playerId}`); + const data = await response.json(); + + if (data.success) { + currentHabitatsData = data.habitats; + + for (let i = 1; i <= 4; i++) { + document.getElementById(`habitat${i}`).innerHTML = ""; + } + data.habitats.forEach((habitat) => { + const habitatEl = document.getElementById(`habitat${habitat.number}`); + + if (habitat.creatures && habitat.creatures.length > 0) { + habitat.creatures.forEach((creature) => { + const div = document.createElement("div"); + div.className = "creature-item"; + div.textContent = `${creature.nickname} (${creature.type})`; + div.onclick = () => moveCreature(creature.id, habitat.id); + habitatEl.appendChild(div); + }); + } else { + habitatEl.textContent = "(empty)"; + } + }); + + const unplacedEl = document.getElementById("unplacedList"); + unplacedEl.innerHTML = ""; + + if (data.unplaced && data.unplaced.length > 0) { + data.unplaced.forEach((creature) => { + const div = document.createElement("div"); + div.className = "creature-item"; + div.textContent = `${creature.nickname} (${creature.type})`; + div.onclick = () => moveCreature(creature.id, null); + unplacedEl.appendChild(div); + }); + } else { + unplacedEl.textContent = "(none)"; + } + } + } catch (error) { + showPopup("Error: " + error, false); + showPage("mainPage"); + } finally { + } +} + +async function moveCreature(creatureId) { + // Ask user hab + const targetHabitat = prompt("Move to habitat (1-4) or 0 for unplaced:"); + + if (targetHabitat === null) return; + + const targetNum = parseInt(targetHabitat); + + if (isNaN(targetNum) || targetNum < 0 || targetNum > 4) { + showPopup("Invalid habitat number", false); + return; + } + + let targetHabitatId = null; + if (targetNum > 0) { + const targetHab = currentHabitatsData.find((h) => h.number === targetNum); + if (targetHab) { + targetHabitatId = targetHab.id; + } + } + + try { + const response = await fetch("/move", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + player_id: playerId, + creature_id: creatureId, + target_habitat_id: targetHabitatId, + }), + }); + + const data = await response.json(); + + if (data.success) { + showPopup("Creature moved successfully!", true); + setTimeout(() => { + hidePopup(); + loadManagePage(); + }, 1000); + } else { + showPopup( + data.messages ? data.messages.join("\n") : "Move failed", + false + ); + } + } catch (error) { + showPopup("Error: " + error, false); + } finally { + } +} + +function loadJournalPage() { + window.location.href = `/journal_page/viewjournal.html?player_id=${playerId}`; +} + +// action +document + .getElementById("exploreBtn") + .addEventListener("click", loadExplorePage); +document.getElementById("manageBtn").addEventListener("click", loadManagePage); +document + .getElementById("journalBtn") + .addEventListener("click", loadJournalPage); +document.getElementById("exitBtn").addEventListener("click", () => { + if (confirm("Are you sure you want to exit?")) { + location.href = "/"; + } +}); +document.getElementById("againBtn").addEventListener("click", () => { + location.href = "/"; +}); +document.getElementById("wildBackBtn").addEventListener("click", () => { + if (!document.getElementById("wildSelection").classList.contains("hidden")) { + loadExplorePage(); + } else { + showPage("mainPage"); + } +}); + +document + .getElementById("manageBackBtn") + .addEventListener("click", () => showPage("mainPage")); +document + .getElementById("journalBackBtn") + .addEventListener("click", () => showPage("mainPage")); +document.getElementById("popupOkBtn").addEventListener("click", hidePopup); diff --git a/static/login.css b/static/login.css new file mode 100644 index 0000000..ef3438f --- /dev/null +++ b/static/login.css @@ -0,0 +1,50 @@ +body { + background: url("backgroundimg.jpg"); + background-size: cover; + background-position: center; + background-repeat: no repeat; + font-family: Pixelify sans, sans-serif; + color: #f1d1aa; + display: flex; + justify-content: center; + align-items: center; + height: 100vh; + margin: 0; +} +.wrapper { + text-align: centre; +} + +.login-box { + margin-top: 20px; + display: flex; + flex-direction: column; + font-size: 22px; + gap: 20px; + width: 260px; + margin-left: auto; + margin-right: auto; + text-align: center; +} +h1 { + font-size: 58.8px; + font-weight: bold; + text-align: center; +} + +.input { + padding: 10px; + border-radius: 6px; + border: 4px; + outline: none; + font-size: 16px; +} +.btn { + padding: 10px; + background: #7ed957; + border-radius: 6px; + border: none; + font-size: 16px; + font-weight: bold; + cursor: pointer; +} diff --git a/static/login.js b/static/login.js new file mode 100644 index 0000000..9c9f304 --- /dev/null +++ b/static/login.js @@ -0,0 +1,37 @@ +const btn = document.getElementById("enterBtn"); +const username = document.getElementById("username"); + +btn.addEventListener("click", async () => { + const user = username.value.trim(); + if (user === "") { + alert("Please enter a username to continue."); + return; + } + + try { + const response = await fetch("/login", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ username: user }), + }); + + const data = await response.json(); + + if (data.success) { + const params = new URLSearchParams({ + player_id: data.player_id, + username: data.username, + }); + location.href = `/game?${params.toString()}`; + } else { + alert( + "Login failed: " + + (data.messages ? data.messages.join("\n") : "Unknown error") + ); + } + } catch (error) { + alert("Error: " + error); + } +}); diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000..bbd03c3 --- /dev/null +++ b/templates/index.html @@ -0,0 +1,95 @@ + + + + + + Creature Capture + + + + +
+ +
+

Main Page

+
+ + + + +
+
+ + +
+
+

Explore

+
+ +
+

Choose companions:

+
+
+ + +
+
+
+ + +
+

Manage

+
+
+
+

Habitat 1

+
+
+
+

Habitat 2

+
+
+
+

Habitat 3

+
+
+
+

Habitat 4

+
+
+
+
+

Unplaced

+
+
+
+ +
+ + +
+

You have successfully logged out.

+

Thank you for playing creature catch.

+

Click play to play again.

+ +
+ + + +
+ + + +