2024-02-05 15:42:31 +00:00
|
|
|
from flask import Flask, render_template, g, abort, request, jsonify, send_from_directory
|
2024-02-11 19:07:40 +00:00
|
|
|
import sqlite3, os, csv
|
2024-01-30 16:06:00 +00:00
|
|
|
|
2024-02-06 23:32:35 +00:00
|
|
|
from src.python.breed import get_breed_id, get_breeding_pairs, get_used_in_breeds
|
|
|
|
|
2024-01-30 16:06:00 +00:00
|
|
|
app = Flask(__name__)
|
|
|
|
|
2024-02-05 17:27:54 +00:00
|
|
|
DATABASE = "src/database.db"
|
2024-01-30 23:21:26 +00:00
|
|
|
|
2024-01-30 16:06:00 +00:00
|
|
|
|
|
|
|
def connect_db():
|
|
|
|
return sqlite3.connect(DATABASE)
|
|
|
|
|
2024-01-30 23:21:26 +00:00
|
|
|
|
2024-01-30 16:06:00 +00:00
|
|
|
@app.before_request
|
|
|
|
def before_request():
|
|
|
|
g.db = connect_db()
|
|
|
|
|
2024-01-30 23:21:26 +00:00
|
|
|
|
2024-01-30 16:06:00 +00:00
|
|
|
@app.teardown_request
|
|
|
|
def teardown_request(exception):
|
2024-01-30 23:21:26 +00:00
|
|
|
if hasattr(g, "db"):
|
2024-01-30 16:06:00 +00:00
|
|
|
g.db.close()
|
|
|
|
|
2024-02-02 02:52:59 +00:00
|
|
|
|
2024-02-01 21:57:44 +00:00
|
|
|
def get_js_files():
|
2024-02-02 02:52:59 +00:00
|
|
|
js_folder = os.path.join(app.static_folder, "js")
|
|
|
|
js_files = [f for f in os.listdir(js_folder) if f.endswith(".js")]
|
2024-02-01 21:57:44 +00:00
|
|
|
return js_files
|
2024-01-30 23:21:26 +00:00
|
|
|
|
2024-02-02 02:52:59 +00:00
|
|
|
|
|
|
|
@app.route("/")
|
2024-02-04 20:21:15 +00:00
|
|
|
def show_app():
|
2024-02-01 21:57:44 +00:00
|
|
|
js_files = get_js_files()
|
2024-02-04 20:21:15 +00:00
|
|
|
return render_template("app.html", js_files=js_files)
|
2024-01-30 16:06:00 +00:00
|
|
|
|
2024-02-05 17:09:23 +00:00
|
|
|
#Serve Monster Sprites
|
2024-02-05 15:47:21 +00:00
|
|
|
@app.route('/img/monster/<selected_monster>.png')
|
2024-02-05 16:01:36 +00:00
|
|
|
def serve_monster_sprite(selected_monster):
|
|
|
|
return send_from_directory('static/img/monster/', f'{selected_monster}.png')
|
2024-02-05 15:42:31 +00:00
|
|
|
|
2024-02-05 17:09:23 +00:00
|
|
|
#Serve Favicon
|
2024-02-05 15:47:21 +00:00
|
|
|
@app.route('/img/favicon.ico')
|
2024-02-05 16:01:36 +00:00
|
|
|
def serve_favicon():
|
2024-02-05 15:47:21 +00:00
|
|
|
return send_from_directory( '','static/img/favicon.ico')
|
2024-01-30 23:21:26 +00:00
|
|
|
|
2024-02-05 19:37:24 +00:00
|
|
|
#API Calls
|
|
|
|
|
2024-02-05 21:25:00 +00:00
|
|
|
# List All Families
|
2024-02-05 19:37:24 +00:00
|
|
|
@app.route("/api/families")
|
|
|
|
def json_families():
|
2024-01-30 16:06:00 +00:00
|
|
|
cursor = g.db.cursor()
|
2024-01-30 23:21:26 +00:00
|
|
|
cursor.execute("SELECT DISTINCT name FROM families")
|
2024-01-30 16:06:00 +00:00
|
|
|
families = [row[0] for row in cursor.fetchall()]
|
|
|
|
return jsonify(families)
|
|
|
|
|
2024-02-05 21:25:00 +00:00
|
|
|
# List All Monsters
|
2024-02-05 19:37:24 +00:00
|
|
|
@app.route("/api/monsters")
|
|
|
|
def json_monsters():
|
2024-01-30 23:21:26 +00:00
|
|
|
selected_family = request.args.get("family")
|
2024-01-30 16:06:00 +00:00
|
|
|
cursor = g.db.cursor()
|
|
|
|
|
|
|
|
if selected_family:
|
2024-01-30 23:21:26 +00:00
|
|
|
cursor.execute(
|
|
|
|
"""
|
2024-02-06 01:34:36 +00:00
|
|
|
SELECT name
|
|
|
|
FROM monsters
|
2024-01-30 16:06:00 +00:00
|
|
|
WHERE family_id = (SELECT id FROM families WHERE name = ?)
|
2024-02-06 01:34:36 +00:00
|
|
|
ORDER BY (agl + int + atk + mp + exp + hp + def) * maxlvl ASC
|
2024-01-30 23:21:26 +00:00
|
|
|
""",
|
|
|
|
(selected_family,),
|
|
|
|
)
|
2024-01-30 16:06:00 +00:00
|
|
|
else:
|
2024-02-06 01:34:36 +00:00
|
|
|
cursor.execute(
|
|
|
|
"""
|
|
|
|
SELECT name
|
|
|
|
FROM monsters
|
|
|
|
ORDER BY (agl + int + atk + mp + exp + hp + def) * maxlvl ASC
|
|
|
|
"""
|
|
|
|
)
|
2024-01-30 16:06:00 +00:00
|
|
|
|
|
|
|
monsters = [row[0] for row in cursor.fetchall()]
|
|
|
|
return jsonify(monsters)
|
|
|
|
|
2024-02-05 21:25:00 +00:00
|
|
|
|
|
|
|
@app.route("/api/monsters/stats")
|
|
|
|
def json_monsters_stats():
|
|
|
|
cursor = g.db.cursor()
|
|
|
|
|
|
|
|
# Check if 'monster' argument is provided
|
|
|
|
selected_monster = request.args.get("monster")
|
|
|
|
|
|
|
|
if selected_monster:
|
|
|
|
# Fetch specific stats for the monster
|
|
|
|
cursor.execute("""
|
|
|
|
SELECT
|
|
|
|
name,
|
|
|
|
agl AS agility,
|
|
|
|
int AS intelligence,
|
|
|
|
maxlvl AS max_level,
|
|
|
|
exp AS experience,
|
|
|
|
hp AS health_points,
|
|
|
|
atk AS attack,
|
|
|
|
def AS defense
|
|
|
|
FROM monsters
|
|
|
|
WHERE LOWER(name) = LOWER(?)
|
|
|
|
""", (selected_monster.lower(),))
|
|
|
|
|
|
|
|
# Fetch the result and convert it to a dictionary
|
|
|
|
monster_stats = cursor.fetchone()
|
|
|
|
|
|
|
|
if monster_stats:
|
|
|
|
# Map stat names to descriptive labels
|
|
|
|
stat_labels = {
|
|
|
|
"max_level": "Max Level",
|
|
|
|
"experience": "Experience",
|
|
|
|
"health_points": "Health Points",
|
|
|
|
"attack": "Attack",
|
|
|
|
"defense": "Defense",
|
|
|
|
"agility": "Agility",
|
|
|
|
"intelligence": "Intelligence"
|
|
|
|
}
|
|
|
|
|
|
|
|
# Create a new dictionary with descriptive stat names
|
|
|
|
formatted_stats = {
|
|
|
|
"name": monster_stats[0],
|
|
|
|
**{stat_labels[key]: monster_stats[i + 1] for i, key in enumerate(["agility", "intelligence", "max_level", "experience", "health_points", "attack", "defense"])}
|
|
|
|
}
|
|
|
|
|
|
|
|
return jsonify(formatted_stats)
|
|
|
|
else:
|
|
|
|
return jsonify({"error": "Monster not found"}), 404
|
|
|
|
else:
|
|
|
|
return jsonify({"error": "Monster name not provided"}), 400
|
|
|
|
|
2024-02-05 19:37:24 +00:00
|
|
|
# Render HTML Templates
|
2024-01-30 23:21:26 +00:00
|
|
|
|
|
|
|
@app.route("/monster/<monster_name>")
|
2024-02-02 15:03:55 +00:00
|
|
|
def monster_stats(monster_name):
|
2024-01-30 16:06:00 +00:00
|
|
|
cursor = g.db.cursor()
|
|
|
|
|
2024-02-02 15:03:55 +00:00
|
|
|
# Retrieve monster stats from the database based on name
|
2024-01-30 23:21:26 +00:00
|
|
|
cursor.execute(
|
|
|
|
"""
|
2024-01-30 16:06:00 +00:00
|
|
|
SELECT
|
|
|
|
monsters.id, monsters.name, families.name AS family, monsters.in_story,
|
|
|
|
monsters.agl, monsters.int, monsters.maxlvl, monsters.atk, monsters.mp,
|
|
|
|
monsters.exp, monsters.hp, monsters.def
|
|
|
|
FROM
|
|
|
|
monsters
|
|
|
|
JOIN families ON monsters.family_id = families.id
|
|
|
|
WHERE
|
|
|
|
monsters.name = ?
|
2024-01-30 23:21:26 +00:00
|
|
|
""",
|
|
|
|
(monster_name,),
|
|
|
|
)
|
2024-01-30 16:06:00 +00:00
|
|
|
|
2024-02-02 15:03:55 +00:00
|
|
|
monster_stats = cursor.fetchone()
|
2024-01-30 16:06:00 +00:00
|
|
|
|
2024-02-02 15:03:55 +00:00
|
|
|
if monster_stats is None:
|
2024-01-30 16:06:00 +00:00
|
|
|
abort(404)
|
|
|
|
|
|
|
|
# Retrieve skills for the monster
|
2024-02-02 15:03:55 +00:00
|
|
|
cursor.execute("SELECT skill FROM skills WHERE monster_id = ?", (monster_stats[0],))
|
2024-01-30 16:06:00 +00:00
|
|
|
skills = [row[0] for row in cursor.fetchall()]
|
|
|
|
|
|
|
|
# Retrieve spawn locations for the monster
|
2024-01-30 23:21:26 +00:00
|
|
|
cursor.execute(
|
|
|
|
"SELECT map, description FROM spawn_locations WHERE monster_id = ?",
|
2024-02-02 15:03:55 +00:00
|
|
|
(monster_stats[0],),
|
2024-01-30 23:21:26 +00:00
|
|
|
)
|
|
|
|
spawn_locations = [
|
|
|
|
{"map": row[0], "description": row[1]} for row in cursor.fetchall()
|
|
|
|
]
|
|
|
|
|
|
|
|
return render_template(
|
2024-02-02 15:03:55 +00:00
|
|
|
"stats.html",
|
2024-01-30 23:21:26 +00:00
|
|
|
monster={
|
2024-02-02 15:03:55 +00:00
|
|
|
"id": monster_stats[0],
|
|
|
|
"name": monster_stats[1],
|
|
|
|
"family": monster_stats[2],
|
|
|
|
"in_story": "Yes" if monster_stats[3] else "No",
|
|
|
|
"agl": monster_stats[4],
|
|
|
|
"int": monster_stats[5],
|
|
|
|
"maxlvl": monster_stats[6],
|
|
|
|
"atk": monster_stats[7],
|
|
|
|
"mp": monster_stats[8],
|
|
|
|
"exp": monster_stats[9],
|
|
|
|
"hp": monster_stats[10],
|
|
|
|
"def": monster_stats[11],
|
2024-01-30 23:21:26 +00:00
|
|
|
"skills": skills,
|
|
|
|
"spawn_locations": spawn_locations,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
|
2024-02-02 02:52:59 +00:00
|
|
|
|
2024-01-31 01:17:15 +00:00
|
|
|
# Add this route for fetching breeding combinations
|
2024-02-06 23:32:35 +00:00
|
|
|
@app.route("/breed")
|
2024-01-31 01:17:15 +00:00
|
|
|
def get_breeding_combinations():
|
|
|
|
selected_monster = request.args.get("monster")
|
|
|
|
if not selected_monster:
|
|
|
|
return jsonify({"error": "Invalid input"})
|
|
|
|
|
2024-01-31 01:38:53 +00:00
|
|
|
# Fetch breed ID based on the selected monster as a target
|
|
|
|
breed_id = get_breed_id(selected_monster)
|
2024-01-31 01:17:15 +00:00
|
|
|
|
2024-01-31 01:38:53 +00:00
|
|
|
if breed_id is None:
|
|
|
|
return jsonify({"error": f"No breed information found for {selected_monster}"})
|
|
|
|
|
2024-02-02 17:00:10 +00:00
|
|
|
base_pair, mate_pair = get_breeding_pairs(breed_id)
|
2024-01-31 01:38:53 +00:00
|
|
|
|
2024-02-06 03:28:23 +00:00
|
|
|
# Fetch breeds in which the selected monster is used
|
|
|
|
used_in_breeds = get_used_in_breeds(selected_monster)
|
|
|
|
|
2024-01-31 01:38:53 +00:00
|
|
|
return render_template(
|
2024-02-06 23:32:35 +00:00
|
|
|
"breed.html",
|
2024-01-31 01:38:53 +00:00
|
|
|
selected_monster={
|
|
|
|
"name": selected_monster,
|
2024-02-02 17:00:10 +00:00
|
|
|
"base_pair": base_pair,
|
|
|
|
"mate_pair": mate_pair,
|
2024-01-31 01:38:53 +00:00
|
|
|
},
|
2024-02-06 03:28:23 +00:00
|
|
|
used_in_breeds=used_in_breeds,
|
|
|
|
)
|
|
|
|
|
2024-02-11 19:07:40 +00:00
|
|
|
def read_csv(file_path):
|
|
|
|
data = []
|
|
|
|
with open(file_path, 'r', newline='', encoding='utf-8') as csvfile:
|
|
|
|
reader = csv.DictReader(csvfile)
|
|
|
|
for row in reader:
|
|
|
|
data.append(row)
|
|
|
|
return data
|
|
|
|
|
|
|
|
@app.route('/skills')
|
|
|
|
def skills():
|
|
|
|
csv_data = read_csv('src/skills_data.csv')
|
|
|
|
return render_template('skills.html', csv_data=csv_data)
|
|
|
|
|
2024-01-30 23:21:26 +00:00
|
|
|
if __name__ == "__main__":
|
2024-01-30 16:06:00 +00:00
|
|
|
app.run(debug=True)
|