markus
1
########################################################################
# XP System for Eggdrop (Multi‑Channel) – Simple DAT version
# Author: YnM | Edited: Markus ([email protected])
# Copyright © 2024‑2025 YnM – Minden jog fenntartva.
########################################################################
############################### Beállítások ##########################
set xp_db "YnM/tmp/xp.dat"
set xp_backup_dir "YnM/tmp/backups"
set xp_cooldown 5 ;# másodperc
set xp_backup_interval 21600 ;# 6 óra
set ::xp_excluded_nicks { "YnM-Ai" "YnM-Bridge" }
set ::xp_channels { "#Magyar" "#YnM" "#Help" }
array set ::ranks {
0 "Újonc"
100 "Haladó"
500 "Veterán"
1000 "Mester"
10000 "Legenda"
100000 "10‑zesek"
}
############################ Segédfüggvények #########################
proc xp_log {level msg} { putlog "XP $level: $msg" }
# --- Könyvtár‑ellenőrzés / létrehozás ---
proc ensure_dirs {} {
set dirs [list "YnM/tmp" "YnM/tmp/backups"]
foreach dir $dirs {
if {![file isdirectory $dir]} {
if {[catch {file mkdir $dir} err]} {
xp_log ERROR "Nem sikerült létrehozni: $dir – $err"
return 0
} else {
xp_log INFO "Létrehozva: $dir"
}
}
if {![file writable $dir]} {
xp_log ERROR "Nincs írási jog: $dir"
return 0
}
}
return 1
}
# --- DAT fájl betöltése dictbe ---
proc load_db {filename} {
set data [dict create]
if {![file exists $filename]} { return $data }
if {[catch {set fh [open $filename r]} err]} {
xp_log ERROR "Nem olvasható a fájl ($filename): $err"
return $data
}
while {[gets $fh line] >= 0} {
if {[regexp {^(\S+)\s+(\S+)\s+(\d+)\s+(\d+)\s+(\d+)$} $line -> chan nick xp lg tm]} {
dict set data $chan $nick \
[dict create xp $xp last_xp_gain $lg total_messages $tm]
} elseif {$line ne ""} {
xp_log WARN "Hibás sor kihagyva: $line"
}
}
close $fh
return $data
}
# --- Dict mentése DAT fájlba (hibatűrő) ---
proc save_db {filename data} {
if {[catch {set fh [open $filename w]} err]} {
xp_log ERROR "Nem írható a fájl ($filename): $err"
return 0
}
dict for {chan users} $data {
dict for {nick ud} $users {
if {[catch {set xp [dict get $ud xp]}]} { set xp 0 }
if {[catch {set lg [dict get $ud last_xp_gain]}]} { set lg 0 }
if {[catch {set tm [dict get $ud total_messages]}]} { set tm 0 }
puts $fh "$chan $nick $xp $lg $tm"
}
}
close $fh
return 1
}
# --- Rang meghatározása ---
proc get_rank {xp} {
set thresholds [lsort -integer -decreasing [array names ::ranks]]
foreach thr $thresholds {
if {$xp >= $thr} { return $::ranks($thr) }
}
return "Ismeretlen"
}
############################# XP kezelés #############################
# XP lekérdezése
proc get_xp {nick chan} {
set db [load_db $::xp_db]
if {[dict exists $db $chan $nick xp]} {
return [dict get $db $chan $nick xp]
}
return 0
}
# XP hozzáadása (cooldown‑nal)
proc add_xp {nick chan amount} {
set now [clock seconds]
set db [load_db $::xp_db]
if {[dict exists $db $chan $nick]} {
set ud [dict get $db $chan $nick]
if {[dict exists $ud last_xp_gain] &&
($now - [dict get $ud last_xp_gain]) < $::xp_cooldown} {
return "cooldown"
}
dict incr ud xp $amount
dict set ud total_messages [expr {[dict get $ud total_messages] + 1}]
} else {
set ud [dict create xp $amount total_messages 1]
}
dict set ud last_xp_gain $now
dict set db $chan $nick $ud
if {![save_db $::xp_db $db]} {
return ""
}
return [dict get $ud xp]
}
########################### IRC bind függvények ######################
# Üzenet alapján XP
bind pubm - * xp_gain
proc xp_gain {nick uhost hand chan text} {
if {[lsearch -exact $::xp_channels $chan] == -1} return
if {[lsearch -exact $::xp_excluded_nicks $nick] != -1} return
if {[string length $text] < 3 || [string index $text 0] eq "!"} return
set len [string length $text]
set words [llength [split $text]]
if {$words == 1} {
set add 1
} elseif {$len <= 10} {
set add 5
} elseif {$len <= 20} {
set add 10
} else {
set add 10
}
set oldxp [get_xp $nick $chan]
set oldrk [get_rank $oldxp]
set newxp [add_xp $nick $chan $add]
if {$newxp eq "cooldown" || $newxp eq ""} return
set newrk [get_rank $newxp]
if {$newrk ne $oldrk} {
putserv "PRIVMSG $chan :$nick rangot lépett: $newrk ($newxp XP)"
}
}
# !xp
bind pub - !xp xp_cmd
proc xp_cmd {nick uhost hand chan text} {
if {[lsearch -exact $::xp_channels $chan] == -1} return
set tgt [string trim $text]
if {$tgt eq ""} { set tgt $nick }
set db [load_db $::xp_db]
set outlist {}
dict for {c users} $db {
if {[dict exists $users $tgt]} {
set xp [dict get $users $tgt xp]
lappend outlist "$c: $xp XP"
}
}
if {[llength $outlist] == 0} {
putserv "PRIVMSG $chan :$tgt nem rendelkezik XP-vel egyik csatornán sem."
return
}
putserv "PRIVMSG $chan :$tgt XP értékei: [join $outlist {, }]"
}
bind pub n !xpreset resetxp_cmd
proc resetxp_cmd {nick uhost hand chan text} {
if {![matchattr $hand n]} return
set tgt [string trim $text]
if {$tgt eq ""} { putserv "PRIVMSG $chan :Használat: !resetxp NICK"; return }
set db [load_db $::xp_db]
dict set db $chan $tgt [dict create xp 0 last_xp_gain 0 total_messages 0]
save_db $::xp_db $db
putserv "PRIVMSG $chan :$tgt XP nullázva."
}
bind pub n !xpadd addxp_cmd
proc addxp_cmd {nick uhost hand chan text} {
if {![matchattr $hand n]} return
set args [split $text]
if {[llength $args] == 2} {
# formátum: NICK Mennyiség
set tgt [lindex $args 0]
set amount [lindex $args 1]
set target_chan $chan
} elseif {[llength $args] == 3} {
# formátum: CSATORNA NICK Mennyiség
set target_chan [lindex $args 0]
set tgt [lindex $args 1]
set amount [lindex $args 2]
# opcionálisan ellenőrizheted, hogy a target_chan benne legyen az engedélyezett csatornákban
if {[lsearch -exact $::xp_channels $target_chan] == -1} {
putserv "PRIVMSG $chan :Érvénytelen csatorna: $target_chan"
return
}
} else {
putserv "PRIVMSG $chan :Használat: !addxp [#csatorna] NICK Mennyiség"
return
}
if {![string is integer -strict $amount]} {
putserv "PRIVMSG $chan :Hibás mennyiség: $amount"
return
}
set newxp [add_xp $tgt $target_chan $amount]
if {$newxp ne "" && $newxp ne "cooldown"} {
putserv "PRIVMSG $chan :$tgt új XP: $newxp ($target_chan)"
}
}
# !xptop
bind pub - !xptop xptop_cmd
proc xptop_cmd {nick uhost hand chan text} {
if {[lsearch -exact $::xp_channels $chan] == -1} return
set db [load_db $::xp_db]
if {![dict exists $db $chan]} {
putserv "PRIVMSG $chan :Még nincs XP adat ezen a csatornán."
return
}
set top {}
dict for {u d} [dict get $db $chan] {
lappend top [list $u [dict get $d xp]]
}
set top [lsort -integer -decreasing -index 1 $top]
set top [lrange $top 0 9]
set out [list]
set r 1
foreach item $top {
lappend out "$r. [lindex $item 0] ([lindex $item 1] XP)"
incr r
}
putserv "PRIVMSG $chan :Top 10: [join $out {, }]"
}
# !globaltop
bind pub - !xpglobal xpglobal_cmd
proc xpglobal_cmd {nick uhost hand chan text} {
if {[lsearch -exact $::xp_channels $chan] == -1} return
set db [load_db $::xp_db]
# Létrehozunk egy dictet user => {csatorna => xp}
set users_dict [dict create]
dict for {c users} $db {
dict for {u d} $users {
set xp [dict get $d xp]
if {[dict exists $users_dict $u]} {
dict set users_dict $u $c $xp
} else {
dict set users_dict $u [dict create $c $xp]
}
}
}
if {[dict size $users_dict] == 0} {
putserv "PRIVMSG $chan :Nincs XP adat az adatbázisban."
return
}
# Kimenet összeállítása felhasználónként
set outlist {}
dict for {user chans} $users_dict {
set parts {}
dict for {ch xp} $chans {
lappend parts "$ch: $xp XP"
}
lappend outlist "$user XP értékei: [join $parts {, }]"
}
# Üzenetek küldése (több sor is lehet)
foreach line $outlist {
putserv "PRIVMSG $chan :$line"
}
}
bind pub n !xpdel xpdel_cmd
proc xpdel_cmd {nick uhost hand chan text} {
if {![matchattr $hand n]} return
set tgt [string trim $text]
if {$tgt eq ""} {
putserv "PRIVMSG $chan :Használat: !xpdel Nick"
return
}
set db [load_db $::xp_db]
set found 0
dict for {c users} $db {
if {[dict exists $users $tgt]} {
dict unset users $tgt
dict set db $c $users
set found 1
}
}
if {!$found} {
putserv "PRIVMSG $chan :$tgt nem szerepel az XP adatbázisban."
return
}
if {[save_db $::xp_db $db]} {
putserv "PRIVMSG $chan :$tgt XP adatai minden csatornából törölve lettek."
} else {
putserv "PRIVMSG $chan :Hiba történt az XP adatbázis mentésekor."
}
}
######################## Biztonsági mentés timer #####################
proc backup_db {} {
set ts [clock format [clock seconds] -format "%Y%m%d_%H%M%S"]
set dest "$::xp_backup_dir/xp_backup_$ts.dat"
if {[file exists $::xp_db]} {
catch { file copy -force $::xp_db $dest }
xp_log INFO "Backup készült: $dest"
}
# --- Régi backup fájlok törlése (max 5 maradjon meg) ---
set backup_files [glob -nocomplain -directory $::xp_backup_dir xp_backup_*.dat]
set sorted [lsort -increasing $backup_files]
set excess_count [expr {[llength $sorted] - 5}]
if {$excess_count > 0} {
foreach f [lrange $sorted 0 [expr {$excess_count - 1}]] {
catch { file delete -force $f }
xp_log INFO "Régi backup törölve: $f"
}
}
timer $::xp_backup_interval backup_db
}
############################### Indítás ##############################
if {![ensure_dirs]} { xp_log ERROR "Könyvtárhiba, kilépés."; return }
if {[file exists $xp_db]} {
xp_log INFO "XP adatbázis betöltve: $xp_db"
} else {
save_db $xp_db [dict create]
xp_log INFO "Új üres adatbázis létrehozva: $xp_db"
}
backup_db
xp_log INFO "Multi‑channel XP system (DAT) loaded"