10-26-2026, 08:07 PM
(10-26-2026, 04:18 AM)Pato_Lucas18 escribió: Buenisimo amigo
Excelente Pato, muchas gracias por toda tu ayuda! Esta semana voy a mirar esos codigos que me envio, lo pude ojear por encima, es ORO puro, me va servir mucho! Muchas Gracias Master!
(10-26-2026, 01:55 PM)Ermolli91 escribió: Muy bien con esos avances. Suerte con el proyecto, especialmente porque PES 6 es el más popular de esa época pero los que mencionaste también fueron grandes juegos. Ánimo.
Excelente amigo, muchas gracias por la motivacion y apoyo! pienso que si dejamos la informacion en este foro, en el futuro servira para desarrollo de nuevos parches. yo estoy avanzando lo que mas puedo en la noche, que es donde tengo un poco de tiempo libre, estudio el SLPM. haciendo Ingeniería Inversa y Estructuras de Datos!
Mapeo de archivos ejecutables y de configuración de PlayStation 2, como el SLPM_622.68 y parameter.ovl
Adjunto video preview: del Mapeo
Tambien se actualzo el Codigo en Python, por si lo desean testear:
Código PHP:
import struct
import tkinter as tk
from tkinter import messagebox, ttk
# --- RUTAS Y OFFSETS ---
SLPM_PATH = "SLPM_622.68"
OVL_PATH = "parameter.ovl"
# Offsets de Jugadores
SLPM_BASE_OFFSET = 0x1F24B0
PLAYER_SIZE = 44
NAMES_BASE_OFFSET = 0x668
NAME_SIZE = 32
NUMBERS_BASE_OFFSET = 0x338D0
NUMBERS_RECORD_SIZE = 23
CLUB_NUMBERS_OFFSET = 0x33F80
CLUB_RECORD_SIZE = 23
SHIRT_NAMES_OFFSET = 0x116C0
SHIRT_NAME_SIZE = 16
NUM_PLAYERS = 50
# Offsets de Equipos y Plantillas (Player Links)
TEAM_NAMES_OFFSET = 0x23F8C8
TEAM_RECORD_SIZE = 32
TEAM_NAME_LIMIT = 16
NUM_TEAMS = 64
LINKS_OFFSET = 0x353B0 # Offset base de Player Links de Clubes
# Lista de los atributos mapeados en el SLPM
ATTRIBUTES_DEF = [
("Ataque", 2), ("Defensa", 3), ("Balance", 4), ("Stamina", 5),
("Top Speed", 6), ("Aceleración", 7), ("Respuesta", 8), ("Agilidad", 9),
("Dribble Acc", 10), ("Dribble Vel", 11), ("P. Corto Acc", 12), ("P. Corto Vel", 13),
("P. Largo Acc", 14), ("P. Largo Vel", 15), ("Tiro Acc", 16), ("Tiro Potencia", 17),
("Tiro Téc", 18), ("Falta / T.Libre", 19), ("Curva", 20), ("Cabezazo", 21),
("Salto", 22), ("Técnica", 23), ("Agresividad", 24), ("Mentalidad", 25),
("Habil. Arquero", 26), ("Trabajo Equipo", 27), ("Condición", 28),
("Pie Bueno Frec", 29), ("Pie Bueno", 30)
]
class WE6FE_EditorApp:
def __init__(self, root):
self.root = root
self.root.title("WE6FE Database Editor - By WE11WORLD & Gemini")
self.root.geometry("1100x820")
self.root.config(bg="#1e1e1e")
self.current_player_index = 0
self.current_team_index = 0
self.current_roster_team_index = 0
self.current_selected_slot = 0
self.entries = {}
self.team_name_entry = None
self.team_listbox = None
self.roster_team_listbox = None
self.roster_slots_listbox = None
self.transfer_id_entry = None
# --- ESTILO DE PESTAÑAS (NOTEBOOK) ---
style = ttk.Style()
style.theme_use('default')
style.configure('TNotebook', background='#1e1e1e', borderwidth=0)
style.configure('TNotebook.Tab', background='#2d2d2d', foreground='#ffffff', font=('Arial', 10, 'bold'), padding=[12, 6])
style.map('TNotebook.Tab', background=[('selected', '#007acc')], foreground=[('selected', '#ffffff')])
self.notebook = ttk.Notebook(root)
self.notebook.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
# Crear Pestañas
self.tab_players = tk.Frame(self.notebook, bg="#1e1e1e")
self.tab_teams = tk.Frame(self.notebook, bg="#1e1e1e")
self.tab_rosters = tk.Frame(self.notebook, bg="#1e1e1e")
self.notebook.add(self.tab_players, text=" ⚽ Edición de Jugadores ")
self.notebook.add(self.tab_teams, text=" ?️ Edición de Equipos ")
self.notebook.add(self.tab_rosters, text=" ? Plantillas y Traspasos ")
# Construir Interfaces de las Pestañas
self.build_players_tab()
self.build_teams_tab()
self.build_rosters_tab()
# ==========================================
# PESTAÑA 1: JUGADORES
# ==========================================
def build_players_tab(self):
main_frame = tk.Frame(self.tab_players, bg="#1e1e1e")
main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
left_frame = tk.Frame(main_frame, bg="#2d2d2d", width=280)
left_frame.pack(side=tk.LEFT, fill=tk.Y, padx=(0, 10))
tk.Label(left_frame, text="Plantilla de Jugadores", bg="#2d2d2d", fg="#ffffff", font=("Arial", 11, "bold")).pack(pady=10)
list_scroll = tk.Scrollbar(left_frame)
list_scroll.pack(side=tk.RIGHT, fill=tk.Y)
self.player_listbox = tk.Listbox(left_frame, yscrollcommand=list_scroll.set, bg="#1e1e1e", fg="#00ffcc", selectbackground="#007acc", font=("Consolas", 10), height=36)
self.player_listbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
self.player_listbox.bind('<<ListboxSelect>>', self.on_player_select)
list_scroll.config(command=self.player_listbox.yview)
right_frame = tk.Frame(main_frame, bg="#2d2d2d")
right_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True)
top_edit_frame1 = tk.Frame(right_frame, bg="#2d2d2d")
top_edit_frame1.pack(fill=tk.X, padx=15, pady=(10, 5))
tk.Label(top_edit_frame1, text="Nombre:", bg="#2d2d2d", fg="#00ffcc", font=("Arial", 10, "bold")).pack(side=tk.LEFT, padx=(0, 5))
self.name_entry = tk.Entry(top_edit_frame1, bg="#3c3c3c", fg="#ffffff", insertbackground="white", font=("Consolas", 10, "bold"), width=18)
self.name_entry.pack(side=tk.LEFT, padx=(0, 15))
tk.Label(top_edit_frame1, text="Nom. Camiseta:", bg="#2d2d2d", fg="#00ffcc", font=("Arial", 10, "bold")).pack(side=tk.LEFT, padx=(0, 5))
self.shirt_name_entry = tk.Entry(top_edit_frame1, bg="#3c3c3c", fg="#ffffff", insertbackground="white", font=("Consolas", 10, "bold"), width=16)
self.shirt_name_entry.pack(side=tk.LEFT)
top_edit_frame2 = tk.Frame(right_frame, bg="#2d2d2d")
top_edit_frame2.pack(fill=tk.X, padx=15, pady=(0, 10))
tk.Label(top_edit_frame2, text="D.Nac:", bg="#2d2d2d", fg="#00ffcc", font=("Arial", 10, "bold")).pack(side=tk.LEFT, padx=(0, 3))
self.dorsal_entry = tk.Entry(top_edit_frame2, bg="#3c3c3c", fg="#ffffff", insertbackground="white", font=("Consolas", 10, "bold"), width=4)
self.dorsal_entry.pack(side=tk.LEFT, padx=(0, 15))
tk.Label(top_edit_frame2, text="D.Club:", bg="#2d2d2d", fg="#00ffcc", font=("Arial", 10, "bold")).pack(side=tk.LEFT, padx=(0, 3))
self.club_dorsal_entry = tk.Entry(top_edit_frame2, bg="#3c3c3c", fg="#ffffff", insertbackground="white", font=("Consolas", 10, "bold"), width=4)
self.club_dorsal_entry.pack(side=tk.LEFT)
canvas = tk.Canvas(right_frame, bg="#2d2d2d", highlightthickness=0)
scrollbar = tk.Scrollbar(right_frame, orient="vertical", command=canvas.yview)
self.form_frame = tk.Frame(canvas, bg="#2d2d2d")
for col_idx in range(4):
self.form_frame.grid_columnconfigure(col_idx, weight=1)
self.form_frame.bind("<Configure>", lambda e: canvas.configure(scrollregion=canvas.bbox("all")))
canvas.create_window((0, 0), window=self.form_frame, anchor="nw")
canvas.configure(yscrollcommand=scrollbar.set)
canvas.pack(side=tk.TOP, fill=tk.BOTH, expand=True, padx=5, pady=5)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
row = 0
col = 0
for name, byte_idx in ATTRIBUTES_DEF:
lbl = tk.Label(self.form_frame, text=name + ":", bg="#2d2d2d", fg="#d4d4d4", font=("Arial", 9, "bold"), anchor="e")
lbl.grid(row=row, column=col*2, sticky="e", padx=5, pady=4)
entry = tk.Entry(self.form_frame, width=8, bg="#3c3c3c", fg="#ffffff", insertbackground="white", font=("Consolas", 10))
entry.grid(row=row, column=col*2+1, sticky="w", padx=5, pady=4)
self.entries[byte_idx] = entry
col += 1
if col > 1:
col = 0
row += 1
btn_save = tk.Button(right_frame, text="Guardar Cambios de Jugador", bg="#007acc", fg="#ffffff", font=("Arial", 10, "bold"), command=self.save_player_data)
btn_save.pack(pady=15)
self.load_players_list()
# ==========================================
# PESTAÑA 2: EQUIPOS
# ==========================================
def build_teams_tab(self):
main_frame = tk.Frame(self.tab_teams, bg="#1e1e1e")
main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
left_frame = tk.Frame(main_frame, bg="#2d2d2d", width=320)
left_frame.pack(side=tk.LEFT, fill=tk.Y, padx=(0, 10))
tk.Label(left_frame, text="Listado de Equipos", bg="#2d2d2d", fg="#ffffff", font=("Arial", 11, "bold")).pack(pady=10)
list_scroll = tk.Scrollbar(left_frame)
list_scroll.pack(side=tk.RIGHT, fill=tk.Y)
self.team_listbox = tk.Listbox(left_frame, yscrollcommand=list_scroll.set, bg="#1e1e1e", fg="#ffcc00", selectbackground="#007acc", font=("Consolas", 10), height=36)
self.team_listbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
self.team_listbox.bind('<<ListboxSelect>>', self.on_team_select)
list_scroll.config(command=self.team_listbox.yview)
right_frame = tk.Frame(main_frame, bg="#2d2d2d")
right_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True)
edit_container = tk.Frame(right_frame, bg="#2d2d2d")
edit_container.pack(pady=40, padx=20, fill=tk.X)
tk.Label(edit_container, text="Nombre del Equipo:", bg="#2d2d2d", fg="#ffcc00", font=("Arial", 11, "bold")).pack(anchor="w", pady=(0, 8))
self.team_name_entry = tk.Entry(edit_container, bg="#3c3c3c", fg="#ffffff", insertbackground="white", font=("Consolas", 12, "bold"), width=25)
self.team_name_entry.pack(anchor="w", pady=(0, 20))
btn_save_team = tk.Button(edit_container, text="Guardar Nombre de Equipo en SLPM", bg="#007acc", fg="#ffffff", font=("Arial", 10, "bold"), command=self.save_team_data)
btn_save_team.pack(anchor="w")
self.load_teams_list()
# ==========================================
# PESTAÑA 3: PLANTILLAS Y TRASPASOS (PLAYER LINKS)
# ==========================================
def build_rosters_tab(self):
main_frame = tk.Frame(self.tab_rosters, bg="#1e1e1e")
main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
# Panel Izquierdo: Selección de Equipo
left_frame = tk.Frame(main_frame, bg="#2d2d2d", width=300)
left_frame.pack(side=tk.LEFT, fill=tk.Y, padx=(0, 10))
tk.Label(left_frame, text="Seleccionar Equipo", bg="#2d2d2d", fg="#ffffff", font=("Arial", 11, "bold")).pack(pady=10)
list_scroll = tk.Scrollbar(left_frame)
list_scroll.pack(side=tk.RIGHT, fill=tk.Y)
self.roster_team_listbox = tk.Listbox(left_frame, yscrollcommand=list_scroll.set, bg="#1e1e1e", fg="#00ffcc", selectbackground="#007acc", font=("Consolas", 10), height=36)
self.roster_team_listbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
self.roster_team_listbox.bind('<<ListboxSelect>>', self.on_roster_team_select)
list_scroll.config(command=self.roster_team_listbox.yview)
# Panel Derecho: Slots de Plantilla y Controles de Traspaso
right_frame = tk.Frame(main_frame, bg="#2d2d2d")
right_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True)
tk.Label(right_frame, text="Plantilla de 16 Slots (Selecciona un Slot para Traspasar)", bg="#2d2d2d", fg="#ffcc00", font=("Arial", 11, "bold")).pack(anchor="w", padx=15, pady=10)
roster_scroll = tk.Scrollbar(right_frame)
roster_scroll.pack(side=tk.RIGHT, fill=tk.Y)
self.roster_slots_listbox = tk.Listbox(right_frame, yscrollcommand=roster_scroll.set, bg="#1e1e1e", fg="#ffffff", selectbackground="#007acc", font=("Consolas", 10), height=25)
self.roster_slots_listbox.pack(side=tk.TOP, fill=tk.BOTH, expand=True, padx=15, pady=(0, 10))
self.roster_slots_listbox.bind('<<ListboxSelect>>', self.on_slot_select)
roster_scroll.config(command=self.roster_slots_listbox.yview)
# Panel de Edición / Traspaso inferior
transfer_frame = tk.Frame(right_frame, bg="#363636", relief=tk.GROOVE, bd=2)
transfer_frame.pack(fill=tk.X, padx=15, pady=(0, 15), ipady=10)
tk.Label(transfer_frame, text="Asignar / Traspasar Jugador al Slot Seleccionado:", bg="#363636", fg="#00ffcc", font=("Arial", 10, "bold")).pack(anchor="w", padx=15, pady=(5, 5))
inputs_subframe = tk.Frame(transfer_frame, bg="#363636")
inputs_subframe.pack(anchor="w", padx=15, pady=5)
tk.Label(inputs_subframe, text="Nuevo ID de Jugador:", bg="#363636", fg="#ffffff", font=("Arial", 9)).pack(side=tk.LEFT, padx=(0, 5))
self.transfer_id_entry = tk.Entry(inputs_subframe, bg="#2d2d2d", fg="#ffffff", insertbackground="white", font=("Consolas", 10, "bold"), width=8)
self.transfer_id_entry.pack(side=tk.LEFT, padx=(0, 15))
btn_transfer = tk.Button(inputs_subframe, text="? Guardar Traspaso en OVL", bg="#007acc", fg="#ffffff", font=("Arial", 9, "bold"), command=self.save_player_transfer)
btn_transfer.pack(side=tk.LEFT)
self.load_roster_teams_list()
def load_roster_teams_list(self):
try:
with open(SLPM_PATH, "rb") as f_slpm:
f_slpm.seek(TEAM_NAMES_OFFSET)
for i in range(NUM_TEAMS):
data = f_slpm.read(TEAM_RECORD_SIZE)
if len(data) < TEAM_RECORD_SIZE:
break
team_name = data[:TEAM_NAME_LIMIT].decode('latin-1', errors='ignore').rstrip('\x00').strip()
if not team_name:
team_name = f"Equipo #{i}"
self.roster_team_listbox.insert(tk.END, f"#{i} - {team_name}")
if NUM_TEAMS > 0:
self.roster_team_listbox.selection_set(0)
self.on_roster_team_select(None)
except FileNotFoundError:
pass
def on_roster_team_select(self, event):
selection = self.roster_team_listbox.curselection()
if not selection:
return
self.current_roster_team_index = selection[0]
self.roster_slots_listbox.delete(0, tk.END)
try:
with open(OVL_PATH, "rb") as f_ovl:
record_offset = LINKS_OFFSET + (self.current_roster_team_index * TEAM_RECORD_SIZE)
f_ovl.seek(record_offset)
data = f_ovl.read(TEAM_RECORD_SIZE)
if len(data) >= 32:
player_ids = struct.unpack("<16H", data[:32])
for idx, pid in enumerate(player_ids):
if 0 < pid < 2500:
pos = NAMES_BASE_OFFSET + (pid * NAME_SIZE)
f_ovl.seek(pos)
raw_name = f_ovl.read(NAME_SIZE)
nombre = raw_name.decode('latin-1', errors='ignore').rstrip('\x00').strip()
if nombre and any(c.isalnum() for c in nombre):
self.roster_slots_listbox.insert(tk.END, f"Slot {idx:2d} --> ID: {pid:4d} ({nombre})")
else:
self.roster_slots_listbox.insert(tk.END, f"Slot {idx:2d} --> ID: {pid:4d} [ Oculto / Sin Mapear ]")
else:
self.roster_slots_listbox.insert(tk.END, f"Slot {idx:2d} --> ID: 0 [ Slot Vacío / Sin Asignar ]")
if self.roster_slots_listbox.size() > 0:
self.roster_slots_listbox.selection_set(0)
self.on_slot_select(None)
except Exception as e:
messagebox.showerror("Error", f"Error al leer plantilla: {e}")
def on_slot_select(self, event):
selection = self.roster_slots_listbox.curselection()
if not selection:
return
self.current_selected_slot = selection[0]
text_line = self.roster_slots_listbox.get(self.current_selected_slot)
try:
id_part = text_line.split("ID:")[1].strip().split()[0]
self.transfer_id_entry.delete(0, tk.END)
self.transfer_id_entry.insert(0, id_part)
except Exception:
pass
def save_player_transfer(self):
try:
new_id = int(self.transfer_id_entry.get().strip())
if new_id < 0 or new_id > 5000:
messagebox.showerror("Error", "El ID de jugador debe estar entre 0 y 5000.")
return
slot_offset = LINKS_OFFSET + (self.current_roster_team_index * TEAM_RECORD_SIZE) + (self.current_selected_slot * 2)
with open(OVL_PATH, "r+b") as f_ovl:
f_ovl.seek(slot_offset)
f_ovl.write(struct.pack("<H", new_id))
messagebox.showinfo("Éxito", f"¡Traspaso guardado! Slot {self.current_selected_slot} actualizado con ID {new_id}.")
self.on_roster_team_select(None)
self.roster_slots_listbox.selection_set(self.current_selected_slot)
except Exception as e:
messagebox.showerror("Error", f"No se pudo guardar el traspaso: {e}")
# ==========================================
# LOGICA DE DATOS: JUGADORES
# ==========================================
def load_players_list(self):
try:
with open(SLPM_PATH, "rb") as f_slpm, open(OVL_PATH, "rb") as f_ovl:
for i in range(NUM_PLAYERS):
f_slpm.seek(SLPM_BASE_OFFSET + (i * PLAYER_SIZE))
data_slpm = f_slpm.read(PLAYER_SIZE)
if len(data_slpm) < PLAYER_SIZE:
break
f_ovl.seek(NAMES_BASE_OFFSET + (i * NAME_SIZE))
raw_name = f_ovl.read(NAME_SIZE)
player_name = raw_name.decode('latin-1', errors='ignore').rstrip('\x00').strip()
if not player_name:
player_name = f"Jugador #{i}"
self.player_listbox.insert(tk.END, f"#{i} - {player_name}")
if NUM_PLAYERS > 0:
self.player_listbox.selection_set(0)
self.on_player_select(None)
except FileNotFoundError:
pass
def on_player_select(self, event):
selection = self.player_listbox.curselection()
if not selection:
return
self.current_player_index = selection[0]
try:
with open(OVL_PATH, "rb") as f_ovl:
f_ovl.seek(NAMES_BASE_OFFSET + (self.current_player_index * NAME_SIZE))
raw_name = f_ovl.read(NAME_SIZE)
self.name_entry.delete(0, tk.END)
self.name_entry.insert(0, raw_name.decode('latin-1', errors='ignore').rstrip('\x00').strip())
f_ovl.seek(SHIRT_NAMES_OFFSET + (self.current_player_index * SHIRT_NAME_SIZE))
raw_shirt = f_ovl.read(SHIRT_NAME_SIZE)
self.shirt_name_entry.delete(0, tk.END)
self.shirt_name_entry.insert(0, raw_shirt.decode('latin-1', errors='ignore').rstrip('\x00').strip())
f_ovl.seek(NUMBERS_BASE_OFFSET + (self.current_player_index * NUMBERS_RECORD_SIZE))
record_bytes = f_ovl.read(NUMBERS_RECORD_SIZE)
self.dorsal_entry.delete(0, tk.END)
self.dorsal_entry.insert(0, str(record_bytes[1] if len(record_bytes) > 1 else 0))
f_ovl.seek(CLUB_NUMBERS_OFFSET + (self.current_player_index * CLUB_RECORD_SIZE))
club_bytes = f_ovl.read(CLUB_RECORD_SIZE)
self.club_dorsal_entry.delete(0, tk.END)
self.club_dorsal_entry.insert(0, str(club_bytes[0] if len(club_bytes) > 0 else 255))
with open(SLPM_PATH, "rb") as f_slpm:
f_slpm.seek(SLPM_BASE_OFFSET + (self.current_player_index * PLAYER_SIZE))
unpacked = struct.unpack("<31B 13s", f_slpm.read(PLAYER_SIZE))
for byte_idx, entry in self.entries.items():
entry.delete(0, tk.END)
entry.insert(0, str(unpacked[byte_idx]))
except Exception as e:
messagebox.showerror("Error", f"Error al leer jugador: {e}")
def save_player_data(self):
try:
with open(OVL_PATH, "r+b") as f_ovl:
new_name = self.name_entry.get().strip()
f_ovl.seek(NAMES_BASE_OFFSET + (self.current_player_index * NAME_SIZE))
f_ovl.write(new_name.encode('latin-1', errors='ignore')[:NAME_SIZE].ljust(NAME_SIZE, b'\x00'))
new_shirt = self.shirt_name_entry.get().strip()
f_ovl.seek(SHIRT_NAMES_OFFSET + (self.current_player_index * SHIRT_NAME_SIZE))
f_ovl.write(new_shirt.encode('latin-1', errors='ignore')[:SHIRT_NAME_SIZE].ljust(SHIRT_NAME_SIZE, b'\x00'))
dorsal_val = int(self.dorsal_entry.get())
f_ovl.seek(NUMBERS_BASE_OFFSET + (self.current_player_index * NUMBERS_RECORD_SIZE))
rec = bytearray(f_ovl.read(NUMBERS_RECORD_SIZE))
rec[1] = dorsal_val
f_ovl.seek(NUMBERS_BASE_OFFSET + (self.current_player_index * NUMBERS_RECORD_SIZE))
f_ovl.write(rec)
club_val = int(self.club_dorsal_entry.get())
f_ovl.seek(CLUB_NUMBERS_OFFSET + (self.current_player_index * CLUB_RECORD_SIZE))
crec = bytearray(f_ovl.read(CLUB_RECORD_SIZE))
crec[0] = club_val
f_ovl.seek(CLUB_NUMBERS_OFFSET + (self.current_player_index * CLUB_RECORD_SIZE))
f_ovl.write(crec)
with open(SLPM_PATH, "rb") as f_slpm:
f_slpm.seek(SLPM_BASE_OFFSET + (self.current_player_index * PLAYER_SIZE))
p_bytes = bytearray(f_slpm.read(PLAYER_SIZE))
for byte_idx, entry in self.entries.items():
p_bytes[byte_idx] = int(entry.get())
with open(SLPM_PATH, "r+b") as f_slpm:
f_slpm.seek(SLPM_BASE_OFFSET + (self.current_player_index * PLAYER_SIZE))
f_slpm.write(p_bytes)
self.player_listbox.delete(self.current_player_index)
self.player_listbox.insert(self.current_player_index, f"#{self.current_player_index} - {new_name}")
self.player_listbox.selection_set(self.current_player_index)
messagebox.showinfo("Éxito", "¡Jugador actualizado correctamente!")
except Exception as e:
messagebox.showerror("Error", f"No se pudo guardar: {e}")
# ==========================================
# LOGICA DE DATOS: EQUIPOS
# ==========================================
def load_teams_list(self):
try:
with open(SLPM_PATH, "rb") as f_slpm:
f_slpm.seek(TEAM_NAMES_OFFSET)
for i in range(NUM_TEAMS):
data = f_slpm.read(TEAM_RECORD_SIZE)
if len(data) < TEAM_RECORD_SIZE:
break
team_name = data[:TEAM_NAME_LIMIT].decode('latin-1', errors='ignore').rstrip('\x00').strip()
if not team_name:
team_name = f"Equipo #{i}"
self.team_listbox.insert(tk.END, f"#{i} - {team_name}")
if NUM_TEAMS > 0:
self.team_listbox.selection_set(0)
self.on_team_select(None)
except FileNotFoundError:
pass
def on_team_select(self, event):
selection = self.team_listbox.curselection()
if not selection:
return
self.current_team_index = selection[0]
try:
with open(SLPM_PATH, "rb") as f_slpm:
f_slpm.seek(TEAM_NAMES_OFFSET + (self.current_team_index * TEAM_RECORD_SIZE))
data = f_slpm.read(TEAM_RECORD_SIZE)
team_name = data[:TEAM_NAME_LIMIT].decode('latin-1', errors='ignore').rstrip('\x00').strip()
self.team_name_entry.delete(0, tk.END)
self.team_name_entry.insert(0, team_name)
except Exception as e:
messagebox.showerror("Error", f"Error al leer equipo: {e}")
def save_team_data(self):
try:
new_team_name = self.team_name_entry.get().strip()
name_bytes = new_team_name.encode('latin-1', errors='ignore')[:TEAM_NAME_LIMIT].ljust(TEAM_NAME_LIMIT, b'\x00')
with open(SLPM_PATH, "r+b") as f_slpm:
record_offset = TEAM_NAMES_OFFSET + (self.current_team_index * TEAM_RECORD_SIZE)
f_slpm.seek(record_offset)
full_record = bytearray(f_slpm.read(TEAM_RECORD_SIZE))
full_record[:TEAM_NAME_LIMIT] = name_bytes
f_slpm.seek(record_offset)
f_slpm.write(full_record)
self.team_listbox.delete(self.current_team_index)
self.team_listbox.insert(self.current_team_index, f"#{self.current_team_index} - {new_team_name}")
self.team_listbox.selection_set(self.current_team_index)
messagebox.showinfo("Éxito", f"¡Equipo #{self.current_team_index} actualizado a '{new_team_name}' en el SLPM!")
except Exception as e:
messagebox.showerror("Error", f"No se pudo guardar el equipo: {e}")
if __name__ == "__main__":
root = tk.Tk()
app = WE6FE_EditorApp(root)
root.mainloop()
Enjoy!

