Register for your free account! | Forgot your password?

Go Back   elitepvpers > MMORPGs > Shaiya > Shaiya Private Server > Shaiya PServer Development
You last visited: Today at 19:50

  • Please register to post and access all features, it's quick, easy and FREE!

Advertisement



hello help codding for edit quest via python and use json files

Discussion on hello help codding for edit quest via python and use json files within the Shaiya PServer Development forum part of the Shaiya Private Server category.

Reply
 
Old   #1
 
[DEV]_Yûko's Avatar
 
elite*gold: 105
Join Date: Jun 2015
Posts: 135
Received Thanks: 74
Wink hello help codding for edit quest via python and use json files

import json
import tkinter as tk
from tkinter import filedialog, messagebox, ttk

class ShaiyaQuestEditor(tk.Tk):
def __init__(self):
super().__init__()
self.title("Shaiya Quest Editor - Dark Mode")
self.geometry("1200x900")
# Theme colors
self.dark_bg = '#2e2e2e'
self.dark_fg = '#ffffff'
self.field_bg = '#3e3e3e'
self.highlight = '#444444'

self.configure(bg=self.dark_bg, padx=10, pady=10)
# Apply dark theme to ttk
style = ttk.Style(self)
style.theme_use('clam')
style.configure('.', background=self.dark_bg, foreground=self.dark_fg)
style.configure('TFrame', background=self.dark_bg)
style.configure('TLabelFrame', background=self.dark_bg, foreground=self.dark_fg)
style.configure('TLabel', background=self.dark_bg, foreground=self.dark_fg)
style.configure('TEntry', fieldbackground=self.field_bg, background=self.field_bg, foreground=self.dark_fg)
style.configure('TCheckbutton', background=self.dark_bg, foreground=self.dark_fg)
style.configure('TButton', background=self.highlight, foreground=self.dark_fg)
style.map('TButton', background=[('active', '#5e5e5e')])

self.data = None
self.current_quest = None
self.file_path = None

self.build_ui()

def create_tooltip(self, widget, text):
tooltip = tk.Toplevel(widget)
tooltip.withdraw()
tooltip.wm_overrideredirect(True)
label = tk.Label(tooltip, text=text, background=self.highlight, foreground=self.dark_fg, relief="solid", borderwidth=1, padx=5, pady=3)
label.pack()

def on_enter(event):
x = widget.winfo_rootx() + 20
y = widget.winfo_rooty() + widget.winfo_height() + 5
tooltip.geometry(f"+{x}+{y}")
tooltip.deiconify()

def on_leave(event):
tooltip.withdraw()

widget.bind("<Enter>", on_enter)
widget.bind("<Leave>", on_leave)

def style_text(self, txt):
txt.configure(bg=self.field_bg, fg=self.dark_fg, insertbackground=self.dark_fg, wrap='word')
txt.tag_configure('center', justify='center')

def build_ui(self):
# Top controls
top = ttk.Frame(self)
top.pack(fill="x", pady=(0, 10))
ttk.Button(top, text="Charger JSON", command=self.load_json).pack(side="left")
ttk.Label(top, text="Quest ID:").pack(side="left", padx=(20, 5))
self.quest_id_entry = ttk.Entry(top, width=8, justify='center')
self.quest_id_entry.pack(side="left")
ttk.Button(top, text="Afficher Quête", command=self.load_quest).pack(side="left", padx=(5, 0))

# Scrollable container
container = ttk.Frame(self)
container.pack(fill="both", expand=True)
canvas = tk.Canvas(container, bg=self.dark_bg, highlightthickness=0)
scrollbar = ttk.Scrollbar(container, orient="vertical", command=canvas.yview)
self.scrollable_frame = ttk.Frame(canvas)
self.scrollable_frame.bind(
"<Configure>",
lambda e: canvas.configure(scrollregion=canvas.bbox("all"))
)
canvas.create_window((0, 0), window=self.scrollable_frame, anchor="nw")
canvas.configure(yscrollcommand=scrollbar.set)
canvas.pack(side="left", fill="both", expand=True)
scrollbar.pack(side="right", fill="y")

# Quest Info section
info_frame = ttk.LabelFrame(self.scrollable_frame, text="Quest Info", padding=(10, 10))
info_frame.pack(fill="x", pady=(0, 10))
self.info_fields = {}
info_labels = [
("Name:", "name", "Nom de la quête"),
("Type:", "questType", "Type de quête (PVE/PVP/Collecte/Dialogue)"),
("Source:", "obtained", "Origine de la quête (NPC, Item...)"),
("Faction:", "faction", "Faction ciblée (Any, Light, Fury...)"),
("Mode:", "mode", "Difficulté de la quête"),
]
for idx, (lbl, key, tip) in enumerate(info_labels):
ttk.Label(info_frame, text=lbl).grid(row=0, column=idx*2, sticky="w", padx=(0,5))
entry = ttk.Entry(info_frame, width=18, justify='center')
entry.grid(row=0, column=idx*2+1, sticky="w", padx=(0,15))
self.info_fields[key] = entry
self.create_tooltip(entry, tip)

