""" 250 örnek craftable üretir: item + tarif. Idempotent (code üzerinden ON CONFLICT DO NOTHING). Gruplar: Kerestecilik, Marangozluk, Okçuluk, Metalurji, Demircilik, Kuyumculuk, Simya, Aşçılık, Dericilik, Balıkçılık. Çalıştırma: cd /opt/stepstead && ./venv/bin/python3 db/seed_craftables.py """ import asyncio import json import sys import asyncpg sys.path.insert(0, "/opt/stepstead") from config import settings DSN = settings.DATABASE_URL.replace("postgresql+asyncpg://", "postgresql://") # (kod, Türkçe ad, tier) WOODS = [ ("oak", "Meşe", 1), ("pine", "Çam", 2), ("birch", "Huş", 3), ("beech", "Kayın", 4), ("maple", "Akçaağaç", 5), ("willow", "Söğüt", 6), ("ash", "Dişbudak", 7), ("cedar", "Sedir", 8), ("walnut", "Ceviz", 9), ("cherry", "Kiraz", 10), ("yew", "Porsuk", 11), ("mahogany", "Maun", 12), ("ebony", "Abanoz", 13), ] METALS = [ ("copper", "Bakır", 1), ("bronze", "Bronz", 2), ("iron", "Demir", 3), ("steel", "Çelik", 4), ("silver", "Gümüş", 5), ("gold", "Altın", 6), ] HERBS = [ ("mint", "Nane", 1), ("sage", "Adaçayı", 2), ("thyme", "Kekik", 3), ("chamomile", "Papatya", 4), ("rosemary", "Biberiye", 5), ("basil", "Fesleğen", 6), ("nettle", "Isırgan", 7), ("lemonbalm", "Melisa", 8), ("fennel", "Rezene", 9), ("lavender", "Lavanta", 10), ("ginseng", "Ginseng", 11), ("saffron", "Safran", 12), ] FISH = [ ("carp", "Sazan", 1), ("perch", "Levrek", 2), ("anchovy", "Hamsi", 3), ("mullet", "Kefal", 4), ("mackerel", "Uskumru", 5), ("bonito", "Palamut", 6), ("bluefish", "Lüfer", 7), ("bream", "Çipura", 8), ("trout", "Alabalık", 9), ("pike", "Turna", 10), ("catfish", "Yayın", 11), ("salmon", "Somon", 12), ("turbot", "Kalkan", 13), ("tuna", "Ton Balığı", 14), ("sturgeon", "Mersin", 15), ] ANIMALS = [ ("rabbit", "Tavşan", 1), ("deer", "Geyik", 2), ("boar", "Yaban Domuzu", 3), ("wolf", "Kurt", 4), ("bear", "Ayı", 5), ] FURNITURE = [("chair", "Sandalye", 3), ("table", "Masa", 4), ("bed", "Yatak", 6), ("cabinet", "Dolap", 5), ("door", "Kapı", 4), ("chest", "Sandık", 5)] # (kod, ad, kereste) WEAPONS = [("axe", "Balta"), ("pickaxe", "Kazma"), ("sword", "Kılıç"), ("dagger", "Hançer"), ("shield", "Kalkan"), ("armor", "Zırh")] JEWELRY = [("ring", "Yüzük"), ("necklace", "Kolye"), ("bracelet", "Bilezik")] LEATHERGOODS = [("bag", "Çanta"), ("belt", "Kemer"), ("boots", "Bot"), ("gloves", "Eldiven")] def rarity_for(tier: int, max_tier: int) -> str: r = tier / max_tier if r <= 0.25: return "common" if r <= 0.5: return "uncommon" if r <= 0.75: return "rare" if r < 1.0: return "epic" return "legendary" items: list[dict] = [] # {code,name,type,rarity,stack_max,description,effect} recipes: list[dict] = [] # {code,name,out,out_qty,skill,level,xp,steps,ings} def add_item(code, name, typ, rarity="common", stack=99, desc=None, effect=None): items.append({"code": code, "name": name, "type": typ, "rarity": rarity, "stack": stack, "desc": desc, "effect": effect}) def add_recipe(code, name, out, skill, level, xp, steps, ings, out_qty=1): recipes.append({"code": code, "name": name, "out": out, "out_qty": out_qty, "skill": skill, "level": min(level, 50), "xp": xp, "steps": steps, "ings": [{"item_code": c, "qty": q} for c, q in ings]}) def build(): # --- Ham maddeler --- for w, tr, t in WOODS: add_item(f"log_{w}", f"{tr} Odunu", "material", rarity_for(t, 13)) for m, tr, t in METALS: if m in ("bronze", "steel"): pass # cevheri yok, alaşım else: add_item(f"ore_{m}", f"{tr} Cevheri", "material", rarity_for(t, 6)) add_item(f"ingot_{m}", f"{tr} Külçe", "material", rarity_for(t, 6)) add_item("ore_tin", "Kalay Cevheri", "material", "common") add_item("coal", "Kömür", "material", "common") for h, tr, t in HERBS: add_item(f"herb_{h}", f"{tr}", "material", rarity_for(t, 12)) for f, tr, t in FISH: add_item(f"fish_{f}", f"{tr}", "material", rarity_for(t, 15)) for a, tr, t in ANIMALS: add_item(f"leather_{a}", f"{tr} Derisi", "material", rarity_for(t, 5)) add_item(f"meat_{a}", f"{tr} Eti", "material", rarity_for(t, 5)) # --- 1) Kerestecilik: 13 kereste --- for w, tr, t in WOODS: add_item(f"plank_{w}", f"{tr} Kereste", "material", rarity_for(t, 13)) add_recipe(f"saw_{w}", f"{tr} Kereste", f"plank_{w}", "woodcutting", max(1, t * 3 - 2), 4 + 2 * t, 2 + t, [(f"log_{w}", 2)], out_qty=2) # --- 2) Marangozluk: 13 odun × 6 mobilya = 78 --- for w, wtr, t in WOODS: for fc, ftr, planks in FURNITURE: add_item(f"{fc}_{w}", f"{wtr} {ftr}", "furniture", rarity_for(t, 13), stack=10) add_recipe(f"build_{fc}_{w}", f"{wtr} {ftr}", f"{fc}_{w}", "construction", max(1, t * 3 - 2), 8 + 3 * t, 4 + t + planks, [(f"plank_{w}", planks)]) # --- 3) Okçuluk: 13 yay + 13 ok = 26 --- for w, wtr, t in WOODS: add_item(f"bow_{w}", f"{wtr} Yay", "tool", rarity_for(t, 13), stack=1) add_recipe(f"craft_bow_{w}", f"{wtr} Yay", f"bow_{w}", "combat", max(1, t * 3 - 2), 10 + 3 * t, 6 + t, [(f"plank_{w}", 2), ("vine", 1)]) add_item(f"arrow_{w}", f"{wtr} Ok", "material", rarity_for(t, 13)) add_recipe(f"craft_arrow_{w}", f"{wtr} Ok (10)", f"arrow_{w}", "combat", max(1, t * 3 - 2), 5 + 2 * t, 3 + t, [(f"plank_{w}", 1), ("stone_small", 1)], out_qty=10) # --- 4) Metalurji: 4 yeni külçe (bakır+demir eritme zaten var) --- add_recipe("smelt_bronze", "Bronz Külçe", "ingot_bronze", "smithing", 4, 12, 5, [("ore_copper", 1), ("ore_tin", 1)]) add_recipe("smelt_steel", "Çelik Külçe", "ingot_steel", "smithing", 10, 18, 6, [("ore_iron", 2), ("coal", 1)]) add_recipe("smelt_silver", "Gümüş Külçe", "ingot_silver", "smithing", 15, 22, 7, [("ore_silver", 2)]) add_recipe("smelt_gold", "Altın Külçe", "ingot_gold", "smithing", 20, 28, 8, [("ore_gold", 2)]) # --- 5) Demircilik: 6 metal × 6 = 36, bakır balta+kazma mevcut → 34 --- for m, mtr, t in METALS: for wc, wtr in WEAPONS: if m == "copper" and wc in ("axe", "pickaxe"): continue # craft_axe_cu / craft_pick_cu zaten var code = f"{wc}_{m}" typ = "tool" if wc in ("axe", "pickaxe") else "gear" add_item(code, f"{mtr} {wtr}", typ, rarity_for(t, 6), stack=1) n_ingot = 3 if wc in ("shield", "armor") else 2 add_recipe(f"forge_{wc}_{m}", f"{mtr} {wtr}", code, "smithing", max(1, t * 5 - 3), 10 + 5 * t, 6 + 2 * t, [(f"ingot_{m}", n_ingot), ("log_oak", 1)]) # --- 6) Kuyumculuk: gümüş+altın × 3 takı = 6 --- for m, mtr, t in [("silver", "Gümüş", 5), ("gold", "Altın", 6)]: for jc, jtr in JEWELRY: add_item(f"{jc}_{m}", f"{mtr} {jtr}", "gear", rarity_for(t, 6), stack=1) add_recipe(f"jewel_{jc}_{m}", f"{mtr} {jtr}", f"{jc}_{m}", "smithing", t * 5, 15 + 4 * t, 8, [(f"ingot_{m}", 1)]) # --- 7) Simya: 12 ot × 3 = 36, nane çayı mevcut → 35 --- for h, htr, t in HERBS: if h != "mint": # brew_tea_mint zaten var add_item(f"tea_{h}", f"{htr} Çayı", "consumable", rarity_for(t, 12), desc=f"Adım bakiyesini +{40 + 5 * t} yeniler.", effect={"type": "steps", "amount": 40 + 5 * t}) add_recipe(f"brew_tea_{h}", f"{htr} Çayı", f"tea_{h}", "alchemy", max(1, t * 4 - 3), 6 + 2 * t, 4, [(f"herb_{h}", 2)]) add_item(f"potion_{h}", f"{htr} İksiri", "consumable", rarity_for(t, 12), desc=f"Adım bakiyesini +{80 + 10 * t} yeniler.", effect={"type": "steps", "amount": 80 + 10 * t}) add_recipe(f"brew_potion_{h}", f"{htr} İksiri", f"potion_{h}", "alchemy", min(50, t * 4), 12 + 3 * t, 6, [(f"herb_{h}", 3), ("vine", 1)]) add_item(f"salve_{h}", f"{htr} Merhemi", "consumable", rarity_for(t, 12), desc="İyileştirici merhem (gelecek özellik).") add_recipe(f"brew_salve_{h}", f"{htr} Merhemi", f"salve_{h}", "alchemy", min(50, t * 4 + 1), 10 + 3 * t, 5, [(f"herb_{h}", 2), ("stone_small", 1)]) # --- 8) Aşçılık: 14 balık (sazan mevcut) + 5 et × 3 = 29 --- for f, ftr, t in FISH: if f == "carp": continue # cook_carp zaten var add_item(f"cooked_{f}", f"Izgara {ftr}", "consumable", rarity_for(t, 15), desc=f"Adım bakiyesini +{25 + 3 * t} yeniler.", effect={"type": "steps", "amount": 25 + 3 * t}) add_recipe(f"cook_{f}", f"Izgara {ftr}", f"cooked_{f}", "cooking", max(1, t * 3 - 2), 6 + 2 * t, 4, [(f"fish_{f}", 1)]) for a, atr, t in ANIMALS: for mc, mtr, bonus in [("grilled", "Izgara", 30), ("stew", "Güveç", 50), ("dried", "Kurutulmuş", 40)]: add_item(f"{mc}_{a}", f"{mtr} {atr} Eti", "consumable", rarity_for(t, 5), desc=f"Adım bakiyesini +{bonus + 8 * t} yeniler.", effect={"type": "steps", "amount": bonus + 8 * t}) ings = [(f"meat_{a}", 1)] if mc != "stew" else [(f"meat_{a}", 1), ("herb_mint", 1)] add_recipe(f"cook_{mc}_{a}", f"{mtr} {atr} Eti", f"{mc}_{a}", "cooking", min(50, t * 6), 8 + 4 * t, 5, ings) # --- 9) Dericilik: 5 deri × 4 = 20 --- for a, atr, t in ANIMALS: for lc, ltr in LEATHERGOODS: add_item(f"{lc}_{a}", f"{atr} Derisi {ltr}", "gear", rarity_for(t, 5), stack=1) add_recipe(f"tailor_{lc}_{a}", f"{atr} Derisi {ltr}", f"{lc}_{a}", "hunting", min(50, t * 7 - 4), 10 + 5 * t, 6 + t, [(f"leather_{a}", 2), ("vine", 1)]) # --- 10) Balıkçılık: 2 gelişmiş olta --- add_item("fishing_rod_fine", "Usta Oltası", "tool", "rare", stack=1) add_recipe("craft_rod_fine", "Usta Oltası", "fishing_rod_fine", "fishing", 10, 25, 8, [("plank_willow", 2), ("vine", 2)]) add_item("fishing_rod_master", "Efsane Olta", "tool", "epic", stack=1) add_recipe("craft_rod_master", "Efsane Olta", "fishing_rod_master", "fishing", 25, 50, 12, [("plank_yew", 2), ("vine", 3), ("ingot_silver", 1)]) # --- 11) İnşaat ekstra: 3 --- add_item("campfire", "Kamp Ateşi", "furniture", "common", stack=10) add_recipe("build_campfire", "Kamp Ateşi", "campfire", "construction", 1, 8, 5, [("stick", 3), ("stone_small", 2)]) add_item("fence", "Çit", "furniture", "common", stack=50) add_recipe("build_fence", "Çit", "fence", "construction", 2, 6, 4, [("plank_pine", 1), ("vine", 1)]) add_item("sign", "Tabela", "furniture", "common", stack=20) add_recipe("build_sign", "Tabela", "sign", "construction", 1, 5, 3, [("plank_oak", 1), ("stick", 1)]) async def main(): build() print(f"Üretilen: {len(recipes)} tarif, {len(items)} item tanımı") assert len(recipes) == 250, f"250 bekleniyor, {len(recipes)} üretildi" conn = await asyncpg.connect(DSN) ins_i = 0 for it in items: r = await conn.execute(""" INSERT INTO items (code, name, type, rarity, stack_max, description, effect) VALUES ($1,$2,$3,$4,$5,$6,$7) ON CONFLICT (code) DO NOTHING """, it["code"], it["name"], it["type"], it["rarity"], it["stack"], it["desc"], json.dumps(it["effect"]) if it["effect"] else None) ins_i += int(r.endswith("1")) ins_r = 0 for rc in recipes: r = await conn.execute(""" INSERT INTO recipes (code, name, output_item_id, output_qty, skill, required_level, xp_reward, step_cost, ingredients) SELECT $1,$2,i.id,$3,$4,$5,$6,$7,$8::jsonb FROM items i WHERE i.code=$9 ON CONFLICT (code) DO NOTHING """, rc["code"], rc["name"], rc["out_qty"], rc["skill"], rc["level"], rc["xp"], rc["steps"], json.dumps(rc["ings"]), rc["out"]) ins_r += int(r.endswith("1")) ti = await conn.fetchval("SELECT count(*) FROM items") tr = await conn.fetchval("SELECT count(*) FROM recipes") await conn.close() print(f"DB'ye eklendi: {ins_i} item, {ins_r} tarif. Toplam: {ti} item, {tr} tarif.") asyncio.run(main())