diff --git a/app.py b/app.py index 8bcefe5..3a7d86a 100644 --- a/app.py +++ b/app.py @@ -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) diff --git a/templates/collector.html b/templates/collector.html index 227ae9c..cefdd00 100644 --- a/templates/collector.html +++ b/templates/collector.html @@ -295,6 +295,8 @@ Quest Trees  |  Loadout Planner +  |  + Injectors

Collector Checklist

diff --git a/templates/index.html b/templates/index.html index 01d5e62..9ec8296 100644 --- a/templates/index.html +++ b/templates/index.html @@ -174,6 +174,8 @@ Quest Trees  |  Loadout Planner +  |  + Injectors

OnlyScavs – Keys

diff --git a/templates/loadout.html b/templates/loadout.html index 8b927c2..5052164 100644 --- a/templates/loadout.html +++ b/templates/loadout.html @@ -223,7 +223,8 @@

Loadout Planner

diff --git a/templates/meds.html b/templates/meds.html new file mode 100644 index 0000000..31495ee --- /dev/null +++ b/templates/meds.html @@ -0,0 +1,574 @@ + + + + OnlyScavs – Injector Reference + + + + +

+ + + +

Injector Quick Reference

+

All stim injectors — situation guide + full effect comparison

+ + +
Situation Guide — what to grab when
+
+ +
+
🩸 Bleeding / Wound
+ {% for inj in situations.bleed %} +
+ {{ inj.short }} + {{ inj.desc }} + {% if inj.warn %}⚠ {{ inj.warn }}{% endif %} +
+ {% endfor %} +
+ +
+
❤️ HP Regen
+ {% for inj in situations.regen %} +
+ {{ inj.short }} + {{ inj.desc }} + {% if inj.warn %}⚠ {{ inj.warn }}{% endif %} +
+ {% endfor %} +
+ +
+
Stamina / Speed
+ {% for inj in situations.stam %} +
+ {{ inj.short }} + {{ inj.desc }} + {% if inj.warn %}⚠ {{ inj.warn }}{% endif %} +
+ {% endfor %} +
+ +
+
💪 Skill Boosts
+ {% for inj in situations.skill %} +
+ {{ inj.short }} + {{ inj.desc }} + {% if inj.warn %}⚠ {{ inj.warn }}{% endif %} +
+ {% endfor %} +
+ +
+
🌡️ Temperature / Special
+ {% for inj in situations.special %} +
+ {{ inj.short }} + {{ inj.desc }} + {% if inj.warn %}⚠ {{ inj.warn }}{% endif %} +
+ {% endfor %} +
+ +
+
☠️ High Risk / Gamble
+ {% for inj in situations.risky %} +
+ {{ inj.short }} + {{ inj.desc }} + {% if inj.warn %}⚠ {{ inj.warn }}{% endif %} +
+ {% endfor %} +
+ +
+ + +
Full Comparison Grid
+ +
+ + + + + +
+ +
+ + + + + {% for inj in injectors %} + + {% endfor %} + + + + + + + {% for inj in injectors %}{% endfor %} + + + + {% for inj in injectors %} + + {% endfor %} + + + + {% for inj in injectors %} + + {% endfor %} + + + + {% for inj in injectors %} + + {% endfor %} + + + + + + {% for inj in injectors %}{% endfor %} + + + + {% for inj in injectors %} + + {% endfor %} + + + + {% for inj in injectors %} + + {% endfor %} + + + + {% for inj in injectors %} + + {% endfor %} + + + + + + {% for inj in injectors %}{% endfor %} + + {% for skill_name in skill_rows %} + + + {% for inj in injectors %} + + {% endfor %} + + {% endfor %} + + + + + {% for inj in injectors %}{% endfor %} + + + + {% for inj in injectors %} + + {% endfor %} + + + + {% for inj in injectors %} + + {% endfor %} + + + + {% for inj in injectors %} + + {% endfor %} + + + + + + {% for inj in injectors %}{% endfor %} + + + + {% for inj in injectors %} + + {% endfor %} + + + + {% for inj in injectors %} + + {% endfor %} + + + + {% for inj in injectors %} + + {% endfor %} + + +
Effect + {% if inj.icon %}{% endif %} + {{ inj.short }} + {% if inj.wiki %}wiki ↗{% endif %} +
Healing
HP regen /s + {% if inj.hp_regen %} + +{{ inj.hp_regen }} + {{ inj.hp_regen_dur }}s + {% else %}{% endif %} +
Stops bleeding + {% if inj.stops_bleed %}{% else %}{% endif %} +
Antidote + {% if inj.antidote %}{% else %}{% endif %} +
Stamina
Max stamina + {% if inj.max_stam %} + + {{ '+' if inj.max_stam > 0 else '' }}{{ inj.max_stam }} + + {{ inj.max_stam_dur }}s + {% else %}{% endif %} +
Stam recovery /s + {% if inj.stam_rec %} + + {{ '+' if inj.stam_rec > 0 else '' }}{{ inj.stam_rec }} + + {{ inj.stam_rec_dur }}s + {% else %}{% endif %} +
Weight limit + {% if inj.weight %} + + {{ '+' if inj.weight > 0 else '' }}{{ (inj.weight * 100)|int }}% + + {{ inj.weight_dur }}s + {% else %}{% endif %} +
Skill Buffs
{{ skill_name }} + {% set val = inj.skills.get(skill_name) %} + {% if val %} + + {{ '+' if val.value > 0 else '' }}{{ val.value }} + + {{ val.duration }}s + {% else %}{% endif %} +
Special
Body temp Δ + {% if inj.body_temp %} + + {{ '+' if inj.body_temp > 0 else '' }}{{ inj.body_temp }}° + + {{ inj.body_temp_dur }}s + {% else %}{% endif %} +
Energy Δ /s + {% if inj.energy %} + + {{ '+' if inj.energy > 0 else '' }}{{ inj.energy }} + + {{ inj.energy_dur }}s + {% else %}{% endif %} +
Hydration Δ /s + {% if inj.hydration %} + + {{ '+' if inj.hydration > 0 else '' }}{{ inj.hydration }} + + {{ inj.hydration_dur }}s + {% else %}{% endif %} +
Side Effects
Tremors + {% if inj.tremor %} + + {{ inj.tremor_delay }}s delay · {{ inj.tremor_dur }}s + {% else %}{% endif %} +
Tunnel vision + {% if inj.tunnel %} + + {{ inj.tunnel_delay }}s delay · {{ inj.tunnel_dur }}s + {% else %}{% endif %} +
Pain + {% if inj.pain %} + + {{ inj.pain_delay }}s delay · {{ inj.pain_dur }}s + {% else %}{% endif %} +
+
+ +
+ + + + diff --git a/templates/quests.html b/templates/quests.html index 15af0bb..cee4c2b 100644 --- a/templates/quests.html +++ b/templates/quests.html @@ -232,6 +232,8 @@ Collector Checklist  |  Loadout Planner +  |  + Injectors

Quest Trees