# Classes section
class_frame = ttk.LabelFrame(self.scrollable_frame, text="Classes Autorisées", padding=(10, 10))
class_frame.pack(fill="x", pady=(0, 10))
self.class_vars = {}
classes = ["Fighter", "Defender", "Ranger", "Archer", "Mage", "Priest"]
for i, cls in enumerate(classes):
var = tk.BooleanVar()
cb = ttk.Checkbutton(class_frame, text=cls, variable=var)
cb.grid(row=0, column=i, padx=5, sticky="w")
self.class_vars[cls.lower()] = var
self.create_tooltip(cb, f"Autoriser la classe {cls}")

# Settings section
setting_frame = ttk.LabelFrame(self.scrollable_frame, text="Settings", padding=(10, 10))
setting_frame.pack(fill="x", pady=(0, 10))
self.setting_fields = {}
settings = [
("Level Min", "minLevel", "Niveau minimum requis"),
("Level Max", "maxLevel", "Niveau maximum requis"),
("Start NPC ID", "startNpcId", "ID du PNJ de départ"),
("Start NPC Type", "startNpcType", "Type du PNJ de départ"),
("End NPC ID", "endNpcId", "ID du PNJ de fin"),
("End NPC Type", "endNpcType", "Type du PNJ de fin"),
("Requires Items", "requires", "Nombre d'items requis"),
]
for idx, (lbl, key, tip) in enumerate(settings):
ttk.Label(setting_frame, text=lbl).grid(row=0, column=idx*2, sticky="w", padx=(0,5))
entry = ttk.Entry(setting_frame, width=8, justify='center')
entry.grid(row=0, column=idx*2+1, sticky="w", padx=(0,15))
self.setting_fields[key] = entry
self.create_tooltip(entry, tip)
self.repeat_var = tk.BooleanVar()
cb = ttk.Checkbutton(setting_frame, text="Repeatable", variable=self.repeat_var)
cb.grid(row=0, column=len(settings)*2, padx=5)
self.create_tooltip(cb, "Quête répétable")

# Objectives section
obj_frame = ttk.LabelFrame(self.scrollable_frame, text="Objectives", padding=(10, 10))
obj_frame.pack(fill="x", pady=(0, 10))
ttk.Label(obj_frame, text="Received Items").grid(row=0, column=0, columnspan=3, sticky="w")
self.received_items = []
for r in range(3):
row_fields = {}
for c, key in enumerate(["type", "typeId", "count"]):
entry = ttk.Entry(obj_frame, width=6, justify='center')
entry.grid(row=r+1, column=c, padx=5, pady=2)
row_fields[key] = entry
self.create_tooltip(entry, f"{key} pour received item {r+1}")
self.received_items.append(row_fields)
ttk.Label(obj_frame, text="Items to Farm").grid(row=0, column=4, columnspan=3, sticky="w", padx=(20,0))
self.farm_items = []
for r in range(3):
row_fields = {}
for c, key in enumerate(["type", "typeId", "count"]):
entry = ttk.Entry(obj_frame, width=6, justify='center')
entry.grid(row=r+1, column=4+c, padx=5, pady=2)
row_fields[key] = entry
self.create_tooltip(entry, f"{key} pour farm item {r+1}")
self.farm_items.append(row_fields)
ttk.Label(obj_frame, text="Mobs to Fight").grid(row=0, column=8, sticky="w", padx=(20,0))
self.mob_type = ttk.Entry(obj_frame, width=6, justify='center')
self.mob_type.grid(row=1, column=8, padx=5, pady=2)
self.create_tooltip(self.mob_type, "ID du mob à tuer")
self.mob_count = ttk.Entry(obj_frame, width=6, justify='center')
self.mob_count.grid(row=1, column=9, padx=5, pady=2)
self.create_tooltip(self.mob_count, "Nombre de mobs à tuer")
ttk.Label(obj_frame, text="PvP Kills").grid(row=0, column=10, sticky="w", padx=(20,0))
self.pvp_kills = ttk.Entry(obj_frame, width=6, justify='center')
self.pvp_kills.grid(row=1, column=10, padx=5, pady=2)
self.create_tooltip(self.pvp_kills, "Nombre de kills en PvP")

