Türkiye'de ilk Mobil & PC Aynı Anda Metin2 Oyna. Triarchonline kalıcı ve uzun ömürlü yapısı ile 24 Temmuz'da açılıyor. | 1-99 Mobil Metin2 Triarch HEMEN TIKLA!
Basit form doldurarak görev questi hazırlamak için yapıldı umarım işinize yarar
HTML:
<!DOCTYPE html>
<html lang="tr">
<head>
<meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>Metin2 Quest Oluşturucu</title>
<style>
:root{
--bg0:#030406;
--bg1:#070a10;
--surface:#0c111a;
--surface2:#101722;
--surface3:#151f2e;
--line:rgba(255,255,255,.10);
--line2:rgba(255,255,255,.16);
--text:#f4f7fb;
--muted:#8f9bad;
--soft:#b8c2d4;
--accent:#c8a45d;
--accent2:#e7c77d;
--blue:#7dd3fc;
--green:#6ee7b7;
--red:#fb7185;
--shadow:0 28px 90px rgba(0,0,0,.56);
--radius:22px;
--radius2:16px;
}
*{box-sizing:border-box}
html{scroll-behavior:smooth}
body{
margin:0;
min-height:100vh;
font-family:Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Arial, sans-serif;
color:var(--text);
background:
radial-gradient(circle at 18% 8%, rgba(200,164,93,.18), transparent 26%),
radial-gradient(circle at 88% 0%, rgba(125,211,252,.10), transparent 28%),
linear-gradient(135deg,#030406 0%,#080b12 46%,#040507 100%);
padding:28px;
}
body::before{
content:"";
position:fixed;
inset:0;
pointer-events:none;
background-image:
linear-gradient(rgba(255,255,255,.025) 1px, transparent 1px),
linear-gradient(90deg, rgba(255,255,255,.025) 1px, transparent 1px);
background-size:40px 40px;
mask-image:linear-gradient(to bottom,rgba(0,0,0,.7),transparent 85%);
}
.app{
width:min(1520px,100%);
margin:0 auto;
display:grid;
grid-template-columns:292px minmax(0,1fr);
min-height:calc(100vh - 56px);
border:1px solid var(--line2);
border-radius:28px;
overflow:visible;
background:rgba(8,12,18,.78);
box-shadow:var(--shadow);
backdrop-filter:blur(18px);
}
.sidebar{
position:sticky;
top:28px;
height:calc(100vh - 56px);
padding:22px;
border-right:1px solid var(--line);
background:
linear-gradient(180deg,rgba(255,255,255,.055),rgba(255,255,255,.018)),
rgba(9,13,19,.88);
border-radius:28px 0 0 28px;
}
.brand{
display:flex;
align-items:center;
gap:13px;
padding:4px 2px 22px;
border-bottom:1px solid var(--line);
margin-bottom:18px;
}
.logo{
width:48px;
height:48px;
border-radius:16px;
display:grid;
place-items:center;
font-weight:900;
letter-spacing:.5px;
color:#111827;
background:
linear-gradient(145deg,var(--accent2),var(--accent) 55%,#806333);
box-shadow:0 12px 34px rgba(200,164,93,.25), inset 0 1px 0 rgba(255,255,255,.5);
}
.brand h1{
font-size:17px;
margin:0;
letter-spacing:.2px;
}
.brand p{
margin:4px 0 0;
color:var(--muted);
font-size:12px;
}
.nav{
display:grid;
gap:9px;
}
.nav button{
width:100%;
text-align:left;
background:transparent;
color:var(--muted);
border:1px solid transparent;
padding:13px 14px;
border-radius:15px;
cursor:pointer;
font-weight:750;
transition:.18s ease;
}
.nav button:hover{
color:var(--text);
border-color:var(--line);
background:rgba(255,255,255,.045);
transform:translateX(2px);
}
.nav button.active{
color:var(--text);
border-color:rgba(200,164,93,.42);
background:
linear-gradient(135deg,rgba(200,164,93,.18),rgba(255,255,255,.045));
box-shadow:inset 3px 0 0 var(--accent);
}
.side-card{
margin-top:22px;
padding:16px;
border:1px solid var(--line);
border-radius:18px;
background:
linear-gradient(180deg,rgba(255,255,255,.06),rgba(255,255,255,.025));
}
.side-card b{
display:block;
font-size:13px;
letter-spacing:.3px;
margin-bottom:7px;
}
.side-card p{
margin:0;
color:var(--muted);
font-size:12.5px;
line-height:1.55;
}
main{
min-width:0;
padding:26px;
}
.topbar{
display:flex;
justify-content:space-between;
gap:20px;
align-items:center;
margin-bottom:20px;
padding:18px 20px;
border:1px solid var(--line);
border-radius:22px;
background:rgba(255,255,255,.035);
}
.title h2{
margin:0;
font-size:27px;
letter-spacing:-.03em;
}
.title p{
margin:6px 0 0;
color:var(--muted);
}
button{
border:0;
border-radius:14px;
padding:11px 15px;
cursor:pointer;
color:var(--text);
font-weight:850;
background:linear-gradient(180deg,rgba(255,255,255,.10),rgba(255,255,255,.045));
border:1px solid var(--line);
transition:.18s ease;
}
button:hover{
transform:translateY(-1px);
border-color:var(--line2);
filter:brightness(1.05);
}
.primary{
color:#111827;
background:linear-gradient(145deg,var(--accent2),var(--accent));
border-color:rgba(255,255,255,.18);
box-shadow:0 12px 30px rgba(200,164,93,.18);
}
.success{
color:#052e1c;
background:linear-gradient(145deg,#a7f3d0,var(--green));
}
.warning{
color:#1f1300;
background:linear-gradient(145deg,#fde68a,var(--accent2));
}
.danger{
color:#fff;
background:linear-gradient(145deg,#fb7185,#be123c);
}
.ghost{
background:rgba(255,255,255,.04);
}
.actions,.inline{
display:flex;
gap:10px;
flex-wrap:wrap;
}
.grid{display:grid;gap:18px}
.grid-2{grid-template-columns:1fr 1fr}
.grid-3{grid-template-columns:repeat(3,1fr)}
.split{
display:grid;
grid-template-columns:minmax(420px,5fr) minmax(0,7fr);
gap:20px;
align-items:start;
}
.card{
position:relative;
background:
linear-gradient(180deg,rgba(255,255,255,.072),rgba(255,255,255,.030)),
rgba(10,15,23,.82);
border:1px solid var(--line);
border-radius:var(--radius);
box-shadow:0 18px 55px rgba(0,0,0,.30);
padding:20px;
}
.card::before{
content:"";
position:absolute;
inset:0;
border-radius:inherit;
pointer-events:none;
background:linear-gradient(135deg,rgba(255,255,255,.10),transparent 28%);
opacity:.55;
}
.card>*{position:relative}
.card h3{
margin:0 0 14px;
font-size:17px;
letter-spacing:-.01em;
}
.metric{
padding:19px;
border-radius:20px;
background:
linear-gradient(135deg,rgba(200,164,93,.18),rgba(125,211,252,.06)),
rgba(255,255,255,.035);
border:1px solid var(--line);
}
.metric span{
color:var(--muted);
font-size:13px;
}
.metric strong{
display:block;
font-size:29px;
margin-top:8px;
letter-spacing:-.04em;
}
label{
display:block;
color:var(--soft);
font-size:12.5px;
font-weight:850;
margin:13px 0 7px;
}
input,select,textarea{
width:100%;
background:rgba(3,7,18,.72);
color:var(--text);
border:1px solid var(--line);
border-radius:14px;
padding:12px;
outline:none;
transition:.18s ease;
}
input:focus,select:focus,textarea:focus{
border-color:rgba(200,164,93,.58);
box-shadow:0 0 0 4px rgba(200,164,93,.10);
}
textarea{
min-height:96px;
resize:vertical;
}
.row{
display:grid;
grid-template-columns:1fr 1fr;
gap:12px;
}
.hidden{display:none!important}
.hint{
margin:9px 0 0;
color:var(--muted);
font-size:12px;
line-height:1.55;
}
.chips{
display:flex;
gap:8px;
flex-wrap:wrap;
margin-top:9px;
}
.chip{
padding:8px 11px;
border-radius:999px;
background:rgba(255,255,255,.055);
border:1px solid var(--line);
color:#dbeafe;
font-size:12px;
cursor:pointer;
transition:.18s ease;
}
.chip:hover{
color:#111827;
background:linear-gradient(145deg,var(--accent2),var(--accent));
}
pre{
margin:0;
background:
linear-gradient(180deg,rgba(255,255,255,.035),transparent),
#02050a;
border:1px solid var(--line);
border-radius:18px;
padding:18px;
min-height:560px;
max-height:72vh;
overflow:auto;
white-space:pre-wrap;
line-height:1.55;
color:#d1fae5;
box-shadow:inset 0 0 0 1px rgba(255,255,255,.02);
}
.flow{
background:rgba(2,5,10,.86);
border:1px solid var(--line);
border-radius:18px;
padding:15px;
color:#cbd5e1;
line-height:1.75;
margin-bottom:14px;
}
.floor,.reward,.fold{
border:1px solid var(--line);
border-radius:18px;
background:rgba(255,255,255,.028);
margin:12px 0;
overflow:hidden;
}
.fold>summary,.floor>summary{
list-style:none;
cursor:pointer;
padding:15px 16px;
display:flex;
align-items:center;
justify-content:space-between;
gap:14px;
font-weight:850;
color:var(--text);
background:
linear-gradient(90deg,rgba(200,164,93,.11),transparent 54%),
linear-gradient(180deg,rgba(255,255,255,.065),rgba(255,255,255,.020));
}
.fold>summary::-webkit-details-marker,.floor>summary::-webkit-details-marker{display:none}
.fold>summary::after,.floor>summary::after{
content:"Aç";
font-size:12px;
color:var(--accent2);
border:1px solid rgba(200,164,93,.35);
border-radius:999px;
padding:4px 10px;
background:rgba(200,164,93,.08);
}
.fold[open]>summary::after,.floor[open]>summary::after{content:"Kapat"}
.fold-body,.floor-body{padding:17px}
.floor-subtitle{
display:block;
margin-top:5px;
font-size:12px;
font-weight:450;
color:var(--muted);
}
.floor-actions{
display:flex;
gap:10px;
align-items:center;
justify-content:flex-end;
margin-top:13px;
}
.floor-actions button{margin-top:0}
.issue{
padding:12px;
border-radius:15px;
border:1px solid var(--line);
background:rgba(255,255,255,.04);
margin:8px 0;
}
.ok{border-color:rgba(110,231,183,.48)}
.warn{border-color:rgba(231,199,125,.54)}
.err{border-color:rgba(251,113,133,.50)}
.lib{
display:grid;
grid-template-columns:repeat(3,1fr);
gap:12px;
}
.lib-card{
padding:15px;
border-radius:18px;
background:rgba(255,255,255,.04);
border:1px solid var(--line);
}
.lib-card span{
color:var(--muted);
font-size:13px;
}
::-webkit-scrollbar{width:12px;height:12px}
::-webkit-scrollbar-track{background:#05070b}
::-webkit-scrollbar-thumb{background:#222b3a;border:3px solid #05070b;border-radius:999px}
::-webkit-scrollbar-thumb:hover{background:#364155}
@media(max-width:1180px){
body{padding:16px}
.app{grid-template-columns:1fr}
.sidebar{
position:relative;
top:auto;
height:auto;
border-radius:28px 28px 0 0;
border-right:0;
border-bottom:1px solid var(--line);
}
.split,.grid-2,.grid-3,.lib{grid-template-columns:1fr}
}
</style></head>
<body><div class="app">
<aside class="sidebar"><div class="brand"><div class="logo">M2</div><div><h1>Quest Oluşturucu</h1><p>Görev ve zindan üretim paneli</p></div></div><div class="nav">
<button class="active" onclick="showTab('dashboard',this)">🏠 Genel Bakış</button><button onclick="showTab('quest',this)">📜 Görev Oluşturucu</button><button onclick="showTab('dungeon',this)">🕯️ Zindan Akışı</button><button onclick="showTab('library',this)">📚 VNUM Kütüphanesi</button><button onclick="showTab('validator',this)">✅ Quest Kontrol</button></div>
<div class="side-card"><b>Çalışma Mantığı</b><p>Alanları doldurdukça sağ tarafta quest kodu ve açıklama yorumları otomatik oluşur.</p></div></aside>
<main><div class="topbar"><div class="title"><h2 id="pageTitle">Genel Bakış</h2><p id="pageDesc">Metin2 quest ve zindan kodlarını panelden üret.</p></div><div class="actions"><button class="ghost" onclick="copyQuest()">Kopyala</button><button class="success" onclick="downloadQuest()">.quest İndir</button><button class="warning" onclick="validateQuest(true)">Kontrol Et</button></div></div>
<section id="dashboard" class="tab"><div class="grid grid-3"><div class="metric"><span>Quest Modülü</span><strong>4 Tip</strong></div><div class="metric"><span>Zindan Kat Sistemi</span><strong>Dinamik</strong></div><div class="metric"><span>Kontrol Motoru</span><strong>Aktif</strong></div></div>
<div class="grid grid-2" style="margin-top:18px"><div class="card"><h3>Hızlı Başlangıç</h3><p style="color:var(--muted);line-height:1.7">Görev oluşturucu ile basit görevler, zindan akışı ile katlı sistemler oluştur. Sağ üstten kodu kopyalayabilir veya .quest olarak indirebilirsin.</p><div class="inline"><button class="primary" onclick="go('quest')">Quest Oluştur</button><button class="primary" onclick="go('dungeon')">Zindan Oluştur</button></div></div><div class="card"><h3>Son Akış</h3><div id="dashFlow" class="flow">Henüz kod üretilmedi.</div></div></div></section>
<section id="quest" class="tab hidden"><div class="split"><div class="card"><h3>Görev Oluşturucu</h3><label>Quest Tipi</label><select id="questType" onchange="generateQuest()"><option value="kill">Belirlenen mobdan istenen adet kadar kestir</option>
<option value="talk">Oyuncuyu seçilen NPC ile konuşturup görevi bitir</option>
<option value="biolog">Belirlenen itemleri NPC'ye teslim ettir</option>
<option value="daily">Her 24 saatte bir yapılabilen av görevi oluştur</option></select>
<div class="row"><div><label>Quest Dosya Adı</label><input id="questName" value="metin2_gorev" oninput="generateQuest()"></div><div><label>Görev Başlığı</label><input id="questTitle" value="Yeni Görev" oninput="generateQuest()"></div></div>
<div class="row">
<div>
<label>Başlama leveli</label>
<input id="level" type="number" value="30" oninput="generateQuest()">
</div>
<div>
<label>Kaç adet hedef tamamlanacak?</label>
<input id="targetCount" type="number" value="10" oninput="generateQuest()">
</div>
</div>
<p class="hint">Mob kesme ve günlük görevlerde bu alan “kaç adet mob kesilecek” anlamına gelir. Biyolog görevinde “kaç item teslim edilecek” olarak kullanılır.</p>
<label>NPC Ara</label><input id="npcSearch" oninput="searchList('npc')" placeholder="Uriel, Biyolog..."><div id="npcChips" class="chips"></div><div class="row"><div><label>NPC Adı</label><input id="npcName" value="Uriel" oninput="generateQuest()"></div><div><label>NPC VNUM</label><input id="npcVnum" value="20011" oninput="generateQuest()"></div></div>
<details class="fold" open>
<summary>Kesilecek mob bilgileri</summary>
<div class="fold-body">
<label>Mob ara ve seç</label>
<input id="mobSearch" oninput="searchList('mob')" placeholder="Yabani Köpek, Ork, Azrail...">
<div id="mobChips" class="chips"></div>
<div class="row">
<div>
<label>Kesilecek mob adı</label>
<input id="mobName" value="Yabani Köpek" oninput="generateQuest()">
</div>
<div>
<label>Kesilecek mob VNUM</label>
<input id="mobVnum" value="101" oninput="generateQuest()">
</div>
</div>
<p class="hint">Bu bilgiler quest içindeki <code>when MOB_VNUM.kill</code> satırını oluşturur.</p>
</div>
</details>
<label>Açıklama</label><textarea id="description" oninput="generateQuest()">Bu görevi tamamlayarak ödül kazanabilirsin.</textarea><h3>Çoklu Ödül</h3><div id="rewards"></div><button class="ghost" onclick="addReward(false)">+ Ödül Ekle</button><div class="inline"><button class="primary" onclick="generateQuest()">Quest Oluştur</button></div></div>
<div class="card"><h3>Önizleme</h3><div id="flow" class="flow"></div><pre id="output"></pre></div></div></section>
<section id="dungeon" class="tab hidden">
<div class="split">
<div class="card">
<h3>Zindan Akışı</h3>
<details class="fold" open>
<summary>Başlangıç Bilgileri</summary>
<div class="fold-body">
<label>Hazır Şablon</label>
<select id="template" onchange="applyTemplate()">
<option value="">Şablon seç</option>
<option value="tower">Şeytan Kulesi benzeri sıralı zindan</option>
<option value="boss">Mob temizleyip boss kesilen arena</option>
<option value="key">Anahtar veya harita toplayarak ilerlenen zindan</option>
<option value="metin">Metin taşı kırarak ilerlenen zindan</option>
</select>
<div class="row">
<div><label>Zindan Quest Adı</label><input id="dQuestName" value="custom_zindan" oninput="generateDungeon()"></div>
<div><label>Giriş Başlığı</label><input id="dTitle" value="Zindana Gir" oninput="generateDungeon()"></div>
</div>
<div class="row">
<div><label>Giriş NPC VNUM</label><input id="dNpcVnum" value="20011" oninput="generateDungeon()"></div>
<div><label>Min Level</label><input id="dLevel" type="number" value="75" oninput="generateDungeon()"></div>
</div>
</div>
</details>
<details class="fold">
<summary>Harita ve Süre Ayarları</summary>
<div class="fold-body">
<div class="row">
<div><label>Dungeon Map Index</label><input id="dMap" value="66" oninput="generateDungeon()"></div>
<div><label>Süre / Dakika</label><input id="dMinutes" type="number" value="60" oninput="generateDungeon()"></div>
</div>
<div class="row">
<div><label>Giriş X</label><input id="dX" value="5905" oninput="generateDungeon()"></div>
<div><label>Giriş Y</label><input id="dY" value="1105" oninput="generateDungeon()"></div>
</div>
<div class="row">
<div><label>Çıkış Map</label><input id="exitMap" value="1" oninput="generateDungeon()"></div>
<div><label>Cooldown / Dakika</label><input id="cooldown" type="number" value="0" oninput="generateDungeon()"></div>
</div>
</div>
</details>
<details class="fold">
<summary>Giriş Şartları</summary>
<div class="fold-body">
<div class="row">
<div><label>Giriş Item VNUM</label><input id="entryItem" value="0" oninput="generateDungeon()"></div>
<div><label>Giriş Yang</label><input id="entryYang" type="number" value="0" oninput="generateDungeon()"></div>
</div>
<div class="row">
<div>
<label>Parti Gerekli</label>
<select id="partyReq" onchange="generateDungeon()">
<option value="no">Hayır</option>
<option value="yes">Evet</option>
</select>
</div>
<div><label>Min Parti Üye</label><input id="minParty" type="number" value="2" oninput="generateDungeon()"></div>
</div>
</div>
</details>
<details class="fold" open>
<summary>Katlar</summary>
<div class="fold-body">
<div id="floors"></div>
<div class="inline">
<button class="ghost" onclick="addFloor('kill')">+ Mob Katı</button>
<button class="ghost" onclick="addFloor('drop')">+ Drop Katı</button>
<button class="ghost" onclick="addFloor('boss')">+ Boss Katı</button>
<button class="ghost" onclick="addFloor('metin')">+ Metin Katı</button>
</div>
</div>
</details>
<details class="fold">
<summary>Zindan Ödülleri</summary>
<div class="fold-body">
<div id="dRewards"></div>
<button class="ghost" onclick="addReward(true)">+ Zindan Ödülü Ekle</button>
</div>
</details>
</div>
<div class="card">
<h3>Zindan Önizleme</h3>
<div id="dFlow" class="flow"></div>
<pre id="dOutput"></pre>
</div>
</div>
</section>
<section id="library" class="tab hidden"><div class="card"><h3>VNUM Kütüphanesi</h3><p style="color:var(--muted)">Şimdilik örnek veriler var. Sonraki aşamada mob_names.txt ve item_names.txt import eklenebilir.</p><div id="libraryList" class="lib"></div></div></section>
<section id="validator" class="tab hidden"><div class="card"><h3>Quest Kontrol Paneli</h3><button class="warning" onclick="validateQuest(false)">Kontrol Et</button><div id="issues" style="margin-top:14px"></div></div></section>
</main></div>
<script>
const npcs=[["Uriel",20011],["Biyolog Chaegirab",20084],["Demirci",20016],["Depocu",9005],["Yaşlı Kadın",9006],["Kapıcı",20348],["Genel Satıcı",9003]];
const mobs=[["Yabani Köpek",101],["Ork",601],["Siyah Ork",636],["Zehirli Örümcek",2031],["Kraliçe Örümcek",2091],["Azrail",1093],["Mavi Ejderha",2493],["Metin Taşı",8001]];
const items=[["Dolunay Kılıcı",19],["Kutsama Kağıdı",25040],["Beceri Kitabı",50300],["Ruh Taşı",50513],["Ork Dişi",30006],["Anahtar",50084],["Harita",30179],["Giriş Bileti",71130]];
function byId(id){return document.getElementById(id)} function val(id,f=""){return byId(id)?.value||f}
function clean(s){return String(s||"quest").toLowerCase().replaceAll("ı","i").replaceAll("ğ","g").replaceAll("ü","u").replaceAll("ş","s").replaceAll("ö","o").replaceAll("ç","c").replace(/[^a-z0-9_]/g,"_")}
function esc(s){return String(s||"").replaceAll('"',"'")}
function showTab(name,btn){document.querySelectorAll(".tab").forEach(t=>t.classList.add("hidden"));byId(name).classList.remove("hidden");document.querySelectorAll(".nav button").forEach(b=>b.classList.remove("active"));if(btn)btn.classList.add("active");const m={dashboard:["Genel Bakış","Metin2 quest ve zindan kodlarını panelden üret."],quest:["Quest Builder","Normal görev, günlük görev ve biyolog questleri oluştur."],dungeon:["Dungeon Builder","Katlı zindan, drop, boss, giriş şartı ve ödül sistemi kur."],library:["VNUM Kütüphanesi","NPC, mob ve item VNUM listelerini yönet."],validator:["Quest Kontrol","Üretilen kodu hata ve eksik bilgi açısından kontrol et."]};byId("pageTitle").textContent=m[name][0];byId("pageDesc").textContent=m[name][1]}
function go(name){showTab(name,[...document.querySelectorAll(".nav button")].find(b=>b.textContent.toLowerCase().includes(name==="quest"?"quest":name==="dungeon"?"dungeon":name)))}
function searchList(type){const data=type==="npc"?npcs:mobs,q=val(type+"Search").toLowerCase(),box=byId(type+"Chips");box.innerHTML="";data.filter(x=>x[0].toLowerCase().includes(q)).slice(0,8).forEach(x=>{const c=document.createElement("span");c.className="chip";c.textContent=`${x[0]} (${x[1]})`;c.onclick=()=>{if(type==="npc"){byId("npcName").value=x[0];byId("npcVnum").value=x[1]}else{byId("mobName").value=x[0];byId("mobVnum").value=x[1]}generateQuest()};box.appendChild(c)})}
function addReward(d=false){const wrap=document.createElement("div");wrap.className="reward";wrap.dataset.reward="1";wrap.innerHTML=`<div class="row"><div><label>Item VNUM</label><input value="25040" data-field="item" oninput="${d?'generateDungeon':'generateQuest'}()"></div><div><label>Adet</label><input type="number" value="1" data-field="count" oninput="${d?'generateDungeon':'generateQuest'}()"></div></div><label>Yang</label><input type="number" value="0" data-field="yang" oninput="${d?'generateDungeon':'generateQuest'}()"><button class="danger" onclick="this.parentElement.remove();${d?'generateDungeon':'generateQuest'}()">Sil</button>`;byId(d?"dRewards":"rewards").appendChild(wrap);d?generateDungeon():generateQuest()}
function rewardCode(container){let code="";byId(container).querySelectorAll("[data-reward]").forEach(b=>{const item=b.querySelector('[data-field="item"]').value,count=b.querySelector('[data-field="count"]').value,yang=b.querySelector('[data-field="yang"]').value;if(Number(yang)>0)code+=` pc.change_money(${yang})\n`;if(Number(item)>0)code+=` pc.give_item2(${item}, ${count})\n`});return code||" -- Ödül eklenmedi\n"}
function generateQuest(){const type=val("questType"),q=clean(val("questName")),title=esc(val("questTitle")),level=val("level"),target=val("targetCount"),npc=val("npcVnum"),npcName=esc(val("npcName")),mob=val("mobVnum"),mobName=esc(val("mobName")),desc=esc(val("description"));let code="",flow="";
if(type==="talk"){flow=`${level}. level → ${npcName} ile konuş → ödül al`;code=`quest ${q} begin\n state start begin\n when login or levelup with pc.get_level() >= ${level} begin set_state(run) end\n end\n state run begin\n when letter begin send_letter("${title}") end\n when ${npc}.chat."${title}" begin\n say_title("${npcName}") say("${desc}")\n${rewardCode("rewards")} set_state(__COMPLETE__)\n end\n end\n state __COMPLETE__ begin end\nend`}
else{flow=`${level}. level → ${npcName} görev verir → ${target} ${mobName} hedefi → ödül`;code=`quest ${q} begin\n state start begin\n when login or levelup with pc.get_level() >= ${level} begin set_state(run) end\n end\n state run begin\n when letter begin send_letter("${title}") end\n when ${npc}.chat."${title}" begin\n say_title("${npcName}") say("${desc}") say("${target} tane ${mobName} öldür.")\n pc.setqf("count",0) set_state(hunt)\n end\n end\n state hunt begin\n when ${mob}.kill begin\n local c=pc.getqf("count")+1 pc.setqf("count",c)\n if c >= ${target} then\n say_title("${title}") say("Görev tamamlandı.")\n${rewardCode("rewards")} set_state(__COMPLETE__)\n end\n end\n end\n state __COMPLETE__ begin end\nend`}
byId("flow").innerHTML=flow;byId("output").textContent=code;byId("dashFlow").textContent=flow}
function floorTypeLabel(type){
if(type==="drop") return "Drop Katı";
if(type==="boss") return "Boss Katı";
if(type==="metin") return "Metin Taşı Katı";
return "Mob Kesme Katı";
}
function updateFloorHeaders(){
[...byId("floors").querySelectorAll(".floor")].forEach((el,i)=>{
const type=el.querySelector('[data-f="type"]')?.value || "kill";
const vnum=el.querySelector('[data-f="vnum"]')?.value || "0";
const count=el.querySelector('[data-f="count"]')?.value || "1";
const drop=el.querySelector('[data-f="dropItem"]')?.value || "0";
const title=el.querySelector(".floor-title");
const sub=el.querySelector(".floor-subtitle");
if(title) title.textContent=`${i+1}. Kat — ${floorTypeLabel(type)}`;
if(sub){
if(type==="drop") sub.textContent=`Hedef VNUM: ${vnum} · Drop Item: ${drop}`;
else sub.textContent=`Hedef VNUM: ${vnum} · Hedef Sayı: ${count}`;
}
});
}
function addFloor(type="kill"){
const el=document.createElement("details");
el.className="floor";
el.open=true;
el.innerHTML=`<summary><span><span class="floor-title">Kat</span><span class="floor-subtitle">Ayarlar</span></span></summary>
<div class="floor-body">
<div class="row">
<div>
<label>Katın amacı</label>
<select data-f="type" onchange="updateFloorHeaders();generateDungeon()">
<option value="kill">Oyuncu bu katta belirlenen mobları keser</option>
<option value="drop">Oyuncu bu katta anahtar/harita/mühür düşürür</option>
<option value="boss">Oyuncu bu katta boss öldürür</option>
<option value="metin">Oyuncu bu katta metin taşı kırar</option>
</select>
</div>
<div>
<label>Hedef VNUM</label>
<input data-f="vnum" value="${type==='boss'?1093:type==='metin'?8001:601}" oninput="updateFloorHeaders();generateDungeon()">
</div>
</div>
<div class="row">
<div>
<label>Hedef Sayı</label>
<input data-f="count" type="number" value="${type==='boss'?1:50}" oninput="updateFloorHeaders();generateDungeon()">
</div>
<div>
<label>Spawn X,Y</label>
<input data-f="spawn" value="6000,1200" oninput="generateDungeon()">
</div>
</div>
<details class="fold">
<summary>Drop Ayarları</summary>
<div class="fold-body">
<div class="row">
<div>
<label>Düşecek Item VNUM</label>
<input data-f="dropItem" value="50084" oninput="updateFloorHeaders();generateDungeon()">
</div>
<div>
<label>Düşme Şansı %</label>
<input data-f="chance" type="number" value="15" oninput="generateDungeon()">
</div>
</div>
<div class="row">
<div>
<label>Kaç kill sonra garanti düşsün?</label>
<input data-f="guarantee" type="number" value="20" oninput="generateDungeon()">
</div>
<div>
<label>Kaç item toplanınca kat geçilsin?</label>
<input data-f="need" type="number" value="1" oninput="generateDungeon()">
</div>
</div>
</div>
</details>
<div class="floor-actions">
<button class="danger" onclick="this.closest('.floor').remove();updateFloorHeaders();generateDungeon()">Katı Sil</button>
</div>
</div>`;
el.querySelector('[data-f="type"]').value=type;
byId("floors").appendChild(el);
updateFloorHeaders();
generateDungeon();
}
function floorData(){return[...byId("floors").querySelectorAll(".floor")].map((el,i)=>{const g=k=>el.querySelector(`[data-f="${k}"]`).value;return{no:i+1,type:g("type"),vnum:g("vnum"),count:g("count"),dropItem:g("dropItem"),chance:g("chance"),guarantee:g("guarantee"),need:g("need")}})}
function applyTemplate(){byId("floors").innerHTML="";const t=val("template");if(t==="tower"){addFloor("kill");addFloor("drop");addFloor("metin");addFloor("boss")}if(t==="boss"){addFloor("kill");addFloor("boss")}if(t==="key"){addFloor("drop");addFloor("boss")}if(t==="metin"){addFloor("metin");addFloor("boss")}generateDungeon()}
function generateDungeon(){const q=clean(val("dQuestName","custom_zindan")),title=esc(val("dTitle")),npc=val("dNpcVnum"),level=val("dLevel"),map=val("dMap"),x=val("dX"),y=val("dY"),mins=val("dMinutes"),cd=Number(val("cooldown",0))*60,entryItem=val("entryItem",0),entryYang=val("entryYang",0),party=val("partyReq"),minParty=val("minParty");const fs=floorData();updateFloorHeaders();let body="",flow=`Giriş NPC → Level ${level}+ → ${fs.length} kat → Ödül`;
fs.forEach(f=>{if(f.type==="drop"){body+=`\n when ${f.vnum}.kill with pc.in_dungeon() begin\n if d.getf("floor") == ${f.no} then\n local c=d.getf("drop_${f.no}_kill")+1 d.setf("drop_${f.no}_kill",c)\n if number(1,100) <= ${f.chance} or c >= ${f.guarantee} then\n game.drop_item_with_ownership(${f.dropItem},1) d.setf("drop_${f.no}_kill",0) notice("Gerekli item düştü.")\n end\n end\n end\n when ${f.dropItem}.use with pc.in_dungeon() begin\n if d.getf("floor") == ${f.no} then item.remove() local k=d.getf("drop_${f.no}_item")+1 d.setf("drop_${f.no}_item",k) if k >= ${f.need} then d.setf("floor",${f.no+1}) end end\n end`}else{body+=`\n when ${f.vnum}.kill with pc.in_dungeon() begin\n if d.getf("floor") == ${f.no} then\n local c=d.getf("floor_${f.no}_count")+1 d.setf("floor_${f.no}_count",c)\n if c >= ${f.count} then notice("${f.no}. kat tamamlandı.") d.setf("floor",${f.no+1}) end\n end\n end`}})
const partyCode=party==="yes"?`\n if not party.is_party() or not party.is_leader() then say("Sadece parti lideri giriş yapabilir.") return end\n if party.get_near_count() + 1 < ${minParty} then say("Yeterli parti üyesi yok.") return end`:"";const entryCode=(Number(entryItem)>0?`\n if pc.count_item(${entryItem}) < 1 then say("Giriş biletin yok.") return end\n pc.remove_item(${entryItem},1)`:"")+(Number(entryYang)>0?`\n if pc.get_money() < ${entryYang} then say("Yeterli yang yok.") return end\n pc.change_money(-${entryYang})`:"");const cdCode=cd>0?`\n if pc.getqf("last_enter") > 0 and get_time() < pc.getqf("last_enter") + ${cd} then say("Cooldown süren dolmadı.") return end\n pc.setqf("last_enter", get_time())`:"";
const code=`quest ${q} begin\n state start begin\n when ${npc}.chat."${title}" begin\n say_title("${title}")\n if pc.get_level() < ${level} then say("Levelin yetersiz.") return end${partyCode}${entryCode}${cdCode}\n local s=select("Gir","Vazgeç") if s==2 then return end\n d.new_jump(${map},${x},${y}) d.setf("floor",1)\n server_timer("${q}_timer",${Number(mins)*60},d.get_map_index())\n end${body}\n when login with pc.in_dungeon() begin\n if d.getf("floor") > ${fs.length} then\n notice("Zindan tamamlandı.")\n${rewardCode("dRewards")} d.exit_all()\n end\n end\n when ${q}_timer.server_timer begin\n if d.select(get_server_timer_arg()) then notice("Zindan süresi doldu.") d.exit_all() end\n end\n end\nend`;byId("dFlow").innerHTML=flow;byId("dOutput").textContent=code;byId("dashFlow").textContent=flow}
function currentCode(){return byId("dungeon").classList.contains("hidden")?byId("output").textContent:byId("dOutput").textContent}function copyQuest(){navigator.clipboard.writeText(currentCode());alert("Kod kopyalandı.")}
function downloadQuest(){const code=currentCode(),name=byId("dungeon").classList.contains("hidden")?clean(val("questName")):clean(val("dQuestName"));const a=document.createElement("a");a.href=URL.createObjectURL(new Blob([code],{type:"text/plain;charset=utf-8"}));a.download=name+".quest";a.click()}
function validateQuest(jump){const code=currentCode(),issues=[];if(!code.trim())issues.push(["err","Kod üretilmemiş."]);if(code.includes(" 0)")||code.includes(" 0,"))issues.push(["warn","Bazı VNUM değerleri 0 olabilir."]);if(!code.includes("quest "))issues.push(["err","Quest başlangıcı bulunamadı."]);if(!issues.length)issues.push(["ok","Kontrol tamam: belirgin hata görünmüyor."]);byId("issues").innerHTML=issues.map(i=>`<div class="issue ${i[0]}">${i[1]}</div>`).join("");if(jump)go("validator")}
function renderLibrary(){const box=byId("libraryList");box.innerHTML="";[...npcs.map(x=>["NPC",...x]),...mobs.map(x=>["Mob",...x]),...items.map(x=>["Item",...x])].forEach(x=>{const d=document.createElement("div");d.className="lib-card";d.innerHTML=`<b>${x[1]}</b><span>${x[0]} VNUM: ${x[2]}</span>`;box.appendChild(d)})}
addReward(false);addReward(true);addFloor("kill");addFloor("boss");searchList("npc");searchList("mob");renderLibrary();generateQuest();generateDungeon();
</script></body></html>
En Çok Reaksiyon Alan Mesajlar
Rica ederimEline sağlık paylaşım için teşekkürler
Evet Chatgpt ile hazırlandıyapay zeka
Rice ederimPaylaşım için Teşekkürler
Şuan için emekliyoruz abi umarım bir gün koşmakta nasip olurYapıyorsun bu sporu Alicim eline sağlık![]()
Teşekkür ederim, iyi kullanımlar.eline sağlık paylaşım için teşekkürler.
Şu an konuyu görüntüleyenler (Toplam : 0, Üye: 0, Misafir: 0)
Benzer konular
- Cevaplar
- 4
- Görüntüleme
- 299
- Cevaplar
- 2
- Görüntüleme
- 60
- Cevaplar
- 0
- Görüntüleme
- 97
- Cevaplar
- 0
- Görüntüleme
- 117
- Cevaplar
- 0
- Görüntüleme
- 142
