Jump to content

Quests are Unresponsive!?!?


Go to solution Solved by ernestminz,

Recommended Posts

  • Active+ Member

Hello community. After getting started with some brand new clean SF I discovered a major issue which is none of the quests work. Shops open but NPC's do not respond to clicks (Uriel, Teleporter, etc..), items do not respond to right click like Soul Stone or stat/skill scrolls, nothing works. I only receive this error in syserr:
 

[2025-09-30 18:40:54.911] [error] [bool quest::CQuestManager::Click(unsigned int, LPCHARACTER)()] CQuestManager::Click(pid=1, target_npc_name=Teleporter) - NOT EXIST NPC RACE VNUM[9012]

for example...

 

I have seen the questnpc.txt solution and it does not work. I have also checked against files that had no issues with quests in the past and the questnpc.txt is identical so the issue is clearly not there. 

Also the qc is compiling the quests without any errors.

In case this is relevant here are the scripts I am using for qc:

make.py:
 

Spoiler
import sys
sys.dont_write_bytecode = True

from pathlib import Path
import shutil
import subprocess
import pre_qc
import os

def _clear_directory(dir_path: Path) -> None:
	for item in dir_path.iterdir():
		if item.is_dir():
			shutil.rmtree(item)
		else:
			item.unlink(missing_ok=True)

def main() -> None:
	script_dir = Path(__file__).resolve().parent

	object_dir = script_dir / "object"
	if object_dir.exists():
		_clear_directory(object_dir)
	else:
		object_dir.mkdir(parents=True, exist_ok=True)
		
	pre_qc_dir = script_dir / "pre_qc"
	if pre_qc_dir.exists():
		_clear_directory(pre_qc_dir)
	else:
		pre_qc_dir.mkdir(parents=True, exist_ok=True)

	qc_exe = script_dir / ("qc.exe" if sys.platform.startswith("win") else "qc")
	
	with open("locale_list") as file:
		for line in file:
			print(f"Compiling {line}...")
			r = pre_qc.run(line)
			if r:
				filename = os.path.join("pre_qc", line)
				
			subprocess.run([str(qc_exe), str(filename.strip())], check=True)


if __name__ == "__main__":
	main()

 

pre_qc.py:
 

Spoiler
# -*- coding: cp949 -*-
# Literally, ¡°pre qc.¡±
# In our quest language, there are only local variables.
# You cannot use global variables that span state, when, or function.
# The use of global variables is impossible due to the language structure and is meaningless.
# However, the use of global constants is absolutely necessary in the quest view.
# Until now, to mimic global constants, we created a new table every time using functions like setting().
# This is very inefficient.
# So, just like C¡¯s preprocessor, we made a ¡°pre qc¡± to allow global constants.
# If you run pre_qc.py before compiling a quest into qc,
# pre_qc.py processes define statements and saves the results into pre_qc/filename.

import sys
from pathlib import Path


def split_by_quat(buf):
	p = False
	l = list(buf)
	l.reverse()
	s = ""
	res = []
	while l:
		c = l.pop()
		if c == '"':
			if p is True:
				s += c
				res += [s]
				s = ""
			else:
				if len(s) != 0:
					res += [s]
				s = '"'
			p = not p
		elif c == "\\" and l and l[0] == '"':
			s += c
			s += l.pop()
		else:
			s += c

	if len(s) != 0:
		res += [s]
	return res


def AddSepMiddleOfElement(l, sep):
	l = list(l)  # avoid in-place mutation
	l.reverse()
	new_list = [l.pop()]
	while l:
		new_list.append(sep)
		new_list.append(l.pop())
	return new_list


def my_split_with_seps(s, seps):
	res = [s]
	for sep in seps:
		new_res = []
		for r in res:
			sp = r.split(sep)
			sp = AddSepMiddleOfElement(sp, sep)
			new_res += sp
		res = new_res
	new_res = []
	for r in res:
		if r != "":
			new_res.append(r)
	return new_res