# Descriptions & Messages section
desc_frame = ttk.LabelFrame(self.scrollable_frame, text="Descriptions & Messages", padding=(10, 10))
desc_frame.pack(fill="both", expand=True, pady=(0,10))
self.desc_fields = {}
descs = [
("Welcome Msg", "welcomeMsg"),
("Initial Description", "initialDescription"),
("Summary", "summary"),
("Reminder Instructions", "reminderInstructions"),
("Alternate Response", "alternateResponse"),
]
for i, (lbl, key) in enumerate(descs):
ttk.Label(desc_frame, text=lbl).grid(row=i, column=0, sticky="nw", pady=2)
txt = tk.Text(desc_frame, height=3, width=100)
self.style_text(txt)
txt.grid(row=i, column=1, padx=5, pady=2)
self.desc_fields[key] = txt
self.create_tooltip(txt, f"Champ {lbl}")
for j in range(6):
lbl = f"Completion Msg {j+1}" if j==0 else f"Alternate Completion Msg {j+1}"
key = "completionMessage" + ("" if j==0 else str(j+1))
ttk.Label(desc_frame, text=lbl).grid(row=len(descs)+j, column=0, sticky="nw", pady=2)
txt = tk.Text(desc_frame, height=2, width=100)
self.style_text(txt)
txt.grid(row=len(descs)+j, column=1, padx=5, pady=2)
self.desc_fields[key] = txt
self.create_tooltip(txt, f"Message de complétion #{j+1}")

# Rewards section
rew_frame = ttk.LabelFrame(self.scrollable_frame, text="Rewards", padding=(10, 10))
rew_frame.pack(fill="both", expand=True)
headers = ["Use", "MobCnt", "ItemCnt", "Gold", "XP",
"Type1", "TypeID1", "Count1",
"Type2", "TypeID2", "Count2",
"Type3", "TypeID3", "Count3", "Unlock"]
for c, h in enumerate(headers):
ttk.Label(rew_frame, text=h).grid(row=0, column=c, padx=5, pady=2)
self.reward_rows = []
for r in range(6):
row_vars = {}
var = tk.BooleanVar()
cb = ttk.Checkbutton(rew_frame, variable=var)
cb.grid(row=r+1, column=0)
row_vars['use'] = var
for c, key in enumerate(headers[1:], start=1):
ent = ttk.Entry(rew_frame, width=6, justify='center')
ent.grid(row=r+1, column=c, padx=5, pady=2)
row_vars[key.lower()] = ent
self.create_tooltip(ent, f"Champ {key} ligne {r+1}")
self.reward_rows.append(row_vars)
self.default_var = tk.BooleanVar()
cbd = ttk.Checkbutton(rew_frame, text="Give default reward", variable=self.default_var)
cbd.grid(row=7, column=0, columnspan=3, pady=(5,0))
self.create_tooltip(cbd, "Activer la récompense par défaut")

# Save button
save_btn = ttk.Button(self, text="Sauvegarder Tout", command=self.save_quest)
save_btn.pack(pady=(10,0))

def load_json(self):
path = filedialog.askopenfilename(filetypes=[("JSON files","*.json")])
if not path: return
with open(path,'r',encoding='utf-8') as f:
self.data = json.load(f)
self.file_path = path
messagebox.showinfo("Chargé","Fichier JSON chargé avec succès.")

def load_quest(self):
if not self.data or "quests" not in self.data:
messagebox.showerror("Erreur","Fichier non chargé ou invalide.")
return
try:
qid = int(self.quest_id_entry.get())
except:
messagebox.showerror("Erreur","ID invalide.")
return
for quest in self.data["quests"]:
if quest.get("id") == qid:
self.current_quest = quest
break
else:
messagebox.showerror("Erreur","Quête non trouvée.")
return

# Fill fields
for key, ent in self.info_fields.items(): ent.delete(0, tk.END); ent.insert(0, str(self.current_quest.get(key, "")))
for cls, var in self.class_vars.items(): var.set(self.current_quest.get(cls, False))
for key, ent in self.setting_fields.items(): ent.delete(0, tk.END); ent.insert(0, str(self.current_quest.get(key, 0)))
self.repeat_var.set(self.current_quest.get("repeat able", False))
for idx, row in enumerate(self.received_items):
data = self.current_quest.get("requiredItems", [])
val = data[idx] if idx < len(data) else {"type":0,"typeId":0,"count":0}
for k, ent in row.items(): ent.delete(0, tk.END); ent.insert(0, str(val.get(k, 0)))
for idx, row in enumerate(self.farm_items):
data = self.current_quest.get("farmItems", [])
val = data[idx] if idx < len(data) else {"type":0,"typeId":0,"count":0}
for k, ent in row.items(): ent.delete(0, tk.END); ent.insert(0, str(val.get(k, 0)))
self.mob_type.delete(0, tk.END); self.mob_type.insert(0, str(self.current_quest.get("requiredMobId1", 0)))
self.mob_count.delete(0, tk.END); self.mob_count.insert(0, str(self.current_quest.get("requiredMobCount1", 0)))
self.pvp_kills.delete(0, tk.END); self.pvp_kills.insert(0, str(self.current_quest.get("pvpKillCount", 0)))
for key, txt in self.desc_fields.items(): txt.delete("1.0", tk.END); txt.insert("1.0", self.current_quest.get(key, "")); txt.tag_add('center', '1.0', 'end')
results = self.current_quest.get("results", [])
mapping = {
'mobcnt':'needMobCount','itemcnt':'needItemCount', 'gold':'money','xp':'exp',
'type1':'itemType1','typeid1':'itemTypeId1','count 1':'itemCount1',
'type2':'itemType2','typeid2':'itemTypeId2','count 2':'itemCount2',
'type3':'itemType3','typeid3':'itemTypeId3','count 3':'itemCount3','unlock':'nextQuestId'
}
for r, row in enumerate(self.reward_rows):
row['use'].set(r < len(results))
if r < len(results):
res = results[r]
for key, ent in row.items():
if key == 'use': continue
ent.delete(0, tk.END)
ent.insert(0, str(res.get(mapping.get(key, key), 0)))
self.default_var.set(False)

