152 lines
8 KiB
Python
152 lines
8 KiB
Python
"""
|
||
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())
|