diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..76c605a
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,6 @@
+*.css linguist-detectable=true
+*.css linguist-language=css
+*.js linguist-detectable=true
+*.js linguist-language=js
+*.sql linguist-detectable=true
+*.sql linguist-language=sql
\ 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..387386b
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..0b45f84
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/congrat.html b/exitpage/congrat.html
new file mode 100644
index 0000000..516aa6f
--- /dev/null
+++ b/exitpage/congrat.html
@@ -0,0 +1,21 @@
+
+
+
+
+
+ Creature Catcher
+
+
+
+
+
+
Congratulations!
+ You have caught all the creatures!
+
+
+
+
+
diff --git a/exitpage/exit.css b/exitpage/exit.css
new file mode 100644
index 0000000..311f948
--- /dev/null
+++ b/exitpage/exit.css
@@ -0,0 +1,26 @@
+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..be1389e
--- /dev/null
+++ b/exitpage/exit.html
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+ Creature Catcher
+
+
+
+
+
+
You have successfully logged out!
+ Thank you for playing creature catch!
+ Click play to play again!
+
+
+
+
+
diff --git a/exitpage/exit.js b/exitpage/exit.js
new file mode 100644
index 0000000..4a6acec
--- /dev/null
+++ b/exitpage/exit.js
@@ -0,0 +1,4 @@
+const playBtn = document.getElementById("playBtn");
+playBtn.addEventListener("click", () => {
+ window.location.href = "/";
+});
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..f0654d8
--- /dev/null
+++ b/game.py
@@ -0,0 +1,590 @@
+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
+
+
+class Base:
+ def get_db(self):
+ return Database(
+ host='127.0.0.1',
+ user='root',
+ password='123456789',
+ database='creature_catcher'
+ )
+
+
+class Front(Base):
+ def login_page(self):
+ return send_from_directory('loginpage', 'login.html')
+
+ def game_page(self):
+ return render_template('index.html')
+
+ def login_assets(self, filename):
+ return send_from_directory('loginpage', filename)
+
+ def journal_page_files(self, filename):
+ return send_from_directory('journal', filename)
+
+ def image_files(self, filename):
+ return send_from_directory('images', filename)
+
+ def manage_page(self):
+ return send_from_directory('manage_page/templates', 'manage.html')
+
+ def manage_assets(self, filename):
+ return send_from_directory('manage_page/static', filename)
+
+ def exit_page(self):
+ return send_from_directory('exitpage', 'exit.html')
+
+ def congrat_page(self):
+ return send_from_directory('exitpage', 'congrat.html')
+
+ def exit_assets(self, filename):
+ return send_from_directory('exitpage', filename)
+
+
+class Authentication(Base):
+ def login(self):
+ data = request.json
+ username = data.get('username', '').strip()
+
+ if not username:
+ return jsonify({'error': 'no username'}), 400
+
+ messages = []
+
+ try:
+ db = self.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
+
+
+class Explore(Base):
+
+ def start(self):
+ player_id = request.args.get('player_id')
+
+ if not player_id:
+ return jsonify({'error': 'Player ID required'}), 400
+
+ try:
+ db = self.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
+
+ def encounter(self):
+ 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 = self.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
+
+ def check_completion(self):
+ player_id = request.args.get('player_id')
+
+ if not player_id:
+ return jsonify({'error': 'Player ID required'}), 400
+
+ try:
+ db = self.get_db()
+ player = Player.from_db(db, int(player_id))
+ discovered = player.get_discovered_species(db)
+
+ # Check if all discovered
+ is_complete = len(discovered) >= 16
+
+ return jsonify({
+ 'success': True,
+ 'completed': is_complete
+ })
+
+ except Exception as e:
+ return jsonify({'error': str(e)}), 500
+
+ def catch(self):
+ """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 = self.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
+
+
+class Place(Base):
+
+ def view_habitats(self):
+ player_id = request.args.get('player_id')
+
+ if not player_id:
+ return jsonify({'error': 'Player ID required'}), 400
+
+ try:
+ db = self.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
+
+ def move_creature(self):
+ 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 = self.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
+
+
+class Journal(Base):
+
+ def view_journal(self):
+ player_id = request.args.get('player_id')
+
+ if not player_id:
+ return jsonify({'error': 'Player ID required'}), 400
+
+ try:
+ db = self.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
+
+
+class CreatureCatcherApp:
+ def __init__(self):
+ self.app = Flask(__name__)
+ CORS(self.app)
+
+ self.front = Front()
+ self.authentication = Authentication()
+ self.explore = Explore()
+ self.place = Place()
+ self.journal = Journal()
+
+ self.setup_routes()
+
+ def setup_routes(self):
+ # file routes
+ @self.app.route('/')
+ def login_page():
+ return self.front.login_page()
+
+ @self.app.route('/game')
+ def game_page():
+ return self.front.game_page()
+
+ @self.app.route('/manage')
+ def manage_page():
+ return self.front.manage_page()
+
+ @self.app.route('/loginpage/')
+ def login_assets(filename):
+ return self.front.login_assets(filename)
+
+ @self.app.route('/journal_page/')
+ def journal_page_files(filename):
+ return self.front.journal_page_files(filename)
+
+ @self.app.route('/images/')
+ def image_files(filename):
+ return self.front.image_files(filename)
+
+ @self.app.route('/manage_page/static/')
+ def manage_assets(filename):
+ return self.front.manage_assets(filename)
+
+ @self.app.route('/exit')
+ def exit_page():
+ return self.front.exit_page()
+
+ @self.app.route('/exitpage/')
+ def exit_assets(filename):
+ return self.front.exit_assets(filename)
+ # API routes
+
+ @self.app.route('/login', methods=['POST'])
+ def login():
+ return self.authentication.login()
+
+ @self.app.route('/explore/start', methods=['GET'])
+ def explore_start():
+ return self.explore.start()
+
+ @self.app.route('/explore/encounter', methods=['POST'])
+ def explore_encounter():
+ return self.explore.encounter()
+
+ @self.app.route('/explore/catch', methods=['POST'])
+ def explore_catch():
+ return self.explore.catch()
+
+ @self.app.route('/habitats', methods=['GET'])
+ def view_habitats():
+ return self.place.view_habitats()
+
+ @self.app.route('/move', methods=['POST'])
+ def move_creature():
+ return self.place.move_creature()
+
+ @self.app.route('/journal', methods=['GET'])
+ def view_journal():
+ return self.journal.view_journal()
+
+ @self.app.route('/congrat')
+ def congrat_page():
+ return self.front.congrat_page()
+
+ @self.app.route('/check_completion', methods=['GET'])
+ def check_completion():
+ return self.explore.check_completion()
+
+ def run(self):
+ self.app.run(debug=True, host='127.0.0.1', port=8080)
+
+
+if __name__ == '__main__':
+ creature_app = CreatureCatcherApp()
+ creature_app.run()
diff --git a/h b/h
new file mode 100644
index 0000000..c3849d4
--- /dev/null
+++ b/h
@@ -0,0 +1,48 @@
+[33m1a437f7[m[33m ([m[1;36mHEAD[m[33m -> [m[1;32mmain_page[m[33m, [m[1;31morigin/main_page[m[33m)[m Merge remote-tracking branch 'origin/main_page' into main_page
+[33m2ec38a8[m updated menu page (main page)
+[33m0c5b4d3[m Merge branch 'main' into main_page
+[33mc7e7c3e[m main page
+[33m96e4b9b[m Merge pull request #3 from Sorathor/exit
+[33m8caaa78[m add exit.html
+[33m38c40c2[m exit
+[33me1c362c[m Merge pull request #2 from Sorathor/login
+[33m419abe5[m[33m ([m[1;31morigin/login[m[33m)[m Merge branch 'main' into login
+[33m90a8d28[m change pwd
+[33m8bf7a6c[m login.c
+[33mb95a462[m login.c
+[33m4269f30[m login.html
+[33mb39b216[m update .gitattributes to include SQL language detection
+[33ma43b85b[m remove .gitattributes file for CSS and JS language detection
+[33m57f38af[m change dir
+[33me7afd5b[m Merge pull request #1 from Sorathor/explore
+[33ma41e01c[m[33m ([m[1;31morigin/explore[m[33m)[m restore .gitattributes for CSS and JS file detection
+[33m72a2d65[m update .gitattributes to enhance language detection for CSS and JS files
+[33m21f345e[m add .gitattributes for CSS and JS file detection
+[33md4de2a1[m add compiled bytecode
+[33m707971b[m core game logic and endpoint
+[33m398da4d[m add frontend
+[33m2ed39bf[m change the password
+[33m0276d7d[m first commit
+[33m5e2377f[m[33m ([m[1;32mmain[m[33m)[m Update README.md
+[33m5f3589c[m Update README.md
+[33mc40bd2b[m Update README.md
+[33ma16321e[m Add files via upload
+[33mb13bd9c[m Create borealynx.png
+[33m732236a[m Delete assets directory
+[33m4cc3764[m Create setup-database.py
+[33m76927a6[m Create creature_schema.sql
+[33m740f20f[m Create creature_game.py
+[33m3fa680c[m Delete game.py
+[33m36840be[m Delete story.py
+[33mf9b04da[m Update README.md
+[33m705f632[m Update README.md
+[33maf57ab1[m Update README.md
+[33m7a76fda[m Update README.md
+[33mc770379[m Add files via upload
+[33m36b225f[m Create text.png
+[33ma6b6a2f[m Create example.pyc
+[33mfec64a0[m Create story.py
+[33me1d8957[m Create game.py
+[33m25d5ba7[m Rename gitignore.txt to .gitignore
+[33me6442be[m Add files via upload
+[33me14510e[m Initial commit
diff --git a/images/borealynx.png b/images/borealynx.png
index 26190bc..cadcaca 100644
Binary files a/images/borealynx.png and b/images/borealynx.png differ
diff --git a/images/capychara.png b/images/capychara.png
index 61fb43c..383022a 100644
Binary files a/images/capychara.png and b/images/capychara.png differ
diff --git a/images/chromutt.png b/images/chromutt.png
index d16184d..b83ddfa 100644
Binary files a/images/chromutt.png and b/images/chromutt.png differ
diff --git a/images/cirroptera.png b/images/cirroptera.png
index ea3b1c9..15714df 100644
Binary files a/images/cirroptera.png and b/images/cirroptera.png differ
diff --git a/images/cosmeow.png b/images/cosmeow.png
index 8d918d8..d985b12 100644
Binary files a/images/cosmeow.png and b/images/cosmeow.png differ
diff --git a/images/geckathyst.png b/images/geckathyst.png
index 1950d80..12a1de2 100644
Binary files a/images/geckathyst.png and b/images/geckathyst.png differ
diff --git a/images/gemwraith.png b/images/gemwraith.png
index 17424f1..142e99b 100644
Binary files a/images/gemwraith.png and b/images/gemwraith.png differ
diff --git a/images/granidam.png b/images/granidam.png
index bb6abc2..34762e8 100644
Binary files a/images/granidam.png and b/images/granidam.png differ
diff --git a/images/marinlet.png b/images/marinlet.png
index 782ccb8..59c75c8 100644
Binary files a/images/marinlet.png and b/images/marinlet.png differ
diff --git a/images/obscurine.png b/images/obscurine.png
index 881fe2c..3cf4b6c 100644
Binary files a/images/obscurine.png and b/images/obscurine.png differ
diff --git a/images/pandascend.png b/images/pandascend.png
index 6889fe7..a42cb9f 100644
Binary files a/images/pandascend.png and b/images/pandascend.png differ
diff --git a/images/reverwing.png b/images/reverwing.png
index 39af02a..30347f8 100644
Binary files a/images/reverwing.png and b/images/reverwing.png differ
diff --git a/images/shaduran.png b/images/shaduran.png
index 98b970f..7c8b0ba 100644
Binary files a/images/shaduran.png and b/images/shaduran.png differ
diff --git a/images/spriggle.png b/images/spriggle.png
index b689e14..d95b078 100644
Binary files a/images/spriggle.png and b/images/spriggle.png differ
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..5630348
--- /dev/null
+++ b/journal/server.py
@@ -0,0 +1,26 @@
+import mysql.connector
+from flask import Flask, request, jsonify
+from flask_cors import CORS
+
+app = Flask(__name__)
+CORS(app)
+
+
+@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)
diff --git a/setup-database.py b/journal/setup-database.py
similarity index 85%
rename from setup-database.py
rename to journal/setup-database.py
index 8e5aec0..c1e5026 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,19 +35,22 @@ 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
- statements = [s.strip() for s in sql_content.split(';') if s.strip()]
+ statements = [s.strip()
+ for s in sql_content.split(';') if s.strip()]
for i, statement in enumerate(statements, 1):
try:
cursor.execute(statement)
if i % 10 == 0:
- print(f" Executed {i}/{len(statements)} statements...")
+ print(
+ f" Executed {i}/{len(statements)} statements...")
except Exception as e:
- print(f" Warning: Statement {i} failed: {str(e)[:50]}")
+ print(
+ f" Warning: Statement {i} failed: {str(e)[:50]}")
connection.commit()
print(f"✅ Database setup complete!")
diff --git a/journal/viewjournal.css b/journal/viewjournal.css
new file mode 100644
index 0000000..65bbfac
--- /dev/null
+++ b/journal/viewjournal.css
@@ -0,0 +1,109 @@
+@import url('https://fonts.googleapis.com/css2?family=Pixelify+Sans:wght@400..700&display=swap');
+body {
+ margin: 0;
+ padding: 20px 0;
+ font-family: "Pixelify Sans";
+ 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..3244696
--- /dev/null
+++ b/journal/viewjournal.html
@@ -0,0 +1,19 @@
+
+
+
+
+
+ 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/backgroundimg.jpg b/loginpage/backgroundimg.jpg
new file mode 100644
index 0000000..49a767d
Binary files /dev/null and b/loginpage/backgroundimg.jpg differ
diff --git a/loginpage/login.css b/loginpage/login.css
new file mode 100644
index 0000000..ef3438f
--- /dev/null
+++ b/loginpage/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/loginpage/login.html b/loginpage/login.html
new file mode 100644
index 0000000..1bf93ce
--- /dev/null
+++ b/loginpage/login.html
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+ Creature Catcher
+
+
+
+
+
+
Welcome to Creature Catcher
+
+
+
+
+
+
+
+
+
diff --git a/loginpage/login.js b/loginpage/login.js
new file mode 100644
index 0000000..f6d549c
--- /dev/null
+++ b/loginpage/login.js
@@ -0,0 +1,43 @@
+const btn = document.getElementById("enterBtn");
+const username = document.getElementById("username");
+
+username.addEventListener("keydown", (event) => {
+ if (event.key === "Enter") {
+ btn.click();
+ }
+});
+
+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/mainpage/Main-Paige.html b/mainpage/Main-Paige.html
new file mode 100644
index 0000000..a7d1fbd
--- /dev/null
+++ b/mainpage/Main-Paige.html
@@ -0,0 +1,21 @@
+
+
+
+
+ Main Page
+
+
+
+
+
+
+Main Page
+
+
+
+
+
+
+
+
+
diff --git a/mainpage/background.jpg b/mainpage/background.jpg
new file mode 100644
index 0000000..f03ebd0
Binary files /dev/null and b/mainpage/background.jpg differ
diff --git a/mainpage/style.css b/mainpage/style.css
new file mode 100644
index 0000000..381424a
--- /dev/null
+++ b/mainpage/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/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/static/PixelifySans-Regular.ttf b/manage_page/static/PixelifySans-Regular.ttf
new file mode 100644
index 0000000..783cefa
Binary files /dev/null and b/manage_page/static/PixelifySans-Regular.ttf differ
diff --git a/manage_page/static/manage.css b/manage_page/static/manage.css
new file mode 100644
index 0000000..849ce55
--- /dev/null
+++ b/manage_page/static/manage.css
@@ -0,0 +1,104 @@
+@font-face {
+ font-family: "pixelify";
+ src:
+ url('./PixelifySans-Regular.ttf') format('truetype')
+}
+
+body{
+ background-image: url('./managepage.png');
+ background-repeat: no-repeat;
+ background-position: center;
+ background-size:cover;
+ background-attachment: fixed;
+ font-family: pixelify, sans-serif
+
+}
+
+.managepagemain{
+ max-width: 100%;
+ /* margin: auto; */
+ padding: 0px;
+ border-radius: 10px;
+
+}
+
+.habitat_table{
+ display: flex;
+ justify-content: center;
+ align-items: center;
+
+
+ max-width: 100%;
+
+
+}
+
+#managetable{
+ justify-content:space-evenly;
+ align-items: center;
+ width: 90%;
+ border: 1px solid black;
+ /* border-radius: 20px; */
+ background-color: rgba(187, 173, 124, 0.5);
+ /* background-color: #7ed957; */
+ color: white;
+ border-collapse: collapse;
+ /* box-shadow: rgba(187, 173, 124, 1) */
+
+}
+
+#managetable thead th{
+ background-color: #8b4513;
+
+ padding: 10px;
+ font-size: 30px;
+
+ text-align: center;
+
+
+}
+
+#managetable tbody{
+ color: black;
+ font-size: 15px;
+
+}
+#managetable tbody td{
+ padding: 10px;
+ font-size: 20px;
+}
+
+#managetable tbody tr td:hover{
+ background-color: #bbad7c
+}
+
+#managetable tbody td img{
+ width: 155px;
+ height: 145px;
+}
+#manage_btn{
+ display: flex;
+ justify-content:center;
+ align-items: center;
+
+}
+#manage_btn button{
+ background: #7ed957;
+ font-family: pixelify;
+ padding: 10px;
+ margin: 30px;
+
+}
+
+#pagetitle{
+ display: flex;
+ justify-content: center;
+
+}
+#pagetitle h1{
+ color: white ;
+ font-size: 58.8px;
+}
+/* #habitat_row{
+ background-color: white;
+} */
\ No newline at end of file
diff --git a/manage_page/static/manage.js b/manage_page/static/manage.js
new file mode 100644
index 0000000..7c8f175
--- /dev/null
+++ b/manage_page/static/manage.js
@@ -0,0 +1,261 @@
+const params = new URLSearchParams(location.search);
+const player_id = params.get("player_id");
+
+if (!player_id) {
+ location.href = "/";
+}
+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("You Clicked the Edit Button");
+
+ 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 = "Click the creature image that you want to move";
+
+ div.appendChild(h4);
+
+ value1 = await after_click();
+
+ h4.innerText = `You Selected ${value1.toUpperCase()}\n Click the habitat name where you want it to locate`;
+
+ value2 = await after_click();
+ ////add the logic to move only after checking the slot if either full or not
+ h4.innerText = `You moved ${value1} to the ${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}`;
+ try {
+ const response = await fetch(url);
+ const result = await response.json();
+ return result;
+ } catch (error) {
+ return JSON.stringify({ status: "fail", message: String(error) });
+ }
+}
+
+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: String(error) });
+ }
+}
+async function put_habitat(params) {
+ //create a variable habitatbox that will be the main table
+ const habitatbox = document.querySelector(".habitat_table");
+ if (!habitatbox) return;
+
+ habitatbox.innerHTML = "";
+ const table = document.createElement("table");
+
+ table.id = "managetable";
+ const thead = document.createElement("thead");
+ thead.innerHTML = "| Habitat | Creature |
";
+
+ let r = await get_habitat();
+ const tbody = document.createElement("tbody");
+ table.appendChild(thead);
+ table.appendChild(tbody);
+ habitatbox.appendChild(table);
+
+ //loop through result to fetch the habitat number
+ if (r["habitats"]) {
+ for (let i = 0; i < r["habitats"].length; i++) {
+ let tr = document.createElement("tr");
+ let num = r["habitats"][i];
+ let td = document.createElement("td");
+ let habitat_num = `Habitat ${num.number}`;
+ 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"];
+ let img_name = crtr_name.toLowerCase();
+ let a = `/images/${img_name}.png`;
+ td2.innerHTML = `
`;
+ tr.appendChild(td2);
+ }
+ //append the habitat name in the table
+ tbody.appendChild(tr);
+ }
+ }
+
+ // Display unplaced creatures
+ if (r["unplaced"] && r["unplaced"].length > 0) {
+ let tr = document.createElement("tr");
+ let td = document.createElement("td");
+ td.innerText = "Unplaced";
+ tr.appendChild(td);
+
+ for (let j = 0; j < r["unplaced"].length; j++) {
+ let td2 = document.createElement("td");
+ let crtr_name = r["unplaced"][j]["nickname"];
+ let img_name = crtr_name.toLowerCase();
+ let a = `/images/${img_name}.png`;
+ td2.innerHTML = `
`;
+ tr.appendChild(td2);
+ }
+ tbody.appendChild(tr);
+ }
+}
+
+async function move_creature(value1, value2) {
+ let result = await get_habitat();
+ console.log(result, "this is the result of move");
+ let current_habitat = [];
+
+ // habitat creatures
+ for (let i = 0; i < result["habitats"].length; i++) {
+ let serial_num = i + 1;
+ let target_habitat_id = result["habitats"][i]["id"];
+ 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);
+ }
+ }
+
+ // unplaced creatures
+ if (result["unplaced"]) {
+ for (let j = 0; j < result["unplaced"].length; j++) {
+ let crtr_name = result["unplaced"][j]["nickname"];
+ let crtr_id = result["unplaced"][j]["id"];
+
+ response = {
+ id: "unplaced",
+ creaturename: `${crtr_name}`,
+ creatureid: `${crtr_id}`,
+ habitat_id: null,
+ };
+ current_habitat.push(response);
+ }
+ }
+ 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;
+ if (value2.startsWith("Habitat")) {
+ let hab_num = +value2.split(" ")[1];
+ for (let h of result.habitats) {
+ if (h.number === hab_num) {
+ final_habitat_id = +h.id;
+ }
+ }
+ } else if (value2 === "Unplaced") {
+ final_habitat_id = null;
+ }
+
+ 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;
+ }
+ }
+
+ const move_result = await move_habitat_API(
+ final_creature_id,
+ final_habitat_id
+ );
+ console.log(move_result, "response api");
+ if (move_result["messages"] && move_result["messages"][1]) {
+ console.log(move_result["messages"][1]);
+ }
+
+ if (move_result.success) {
+ await put_habitat();
+ }
+ return move_result;
+}
+
+get_habitat();
+
+put_habitat();
+
+const backBtn = document.getElementById("Backbtn");
+if (backBtn) {
+ backBtn.addEventListener("click", () => {
+ location.href = "/game" + location.search;
+ });
+}
diff --git a/manage_page/static/managepage.png b/manage_page/static/managepage.png
new file mode 100644
index 0000000..834af03
Binary files /dev/null and b/manage_page/static/managepage.png differ
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..d1260e2
--- /dev/null
+++ b/manage_page/templates/manage.html
@@ -0,0 +1,22 @@
+
+
+
+
+
+ Creature Catcher
+
+
+
+
+ Manage Habitat
+
+
+
+
+
+
+
+
+
+
+
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..15f684a
--- /dev/null
+++ b/static/game.css
@@ -0,0 +1,221 @@
+body {
+ padding: 20px;
+ line-height: 1.5;
+}
+.container {
+ max-width: 800px;
+ margin: 0 auto;
+}
+.page,
+.hidden,
+.popup.hidden {
+ display: none;
+}
+.page.active {
+ display: block;
+}
+.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;
+}
+#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,
+#exploreBackBtn {
+ background-color: #ef4444;
+ color: white;
+ font-weight: bold;
+ padding: 10px 30px;
+ border-radius: 25px;
+ border: none;
+ cursor: pointer;
+ margin-top: 20px;
+}
+
+#mainPage.active {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ z-index: 40;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ font-family: "Pixelify Sans", sans-serif;
+ text-align: center;
+ color: #8b4513;
+ background-image: url("main_background.jpg");
+ background-size: cover;
+ background-position: center;
+ font-size: 40px;
+ text-shadow: 0px 0px 10px rgba(0, 0, 0, 0.3);
+}
+
+#mainPage ul {
+ list-style: none;
+ padding: 0;
+ margin: 0;
+}
+
+#mainPage 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;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
+
+#mainPage button:hover {
+ background-color: darkolivegreen;
+ color: white
+}
diff --git a/static/game.js b/static/game.js
new file mode 100644
index 0000000..327d51d
--- /dev/null
+++ b/static/game.js
@@ -0,0 +1,201 @@
+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);
+ document.getElementById("wildBackBtn").addEventListener("click", () => {
+ hidePopup();
+ showPage("mainPage");
+ });
+ }
+ } catch (error) {
+ showPopup("Error: " + error, false);
+ } finally {
+ }
+}
+async function completeCheck() {
+ if (!playerId) return false;
+ try {
+ const response = await fetch(`/check_completion?player_id=${playerId}`);
+ const data = await response.json();
+ if (data.success && data.completed) {
+ location.href = "/congrat";
+ return true;
+ }
+ } catch (error) {
+ console.error("Error checking completion:", error);
+ }
+ return false;
+}
+
+// action
+document.getElementById("exploreBtn").addEventListener("click", async () => {
+ const Done = await completeCheck();
+ if (!Done) {
+ loadExplorePage();
+ }
+});
+
+document.getElementById("manageBtn").addEventListener("click", () => {
+ location.href = "/manage" + location.search;
+});
+document.getElementById("journalBtn").addEventListener("click", () => {
+ location.href = `/journal_page/viewjournal.html?player_id=${playerId}`;
+});
+document.getElementById("exitBtn").addEventListener("click", async () => {
+ const Done = await completeCheck();
+ if (!Done) {
+ if (confirm("Are you sure you want to exit?")) {
+ location.href = "/exit";
+ }
+ }
+});
+document.getElementById("wildBackBtn").addEventListener("click", () => {
+ if (!document.getElementById("wildSelection").classList.contains("hidden")) {
+ loadExplorePage();
+ } else {
+ showPage("mainPage");
+ }
+});
+document.getElementById("exploreBackBtn").addEventListener("click", () => {
+ showPage("mainPage");
+});
+document.getElementById("popupOkBtn").addEventListener("click", () => {
+ hidePopup();
+ showPage("mainPage");
+});
diff --git a/static/main_background.jpg b/static/main_background.jpg
new file mode 100644
index 0000000..f03ebd0
Binary files /dev/null and b/static/main_background.jpg differ
diff --git a/templates/index.html b/templates/index.html
new file mode 100644
index 0000000..27f670e
--- /dev/null
+++ b/templates/index.html
@@ -0,0 +1,58 @@
+
+
+
+
+
+ Creature Catcher
+
+
+
+
+
+
+
+
Main Page
+
+
+
+
+
+
+
+
+
+
+
+
Explore
+
+
+
+
Choose companions:
+
+
+
+
+
+
Choose the wild creature:
+
+
+
+
+
+
+
+
+
+
+
+
+
+