def save_quest(self):
if not self.current_quest: messagebox.showerror("Erreur","Aucune quête chargée."); return
for key, ent in self.info_fields.items(): self.current_quest[key] = ent.get()
for cls, var in self.class_vars.items(): self.current_quest[cls] = var.get()
for key, ent in self.setting_fields.items():
try: self.current_quest[key] = int(ent.get())
except: self.current_quest[key] = 0
self.current_quest['repeatable'] = self.repeat_var.get()
self.current_quest['requiredItems'] = [{k:int(row[k].get()) for k in row} for row in self.received_items]
self.current_quest['farmItems'] = [{k:int(row[k].get()) for k in row} for row in self.farm_items]
try: self.current_quest['requiredMobId1'] = int(self.mob_type.get())
except: self.current_quest['requiredMobId1'] = 0
try: self.current_quest['requiredMobCount1'] = int(self.mob_count.get())
except: self.current_quest['requiredMobCount1'] = 0
try: self.current_quest['pvpKillCount'] = int(self.pvp_kills.get())
except: self.current_quest['pvpKillCount'] = 0
for key, txt in self.desc_fields.items(): self.current_quest[key] = txt.get("1.0", tk.END).strip()
results = []
for row in self.reward_rows:
if row['use'].get():
res = { 'needMobCount': int(row['mobcnt'].get()), 'needItemCount': int(row['itemcnt'].get()), 'money': int(row['gold'].get()), 'exp': int(row['xp'].get()),
'itemType1': int(row['type1'].get()), 'itemTypeId1': int(row['typeid1'].get()), 'itemCount1': int(row['count1'].get()),
'itemType2': int(row['type2'].get()), 'itemTypeId2': int(row['typeid2'].get()), 'itemCount2': int(row['count2'].get()),
'itemType3': int(row['type3'].get()), 'itemTypeId3': int(row['typeid3'].get()), 'itemCount3': int(row['count3'].get()),
'nextQuestId': int(row['unlock'].get()) }
results.append(res)
self.current_quest['results'] = results
with open(self.file_path,'w',encoding='utf-8') as f:
json.dump(self.data,f,ensure_ascii=False,indent=4)
messagebox.showinfo("Succès","Quête sauvegardée avec succès.")

if __name__ == "__main__":
app = ShaiyaQuestEditor()
app.mainloop()
[DEV]_Yûko is offline  
Reply


Similar Threads Similar Threads
[Selling] TELEGRAM ACCOUNTS (TDATA, SESSION + JSON, TDATA +SESSION + JSON)
06/01/2022 - Social Media Trading - 0 Replies
�� Excellent Telegram accounts available: RU format "session". Ideal for an invite. �� 3 days+ - 0.45USD / 0.42USD - (when buying from 1000 pcs). �� Excellent Telegram accounts available: Indonesia "session" format. They are well suited for spam. �� 3 days+ -0.40USD / 0.37USD - (when buying from 1000 pcs). ❗ Discounts on wholesale. A test is possible. TG: nice_accs_6 ТамТам: nice_acc_support
[Help]Codding item to update column
06/11/2015 - Flyff Private Server - 3 Replies
Slove ::
[Question]How to codding epx client files
11/25/2010 - Metin2 Private Server - 0 Replies
Hello elitepvppers me have 1 question how to codding files epx locale addr and eix client files plz help me with this question Very thanks



All times are GMT +1. The time now is 19:50.


Powered by vBulletin®
Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
SEO by vBSEO ©2011, Crawlability, Inc.
This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

Support | Contact Us | FAQ | Advertising | Privacy Policy | Terms of Service | Abuse
Copyright ©2025 elitepvpers All Rights Reserved.