""" Lokasyona özel olaylar — combat/hunting ağırlıklı 8 yeni kart (2026-07-04). events.location_codes: seyahatin VARIŞ lokasyonu listede ise olay çıkabilir; NULL = her yerde. Çalıştırma (idempotent): cd /opt/stepstead && ./venv/bin/python3 db/seed_events_combat.py """ import asyncio import json import sys sys.path.insert(0, "/opt/stepstead") import asyncpg # noqa: E402 from config import settings # noqa: E402 EVENTS = [ { "code": "kurt_surusu", "name": "Kurt Sürüsü", "text": "Alacakaranlıkta parlayan gözler... Bir kurt sürüsü yolunu kesti. Liderleri dişlerini gösteriyor.", "locations": ["av_topraklari", "karanlik_orman"], "choices": [ {"text": "⚔ Savaş!", "skill": "combat", "dc": 13, "success": {"text": "Sürüyü püskürttün, lider kurdu yere serdin.", "items": [{"code": "meat_wolf", "qty": 2}, {"code": "leather_wolf", "qty": 1}], "xp": {"skill": "combat", "amount": 60}}, "fail": {"text": "Kurtlar seni kovaladı, kan kaybederek kaçtın.", "steps": -150}}, {"text": "🏃 Kaç", "outcome": {"text": "Uzun bir koşuyla kurtuldun ama yorgun düştün.", "steps": -80}}, ], }, { "code": "vahsi_domuz", "name": "Vahşi Domuz", "text": "Çalılıklar hışırdıyor — kocaman bir yaban domuzu toprağı eşeliyor. Henüz seni fark etmedi.", "locations": ["av_topraklari", "fisilti_ormani", "akca_koru"], "choices": [ {"text": "🏹 Sessizce avla", "skill": "hunting", "dc": 12, "success": {"text": "Tek atışla indirdin. Temiz bir av.", "items": [{"code": "meat_boar", "qty": 2}, {"code": "leather_boar", "qty": 1}], "xp": {"skill": "hunting", "amount": 50}}, "fail": {"text": "Dal kırıldı, domuz sana saldırdı! Zor kaçtın.", "steps": -100}}, {"text": "🤫 Rahat bırak", "outcome": {"text": "Domuz homurdanarak uzaklaştı.", "steps": 0}}, ], }, { "code": "geyik_izi", "name": "Taze Geyik İzi", "text": "Toprakta taze geyik izleri var. İzler sık çalılığın içine gidiyor.", "locations": ["cayirlar", "av_topraklari", "gumus_camlik"], "choices": [ {"text": "🦌 İzi sür", "skill": "hunting", "dc": 10, "success": {"text": "İzi sürüp genç bir geyik avladın.", "items": [{"code": "meat_deer", "qty": 1}, {"code": "leather_deer", "qty": 1}], "xp": {"skill": "hunting", "amount": 40}}, "fail": {"text": "İzi çalılıkta kaybettin, boşa yürüdün.", "steps": -60}}, {"text": "➡ Yoluna devam et", "outcome": {"text": "Avı başka zamana bıraktın.", "steps": 0}}, ], }, { "code": "magara_orumcegi", "name": "Mağara Örümceği", "text": "Madenin karanlık bir kovuğunda dev bir örümcek ağını germiş. Ağın arkasında parlayan bir cevher damarı var.", "locations": ["derin_maden", "ejder_dagi", "tas_ocagi"], "choices": [ {"text": "⚔ Örümceği öldür", "skill": "combat", "dc": 14, "success": {"text": "Örümceği alt ettin, damardaki cevheri söktün.", "items": [{"code": "ore_silver", "qty": 2}], "xp": {"skill": "combat", "amount": 70}}, "fail": {"text": "Ağa dolandın! Kendini zor kurtardın.", "steps": -120}}, {"text": "🕯 Geri çekil", "outcome": {"text": "O gözlerle uğraşmaya değmez. Geri döndün.", "steps": -30}}, ], }, { "code": "korsan_yagmasi", "name": "Korsan Artığı", "text": "Kıyıya vurmuş kırık bir filika... İçinde kilitli küçük bir para sandığı var. Ama iki serseri de sandığı görmüş, sana doğru geliyorlar.", "locations": ["liman", "firtina_kiyisi"], "choices": [ {"text": "⚔ Sandık için dövüş", "skill": "combat", "dc": 15, "success": {"text": "Serserileri kaçırttın. Sandıktan gold çıktı!", "gold": 40, "xp": {"skill": "combat", "amount": 80}}, "fail": {"text": "İki kişiye gücün yetmedi, dayak yiyip uzaklaştın.", "steps": -180}}, {"text": "🚶 Sandığı onlara bırak", "outcome": {"text": "Belaya bulaşmadın.", "steps": 0}}, ], }, { "code": "yasli_avci", "name": "Yaşlı Avcı", "text": "Kamp ateşinin başında yaşlı bir avcı oturuyor. 'Otur evlat,' diyor, 'sana av hikâyeleri anlatayım.'", "locations": ["av_topraklari", "cayirlar"], "choices": [ {"text": "🔥 Otur ve dinle", "outcome": {"text": "Saatlerce iz sürme ve tuzak kurma taktikleri dinledin.", "xp": {"skill": "hunting", "amount": 45}, "steps": -40}}, {"text": "🙏 Teşekkür edip geç", "outcome": {"text": "Vaktin yoktu, yola devam ettin.", "steps": 0}}, ], }, { "code": "balikci_aginda", "name": "Terk Edilmiş Ağ", "text": "Kıyıda yarısı suda bir balıkçı ağı duruyor. İçinde hâlâ çırpınan balıklar var ama ağ kayalara dolanmış.", "locations": ["aynali_gol", "firtina_kiyisi", "liman"], "choices": [ {"text": "🎣 Ağı çöz", "skill": "fishing", "dc": 11, "success": {"text": "Ağı ustaca çözdün, balıklar senin.", "items": [{"code": "fish_mackerel", "qty": 2}, {"code": "fish_bream", "qty": 1}], "xp": {"skill": "fishing", "amount": 40}}, "fail": {"text": "Ağ iyice dolandı, üstüne bir de sırılsıklam oldun.", "steps": -70}}, {"text": "🌊 Denize bırak", "outcome": {"text": "Balıkları özgür bıraktın, için rahat.", "steps": 0}}, ], }, { "code": "ayi_ini", "name": "Ayı İni", "text": "Kadim ormanın derinliklerinde bir in... İçeriden horultu geliyor. Girişte yarım kalmış bir bal peteği duruyor.", "locations": ["kadim_orman", "karanlik_orman"], "choices": [ {"text": "⚔ İne gir, ayıyla yüzleş", "skill": "combat", "dc": 16, "success": {"text": "Efsanevi bir dövüştü. Ayıyı devirdin!", "items": [{"code": "meat_bear", "qty": 2}, {"code": "leather_bear", "qty": 1}], "xp": {"skill": "combat", "amount": 100}}, "fail": {"text": "Ayı seni köpek gibi kovaladı. Canını zor kurtardın.", "steps": -250}}, {"text": "🍯 Sadece peteği al ve kaç", "skill": "hunting", "dc": 12, "success": {"text": "Sessizce peteği kapıp uzaklaştın.", "items": [{"code": "herb_chamomile", "qty": 2}], "xp": {"skill": "hunting", "amount": 30}}, "fail": {"text": "Ayı uyandı! Peteği bırakıp kaçtın.", "steps": -100}}, {"text": "🚶 Hiç bulaşma", "outcome": {"text": "Uyuyan ayıyı rahat bıraktın.", "steps": 0}}, ], }, ] async def main() -> None: dsn = settings.DATABASE_URL.replace("postgresql+asyncpg://", "postgresql://") conn = await asyncpg.connect(dsn) for ev in EVENTS: await conn.execute(""" INSERT INTO events (code, name, text, choices, location_codes) VALUES ($1, $2, $3, $4::jsonb, $5) ON CONFLICT (code) DO UPDATE SET name = EXCLUDED.name, text = EXCLUDED.text, choices = EXCLUDED.choices, location_codes = EXCLUDED.location_codes """, ev["code"], ev["name"], ev["text"], json.dumps(ev["choices"]), ev["locations"]) total = await conn.fetchval("SELECT count(*) FROM events") targeted = await conn.fetchval("SELECT count(*) FROM events WHERE location_codes IS NOT NULL") print(f"OK — toplam {total} olay ({targeted} lokasyona özel)") await conn.close() if __name__ == "__main__": asyncio.run(main())