Commit f8d64192 authored by 神楽坂玲奈's avatar 神楽坂玲奈

linux fix

parent 5b522cc2
source http://rubygems.org
source 'http://rubygems.org'
ruby '1.9.3'
gem 'rubysdl', :platform => :ruby
......
......@@ -11,6 +11,56 @@ module Association
Win32::Registry::HKEY_CLASSES_ROOT.create('.ydk') { |reg| reg[nil] = 'mycard' }
Win32::Registry::HKEY_CLASSES_ROOT.create('.yrp') { |reg| reg[nil] = 'mycard' }
Win32::Registry::HKEY_CLASSES_ROOT.create('.deck') { |reg| reg[nil] = 'mycard' }
else
require 'fileutils'
FileUtils.mkdir_p("#{ENV['HOME']}/.local/share/applications") unless File.directory?("#{ENV['HOME']}/.local/share/applications")
open("#{ENV['HOME']}/.local/share/applications/mycard.desktop", 'w') { |f| f.write <<EOF
#!/usr/bin/env xdg-open
[Desktop Entry]
Name=Mycard
Name[zh_CN]=Mycard - 萌卡
Comment=a card game platform
Comment[zh_CN]=卡片游戏对战客户端
Exec=/usr/bin/env ruby -KU lib/main.rb %u
Terminal=false
Icon=#{Dir.pwd}/graphics/system/icon.png
Type=Application
Categories=Game
Path=#{Dir.pwd}
URL=http://my-card.in/
MimeType=x-scheme-handler/mycard;application/x-ygopro-deck;application/x-ygopro-replay'
EOF
}
FileUtils.mkdir_p("#{ENV['HOME']}/.local/share/mime/packages") unless File.directory?("#{ENV['HOME']}/.local/share/mime/packages")
open("#{ENV['HOME']}/.local/share/mime/packages/application-x-ygopro-deck.xml", 'w') { |f| f.write <<EOF
<?xml version="1.0" encoding="UTF-8"?>
<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">
<mime-type type="application/x-ygopro-deck">
<comment>ygopro deck</comment>
<icon name="application-x-ygopro-deck"/>
<glob-deleteall/>
<glob pattern="*.ydk"/>
</mime-type>
</mime-info>
EOF
}
open("#{ENV['HOME']}/.local/share/mime/packages/application-x-ygopro-replay.xml", 'w') { |f| f.write <<EOF
<?xml version="1.0" encoding="UTF-8"?>
<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">
<mime-type type="application/x-ygopro-replay">
<comment>ygopro replay</comment>
<icon name="application-x-ygopro-replay"/>
<glob-deleteall/>
<glob pattern="*.yrp"/>
</mime-type>
</mime-info>
EOF
}
system("install -D #{Dir.pwd}/graphics/system/icon.png ~/.icons/application-x-ygopro-deck.png")
system("install -D #{Dir.pwd}/graphics/system/icon.png ~/.icons/application-x-ygopro-replay.png")
system("xdg-mime default mycard.desktop application/x-ygopro-deck application/x-ygopro-replay x-scheme-handler/mycard")
system("update-mime-database #{ENV['HOME']}/.local/share/mime")
system("update-desktop-database #{ENV['HOME']}/.local/share/applications")
end
end
......@@ -23,19 +73,22 @@ module Association
end
def need?
return false unless Windows
return false if $config['no_assoc']
path, command, icon = paths
require 'win32/registry'
begin
Win32::Registry::HKEY_CLASSES_ROOT.open('mycard') { |reg| return true unless reg['URL Protocol'] == path }
Win32::Registry::HKEY_CLASSES_ROOT.open('mycard\shell\open\command') { |reg| return true unless reg[nil] == command }
Win32::Registry::HKEY_CLASSES_ROOT.open('mycard\DefaultIcon') { |reg| return true unless reg[nil] == icon }
Win32::Registry::HKEY_CLASSES_ROOT.open('.ydk') { |reg| return true unless reg[nil] == 'mycard' }
Win32::Registry::HKEY_CLASSES_ROOT.open('.yrp') { |reg| return true unless reg[nil] == 'mycard' }
Win32::Registry::HKEY_CLASSES_ROOT.open('.deck') { |reg| return true unless reg[nil] == 'mycard' }
rescue
return true
if Windows
path, command, icon = paths
require 'win32/registry'
begin
Win32::Registry::HKEY_CLASSES_ROOT.open('mycard') { |reg| return true unless reg['URL Protocol'] == path }
Win32::Registry::HKEY_CLASSES_ROOT.open('mycard\shell\open\command') { |reg| return true unless reg[nil] == command }
Win32::Registry::HKEY_CLASSES_ROOT.open('mycard\DefaultIcon') { |reg| return true unless reg[nil] == icon }
Win32::Registry::HKEY_CLASSES_ROOT.open('.ydk') { |reg| return true unless reg[nil] == 'mycard' }
Win32::Registry::HKEY_CLASSES_ROOT.open('.yrp') { |reg| return true unless reg[nil] == 'mycard' }
Win32::Registry::HKEY_CLASSES_ROOT.open('.deck') { |reg| return true unless reg[nil] == 'mycard' }
rescue
return true
end
else
true #how to detect?
end
end
......@@ -51,11 +104,17 @@ module Association
end
end
end
def start
if need?
request do
register rescue Dialog.uac("ruby/bin/rubyw.exe", "-KU lib/main.rb register_association")
if Windows
request do
register rescue Dialog.uac("ruby/bin/rubyw.exe", "-KU lib/main.rb register_association")
end
else
register
end
end
end
end
\ No newline at end of file
module Dialog
#选择文件对话框
require 'win32api'
GetOpenFileName = Win32API.new("comdlg32.dll", "GetOpenFileNameW", "p", "i")
GetSaveFileName = Win32API.new("comdlg32.dll", "GetSaveFileNameW", "p", "i")
OFN_EXPLORER = 0x00080000
OFN_PATHMUSTEXIST = 0x00000800
OFN_FILEMUSTEXIST = 0x00001000
OFN_ALLOWMULTISELECT = 0x00000200
OFN_FLAGS = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST |
OFN_ALLOWMULTISELECT
#打开网页
require 'win32ole'
Shell = WIN32OLE.new('Shell.Application')
module_function
if Windows
#选择文件对话框
require 'win32api'
GetOpenFileName = Win32API.new("comdlg32.dll", "GetOpenFileNameW", "p", "i")
GetSaveFileName = Win32API.new("comdlg32.dll", "GetSaveFileNameW", "p", "i")
OFN_EXPLORER = 0x00080000
OFN_PATHMUSTEXIST = 0x00000800
OFN_FILEMUSTEXIST = 0x00001000
OFN_ALLOWMULTISELECT = 0x00000200
OFN_FLAGS = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST |
OFN_ALLOWMULTISELECT
#打开网页
require 'win32ole'
Shell = WIN32OLE.new('Shell.Application')
end
def get_open_file(title="选择文件", filter = {"所有文件 (*.*)" => "*.*"}, save=nil)
szFile = (0.chr * 20481).encode("UTF-16LE")
szFileTitle = 0.chr * 2049
szTitle = (title+"\0").encode("UTF-16LE")
szFilter = (filter.flatten.join("\0")+"\0\0").encode("UTF-16LE")
szInitialDir = "\0"
if Windows
szFile = (0.chr * 20481).encode("UTF-16LE")
szFileTitle = 0.chr * 2049
szTitle = (title+"\0").encode("UTF-16LE")
szFilter = (filter.flatten.join("\0")+"\0\0").encode("UTF-16LE")
szInitialDir = "\0"
ofn =
[
76, # lStructSize L
0, # hwndOwner L
0, # hInstance L
szFilter, # lpstrFilter L
0, # lpstrCustomFilter L
0, # nMaxCustFilter L
1, # nFilterIndex L
szFile, # lpstrFile L
szFile.size - 1, # nMaxFile L
szFileTitle, # lpstrFileTitle L
szFileTitle.size - 1, # nMaxFileTitle L
szInitialDir, # lpstrInitialDir L
szTitle, # lpstrTitle L
OFN_FLAGS, # Flags L
0, # nFileOffset S
0, # nFileExtension S
0, # lpstrDefExt L
0, # lCustData L
0, # lpfnHook L
0 # lpTemplateName L
].pack("LLLPLLLPLPLPPLS2L4")
Dir.chdir {
if save
GetSaveFileName.call(ofn)
else
GetOpenFileName.call(ofn)
ofn =
[
76, # lStructSize L
0, # hwndOwner L
0, # hInstance L
szFilter, # lpstrFilter L
0, # lpstrCustomFilter L
0, # nMaxCustFilter L
1, # nFilterIndex L
szFile, # lpstrFile L
szFile.size - 1, # nMaxFile L
szFileTitle, # lpstrFileTitle L
szFileTitle.size - 1, # nMaxFileTitle L
szInitialDir, # lpstrInitialDir L
szTitle, # lpstrTitle L
OFN_FLAGS, # Flags L
0, # nFileOffset S
0, # nFileExtension S
0, # lpstrDefExt L
0, # lCustData L
0, # lpfnHook L
0 # lpTemplateName L
].pack("LLLPLLLPLPLPPLS2L4")
Dir.chdir {
if save
GetSaveFileName.call(ofn)
else
GetOpenFileName.call(ofn)
end
}
szFile.delete!("\0".encode("UTF-16LE"))
result = szFile.encode("UTF-8")
if !result.empty? and save.is_a? Array
ext = save[ofn.unpack("LLLPLLLPLPLPPLS2L4")[6] - 1]
if result[-ext.size, ext.size].downcase != ext.downcase
result << ext
end
end
}
szFile.delete!("\0".encode("UTF-16LE"))
result = szFile.encode("UTF-8")
if !result.empty? and save.is_a? Array
ext = save[ofn.unpack("LLLPLLLPLPLPPLS2L4")[6] - 1]
if result[-ext.size, ext.size].downcase != ext.downcase
result << ext
end
result
else
[]
end
result
end
def web(url)
Shell.ShellExecute url
if Windows
Shell.ShellExecute url
else
system('xdg-open ' + url)
end
end
def uac(command, *args)
Shell.ShellExecute File.expand_path(command), args.join(' '), Dir.pwd, "runas"
if Windows
Shell.ShellExecute File.expand_path(command), args.join(' '), Dir.pwd, "runas"
end
end
end
\ No newline at end of file
end
This diff is collapsed.
class Game_Event
def self.parse(info)
info =~ /^\$([A-Z])\|(.*)$/m
case $1
when "A"
Error
when "B"
Login
when "C"
AllUsers
when "F"
Join
when "Q"
NewRoom
when "G"
Watch
when "H", "M"
Leave
when "J"
Action
when "K"
WatchAction
when 'N'
PrivateChat
when "O"
Chat
when "P"
AllRooms
when "R"
QROOMOK #卡表
else
Unknown
end.parse($2)
end
class Login
def self.parse(info)
info = info.split(",")
#>> $B|201629,zh99997,5da9e5fa,Level-1 (总经验:183),,20101118
info[3] =~ /Level-(\d)+ \(总经验:(\d+)\)/
result = self.new User.new(info[0].to_i, info[1], $1.to_i, $2.to_i)
$game.get_friends
$game.session = info[2]
$game.key = ($game.user.id - 0x186a0) ^ 0x22133
result
end
end
class AllUsers
def self.parse(info)
self.new info.split(',').collect{|user|User.parse(user)}
end
end
class AllRooms
def self.parse(info)
info = info.split("|")
rooms = []
templist = rooms
empty = false
info.each do |room|
if room == '~~'
empty = true
templist = []
else
room = room.split(",")
room = if empty
Room.new(room[0].to_i, room[1], User.parse(room[2]), nil, room[3]=="1", Room::Color[room[4].to_i], nil, room[6])
else
Room.new(room[0].to_i, room[3], User.parse(room[1]), User.parse(room[2]), false, Room::Color[room[5].to_i], room[3])
end
room.name = room.name[1,room.name.size-1] #iduel服务器发来的消息中,房名前有一空格
templist << room
end
end
rooms = templist + rooms
self.new rooms
end
end
class NewUser
def self.parse(info)
p info
#super
#@args = @args.collect do |user|
# User.new(user)
#end
end
end
class MissingUser
def self.parse(info)
p info
#super
#@args = @args.collect do |user|
# User.new(user)
#end
end
end
class Join
def self.parse(info)
self.new Room.new(info.to_i)
end
end
class Leave
def self.parse(info)
self.new
end
end
class NewRoom
def self.parse(info)
id, x, player1, player2 = info.split(",", 4)
room = Room.new(id.to_i)
room.player1 = User.parse(player1)
room.player2 = User.parse(player2)
room.name = room.name[1,room.name.size-1] #iduel服务器发来的消息中,房名前有一空格
self.new room
end
end
#"Q"
#"273,1,zh99998(201448),zh99997(201629)"
class Watch
def self.parse(info)
id, name = info.split(",", 2)
name = name[1,name.size-1] #iduel服务器发来的消息中,房名前有一空格
self.new Room.new(id.to_i, name)
end
end
class Action
def self.parse(info)
info =~ /(.*)▊▊▊.*?$/m
info = $1
info["◎"] = "●" if info["◎"]
self.new ::Action.parse(info), info
end
end
class Leave
end
class Chat
def self.parse(info)
user, content = info.split(",", 2)
user = user == "System" ? User.new(100000, "iDuel管理中心") : User.parse(user)
content.gsub!('@@@@', ',')
self.new(ChatMessage.new(user, content, :lobby))
end
end
class Error
def self.parse(info)
title, message,fatal = case info.to_i
when 0x00
["网络错误", "网络连接中断",true]
when 0x65
["出错啦~", "服务器程序出现未知错误,请记录好出现错误的事件,并联系管理员。",true]
when 0x66
["错误", "通信验证错误",true]
when 0x67
["错误", "通信钥匙错误",true]
when 0xc9
["登录失败", "错误的帐号名或密码",true]
when 0xca
["登录失败", "你的账号还未激活",true]
when 0xcb
["登录失败", "你的账号被系统封锁",true]
when 0x12d
["错误", "房间已满",false]
when 0x12e
["错误", "房间密码错误",false]
when 0x12f
["错误", "你没有权限给房间上密码",false]
when 0x130
["错误", "你已经加入房间,请不要重新加入",false]
when 0x131
["加入房间", "你未达到房间要求的等级限制。",false]
when 0x132
["观战错误", "所请求的房间无效,或未开始决斗",false]
when 0x133
["观战错误", "你已经在该房间观战",false]
when 0x134
["发送信息错误", "你还未加入房间",false]
when 0x135
["错误", "请求的房间无效",false]
end
self.new title, message, fatal
end
end
class Unknown
def self.parse(*args)
$log.info '--------Unknown iDuel Event-------'
p $1, $2, args
end
end
#以下iDuel专有
class WatchAction < Action
attr_reader :user
def initialize(action, str, user)
@user = user
super(action, str)
if $game.room.nil? #通常是由于断线重连引起的
Game_Event.push Watch.new(Room.new(0, @user, User.new(0,"")))
#$game.refresh
end
@action.from_player = @user == $game.room.player1
end
def self.parse(info)
info =~ /(.+)\((\d+)\), (.*)/m
self.new ::Action.parse($3), $3, User.new($2.to_i, $1)
end
end
class QROOMOK < Game_Event
def self.parse(info)
end
end
class PrivateChat < Chat
def self.parse(info)
user, content = info.split(",", 2)
user = User.parse(user)
content.gsub!('@@@@', ',')
self.new(ChatMessage.new(user, content, user))
end
end
end
\ No newline at end of file
#encoding: UTF-8
load 'lib/iduel/window_login.rb'
require 'open-uri'
class Iduel < Game
Version = "20110131"
Server = "iduel.ocgsoft.cn"
Register_Url = 'http://www.duelcn.com/member.php?mod=join_id'
Port = 38522
RS = "¢"
attr_accessor :session
attr_accessor :key
def initialize
super
require 'digest/md5'
load 'lib/iduel/action.rb'
load 'lib/iduel/event.rb'
load 'lib/iduel/user.rb'
load 'lib/iduel/replay.rb'
end
def rename
##8|241019,测试改昵称,5b58559aaf8869282fe3cb9585ffa909¢
#$N|iDuel系统,您的改名请求已经提交,重新登录后即可看到效果。¢
end
def login(username, password)
connect
md5 = Digest::MD5.hexdigest(password)
send(0, username, md5, checknum("LOGINMSG", username, md5), Version)
end
def refresh
send(1, @key, checknum("UPINFOMSG", @session))
end
def host(name, password="", lv=0, color = 0)
end
def host(room_name, room_config)
password = ""
color = 0
lv = 0
send(6, @key, room_name, password, checknum("JOINROOMMSG", @session + room_name + password + "0"), 0, color, lv, 0, 0, 0) #TODO:v.ak, v.al
end
def join(room, password="")
send(6, @key, room.id, password, checknum("JOINROOMMSG", @session + room.id.to_s + password + "1"),1)
end
def watch(room, password="")
send(5, @key, room.id, password, checknum("WATCHROOMMSG", "#{@session}#{room.id}#{password}"))
end
def leave
return unless @room
if @room.include? @user
send(10, @key, room.id, checknum("QROOM", @session + room.id.to_s))
else
send(9, @key, checknum("QUITWATCHROOM", @session))
end
end
def action(action)
send(2, "#{checknum("RMSG", @session)}@#{@key}", "#{action.escape}▊▊▊mycard") #消息校验字串,为了防止由于mycard开源造成外挂泛滥扰乱正常iduel秩序,这里不模仿iduel计算校验字串,直接发送mycard供iduel识别
end
def exit
@recv.exit if @recv
if @conn
leave
send(11, @key, checknum("ULO", "#{@session}"))
@conn.close
@conn = nil
end
super
end
def recv(info)
if info.nil?
@conn.close
@conn = nil
$log.error 'socket已中断'
Game_Event.push Game_Event::Error.parse(0)
else
info.chomp!(RS)
info.delete!("\r")
$log.info ">> #{info}"
Game_Event.push Game_Event.parse info
end
end
#def qroom(room)
# send(10, @key, room.id, checknum("QROOM", @session + room.id.to_s))
#end
def chat(chatmessage)
msg = chatmessage.message.gsub(",", "@@@@")
case chatmessage.channel
when :lobby
send(4, @key, msg, checknum("CHATP", @session))
when User #私聊
send(3, @key, "#{chatmessage.channel.name}(#{chatmessage.channel.id})", msg, checknum("CHATX", @session + "X" + "#{chatmessage.channel.name}(#{chatmessage.channel.id})"))
when Room #房间消息:向双方分别私聊
channel = chatmessage.channel
chatmessage.channel = channel.player1
chat chatmessage
if channel.player2
chatmessage.channel = channel.player2
chat chatmessage
end
chatmessage.channel = channel
end
#4|241019,test,2368c6b89b3e2eedb92e1b624a2a157c
end
def get_friends
$config['iDuel']['friends'] ||= []
$config['iDuel']['friends'].each {|id|User.new(id).friend = true}
Thread.new do
begin
open("http://www.duelcn.com/home.php?mod=space&uid=#{@user.id-100000}&do=friend&view=me&from=space") do |file|
$config['iDuel']['friends'].each {|id|User.new(id).friend = false}
$config['iDuel']['friends'].clear
file.set_encoding "GBK", "UTF-8"
file.read.scan(/<a href="home.php\?mod=space&amp;uid=(\d+)" title=".*" target="_blank">.*<\/a>/) do |uid, others|
id = uid.to_i + 100000
User.new(id).friend = true
$config['iDuel']['friends'] << id
end
Config.save
end
rescue Exception => exception
$log.error('读取好友信息') {[exception.inspect, *exception.backtrace].collect{|str|str.encode("UTF-8")}.join("\n")}
end
end
end
def show_chat_self
true
end
private
def connect
require 'socket'
begin
@conn = TCPSocket.new(Server, Port) #TODO: 阻塞优化,注意login。下面注释掉的两句实现connect无阻塞,但是login依然会阻塞所以只优化这里没有意义
#@conn = Socket.new(:INET, :STREAM)
@conn.set_encoding "GBK", "UTF-8", :invalid => :replace, :undef => :replace
Thread.abort_on_exception=true
@recv = Thread.new do
begin
#@conn.connect Socket.pack_sockaddr_in(Port, Server)
recv @conn.gets(RS) while @conn
rescue => exception
$log.error('iduel-connect-1') {[exception.inspect, *exception.backtrace].collect{|str|str.encode("UTF-8")}.join("\n")}
Game_Event.push Game_Event::Error.new(exception.class.to_s, exception.message)
ensure
self.exit
end
end
rescue => exception
$log.error('iduel-connect-2') {[exception.inspect, *exception.backtrace].collect{|str|str.encode("UTF-8")}.join("\n")}
Game_Event.push Game_Event::Error.new("网络错误", "连接服务器失败")
end
end
def checknum(head, *args)
Digest::MD5.hexdigest("[#{head}]_#{args.join('_')}_SCNERO".gsub("\n", "\r\n").encode("GBK"))
end
def send(head, *args)
return unless @conn
info = "##{head.to_s(16).upcase}|#{args.join(',')}" + RS
$log.info "<< #{info}"
info.gsub!("\n", "\r\n")
(@conn.write info) rescue Game_Event.push Game_Event::Error.new($!.class.to_s, $!.message)
end
def self.get_announcements
#公告
$config['iDuel']['announcements'] ||= [Announcement.new("正在读取公告...", nil, nil)]
Thread.new do
begin
open('http://www.duelcn.com/topic-Announce.html') do |file|
announcements = []
file.read.scan(/<li><a href="(.*?)" title="(.*?)" target="_blank">/).each do |url, title|
announcements << Announcement.new(title.encode("UTF-8"), "http://www.duelcn.com/#{url}", nil)
end
$config['iDuel']['announcements'].replace announcements
Config.save
end
rescue Exception => exception
$log.error('公告') {[exception.inspect, *exception.backtrace].collect{|str|str.encode("UTF-8")}.join("\n")}
end
end
end
get_announcements
end
name: iDuel
\ No newline at end of file
class Replay
User_Filter = /(.+?)(?:\((\d+)\))?(?:\(\d+:\d+:\d+\))?(?:: |:) */
Delimiter = /^#{User_Filter}\n ?/
Player_Filter = /#{Delimiter}\[\d+\] ◎→/
Opponent_Filter =/#{Delimiter}\[\d+\] ●→/
HTML_Player_Filter = /<font color=blue><strong>#{User_Filter}<\/strong>/
HTML_Opponent_Filter = /<font color=red><strong>#{User_Filter}<\/strong>/
attr_accessor :room, :player1, :player2, :actions
def add(action)
# user = action.from_player ? $game.player1 : $game.player2
# @file.write("#{user.name}(#{user.id}):\r\n#{action.escape}\r\n")
end
def self.load(filename)
#TODO:效率优化
file = open(filename)
file.set_encoding "GBK", "UTF-8", :invalid => :replace, :undef => :replace
result = self.new(file)
contents = file.read.strip
if contents['<td width="75%" valign="top">']
result.player1 = User.new($2.to_i, $1) if contents =~ HTML_Player_Filter
result.player2 = User.new($2.to_i, $1) if contents =~ HTML_Opponent_Filter
from_players = contents.scan(Regexp.union(HTML_Player_Filter, HTML_Opponent_Filter)).collect{|matched|matched[0] ? true : false} #匹配player成功matched前两位有值,opponent成功后两位有值,["尸体", "100015", nil, nil], il, nil], [nil, nil, "游戏的徒弟", "288436"]
#去除HTML标签
contents.gsub!(/<.*?>/,'')
#处理HTML转义字符
require 'cgi'
contents = CGI.unescape_html(contents)
else
result.player1 = User.new($2 ? $2.to_i : $1.to_sym, $1) if contents =~ Player_Filter
result.player2 = User.new($2 ? $2.to_i : $1.to_sym, $1) if contents =~ Opponent_Filter
from_players = contents.scan(Delimiter).collect do |matched|
id = (matched[1] || matched[0]).to_sym
name = matched[0]
if result.player1 and result.player1.id == id
true
elsif result.player2 and result.player2.id == id
false
elsif result.player1.nil?
result.player1 = User.new(id , name)
true
elsif result.player2.nil?
result.player2 = User.new(id, name)
false
else
#无法匹配玩家,一般是观战消息..
false
end
end
end
result.player1 ||= User.new($1.to_sym, "我")
result.player2 ||= User.new($1.to_sym, "对手")
lines = contents.split(Delimiter)
lines.shift #split后,在第一个操作之前会多出一个空白元素
if from_players.empty?
Game_Event.push Game_Event::Error.new("播放战报", "战报无法识别")
return []
end
lines = lines.each_slice(lines.size/from_players.size).collect{|a|a.last.strip}
from_players = from_players.to_enum
result.actions = lines.collect do |action_str|
action = Action.parse action_str
action.from_player = from_players.next
Game_Event::Action.new(action, action_str)
end
$game.room = result.room = Room.new(0, "Replay", result.player1, result.player2)
result
end
def self.html_decode(text)
text.gsub(Regexp.new(HTML_Replacement.keys.collect{|key|Regexp.escape key}.join('|')), HTML_Replacement)
end
def get
@actions.shift
end
def eof?
@actions.empty?
end
end
class User
attr_accessor :level, :exp
def self.parse(info)
if info =~ /(.+)\((\d+)\)/
new $2.to_i, $1
else
nil
end
end
def initialize(id, name = "", level = nil, exp = nil)
@id = id
@name = name
@level = level
@exp = exp
end
def set(id, name = :keep, level = :keep, exp = :keep)
@id = id unless id == :keep
@name = name unless name == :keep
@level = level unless level == :keep
@exp = exp unless exp == :keep
end
def avatar(size = :small)
cache = "graphics/avatars/#{@id}_#{size}.png"
result = Surface.load(cache) rescue Surface.load("graphics/avatars/loading_#{size}.png")
scene = $scene
if block_given?
yield result
Thread.new do
open("http://www.duelcn.com/uc_server/avatar.php?uid=#{id-100000}&size=#{size}", 'rb') {|io|open(cache, 'wb') {|c|c.write io.read}} rescue cache = "graphics/avatars/error_#{size}.png"
(yield Surface.load(cache) if scene == $scene) rescue nil
end
else
result
end
end
def status
room = room()
result = case
when room.nil?
:lobby
when room.player2
:dueling
else
:waiting
end
result
end
def room
$game.rooms.find{|room|room.include? self}
end
def space
Dialog.web "http://www.duelcn.com/home.php?mod=space&uid=#{@id-100000}"
end
def color
@friend ? [255,0,0] : [0,0,0]
end
end
class Window_Login
def clicked
return if @last_clicked and Time.now - @last_clicked < 3 #防止重复点击
case @index
when :login
Widget_Msgbox.new("iDuel", "正在登录")
$scene.draw #强制重绘一次,下面会阻塞
$game = Iduel.new
$config[$config['game']]['username'] = @username_inputbox.value
$config[$config['game']]['password'] = @remember_password.checked? ? @password_inputbox.value : nil
Config.save
$game.login(@username_inputbox.value, @password_inputbox.value)
@last_clicked = Time.now
when :register
Dialog.web Iduel::Register_Url
@last_clicked = Time.now
when :replay
file = Dialog.get_open_file("播放录像", "所有支持的录像 (*.txt;*.htm)" => "*.txt;*.htm", "iDuel的html的录像 (*.htm)" => "*.htm", "文本录像 (*.txt)" => "*.txt")
if !file.empty?
$game = Iduel.new
$game.user = User.new(0)
Widget_Msgbox.new("回放录像", "录像读取中...")
$scene.draw
$log.info('iduel window_login'){'loading reply file'}
$scene = Scene_Replay.new Replay.load file
end
@last_clicked = Time.now
end
end
end
\ No newline at end of file
#输入法by夏娜
require 'dl'
require 'dl/import'
module RM_IME
extend DL::Importer
Dir.chdir('ruby/bin'){dlload 'RMIME.dll'}
extern 'void _init(long, int, int)'
extern 'void _update(int, int)'
extern 'void _dispose()'
extern 'void _get_text(char*)'
extern 'void _back(char*)'
module RM_INPUT
if Windows
require 'dl'
require 'dl/import'
extend DL::Importer
dlload 'user32.dll'
extern 'int GetAsyncKeyState(int)'
extern 'long FindWindow(char*, char*)'
ENTER = 0x0D
ESC = 0x1B
TAB = 0x09
UP = 0x26
DOWN = 0x28
LEFT = 0x25
RIGHT = 0x27
Key_Hash = {}
Key_Repeat = {}
module_function
#----------------------------------------------------------------------
# ● 按下判断
#----------------------------------------------------------------------
def press?(rkey)
return GetAsyncKeyState(rkey) != 0
end
#----------------------------------------------------------------------
# ● 重复按下判断
#----------------------------------------------------------------------
def repeat?(rkey)
result = GetAsyncKeyState(rkey)
if result != 0
if Key_Repeat[rkey].nil?
Dir.chdir('ruby/bin') { dlload 'RMIME.dll' }
extern 'void _init(long, int, int)'
extern 'void _update(int, int)'
extern 'void _dispose()'
extern 'void _get_text(char*)'
extern 'void _back(char*)'
module RM_INPUT
extend DL::Importer
dlload 'user32.dll'
extern 'int GetAsyncKeyState(int)'
extern 'long FindWindow(char*, char*)'
ENTER = 0x0D
ESC = 0x1B
TAB = 0x09
UP = 0x26
DOWN = 0x28
LEFT = 0x25
RIGHT = 0x27
Key_Hash = {}
Key_Repeat = {}
module_function
#----------------------------------------------------------------------
# ● 按下判断
#----------------------------------------------------------------------
def press?(rkey)
return GetAsyncKeyState(rkey) != 0
end
#----------------------------------------------------------------------
# ● 重复按下判断
#----------------------------------------------------------------------
def repeat?(rkey)
result = GetAsyncKeyState(rkey)
if result != 0
if Key_Repeat[rkey].nil?
Key_Repeat[rkey] = 0
return true
end
Key_Repeat[rkey] += 1
else
Key_Repeat[rkey] = nil
Key_Hash[rkey] = 0
end
if !Key_Repeat[rkey].nil? and Key_Repeat[rkey] > 4
Key_Repeat[rkey] = 0
return true
else
return false
end
Key_Repeat[rkey] += 1
else
Key_Repeat[rkey] = nil
Key_Hash[rkey] = 0
end
if !Key_Repeat[rkey].nil? and Key_Repeat[rkey] > 4
Key_Repeat[rkey] = 0
return true
else
return false
end
end
#----------------------------------------------------------------------
# ● 击键判断
#----------------------------------------------------------------------
def trigger?(rkey)
result = GetAsyncKeyState(rkey)
if Key_Hash[rkey] == 1 and result != 0
return false
end
if result != 0
Key_Hash[rkey] = 1
return true
else
Key_Hash[rkey] = 0
return false
#----------------------------------------------------------------------
# ● 击键判断
#----------------------------------------------------------------------
def trigger?(rkey)
result = GetAsyncKeyState(rkey)
if Key_Hash[rkey] == 1 and result != 0
return false
end
if result != 0
Key_Hash[rkey] = 1
return true
else
Key_Hash[rkey] = 0
return false
end
end
end
HWND = RM_INPUT.FindWindow('SDL_app', WM.caption[0])
end
HWND = RM_INPUT.FindWindow('SDL_app', WM.caption[0])
module_function
def init
return unless Windows
return if @active
$log.info('输入法'){'开启'}
$log.info('输入法') { '开启' }
_init(HWND, 0, 0)
@x = 0
@y = 0
@active = true
end
def set(x,y)
def set(x, y)
return unless Windows
@x = x
@y = y
end
def text
return "" unless Windows
buf = 0.chr * 1024
_get_text(buf)
buf.force_encoding("UTF-8")
buf.delete!("\0")
end
def update
_update(@x,@y)
buf = [0,0].pack("LL")
return unless Windows
_update(@x, @y)
buf = [0, 0].pack("LL")
_back(buf)
buf = buf.unpack("LL")
@backspace = buf[0] == 1
@delete = buf[1] == 1
end
def dispose
return unless Windows
return if !@active
$log.info('输入法'){'关闭'}
$log.info('输入法') { '关闭' }
_dispose
@active = false
end
def active?
@active
end
def backspace?
@backspace
end
def delete?
@delete
end
def left?
return unless Windows
RM_INPUT.repeat?(RM_INPUT::LEFT)
end
def right?
return unless Windows
RM_INPUT.repeat?(RM_INPUT::RIGHT)
end
def tab?
return unless Windows
RM_INPUT.trigger?(RM_INPUT::TAB)
end
def enter?
return unless Windows
RM_INPUT.trigger?(RM_INPUT::ENTER)
end
def esc?
return unless Windows
RM_INPUT.trigger?(RM_INPUT::ESC)
end
end
class Widget_InputBox < Window
attr_accessor :type
attr_reader :value
......@@ -139,8 +167,9 @@ class Widget_InputBox < Window
@@active = nil
@@cursor = nil
@@focus = true
def initialize(x,y,width,height,z=300, &proc)
super(x,y,width,height,z)
def initialize(x, y, width, height, z=300, &proc)
super(x, y, width, height, z)
@font = TTF.open("fonts/wqy-microhei.ttc", 20)
@proc = proc
@value = ""
......@@ -149,6 +178,7 @@ class Widget_InputBox < Window
@count = 0
@char_pos = [2]
end
def value=(value)
return if @value == value
@value = value
......@@ -161,6 +191,7 @@ class Widget_InputBox < Window
end
refresh
end
def index=(index)
if index > @value.size
index = @value.size
......@@ -174,17 +205,19 @@ class Widget_InputBox < Window
@@cursor.x = @x + @char_pos[@index]
RM_IME.set(@@cursor.x, @@cursor.y)
end
def refresh
clear
@font.draw_blended_utf8(@contents, @type == :password ? '*' * @value.size : @value, 2, 0, 0x00, 0x00, 0x00) unless @value.empty?
end
def clicked
RM_IME.init
@@active = self
@@focus = true
unless @@cursor and !@@cursor.destroyed?
@@cursor = Window.new(0,0,2,@height-4,301)
@@cursor.contents.fill_rect(0,0,@@cursor.width,@@cursor.height,0xFF000000)
@@cursor = Window.new(0, 0, 2, @height-4, 301)
@@cursor.contents.fill_rect(0, 0, @@cursor.width, @@cursor.height, 0xFF000000)
end
@@cursor.y = @y + 2
mouse_x = Mouse.state[0] - @x
......@@ -197,15 +230,17 @@ class Widget_InputBox < Window
return self.index = index - 1
end
end
self.index = @value.size
end
end
def clear(x=0, y=0, width=@width, height=@height)
@contents.fill_rect(x,y,width,height,0x110000FF)
@contents.fill_rect(x+2,y+2,width-4,height-4,0xFFFFFFFF)
@contents.fill_rect(x, y, width, height, 0x110000FF)
@contents.fill_rect(x+2, y+2, width-4, height-4, 0xFFFFFFFF)
end
def update
return unless self == @@active and @@focus
if @count >= 40
......@@ -214,7 +249,6 @@ class Widget_InputBox < Window
else
@count += 1
end
RM_IME.update
new_value = self.value.dup
new_index = self.index
......@@ -240,7 +274,7 @@ class Widget_InputBox < Window
self.index = new_index
if @proc
if RM_IME.esc?
self.value = '' if @proc.call :ESC
self.value = '' if @proc.call :ESC
end
if RM_IME.tab?
self.value = '' if @proc.call :TAB
......@@ -250,12 +284,14 @@ class Widget_InputBox < Window
end
end
end
def destroy
if @@active == self
Widget_InputBox.focus = false
end
super
end
def self.focus=(focus)
@@focus = focus
if !@@focus
......
......@@ -11,7 +11,7 @@ class Widget_ScrollBar < Window
@scroll ||= 0
@scroll_max ||= 0
@scrolling = nil
Surface.transform_draw(@back,@contents,0,1,@contents.h.to_f/@back.h,0,0,0,0,0)
Surface.transform_draw(@back,@contents,0,1,@contents.h.to_f/@back.h,0,0,0,0,0) rescue nil
refresh
end
def index=(index)
......
require_relative 'window_host'
class Window_LobbyButtons < Window_List
def initialize(x, y)
@items = [I18n.t('lobby.faq'), I18n.t('lobby.filter'), I18n.t('lobby.editdeck'), I18n.t('lobby.newroom'), "自动匹配"]
@items = [I18n.t('lobby.faq'), I18n.t('lobby.filter'), I18n.t('lobby.editdeck'), I18n.t('lobby.newroom'), I18n.t('lobby.match')]
@button = Surface.load("graphics/lobby/button.png")
super(x, y, @items.size*@button.w/3+@items.size*4, 30)
@font = TTF.open("fonts/wqy-microhei.ttc", 15)
......
......@@ -39,10 +39,10 @@ class Ygocore < Game
jid = Jabber::JID::new @username, 'my-card.in', 'mycard'
end
@@im = Jabber::Client.new(jid)
@@im_room = Jabber::MUC::MUCClient.new(@@im)
Jabber.logger = $log
Jabber.debug = true
@@im = Jabber::Client.new(jid)
@@im_room = Jabber::MUC::MUCClient.new(@@im)
Jabber.logger = $log
Jabber.debug = true
@@im.on_exception do |exception, c, where|
$log.error('聊天出错') { [exception, c, where] }
......@@ -87,7 +87,7 @@ class Ygocore < Game
http = EM::HttpRequest.new("http://my-card.in/servers.json").get
http.callback {
begin
self.servers.replace JSON.parse(http.response).collect {|data| Server.new(data['id'], data['name'], data['ip'], data['port'], data['auth'])}
self.servers.replace JSON.parse(http.response).collect { |data| Server.new(data['id'], data['name'], data['ip'], data['port'], data['auth']) }
self.filter[:servers] = self.servers.clone
rescue
Game_Event.push Game_Event::Error.new('ygocore', '读取服务器列表失败.1', true)
......@@ -96,7 +96,7 @@ class Ygocore < Game
#EventMachine::connect "mycard-server.my-card.in", 9997, Client
ws = WebSocket::EventMachine::Client.connect(:host => "mycard-server.my-card.in", :port => 9998);
ws.onmessage do |msg, type|
$log.info('收到websocket消息'){msg.force_encoding("UTF-8")}
$log.info('收到websocket消息') { msg.force_encoding("UTF-8") }
Game_Event.push Game_Event::RoomsUpdate.new JSON.parse(msg).collect { |room| Game_Event.parse_room(room) }
end
ws.onclose do
......@@ -105,7 +105,7 @@ class Ygocore < Game
end
}
http.errback{
http.errback {
Game_Event.push Game_Event::Error.new('ygocore', '读取服务器列表失败', true)
}
}
......@@ -116,12 +116,16 @@ class Ygocore < Game
Thread.new {
begin
@@im.allow_tls = false
@@im.use_ssl = true
@@im.use_ssl = true
connected = false
if @@im.jid.domain == "my-card.in"
@@im.connect("ygopro-server.my-card.in", 5223) rescue Game_Event.push Game_Event::Error.new('登录', '连接服务器失败')
connected = true
begin
@@im.connect("ygopro-server.my-card.in", 5223)
connected = true
rescue
Game_Event.push Game_Event::Error.new('登录', '连接服务器失败')
end
else
srv = []
Resolv::DNS.open { |dns|
......@@ -131,10 +135,9 @@ class Ygocore < Game
if srv.empty?
Game_Event.push Game_Event::Error.new('登录', '解析服务器地址失败')
Thread.exit
end
# Sort SRV records: lowest priority first, highest weight first
srv.sort! { |a,b| (a.priority != b.priority) ? (a.priority <=> b.priority) : (b.weight <=> a.weight) }
srv.sort! { |a, b| (a.priority != b.priority) ? (a.priority <=> b.priority) : (b.weight <=> a.weight) }
srv.each { |record|
begin
......@@ -150,6 +153,7 @@ class Ygocore < Game
if connected
begin
@@im.fd.define_singleton_method(:external_encoding) { |*args| @@im.fd.io.external_encoding(*args) }
@@im.auth(@password)
rescue Jabber::ClientAuthenticationFailure
Game_Event.push Game_Event::Error.new('登录', '用户名或密码错误')
......@@ -168,9 +172,6 @@ class Ygocore < Game
end
end
Game_Event.push Game_Event::AllUsers.new @@im_room.roster.keys.collect { |nick| User.new(nick.to_sym, nick) } rescue p $!
else
$log.error('聊天连接出错.1') { exception }
Game_Event.push Game_Event::Error.new('登录', '连接服务器失败.1')
end
rescue StandardError => exception
$log.error('聊天连接出错') { exception }
......@@ -190,6 +191,7 @@ class Ygocore < Game
#send(:chat, channel: chatmessage.channel.id, message: chatmessage.message, time: chatmessage.time)
end
end
#def chat(chatmessage)
# case chatmessage.channel
# when :lobby
......@@ -239,8 +241,8 @@ class Ygocore < Game
@recv = nil
end
def ygocore_path
"ygocore/ygopro_vs.exe"
def self.ygocore_path
Windows ? 'ygocore/ygopro_vs.exe' : 'ygocore/gframe'
end
def self.register
......@@ -267,10 +269,9 @@ class Ygocore < Game
if !image_downloading and !Update.images.empty?
return Widget_Msgbox.new("加入房间", "卡图正在下载中,可能显示不出部分卡图", :ok => "确定") { run_ygocore(option, true) }
end
path = 'ygocore/ygopro_vs.exe'
Widget_Msgbox.new("ygocore", "正在启动ygocore") rescue nil
#写入配置文件并运行ygocore
Dir.chdir(File.dirname(path)) do
Dir.chdir(File.dirname(ygocore_path)) do
case option
when Room
room = option
......@@ -305,14 +306,18 @@ class Ygocore < Game
system_conf[field] = contents
end
rescue
system_conf['antialias'] = 2
system_conf['textfont'] = 'c:/windows/fonts/simsun.ttc 14'
system_conf['numfont'] = 'c:/windows/fonts/arialbd.ttf'
end
if $game.user
system_conf['nickname'] = $game.user.name
system_conf['nickname'] += '$' + $game.password if $game.password and !$game.password.empty? and room.server.auth
end
font, size = system_conf['textfont'].split(' ')
if !File.file?(font) or size.to_i.to_s != size
system_conf['textfont'] = '../fonts/wqy_microhei.ttc 14'
end
if !File.file?(system_conf['numfont'])
system_conf['textfont'] = Windows ? '../fonts/wqy_microhei.ttc 14' : '/usr/share/fonts/gnu-free/FreeSansBold.ttf'
end
system_conf['lastip'] = room.server.ip
system_conf['lastport'] = room.server.port.to_s
system_conf['roompass'] = room_name if room_name and !room_name.empty?
......@@ -340,7 +345,7 @@ class Ygocore < Game
open('system.conf', 'w') { |file| file.write system_conf.collect { |key, value| "#{key} = #{value}" }.join("\n") }
args = '-d'
end
IO.popen("ygopro_vs.exe #{args}")
IO.popen("./#{File.basename(ygocore_path)} #{args}")
WM.iconify rescue nil
end
Widget_Msgbox.destroy rescue nil
......@@ -368,7 +373,7 @@ class Ygocore < Game
Config.save
end
rescue Exception => exception
$log.error('公告读取失败') { [exception.inspect, *exception.backtrace].collect { |str| str.force_encoding("UTF-8") }.join("\n") }
$log.error('公告读取失败') { [exception.inspect, *exception.backtrace].collect { |str| str.encode("UTF-8") }.join("\n") }
end
end
end
......
......@@ -12,7 +12,9 @@ en:
replay: "Replay"
lobby:
faq: "FAQ"
filter: "Filter"
editdeck: "Edit Deck"
newroom: "NewRoom"
match: "QuickMatch"
lobby: "Lobby"
en:
zh:
lang: "中文"
chat:
room: "lobby.zh"
......@@ -16,6 +16,7 @@ en:
newroom: "建立房间"
lobby: "大厅"
filter: "房间筛选"
match: "自动匹配"
waiting_only: "仅等待中"
normal_only: "仅标准房"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment