import pyautogui
import cv2
import numpy as np
import time
import random
import threading
from PIL import ImageGrab
import keyboard
import win32gui
import win32con
import win32api
import json
import os
from datetime import datetime
class Metin2Bot:
def __init__(self, config_file="bot_config.json"):
self.running = False
self.paused = False
self.config = self.load_config(config_file)
# Pencere ayarları
self.window_title = "Metin2"
self.window_handle = None
self.window_region = None
# Zaman sayaçları
self.last_pickup_time = time.time()
self.last_hp_check = time.time()
self.last_skill_time = time.time()
self.pickup_interval = random.uniform(5, 10)
# Bot durumu
self.current_target = None
self.attack_mode = False
self.stats = {
"metin_destroyed": 0,
"items_picked": 0,
"start_time": None,
"total_clicks": 0
}
# Görüntü şablonları
self.templates = {}
self.load_templates()
def load_config(self, config_file):
"""Konfigürasyon dosyasını yükle"""
default_config = {
"window_width": 1600,
"window_height": 900,
"metin_colors": {
"lower": [80, 80, 80],
"upper": [220, 220, 220]
},
"hp_bar_position": [100, 50],
"hp_threshold": 30,
"pickup_key": "z",
"hp_potion_key": "1",
"mp_potion_key": "2",
"skills": {
"skill_1": {"key": "q", "cooldown": 5},
"skill_2": {"key": "w", "cooldown": 10},
"skill_3": {"key": "e", "cooldown": 15}
},
"attack_delay": [0.5, 1.0],
"scan_interval": 0.3,
"debug_mode": False
}
if os.path.exists(config_file):
with open(config_file, 'r', encoding='utf-8') as f:
loaded_config = json.load(f)
default_config.update(loaded_config)
else:
with open(config_file, 'w', encoding='utf-8') as f:
json.dump(default_config, f, indent=4)
return default_config
def load_templates(self):
"""Görüntü şablonlarını yükle"""
template_files = {
"metin": "templates/metin.png",
"hp_bar": "templates/hp_bar.png",
"item": "templates/item.png",
"mob": "templates/mob.png"
}
for name, path in template_files.items():
if os.path.exists(path):
self.templates[name] = cv2.imread(path, cv2.IMREAD_GRAYSCALE)
else:
print(f"Uyarı: {path} bulunamadı")
def find_game_window(self):
"""Oyun penceresini bul ve konumunu al"""
def enum_windows_callback(hwnd, windows):
if win32gui.IsWindowVisible(hwnd):
window_text = win32gui.GetWindowText(hwnd)
if self.window_title in window_text:
windows.append(hwnd)
return True
windows = []
win32gui.EnumWindows(enum_windows_callback, windows)
if windows:
self.window_handle = windows[0]
rect = win32gui.GetWindowRect(self.window_handle)
self.window_region = (rect[0], rect[1], rect[2], rect[3])
print(f"Oyun penceresi bulundu: {self.window_region}")
return True
return False
def bring_window_to_front(self):
"""Oyun penceresini öne getir"""
if self.window_handle:
win32gui.SetForegroundWindow(self.window_handle)
time.sleep(0.1)
def capture_screen(self):
"""Oyun ekranını yakala"""
if self.window_region:
screenshot = ImageGrab.grab(bbox=self.window_region)
return cv2.cvtColor(np.array(screenshot), cv2.COLOR_RGB2BGR)
return None
def find_metin_stones(self, screenshot):
"""Metin taşlarını tespit et"""
# Renk tabanlı tespit
lower = np.array(self.config["metin_colors"]["lower"])
upper = np.array(self.config["metin_colors"]["upper"])
mask = cv2.inRange(screenshot, lower, upper)
# Morfolojik işlemler ile gürültüyü azalt
kernel = np.ones((5, 5), np.uint8)
mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel)
mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)
# Konturları bul
contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
metin_positions = []
for contour in contours:
area = cv2.contourArea(contour)
if 1000 < area < 50000: # Alan filtresi
# Dikdörtgen kontrolü
x, y, w, h = cv2.boundingRect(contour)
aspect_ratio = float(w) / h
if 0.5 < aspect_ratio < 2.0: # Metin taşları genelde kareye yakın
cx = x + w // 2
cy = y + h // 2
metin_positions.append({
"position": (cx + self.window_region[0], cy + self.window_region[1]),
"size": area,
"bounds": (x, y, w, h)
})
# Template matching ile doğrula (eğer template varsa)
if "metin" in self.templates and self.templates["metin"] is not None:
metin_positions = self.verify_with_template(screenshot, metin_positions)
# Mesafeye göre sırala (yakından uzağa)
center_x = self.config["window_width"] // 2
center_y = self.config["window_height"] // 2
metin_positions.sort(key=lambda m:
((m["position"][0] - center_x - self.window_region[0])**2 +
(m["position"][1] - center_y - self.window_region[1])**2)**0.5
)
return metin_positions
def verify_with_template(self, screenshot, positions):
"""Template matching ile pozisyonları doğrula"""
gray = cv2.cvtColor(screenshot, cv2.COLOR_BGR2GRAY)
template = self.templates["metin"]
verified = []
for metin in positions:
x, y, w, h = metin["bounds"]
roi = gray[max(0, y-20):min(gray.shape[0], y+h+20),
max(0, x-20):min(gray.shape[1], x+w+20)]
if roi.size > 0:
result = cv2.matchTemplate(roi, template, cv2.TM_CCOEFF_NORMED)
if result.max() > 0.6:
verified.append(metin)
return verified if verified else positions
def check_hp(self, screenshot):
"""HP kontrolü yap"""
# Basit renk tabanlı HP kontrolü
hp_region = screenshot[
self.config["hp_bar_position"][1]:self.config["hp_bar_position"][1]+20,
self.config["hp_bar_position"][0]:self.config["hp_bar_position"][0]+200
]
# Kırmızı pikselleri say
red_pixels = cv2.inRange(hp_region, np.array([0, 0, 150]), np.array([50, 50, 255]))
hp_percentage = (cv2.countNonZero(red_pixels) / red_pixels.size) * 100
return hp_percentage
def use_potion(self, potion_type="hp"):
"""Pot kullan"""
key = self.config["hp_potion_key"] if potion_type == "hp" else self.config["mp_potion_key"]
pyautogui.press(key)
print(f"{potion_type.upper()} potu kullanıldı")
def attack_target(self, target):
"""Hedefe saldır"""
x, y = target["position"]
# Hedefi tıkla
pyautogui.click(x, y, button='left')
self.stats["total_clicks"] += 1
# Rastgele gecikme
delay = random.uniform(*self.config["attack_delay"])
time.sleep(delay)
# Skill kullan
self.use_skills()
def use_skills(self):
"""Becerileri kullan"""
current_time = time.time()
for skill_name, skill_info in self.config["skills"].items():
if current_time - self.last_skill_time > skill_info["cooldown"]:
pyautogui.press(skill_info["key"])
self.last_skill_time = current_time
if self.config["debug_mode"]:
print(f"{skill_name} kullanıldı")
break
def pickup_items(self):
"""Yerdeki itemleri topla"""
pyautogui.press(self.config["pickup_key"])
self.stats["items_picked"] += 1
if self.config["debug_mode"]:
print("Item toplandı")
def find_items_on_ground(self, screenshot):
"""Yerdeki itemleri tespit et"""
# Parlak itemler için renk tespiti
hsv = cv2.cvtColor(screenshot, cv2.COLOR_BGR2HSV)
# Parlak renk aralığı
lower_bright = np.array([0, 0, 200])
upper_bright = np.array([255, 30, 255])
mask = cv2.inRange(hsv, lower_bright, upper_bright)
contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
items = []
for contour in contours:
area = cv2.contourArea(contour)
if 50 < area < 1000: # Küçük parlak alanlar
M = cv2.moments(contour)
if M["m00"] != 0:
cx = int(M["m10"] / M["m00"])
cy = int(M["m01"] / M["m00"])
items.append((cx, cy))
return items
def is_target_alive(self, target_pos):
"""Hedefin hala var olup olmadığını kontrol et"""
screenshot = self.capture_screen()
if screenshot is None:
return False
# Hedef bölgesini kontrol et
x, y = target_pos["position"]
x -= self.window_region[0]
y -= self.window_region[1]
roi_size = 50
roi = screenshot[
max(0, y-roi_size):min(screenshot.shape[0], y+roi_size),
max(0, x-roi_size):min(screenshot.shape[1], x+roi_size)
]
# Hedefin rengini kontrol et
lower = np.array(self.config["metin_colors"]["lower"])
upper = np.array(self.config["metin_colors"]["upper"])
mask = cv2.inRange(roi, lower, upper)
return cv2.countNonZero(mask) > 100
def main_loop(self):
"""Ana bot döngüsü"""
print("Bot başlatıldı.")
print("Komutlar:")
print(" P - Duraklat/Devam et")
print(" Q - Çıkış")
print(" S - İstatistikleri göster")
self.stats["start_time"] = datetime.now()
while self.running:
try:
if self.paused:
time.sleep(0.1)
continue
# Ekran görüntüsü al
screenshot = self.capture_screen()
if screenshot is None:
print("Oyun penceresi bulunamadı, tekrar arıyor...")
if self.find_game_window():
self.bring_window_to_front()
time.sleep(1)
continue
# HP kontrolü
current_time = time.time()
if current_time - self.last_hp_check > 1:
hp = self.check_hp(screenshot)
if hp < self.config["hp_threshold"]:
self.use_potion("hp")
self.last_hp_check = current_time
# Mevcut hedef kontrolü
if self.current_target and self.attack_mode:
if self.is_target_alive(self.current_target):
self.attack_target(self.current_target)
continue
else:
print("Metin taşı yok edildi!")
self.stats["metin_destroyed"] += 1
self.current_target = None
self.attack_mode = False
# Item toplama zamanı
for _ in range(3):
self.pickup_items()
time.sleep(0.5)
# Yeni metin taşı ara
metin_stones = self.find_metin_stones(screenshot)
if metin_stones:
self.current_target = metin_stones[0]
self.attack_mode = True
print(f"Yeni hedef: {self.current_target['position']}")
else:
# Item toplama kontrolü
if current_time - self.last_pickup_time >= self.pickup_interval:
items = self.find_items_on_ground(screenshot)
if items or random.random() < 0.3: # %30 şans ile de topla
self.pickup_items()
self.last_pickup_time = current_time
self.pickup_interval = random.uniform(5, 10)
# Debug modu
if self.config["debug_mode"]:
self.draw_debug_info(screenshot, metin_stones)
# Döngü gecikmesi
time.sleep(self.config["scan_interval"])
except Exception as e:
print(f"Hata: {e}")
import traceback
traceback.print_exc()
time.sleep(1)
def draw_debug_info(self, screenshot, metin_stones):
"""Debug bilgilerini göster"""
debug_img = screenshot.copy()
# Metin taşlarını işaretle
for metin in metin_stones:
x, y, w, h = metin["bounds"]
cv2.rectangle(debug_img, (x, y), (x+w, y+h), (0, 255, 0), 2)
cv2.putText(debug_img, f"Size: {metin['size']}",
(x, y-10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 1)
# Debug penceresini göster
cv2.imshow("Bot Debug", debug_img)
cv2.waitKey(1)
def show_stats(self):
"""İstatistikleri göster"""
if self.stats["start_time"]:
runtime = datetime.now() - self.stats["start_time"]
print("\n=== Bot İstatistikleri ===")
print(f"Çalışma Süresi: {runtime}")
print(f"Yok Edilen Metin: {self.stats['metin_destroyed']}")
print(f"Toplanan Item: {self.stats['items_picked']}")
print(f"Toplam Tıklama: {self.stats['total_clicks']}")
print(f"Metin/Saat: {self.stats['metin_destroyed'] / (runtime.seconds / 3600):.2f}")
print("========================\n")
def save_stats(self):
"""İstatistikleri dosyaya kaydet"""
stats_file = f"bot_stats_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json"
with open(stats_file, 'w', encoding='utf-8') as f:
stats_copy = self.stats.copy()
stats_copy["start_time"] = str(stats_copy["start_time"])
stats_copy["end_time"] = str(datetime.now())
json.dump(stats_copy, f, indent=4)
print(f"İstatistikler kaydedildi: {stats_file}")
def keyboard_handler(self):
"""Klavye komutlarını dinle"""
while self.running:
if keyboard.is_pressed('q'):
self.stop()
break
elif keyboard.is_pressed('p'):
self.paused = not self.paused
status = "duraklatıldı" if self.paused else "devam ediyor"
print(f"Bot {status}")
time.sleep(0.5)
elif keyboard.is_pressed('s'):
self.show_stats()
time.sleep(0.5)
time.sleep(0.1)
def start(self):
"""Botu başlat"""
print("Oyun penceresi aranıyor...")
if not self.find_game_window():
print(f"'{self.window_title}' penceresi bulunamadı!")
return
self.bring_window_to_front()
self.running = True
# Thread'leri başlat
bot_thread = threading.Thread(target=self.main_loop)
keyboard_thread = threading.Thread(target=self.keyboard_handler)
bot_thread.start()
keyboard_thread.start()
bot_thread.join()
keyboard_thread.join()
def stop(self):
"""Botu durdur"""
self.running = False
self.show_stats()
self.save_stats()
cv2.destroyAllWindows()
print("Bot durduruldu.")
# Gelişmiş özellikler için ek sınıf
class Metin2BotAdvanced(Metin2Bot):
def __init__(self, config_file="bot_config.json"):
super().__init__(config_file)
# Ek özellikler
self.mob_detection = True
self.auto_buff = True
self.path_memory = []
self.danger_zones = []
def detect_mobs(self, screenshot):
"""Yakındaki mobları tespit et"""
# Mob tespiti için HSV renk aralığı
hsv = cv2.cvtColor(screenshot, cv2.COLOR_BGR2HSV)
# Kırmızı isim rengi (düşman moblar)
lower_red = np.array([0, 100, 100])
upper_red = np.array([10, 255, 255])
mask1 = cv2.inRange(hsv, lower_red, upper_red)
lower_red2 = np.array([170, 100, 100])
upper_red2 = np.array([180, 255, 255])
mask2 = cv2.inRange(hsv, lower_red2, upper_red2)
mask = cv2.bitwise_or(mask1, mask2)
# Mob pozisyonlarını bul
contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
mobs = []
for contour in contours:
area = cv2.contourArea(contour)
if 50 < area < 500: # İsim etiketi boyutu
x, y, w, h = cv2.boundingRect(contour)
mobs.append({
"position": (x + w//2, y + h//2),
"danger_level": self.calculate_danger(x, y)
})
return mobs
def calculate_danger(self, x, y):
"""Tehlike seviyesini hesapla"""
center_x = self.config["window_width"] // 2
center_y = self.config["window_height"] // 2
distance = ((x - center_x)**2 + (y - center_y)**2)**0.5
if distance < 100:
return "high"
elif distance < 200:
return "medium"
else:
return "low"
def auto_buff_check(self):
"""Otomatik buff kontrolü"""
buff_schedule = {
"aura": {"key": "g", "interval": 300}, # 5 dakika
"berserk": {"key": "h", "interval": 120} # 2 dakika
}
current_time = time.time()
for buff_name, buff_info in buff_schedule.items():
last_used = getattr(self, f"last_{buff_name}_time", 0)
if current_time - last_used > buff_info["interval"]:
pyautogui.press(buff_info["key"])
setattr(self, f"last_{buff_name}_time", current_time)
print(f"{buff_name} buff'ı yenilendi")
# Ana program
if __name__ == "__main__":
print("Metin2 Bot v2.0")
print("1. Normal Bot")
print("2. Gelişmiş Bot")
choice = input("Seçiminiz (1/2): ")
if choice == "2":
bot = Metin2BotAdvanced()
else:
bot = Metin2Bot()
print("\nBot 3 saniye içinde başlayacak...")
print("Oyunun 1600x900 pencere modunda açık olduğundan emin olun!")
time.sleep(3)
bot.start()şu kodu dene bakalım gereken ksıımları kendine göre düzenle.