# librarie pour gestion des scripts publiques de MountyHall # par Tyrollus (johnatofjj.net) require 'libhttpclient' require 'libhtml' class MHInfo @@files = %w{Competences Diplomatie Distinctions Equipement Guildes GuildeRangs Monstres Mouches Sortileges StationsTGV Tresors TresorsMagie Trolls Trolls2} @@local_cache_pfx = '.mh_cache/' def self.local_cache_pfx() @@local_cache_pfx end def self.local_cache_pfx=(cp) @@local_cache_pfx = cp end def self.load_monstre_cache cachefile = @@local_cache_pfx + 'file_monstre_niveau' @@monstre = Hash.new begin File.open(cachefile) { |fd| fd.each { |l| s = l.chomp.split(';') @@monstre[s[0]] = s[1] } } rescue Errno::ENOENT end end def self.save_monstre_cache cachefile = @@local_cache_pfx + 'file_monstre_niveau' File.open(cachefile, 'w') { |fd| @@monstre.each { |k, v| fd.puts "#{k};#{v}" } } rescue nil end @@monstre = nil @@httpserver_monstres = HttpClient.new('trolls.ratibus.net').http_s # 'trolls.game-host.org').http_s def self.monstre_niveau(nom) load_monstre_cache unless @@monstre return @@monstre[nom] if @@monstre[nom] # http://trolls.game-host.org/mountyhall/cdm.php?monstre=Ma%EEtre+Squelette+%5BNaissant%5D req = '/mountyhall/cdm.php?monstre=' req += HttpServer.urlenc nom raw = @@httpserver_monstres.get(req).content p = parsehtml(raw) go = false p.each { |e| if go and e.type == 'String' e['content'] =~ / (\d+)$/ @@monstre[nom] = $1 break end go = true if e.type == 'h1' } save_monstre_cache @@monstre[nom] end @@httpserver_www = HttpClient.new('www.mountyhall.com').http_s def self.get_file(base, timeout = 24*3600) raise "invalid base #{base.inspect}" unless @@files.include? base cachefile = @@local_cache_pfx + 'file_' + base if File.exists?(cachefile) and Time.now.to_i - File.stat(cachefile).mtime.to_i < timeout or $nonet return File.read(cachefile) end req = '/ftp/Public_'+base+'.txt' puts "retrieving public file #{req} from www" raw = @@httpserver_www.get(req).content File.open(cachefile, 'w') { |fd| fd.write raw } raw end def self.update_cache @@files.each { |f| get_file(f, 0) } end @@httpserver_sp = HttpClient.new('sp.mountyhall.com').http_s def self.get_generic(script, login, pass, timeout, values = {}) cachefile = @@local_cache_pfx + script.downcase + login if File.exists?(cachefile) and Time.now.to_i - File.stat(cachefile).mtime.to_i < timeout or $nonet return File.read(cachefile) end values['Numero'] = login values['Motdepasse'] = pass req = "/SP_#{script}.php?" + values.map { |k, v| "#{k}=#{v}" } * '&' puts "req #{req}" if $VERBOSE raw = @@httpserver_sp.get(req).content File.open(cachefile, 'w') { |fd| fd.write raw } raw end def self.get_spprofil(login, passr, timeout = 6*3600) get_generic('Profil', login, passr, timeout) end def self.get_spvue(login, passr, timeout = 6*3600) get_generic('Vue', login, passr, timeout, 'Tresors' => 1, 'Lieux' => 1, 'Champignons' => 1) end def self.get_splistesvente(login, passr, timeout = 6*3600) get_generic('Listesdevente', login, passr, timeout) end def self.get_spbm(login, passr, timeout = 6*3600) get_generic('Bonusmalus', login, passr, timeout) end def self.get_equip(login, passr, timeout = 6*3600) get_generic('Equipement', login, passr, timeout) end def self.help puts <<-EOH ORDRE DES CHAMPS DANS LES LISTES PUBLIQUES : ** Public_Trolls.txt ** Id ; Nom ; Race ; Niveau ; Nb de Kills ; Nb de Morts ; Id Guilde ; Nb de Mouches ** Public_Trolls2.txt ** Id ; Nom ; Race ; Niveau ; Nb de Kills ; Nb de Morts ; Nb de Mouches ; Id Guilde ; Rang Guilde ; Etat Troll ; Intangible (*); PNJ (*) ; Ami de MH (*) ; Date d'Inscription ; Blason ** Publics_Guildes.txt ** Id ; Nom ; Nb Membres ** Public_GuildesRangs.txt ** Id Guilde ; Rang ; Description; ** Public_Sortileges.txt ** Id ; Nom ; Type ; Cout PA ; Duree ; Usage RM (*) ; Usage en Surface (*) ; Effet de Zone (*) ** Public_Competences.txt ** Id ; Nom ; Type ; Cout PA ; Pourcentage Base ; Niveau Minimum ** Public_Tresors.txt ** Id ; Nom ; Type ** Public_TresorsMagie.txt ** Id ; Nom ** Public_Distinctions.txt ** Id Troll ; Nom ** Public_Equipement.txt ** Id ; Id Troll ; Nom ; Magie ; Type ; Identification (*); ** Public_Diplomatie.txt ** Id Guilde ; Type (**) ; Id Cible ; Description ; Ami ou Ennemi (*) 1 : Oui, 0 : Non (**) G : Guilde, T : Troll ** Public_StationsTGV.txt ** Id Lieu ; Position X ; Position Y ; Position N ; Prix public ; Coefficient ; Nom du Lieu ; EOH end end class Array def shrink!(sz, elem, sep) # reduit le tableau a sz length en mergeant elem avec elem+1 while length > sz self[elem] << sep << delete_at(elem+1) end self[elem] end end class MHElem attr_reader :attrs, :cat attr_reader :id, :x, :y, :n attr_accessor :nom, :guilde, :lvl def initialize(cat, s) @cat = cat @attrs = s.split ';' @nom = @guilde = @lvl = nil if @attrs.length == 4 @id, @x, @y, @n = @attrs.map { |e| e.to_i } else @nom = @attrs.shrink!(5, 1, ?;) @id, bla, @x, @y, @n = @attrs.map { |e| e.to_i } end end def trollinfo(i) # Id ; Nom ; Race ; Niveau ; Kills ; Morts ; Nb mch ; Gld ; Rg Gld ; Etat ; Itg ; PNJ ; ami mh ; Date Inscr ; Blason @nom = i[1] @race = i[2] @lvl = i[3].to_i @guilde = i[7].to_i if i[7].to_i != 1 @misc = i[9..-1] end attr_reader :misc end class MHVueSP attr_reader :raw attr_reader :cat def initialize @raw = '' @cat = Hash.new @parsed = false end def dump parse @cat.map { |k, v| ["#DEBUT #{k}", v.map { |el| el.attrs.join ';' }, "#FIN"] }.flatten.join("\n") end def update raw @parsed = false @raw << raw end def calc_dist(src) @cat.each { |k, v| v.each { |e| if src e.d = [e.x, e.y, e.n].zip(src).map { |c1, c2| (c1.to_i - c2.to_i).abs }.max else e.d = e.n.to_i end } } end def parse return @cat if @parsed cat = ar = nil @raw.each { |l| l.chomp! case l when /^#DEBUT (.*)/: cat = $1 ; ar = @cat[cat] ||= [] when /^#FIN/: ar = nil else ar << MHElem.new(cat, l) end } sp = t = nil if @cat['TROLLS'] unk_trolls = @cat['TROLLS'].dup.sort_by { |t| t.id } MHInfo.get_file('Trolls2').each { |t| sp = t.chomp.split(';') dx = sp[0].to_i if dx == unk_trolls[0].id sp.shrink!(15, 1, ?;) unk_trolls.shift.trollinfo(sp) end while unk_trolls[0] and dx > unk_trolls[0].id unk_trolls.shift.nom ||= '' end break if unk_trolls.empty? } unk_guild = @cat['TROLLS'].map{ |t| t.guilde }.uniq.compact.sort MHInfo.get_file('Guildes').each { |g| sp = g.chomp.split(';') dx = sp[0].to_i if dx == unk_guild[0] sp.shrink!(3, 1, ?;) @cat['TROLLS'].each { |t| t.guilde = sp[1] if t.guilde == dx } unk_guild.shift end while not unk_guild.empty? and dx > unk_guild[0] unk_guild.shift end break if unk_guild.empty? } end @cat['MONSTRES'].each { |m| m.lvl = MHInfo.monstre_niveau(m.nom).to_i rescue 0 } rescue nil # remove dupes (for catted multiple vues) @cat.each_value { |ar| seen = [] ar.delete_if { |x| s = seen.include? x.id seen << x.id s } } @parsed = true @cat end end