Add: armor plates support with new database tables and loadout functionality
fix: only required mods are applied to guns for weight management.
This commit is contained in:
71
app.py
71
app.py
@@ -357,7 +357,7 @@ def loadout():
|
||||
tab = request.args.get("tab", "guns")
|
||||
sort = request.args.get("sort", "weight_asc")
|
||||
|
||||
guns = armor = helmets = headwear = backpacks = rigs = []
|
||||
guns = armor = helmets = headwear = backpacks = rigs = plates = []
|
||||
builder_guns = builder_armor = builder_helmets = builder_rigs = builder_backpacks = []
|
||||
requires = request.args.getlist("requires") # list of slot_nameids that must exist
|
||||
min_class = request.args.get("min_class", 0, type=int)
|
||||
@@ -443,6 +443,14 @@ def loadout():
|
||||
ORDER BY {sort_frag}
|
||||
""", (min_capacity, min_capacity, min_class, min_class)).fetchall()
|
||||
|
||||
elif tab == "plates":
|
||||
plates = conn.execute(f"""
|
||||
SELECT * FROM gear_items
|
||||
WHERE category = 'plate'
|
||||
AND (? = 0 OR armor_class >= ?)
|
||||
ORDER BY {sort_frag}
|
||||
""", (min_class, min_class)).fetchall()
|
||||
|
||||
elif tab == "builder":
|
||||
builder_guns = conn.execute("SELECT id, name, weight_kg FROM gear_items WHERE category='gun' ORDER BY name").fetchall()
|
||||
builder_armor = conn.execute("SELECT id, name, weight_kg FROM gear_items WHERE category='armor' ORDER BY name").fetchall()
|
||||
@@ -450,12 +458,16 @@ def loadout():
|
||||
builder_rigs = conn.execute("SELECT id, name, weight_kg FROM gear_items WHERE category='rig' ORDER BY name").fetchall()
|
||||
builder_backpacks = conn.execute("SELECT id, name, weight_kg FROM gear_items WHERE category='backpack' ORDER BY name").fetchall()
|
||||
|
||||
# IDs of carriers that have at least one open plate slot (shell weight only)
|
||||
open_slot_rows = conn.execute("SELECT DISTINCT carrier_id FROM armor_open_slots").fetchall()
|
||||
carrier_ids_with_open_slots = {row["carrier_id"] for row in open_slot_rows}
|
||||
|
||||
conn.close()
|
||||
return render_template(
|
||||
"loadout.html",
|
||||
tab=tab, sort=sort,
|
||||
guns=guns, armor=armor, helmets=helmets, headwear=headwear,
|
||||
backpacks=backpacks, rigs=rigs,
|
||||
backpacks=backpacks, rigs=rigs, plates=plates,
|
||||
slot_filters=LOADOUT_SLOT_FILTERS,
|
||||
requires=requires,
|
||||
min_class=min_class, min_capacity=min_capacity,
|
||||
@@ -464,6 +476,7 @@ def loadout():
|
||||
builder_helmets=builder_helmets,
|
||||
builder_rigs=builder_rigs,
|
||||
builder_backpacks=builder_backpacks,
|
||||
carrier_ids_with_open_slots=carrier_ids_with_open_slots,
|
||||
)
|
||||
|
||||
|
||||
@@ -506,17 +519,19 @@ def gun_detail(gun_id):
|
||||
if row["mod_id"]:
|
||||
slots[sid]["mods"].append(dict(row))
|
||||
|
||||
# Key slots to show at top (highlighted)
|
||||
# Split into required vs optional slots
|
||||
KEY_SLOTS = {"mod_muzzle", "mod_magazine"}
|
||||
ordered_slots = [slots[s] for s in slot_order]
|
||||
key_slots = [s for s in ordered_slots if s["slot_nameid"] in KEY_SLOTS]
|
||||
other_slots = [s for s in ordered_slots if s["slot_nameid"] not in KEY_SLOTS]
|
||||
# Required slots (always needed) shown at top — key slots (magazine/muzzle) highlighted
|
||||
key_slots = [s for s in ordered_slots if s["required"] and s["slot_nameid"] in KEY_SLOTS]
|
||||
req_slots = [s for s in ordered_slots if s["required"] and s["slot_nameid"] not in KEY_SLOTS]
|
||||
optional_slots = [s for s in ordered_slots if not s["required"]]
|
||||
|
||||
# Lightest total (base + lightest per slot)
|
||||
# Lightest total (base + lightest per REQUIRED slot only)
|
||||
lightest_total = (gun["weight_kg"] or 0) + sum(
|
||||
s["mods"][0]["weight_kg"]
|
||||
for s in ordered_slots
|
||||
if s["mods"] and s["mods"][0]["weight_kg"] is not None
|
||||
if s["required"] and s["mods"] and s["mods"][0]["weight_kg"] is not None
|
||||
)
|
||||
|
||||
conn.close()
|
||||
@@ -524,7 +539,8 @@ def gun_detail(gun_id):
|
||||
"gun_detail.html",
|
||||
gun=gun,
|
||||
key_slots=key_slots,
|
||||
other_slots=other_slots,
|
||||
req_slots=req_slots,
|
||||
optional_slots=optional_slots,
|
||||
lightest_total=lightest_total,
|
||||
)
|
||||
|
||||
@@ -571,6 +587,45 @@ def gun_slots_json(gun_id):
|
||||
return jsonify(result)
|
||||
|
||||
|
||||
@app.route("/loadout/carrier/<carrier_id>/slots.json")
|
||||
def carrier_slots_json(carrier_id):
|
||||
"""Returns open plate slots and allowed plates for a carrier (armor or rig)."""
|
||||
conn = get_db()
|
||||
rows = conn.execute("""
|
||||
SELECT aos.slot_nameid, aos.zones,
|
||||
p.id AS plate_id, p.name AS plate_name, p.short_name AS plate_short,
|
||||
p.weight_kg, p.armor_class, p.durability, p.material
|
||||
FROM armor_open_slots aos
|
||||
LEFT JOIN armor_slot_plates asp ON asp.carrier_id = aos.carrier_id
|
||||
AND asp.slot_nameid = aos.slot_nameid
|
||||
LEFT JOIN gear_items p ON p.id = asp.plate_id
|
||||
WHERE aos.carrier_id = ?
|
||||
ORDER BY aos.slot_nameid, p.armor_class DESC, p.weight_kg ASC
|
||||
""", (carrier_id,)).fetchall()
|
||||
conn.close()
|
||||
|
||||
# Group by slot
|
||||
slots = {}
|
||||
slot_order = []
|
||||
for row in rows:
|
||||
sn = row["slot_nameid"]
|
||||
if sn not in slots:
|
||||
slots[sn] = {"slot_nameid": sn, "zones": row["zones"], "plates": []}
|
||||
slot_order.append(sn)
|
||||
if row["plate_id"]:
|
||||
slots[sn]["plates"].append({
|
||||
"id": row["plate_id"],
|
||||
"name": row["plate_name"],
|
||||
"short_name": row["plate_short"],
|
||||
"weight_kg": row["weight_kg"],
|
||||
"armor_class": row["armor_class"],
|
||||
"durability": row["durability"],
|
||||
"material": row["material"],
|
||||
})
|
||||
|
||||
return jsonify([slots[s] for s in slot_order])
|
||||
|
||||
|
||||
@app.route("/loadout/save-build", methods=["POST"])
|
||||
def save_build():
|
||||
data = request.get_json() or {}
|
||||
|
||||
Reference in New Issue
Block a user