feat: Added new injector chart page.

This commit is contained in:
serversdwn
2026-03-01 21:49:32 +00:00
parent 394c7ebde7
commit 4893f3deee
6 changed files with 783 additions and 1 deletions

201
app.py
View File

@@ -751,5 +751,206 @@ def save_build():
return jsonify({"build_id": build_id, "name": name})
@app.route("/meds")
def meds():
import requests as _req
API_URL = "https://api.tarkov.dev/graphql"
query = """
{
items(types: [injectors], lang: en) {
id
name
shortName
iconLink
wikiLink
properties {
__typename
... on ItemPropertiesStim {
useTime
cures
stimEffects {
type
skill { name }
value
percent
duration
delay
chance
}
}
}
}
}
"""
try:
resp = _req.post(API_URL, json={"query": query}, timeout=8)
raw_items = resp.json()["data"]["items"]
except Exception:
raw_items = []
# ── helper: pick first matching effect ──────────────────────────────
def pick(effects, type_str, positive_only=False, negative_only=False):
for e in effects:
if e["type"] == type_str:
if positive_only and e["value"] <= 0:
continue
if negative_only and e["value"] >= 0:
continue
return e
return None
def pick_skill(effects, skill_name):
for e in effects:
if e["type"] == "Skill" and e.get("skill") and e["skill"]["name"] == skill_name:
return e
return None
# ── collect all skill names across all injectors ──────────────────
all_skills = []
for item in raw_items:
p = item.get("properties") or {}
for e in p.get("stimEffects", []):
if e["type"] == "Skill" and e.get("skill"):
sn = e["skill"]["name"]
if sn not in all_skills:
all_skills.append(sn)
skill_rows = sorted(all_skills)
# ── build injector data rows ──────────────────────────────────────
injectors = []
for item in raw_items:
p = item.get("properties") or {}
effs = p.get("stimEffects", [])
def _val(eff): return round(eff["value"], 2) if eff else None
def _dur(eff): return eff["duration"] if eff else 0
def _delay(eff): return eff["delay"] if eff else 0
hp_e = pick(effs, "Health regeneration", positive_only=True)
stam_e = pick(effs, "Stamina recovery", positive_only=True)
stam_neg_e = pick(effs, "Stamina recovery", negative_only=True)
stam_rec_e = stam_e or stam_neg_e
maxstam_e = pick(effs, "Max stamina")
weight_e = pick(effs, "Weight limit")
energy_e = pick(effs, "Energy recovery")
hydra_e = pick(effs, "Hydration recovery")
bleed_e = pick(effs, "Stops and prevents bleedings")
anti_e = pick(effs, "Antidote")
tremor_e = pick(effs, "Hands tremor")
tunnel_e = pick(effs, "Tunnel effect")
pain_e = pick(effs, "Pain")
temp_e = pick(effs, "Body temperature")
# skills dict
skills = {}
for sn in skill_rows:
se = pick_skill(effs, sn)
if se:
skills[sn] = {"value": round(se["value"], 1), "duration": se["duration"]}
# tags for column filtering
tags = []
if hp_e or bleed_e or anti_e:
tags.append("heal")
if maxstam_e or stam_rec_e:
tags.append("stam")
if skills:
tags.append("skill")
if temp_e or weight_e:
tags.append("special")
if not tags:
tags.append("special")
injectors.append({
"name": item["name"],
"short": item["shortName"],
"icon": item.get("iconLink"),
"wiki": item.get("wikiLink"),
"tags": ",".join(tags),
# healing
"hp_regen": _val(hp_e),
"hp_regen_dur": _dur(hp_e),
"stops_bleed": bool(bleed_e),
"antidote": bool(anti_e),
# stamina
"max_stam": _val(maxstam_e),
"max_stam_dur": _dur(maxstam_e),
"stam_rec": _val(stam_rec_e),
"stam_rec_dur": _dur(stam_rec_e),
# weight
"weight": _val(weight_e),
"weight_dur": _dur(weight_e),
# special
"body_temp": _val(temp_e),
"body_temp_dur": _dur(temp_e),
"energy": round(energy_e["value"], 2) if energy_e else None,
"energy_dur": _dur(energy_e),
"hydration": round(hydra_e["value"], 2) if hydra_e else None,
"hydration_dur": _dur(hydra_e),
# skills
"skills": skills,
# side effects
"tremor": bool(tremor_e),
"tremor_delay": _delay(tremor_e),
"tremor_dur": _dur(tremor_e),
"tunnel": bool(tunnel_e),
"tunnel_delay": _delay(tunnel_e),
"tunnel_dur": _dur(tunnel_e),
"pain": bool(pain_e),
"pain_delay": _delay(pain_e),
"pain_dur": _dur(pain_e),
})
# ── situation guide ───────────────────────────────────────────────
situations = {
"bleed": [
{"short": "Zagustin", "desc": "Stops bleeding, +Vitality 180s", "warn": "tremors delayed"},
{"short": "AHF1-M", "desc": "Stops bleeding, +Health 60s", "warn": "-hydration"},
{"short": "Perfotoran", "desc": "Stops bleed + antidote + regen", "warn": "-energy after"},
{"short": "xTG-12", "desc": "Antidote only (no bleed stop)", "warn": "-Health skill"},
],
"regen": [
{"short": "eTG-c", "desc": "+6.5 HP/s for 60s (fast burst)", "warn": "-energy after"},
{"short": "Adrenaline","desc": "+4 HP/s for 15s, stam boost", "warn": "-hydration after"},
{"short": "PNB", "desc": "+3 HP/s for 40s, +Strength", "warn": "tremors + skill debuff"},
{"short": "Propital", "desc": "+1 HP/s for 300s, skill buffs", "warn": "tremors at 270s"},
{"short": "Perfotoran","desc": "+1.5 HP/s for 60s + antidote", "warn": "-energy after"},
],
"stam": [
{"short": "Trimadol", "desc": "+3 stam rec, +10 max stam, 180s", "warn": "-energy/-hydration"},
{"short": "SJ6", "desc": "+2 stam rec, +30 max stam, 240s", "warn": "tremors + tunnel after"},
{"short": "Meldonin", "desc": "+0.5 stam rec, +Endurance 900s", "warn": "-hydration/-energy (minor)"},
{"short": "L1", "desc": "+30 max stam, +Strength, 120s", "warn": "-hydration/-energy"},
{"short": "SJ1", "desc": "+Endurance/Strength 180s", "warn": "-energy/-hydration after"},
{"short": "Adrenaline","desc": "Short burst +Endurance/Strength", "warn": "-Stress Resist"},
],
"skill": [
{"short": "Obdolbos 2", "desc": "All skills +20, weight +45%, 1800s", "warn": "-stam, -HP regen"},
{"short": "3-(b-TG)", "desc": "+Attention/Perception/Strength 240s", "warn": "tremors after"},
{"short": "SJ12", "desc": "+Perception 600s, body cool", "warn": "overheats at end"},
{"short": "2A2-(b-TG)", "desc": "+Attention/Perception, weight +15%, 900s", "warn": "-hydration"},
{"short": "Trimadol", "desc": "Broad skill buff + stam, 180s", "warn": "-energy/-hydration"},
],
"special": [
{"short": "SJ9", "desc": "Cools body -7°, 300s — hot map survival", "warn": "HP drain + tremors"},
{"short": "SJ12", "desc": "Cools body -4°, +Perception, 600s", "warn": "rebound heat after"},
{"short": "M.U.L.E.", "desc": "Weight limit +50% for 900s", "warn": "-HP regen"},
{"short": "Obdolbos","desc": "25% chance: all buffs + all debuffs", "warn": "may kill you"},
],
"risky": [
{"short": "Obdolbos", "desc": "25% chance everything fires at once", "warn": "may cause -600 HP"},
{"short": "PNB", "desc": "Fast HP/Strength burst then hard crash", "warn": "-Health/-Vitality 180s"},
{"short": "SJ9", "desc": "-HP regen whole duration, tremors", "warn": "don't use while injured"},
{"short": "Propital", "desc": "Tremors + tunnel vision at 270s delay", "warn": "plan ahead"},
],
}
return render_template("meds.html",
injectors=injectors,
skill_rows=skill_rows,
situations=situations)
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000, debug=True)