class Mounty def self.portee(x) ((Math.sqrt(19+8*(x+3))-7)/2).ceil end def to_s stat = [:pa, :px, :pi].map { |k| "#{@status[k]}#{k}".rjust(k == :pa ? 3 : 4) }.join(' ') stat << " n#{@status[:lvl]}" stat << " [#{pos.join ' '}]" stat << " #{@status[:pv]}/#{@caracs[:pv]}" ['att', 'deg', 'esq', 'reg', 'vue', 'arm', 'rm', 'mm'].each { |c| stat << ' ' << (c.length == 2 ? c : c[0,1]) << "#{self[c.to_sym]}+#{self['bm_'+c]}".sub('+-', '-') rescue nil stat << "+#{self['bmm_'+c]}".sub('+-', '-') if self['bmm_'+c] rescue nil stat << "-#{self[:nb_attaques_subies]}" if c == 'esq' and self[:nb_attaques_subies].to_i > 0 } stat << " f#{@status[:fatigue]}" if @status[:fatigue].to_i >= 0 rescue nil stat << ' [invisible]' if @status[:invisible] stat << ' [camou]' if @status[:camoufled] stat << ' [intangible]' if @status[:intangible] stat << ' [vlc]' if @status[:voit_le_cache] stat << ' [glue]' if @status[:englue] stat << ' [flotte]' if @status[:levite] cc = @status[:concentration] stat << " #{'+' if cc > 0}#{cc}%" if cc.to_i != 0 stat << ' dla ' << @status[:dla].strftime('%H:%M:%S') if @status[:dla] d1 = @caracs[:duree_tour] d2 = @status[:duree_prochain_tour] stat << " #{d1.join('h')}+#{d2[0]*60+d2[1]-d1[0]*60-d1[1]}" if d1 stat end def inspect "#" end def [](c) bla = [@comps, @status, @caracs].inject { |a, b| b.merge a } bla[c] or bla[bla.keys.find { |k| k.to_s =~ /^#{c}/i } || bla.keys.find { |k| k.to_s =~ /#{c}/i }] or (cm = c.to_s[/^bm_(.*)/, 1] ; cm and @caracs_bm[@caracs_bm.keys.find { |k| k.to_s.downcase =~ /#{cm}/ }]) or (cmm = c.to_s[/^bmm_(.*)/, 1] ; cmm and @caracs_bmm[@caracs_bmm.keys.find { |k| k.to_s.downcase =~ /#{cmm}/ }]) end def pos ; @status.values_at(:x, :y, :n) end def x ; @status[:x] end def y ; @status[:y] end def n ; @status[:n] end def pa ; @status[:pa] end def lvl ; @status[:level] end def fatigue if (f = @status[:fatigue]) >= 0 arr = [] while f > 4 arr << f f = (f/1.25).to_i end arr end end attr_reader :status, :caracs, :comps, :caracs_bm, :caracs_bmm, :gg def now Time.now + (@now_delta || 0) end def profil return self if (@http_client.history - ['/mountyhall/MH_Play/Play_vue.php']).last =~ /MH_Play\/Play_profil(_rev)?.php/ d "profil" menu_get '/mountyhall/MH_Play/Play_profil.php' @status ||= {} @caracs ||= {} @comps ||= {} @caracs_bm ||= {} @caracs_bmm ||= {} txt = get_text(nil, false).gsub(/\.\.+/, '').gsub(/\s+:/, ':') parse_duree = proc { |start| /#{start}.*?(?:(\d+) heures? et )?(\d+) minutes?/.match(txt).captures.map { |i| i.to_i } rescue nil } parse_carac = proc { |start, id| md = /#{start} *:? *([+-]?\d+) *(?:D\d|Cases|points)? *([+-]\d+) *([+-]\d+)?/i.match(txt) @caracs[id] = md[1].to_i @caracs_bm[id] = md[2].to_i @caracs_bmm[id] = md[3].to_i if md[3] } @now_delta = Time.mktime(*%r{Heure Serveur: (\d+)/(\d+)/(\d+) (\d+):(\d+):(\d+)}.match(txt).values_at(3, 2, 1, 4, 5, 6)) - Time.now rescue nil @status[:matricule] = txt[/Identifiants: (\d+)/, 1].to_i @status[:nom] = txt[/Identifiants: \d+ - (.*)/, 1] @status[:race] = txt[/Race: (.*)/, 1] @status[:date_creation] = Time.mktime(*txt[/Date de Cr.ation: (.*)/, 1].split('/').reverse) rescue nil @status[:dla] = Time.mktime(*%r{Date Limite d'Action: (\d+)/(\d+)/(\d+) (\d+):(\d+):(\d+)}.match(txt).values_at(3, 2, 1, 4, 5, 6)) rescue nil @status[:pa] = txt[/Il me reste (\d+) PA/, 1].to_i @caracs[:duree_tour] = parse_duree.call 'Dur.e normale de mon Tour' @status[:duree_blessures] = parse_duree.call 'Augmentation due aux blessures' @status[:poids_equipement] = parse_duree.call 'Poids de l..quipement' @status[:duree_prochain_tour] = parse_duree.call 'Dur.e de mon prochain Tour' @status[:x], @status[:y], @status[:n] = %r{Position X = (-?\d+) \| Y = (-?\d+) \| N = (-?\d+)}.match(txt).captures.map { |i| i.to_i } @status[:camoufled] = txt[/\[camoufl\S*\]/i] @status[:intangible] = txt[/\[intangible\]/i] @status[:invisible] = txt[/\[invisible\]/i] @status[:levite] = txt[/\[l\S*vite\]/i] @status[:vlc] = @status[:voit_le_cache] = txt[/\[voit le cach\S*\]/i] @status[:englue] = txt.include?('[Immobilis') || txt.include?('[Englu') @status[:niveau] = @status[:level] = @status[:lvl] = txt[/Niveau: (\d+)/, 1].to_i @status[:pitot] = txt[/Niveau: \d+ \((\d+) PI\)/, 1].to_i @status[:pi] = txt[/PI: (\d+)/, 1].to_i @status[:pxr] = txt[/PX: (\d+)/, 1].to_i @status[:pxp] = txt[/PX Personnels?: (\d+)/, 1].to_i @status[:px] = @status[:pxp] + @status[:pxr] @status[:pv] = txt[/Actuels: (\d+)/, 1].to_i pvmaxbonus = txt[/Maximum: \d+\s*([+-]\d+)/, 1].to_i @caracs[:pv] = @status[:pvmax] = txt[/Maximum: (\d+)/, 1].to_i + pvmaxbonus @status[:fatigue] = (txt[/Fatigue(?: du Kastar)? ?:.*? (\d+)/, 1] || -1).to_i @status[:minute_per_pv] = txt[/Fatigue du Kastar: \d+ \(1 PV = (\d+)'\)/, 1].to_i @status[:nb_attaques_subies] = txt[/Nb d'Attaques subies ce Tour: (\d+)/, 1].to_i @status[:nb_meurtres] = txt[/Nombre d'Adversaires tu.s: (\d+)/, 1].to_i @status[:nb_morts] = txt[/Nombre de D.c.s: (\d+)/, 1].to_i @status[:concentration] = txt[/Bonus de Concentration: (-?\d+)/, 1].to_i [['Vue', :vue], ['R.g.n.ration', :regeneration], ['Attaque', :attaque], ['Esquive', :esquive], ['D.g.ts', :degats], ['Armure', :armure], ['R.sistance . la Magie', :rm], ['Ma.trise de la Magie', :mm] ].each { |st, id| parse_carac.call st, id } @caracs_bm[:regeneration] += @caracs_bmm.delete :regeneration @caracs[:vue_tot] = @caracs[:vue].to_i + @caracs_bm[:vue].to_i + @caracs_bmm[:vue].to_i amnlist = [] txt[/\nComp.tences\b.*/m].scan(/(.*?)(?: \(-(\d+) ?%\))? -?>? ?\(?niveau (\d+): (\d+) %\)?/) { |cmp, amn, nv, pc| cmp = 'Atq precise' if cmp =~ /attaque.*pr.*cise/i amnlist << cmp if amn.to_i >= pc.to_i @comps[cmp] = [nv.to_i, pc.to_i] #@comps[cmp + nv] = pc.to_i } amnlist.each { |a| @comps.delete a } self end def messages(nr = nil, cat = nil) d "messagerie" if not nr or @http_client.curpage.parse('a').map { |e| e['href'] }.grep(/^ViewMessage.*msgId=#{nr}/).empty? p = menu_get '/mountyhall/Messagerie/MH_Messagerie.php' case cat.to_s when 'bot': p = get 'MH_Messagerie.php?cat=9' when 'archive': p = get 'MH_Messagerie.php?cat=5' when 'sent': p = get 'MH_Messagerie.php?cat=2' end else p = @http_client.curpage end msgs = p.parse('a').map { |e| e['href'] }.grep(/^ViewMessage/) if nr url = msgs.find { |u| u =~ /msgId=#{nr}/ } return unless url bck = @http_client.status_save @http_client.get_url_allowed << "/mountyhall/Messagerie/#{url[/.*(?=\?)/]}" get url txt = get_text.reject { |l| l =~ /^[\*=]*$|votre compte pour recevoir|est impliqu.* dans un .*nement|recevoir ces Emails|configuration dans le profil| : http:.*mountyhall.com/i }.join.chomp puts txt, '' @http_client.status_restore bck txt else puts get_text.sub(/Messages.*?Page 1/m, '') msgs.map { |u| u[/msgId=(\d+)/, 1].to_i } end end def messages_bot(nr = nil) messages nr, 'bot' end def message_send(dest, subj, body) menu_get '/mountyhall/Messagerie/MH_Messagerie.php' get 'MH_Messagerie.php?cat=3' dest = [dest] unless Array === dest dest = dest.map { |d| " #{d}," }.join pd = @http_client.post_allowed.first pd.vars.delete 'bAddTrollOnId' pd.vars.delete 'bEmptyDest' post pd.url, pd.vars.merge('Titre' => subj, 'Message' => body, 'sbMSG_destinataires' => '', 'MSG_destinataires' => dest) puts get_text.grep(/envoy/i) end def options menu_get '/mountyhall/MH_Play/Play_option.php' show nil, false end def description menu_get '/mountyhall/MH_Play/Play_option.php' get '/mountyhall/MH_Play/Options/Play_o_Descr.php' get_text end def description=(txt) menu_get '/mountyhall/MH_Play/Play_option.php' get '/mountyhall/MH_Play/Options/Play_o_Descr.php' pd = @http_client.post_allowed.first post pd.url, pd.vars.merge('as_Description' => txt) end def lieu(verb=true) d "lieu" menu_get '/mountyhall/MH_Lieux/Lieu_Description.php' t = get_text puts t if verb t end def bm d "bonus/malus" menu_get '/mountyhall/MH_Play/Play_BM.php' show_table_content end def mouches d "mouches" menu_get '/mountyhall/MH_Play/Play_mouche.php' show_table_content end def equipement(id=nil, verb = true) d "equipement" p = menu_get '/mountyhall/MH_Play/Play_equipement.php' if id @http_client.get_url_allowed << '/mountyhall/View/TresorHistory.php' get "/mountyhall/View/TresorHistory.php?ai_IDTresor=#{id}" show nil, false else curp, cur = [], [] # ret = [[[42, 'botte equip', 'bon etat', 'esq: +2']], [[432, 'casque', 'intact', 'att: +4']]] # XXX 'casque [Ballu]', should move ballu.. ret = [[]] show = proc { |s| puts s if s.length > 0 and verb case s when /\[(\d+)\]\s*(.*)/ id, eq = $1.to_i, $2 if eq =~ /(.*) Etat : (\S+(?: etat)?) (.*)/i eq, et, car = $1, $2, $3 end ret.last << [id, eq, et, car] when /(\d+) gigots/i @gg = $1.to_i ret << [] end } p.each_table { |pos, el| next if el.type != 'String' el = el['content'] next if pos.length < 3 next if pos[0, 2] != [[1, 2, 1], [1, 1, 1]] or pos[2][0] != 3 # XXX jj 3 -> 4 -> 3 next if pos[2] == [3, 4, 2] if pos[2] == [3, 1, 1] next if not pos[3] # titre colonne (tete/cou/pieds) next if (pos[3][1] % 2 != 0 and pos[3][1] != 7) next if pos[3] == [1, 6, 4] end if curp[0, 4] != pos[0, 4] curp = pos.map { |e| e.dup } show[cur.join(' ').strip] cur.clear end cur << HttpServer.htmlentitiesdec(el.gsub(/(?: |\s)+/, ' ').strip) } ret.first.uniq! # 2 handed weapon show[cur.join(' ').strip] ret end end # return array of |id| (non idt) or |'18481234', 'oeil', 'momie', 'tres bonne', 'tete', ' [balluchonn\xe9]'| def petit_equipement d "petit equipement" equipement(nil, false) get '/mountyhall/MH_Play/Play_e_ChampComp.php' t = get_text puts t t.scan(/\[(\d+)\] (?:(.*) d'une? (.*) de Qualit. (.*?) \[(.*?)\](.*)|Composant)/) end def equip_commandes equipement nil, false get '/mountyhall/MH_Play/Play_e_enchantements.php' show end attr_accessor :cursuivant def suivants(id=nil, cat=nil, *list) d "suivants" if id.kind_of? ::Symbol list.unshift cat id, cat = cursuivant, id end if not id or @http_client.cur_url !~ /MH_Follower/ equipement(nil, false) if @http_client.cur_url !~ /Play_equipement/ p = get '/mountyhall/MH_Play/Play_equipement.php?as_CurSect=follo' flwlist = p.parse('a').map { |e| e['href'] }.grep(/MH_Follower/).map { |e| e[/IdFollower=(\d+)/, 1] } @cursuivant = id = flwlist.grep(/#{id}/).first if id or flwlist.length == 1 if not id show nil, false return flwlist end else id = @cursuivant if cursuivant and @cursuivant.include? id.to_s end get "/mountyhall/MH_Follower/FO_Profil.php?ai_IdFollower=#{id}" if @http_client.cur_url !~ /MH_Follower/ case cat when nil; [id] when :profil get "/mountyhall/MH_Follower/FO_Profil.php?ai_IdFollower=#{id}" show nil, false when :ordre, :ordres p = get "/mountyhall/MH_Follower/FO_Ordres.php?ai_IdFollower=#{id}" case list.shift when nil show nil, false when :effacer # :effacer, 0 => efface 1er ordre (qqsoit son num) lnks = p.parse('a').map { |e| e['href'] }.grep /DeleteOrder.php/ nr = list.shift nr ||= 0 if lnks.length == 1 if not lnks[nr] puts "bad order nr (1st = 0, ... #{lnks.length})" return end get lnks[nr] show get_confirm suivants(id, :ordres) when :aller, :move, :move_to #raise "invalid order #{order.inspect} (aller, suivre, attaquer, arret)" if not oid = {:aller => 1, :suivre => 2, :attaquer => 3, :arret => 5}[order] pd = @http_client.post_allowed.first get HttpServer.get_form_url(pd.url, pd.vars.merge('ai_IdOrdre' => '1')) pd = @http_client.post_allowed.first x = list.shift if x.kind_of? Array x, y, z = x else y, z = list.shift, list.shift end get HttpServer.get_form_url(pd.url, pd.vars.merge('ai_X' => x.to_s, 'ai_Y' => y.to_s, 'ai_N' => z.to_s)) show get_confirm suivant @cursuivant, :ordres, :foo when :suivre pd = @http_client.post_allowed.first get HttpServer.get_form_url(pd.url, pd.vars.merge('ai_IdOrdre' => '2')) pd = @http_client.post_allowed.first if not target = list.shift or not target = pd.vars['ai_IdTarget'].grep(/#{target}/).first show nil, false, false @http_client.get_url_allowed << '/mountyhall/MH_Follower/FO_Ordres.php' suivant @cursuivant, :ordres, :foo pd.vars['ai_IdTarget'] else dist = list.shift dist ||= 1 get HttpServer.get_form_url(pd.url, pd.vars.merge('ai_IdTarget' => target, 'ai_Distance' => dist.to_s)) show get_confirm suivant @cursuivant, :ordres, :foo rescue nil end when :attaquer, :attaque pd = @http_client.post_allowed.first get HttpServer.get_form_url(pd.url, pd.vars.merge('ai_IdOrdre' => '3')) pd = @http_client.post_allowed.first if not target = list.shift or not target = pd.vars['ai_IdTarget'].grep(/#{target}/).first show nil, false, false @http_client.get_url_allowed << '/mountyhall/MH_Follower/FO_Ordres.php' suivant @cursuivant, :ordres, :foo pd.vars['ai_IdTarget'] else get HttpServer.get_form_url(pd.url, pd.vars.merge('ai_IdTarget' => target)) show get_confirm suivant @cursuivant, :ordres, :foo rescue nil end when :arret, :stop pd = @http_client.post_allowed.first get HttpServer.get_form_url(pd.url, pd.vars.merge('ai_IdOrdre' => '5')) pd = @http_client.post_allowed.first get HttpServer.get_form_url(pd.url, pd.vars) show get_confirm end when :equip, :equipement get "/mountyhall/MH_Follower/FO_Equipement.php?ai_IdFollower=#{id}" show nil, false, false when :descr, :description get "/mountyhall/MH_Follower/FO_Description.php?ai_IdFollower=#{id}" show nil, false, false end end alias suivant suivants def evenements(verbose = true, cat = nil) d "evenements" raise "invalid category #{cat}" if cat and not %w{ACHAT AMELIORATION APPARITION COMBAT COMPETENCE DEPLACEMENT DIVERS ENTRAINEMENT GUILDE MONSTRE MORT PARCHEMIN POTION SORTILEGE TRESOR}.include? cat and not ['DON de PX', 'DON de GG'].include? cat parm = [] parm << ['as_EventType', cat] if cat set_ctx :menu get HttpServer.get_form_url('/mountyhall/MH_Play/Play_evenement.php', parm) show_table_content nil, verbose end def evenements_troll(id, cat = nil, verbose = true) set_ctx :vue if not @http_client.cur_url =~ /MH_event/i end def evenements_monstre(id, cat = nil, verbose = true) end def liste_taniere(id=nil, verb=true) vue liste = @http_client.curpage.parse('a').map { |e| $1.to_i if e['href'] =~ /TaniereDescription\.php\?ai_IDLieu=(\d+)/ }.compact return liste if not id return if not liste.include? id.to_i get "/mountyhall/View/TaniereDescription.php?ai_IDLieu=#{id}" t = get_text puts t if verb set_ctx :vue t end def guilde(topic=nil, target=nil, args=nil) set_ctx :menu get '/mountyhall/MH_Guildes/Guilde.php' case topic when :membre, :membres get 'Guilde_Membres.php' when :membre_new, :membres_new, :newmembre get 'Guilde_NewMembres.php' when :rang, :rangs get 'Guilde_Rangs.php' when :diplo get 'Guilde_o_AmiEnnemi.php' when :passer_flambeau get 'Guilde_NewLeader.php' end show end class Vue attr_reader :monstres, :trolls, :tresors, :champignons, :lieux class Elem attr_accessor :dist, :id, :nom, :x, :y, :n, :marquage attr_accessor :esq, :hit, :rm, :arm, :niveau alias name nom def mat ; @id end def initialize(dist, id, nom, x, y, n=nil) nom, x, y, n, id = id, nom, x, y, n if not n # champi @dist, @id, @nom, @x, @y, @n = dist.to_i, (id.to_i if id), nom, x.to_i, y.to_i, n.to_i if @nom =~ /.+ \[.+\]( .+)/ # [bidouille] foo @marquage = $1 @nom.sub!(@marquage, '') end end def pos [@x, @y, @n] end def [](key) instance_variable_get "@#{key}" end def []=(key, val) instance_variable_set "@#{key}", val end def niv_s niveau ? @niveau.to_s.rjust(2).ljust(3) : '' end def to_s(showpos=true) (showpos ? "#@dist (#{@x.to_s.rjust 3},#{@y.to_s.rjust 3},#{@n.to_s.rjust 3})" : "#@dist#{' '*14}") + " #{"[#@id]".ljust 9 if @id} #{niv_s}#@nom#@marquage" end end class Troll < Elem attr_accessor :race, :guilde alias lvl niveau def initialize(dist, id, nom, niveau, race, guilde, x, y, n) super(dist, id, nom, x, y, n) @niveau, @race, @guilde = niveau.to_i, race, guilde end def niv_s @race[0, 1].upcase + super end def to_s(showpos=true) super + (guilde ? " - #{@guilde.inspect}" : '') end end def initialize @monstres = [] @trolls = [] @tresors = [] @champignons = [] @lieux = [] @acc = [] end def all ary = [:monstres, :trolls, :tresors, :champignons, :lieux] if block_given? ary.each { |sv| yield send(sv) } else ary.map { |sv| send sv }.flatten end end def anim @monstres + @trolls end def feed(pos, value) return if value.type != 'String' return if pos.length != 3 or pos[0] != [1, 2, 1] or pos[1] != [1, 1, 1] return if pos[2][1] == 1 # titres colonnes # XXX jj 28/3/08 11h: 3 -> 4 # XXX jj 18/6/09 14h: 4 -> 3 cat = pos[2][0] - 3 return unless limit = [6, 9, 6, 5, 6][cat] (@acc[pos[2][2]-1] ||= []) << value['content'] if pos[2][2] == limit [@monstres, @trolls, @tresors, @champignons, @lieux][cat] << [Elem,Troll,Elem,Elem,Elem][cat].new(*@acc.map { |e| e.join(' ') if e }) @acc.clear end end def to_s(inc=[:trolls, :monstres, :tresors, :champignons, :lieux]) lastpos = nil inc.inject([]) { |a, m| a + send(m) }.sort_by { |e| [e.dist, e.n, e.x, e.y, e.id.to_i] }.map { |e| f = (e.pos != lastpos) lastpos = e.pos e.to_s f }.join("\n") end def inspect "#" end end def vue(lim=200, vlim=(lim+1)/2) d "vue" p = menu_get '/mountyhall/MH_Play/Play_vue.php' @http_client.get_url_allowed << '/mountyhall/View/TaniereDescription.php' @http_client.get_url_allowed << '/mountyhall/View/TresorHistory2.php' save_ctx(:vue) v = Vue.new p.each_table { |pos, value| v.feed(pos, value) } @case_occupee = ((self[:n] != 0) && v.anim.find { |e| e.dist == 0 }) v.monstres.each { |e| e.niveau = monstre_niveau(e.nom) } if respond_to? :monstre_niveau v.all { |t| t.delete_if { |e| e.dist > lim or (e.n - self[:n]).abs > vlim } } v end def vue_limit vue h = @http_client.post_allowed.first.vars [h['ai_MaxVue'], h['ai_MaxVueVert']] end def vue_limit=(lim) vue pd = @http_client.post_allowed.first post pd.url, pd.vars.merge('ai_MaxVue' => lim.first.to_s, 'ai_MaxVueVert' => lim.last.to_s) end end