def my_split(s, seps):
	res = [s]
	for sep in seps:
		new_res = []
		for r in res:
			sp = r.split(sep)
			new_res += sp
		res = new_res
	new_res = []
	for r in res:
		if r != "":
			new_res.append(r)
	return new_res


def MultiIndex(seq, key):
	l = []
	i = 0
	for s in seq:
		if s == key:
			l.append(i)
		i = i + 1
	return l


def Replace(lines, parameter_table, keys):
	r = []
	for string in lines:
		l = split_by_quat(string)
		for s in l:
			if s and s[0] == '"':
				r += [s]
			else:
				tokens = my_split_with_seps(
					s,
					["\t", ",", " ", "=", "[", "]", "-", "<", ">", "~", "!", ".", "(", ")"],
				)
				for key in keys:
					try:
						indices = MultiIndex(tokens, key)
						for i in indices:
							tokens[i] = parameter_table[key][0]
					except Exception:
						pass
				r += tokens
	return r


def MakeParameterTable(lines, parameter_table, keys):
	names = []
	values = []
	group_names = []
	group_values = []
	idx = 0
	start = 1
	for line in lines:
		idx += 1
		line = line.strip("\n")
		if line.find("--") != -1:
			line = line[0 : line.find("--")]

		tokens = my_split(line, ["\t", ",", " ", "=", "[", "]", "\r", "\n"])
		if len(tokens) == 0:
			continue
		if tokens[0] == "quest":
			start = idx
			break
		if tokens[0] == "define":
			if len(tokens) > 1 and tokens[1] == "group":
				if len(tokens) >= 3:
					group_value = []
					for value in tokens[3:]:
						if parameter_table.get(value, 0) != 0:
							value = parameter_table[value]
						group_value.append(value)
					parameter_table[tokens[2]] = group_value
					keys.append(tokens[2])
			elif len(tokens) > 5:
				print(f"{idx} Invalid syntax")
				print("define [name] = [value]")
				print('define group [name] = "["[v0],[v1], ... "]"')
			else:
				value = tokens[2] if len(tokens) > 2 else ""
				if parameter_table.get(value, 0) != 0:
					value = parameter_table[value]
				parameter_table[tokens[1]] = [value]
				keys.append(tokens[1])
	return start


def run(filename):
	parameter_table = dict()
	keys = []

	filename = filename.strip("\n")
	if filename == "":
		return
	try:
		with open(filename, "r", encoding='utf-8') as fh:
			lines = fh.readlines()
	except UnicodeDecodeError:
		with open(filename, "r", encoding='cp1252') as fh:
			lines = fh.readlines()

	start = MakeParameterTable(lines, parameter_table, keys)
	if len(keys) == 0:
		return False

	lines = lines[start - 1 :]
	r = Replace(lines, parameter_table, keys)

	out_dir = Path("pre_qc")
	out_dir.mkdir(parents=True, exist_ok=True)
	out_path = out_dir / filename

	with open(out_path, "w", newline="") as f:
		for s in r:
			f.write(s)
	return True


if __name__ == "__main__":
	if len(sys.argv) >= 2:
		run(sys.argv[1])

 

Has anyone any idea of what to look next? Thanks!

Link to comment
https://metin2.dev/topic/34062-quests-are-unresponsive/
Share on other sites

  • Active+ Member
On 10/31/2025 at 1:30 AM, ernestminz said:

Hi, just put the TM4 Serverfiles Quests Folder in ur server/share/locale/english it should solve ur problem

 

Thanks! Turns out python scripts may had something to do with it but a simple replacement was the fix all along.

Link to comment
https://metin2.dev/topic/34062-quests-are-unresponsive/#findComment-172896
Share on other sites

Don't use any images from : imgur, turkmmop, freakgamers, inforge, hizliresim... Or your content will be deleted without notice...
Use : https://metin2.download/media/add/

Please use https://metin2.download/ when uploading files smaller than 100MB, otherwise the approval will take longer due to manual upload.

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
×
×
  • Create New...

Important Information

Terms of Use / Privacy Policy / Guidelines / We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.