Commit 471d7d87 authored by 神楽坂玲奈's avatar 神楽坂玲奈

2.0.0

parent 583e0311
source 'https://rubygems.org'
ruby '1.9.3'
gem 'rubysdl', :platform => :ruby
gem 'rubysdl-mswin32-1.9', :platforms => [:mswin, :mingw]
gem 'eventmachine'
gem 'em-http-request'
gem 'xmpp4r'
gem 'locale'
gem 'i18n'
gem 'ruby-ogginfo'
gem 'sqlite3'
gem 'zip'
gem 'websocket'
gem 'net-http-pipeline'
gem 'fssm'
group :development do
gem 'rake'
gem 'bundler'
end
const path = require('path');
module.exports = function (grunt) {
switch (process.platform) {
case 'darwin':
build_prefix = 'Electron.app/Contents/Resources';
grunt.loadNpmTasks('grunt-appdmg');
var release_task = 'appdmg';
break;
case 'win32':
build_prefix = 'resources';
grunt.loadNpmTasks('grunt-electron-installer');
release_task = 'create-windows-installer';
break;
}
grunt.initConfig({
clean: ["build"],
copy: {
electron: {
expand: true,
options: {
mode: true,
timestamp: true
},
cwd: 'node_modules/electron-prebuilt/dist',
src: '**',
dest: 'build'
},
app: {
expand: true,
options: {
timestamp: true
},
src: ['package.json', 'README.txt', 'LICENSE.txt', 'index.html', 'main.js', 'ygopro.js', 'ygopro/**', 'node_modules/ws/**'],
dest: path.join('build', build_prefix, 'app')
}
},
electron: {
osxBuild: {
options: {
name: 'Fixture',
dir: 'app',
out: 'dist',
version: '0.25.3',
platform: 'darwin',
arch: 'x64'
}
}
},
'create-windows-installer': {
x64: {
appDirectory: 'build',
outputDirectory: 'release',
authors: 'MyCard',
exe: 'electron.exe',
description: 'nyanya'
}/*,
ia32: {
appDirectory: 'build/32',
outputDirectory: 'release/32',
authors: 'MyCard',
exe: 'mycard.exe'
}*/
}
});
grunt.loadNpmTasks('grunt-contrib-clean');
grunt.loadNpmTasks('grunt-contrib-copy');
grunt.registerTask('build', ['clean', 'copy:electron','copy:app']);
grunt.registerTask('release', ['build', release_task]);
grunt.registerTask('default', ['release']);
};
This diff is collapsed.
== mycard
这是一个游戏王对战器,与ygocore协议兼容
快捷键:
F12 返回上一层
常见问题:
Q:登陆时显示“解析服务器失败”怎么办?
A:如果是以Mycard用户登陆的话,请在登陆时去掉用户名中「@」后的内容。 Gmail用户请将DNS修改成8.8.8.8 208.67.222.222。
Q:为什么打完一局后换side时会无反应?&为什么经常提示内存不能为read?&为什么我的游戏的帧率(左上角的数字)极低?
A:可尝试用记事本打开mycard\ygocore\中的system.conf文件,找到use_d3d,其后边的数值原来是0就改成1,原来是1就改成0。或下载“驱动精灵”更新显卡驱动。
更多常见问题请到 https://forum.my-card.in/faq
作者联系方式:
1. mycard的论坛 https://forum.my-card.in
2. E-mail/QQ/GT: zh99998@gmail.com
nyaa
\ No newline at end of file
#encoding: UTF-8
require 'rubygems'
require 'rake'
require 'rake/clean'
require 'rubygems/package_task'
require 'rdoc/task'
#require 'rake/testtask'
Windows = RUBY_PLATFORM["mingw"] || RUBY_PLATFORM["mswin"]
#在windows上UTF-8脚本编码环境中 Dir.glob无法列出中文目录下的文件 所以自己写个递归
def list(path)
result = []
Dir.foreach(path) do |file|
next if file == "." or file == ".."
result << "#{path}/#{file}"
result.concat list(result.last) if File.directory? result.last
end rescue p $!
result
end
spec = Gem::Specification.new do |s|
s.name = 'mycard'
s.version = '1.2.2'
s.extra_rdoc_files = ['README.txt', 'LICENSE.txt']
s.summary = 'a card game platform'
s.description = s.summary
s.author = 'zh99998'
s.email = 'zh99998@gmail.com'
s.homepage = 'http://my-card.in/'
# s.executables = ['your_executable_here']
s.files = %w(LICENSE.txt README.txt replay)
%w{lib audio data locales graphics ygocore}.each{|dir|s.files.concat list(dir)}
if Windows
s.files += %w(mycard.exe) + list("ruby") + list("fonts")
else
s.files += %w(mycard.sh)
s.platform = Gem::Platform::CURRENT
end
s.require_path = "lib"
#s.bindir = "bin"
end
Gem::PackageTask.new(spec) do |p|
p.gem_spec = spec
if Windows
p.need_zip = true
p.zip_command = '7z a'
def p.zip_file
"#{package_name}-win32.7z"
end
else
p.need_tar_gz = true
end
end
Rake::RDocTask.new do |rdoc|
files =['README.txt', 'LICENSE.txt', 'lib/**/*.rb']
rdoc.rdoc_files.add(files)
rdoc.main = "README.txt" # page to start on
rdoc.title = "Mycard Docs"
rdoc.rdoc_dir = 'doc/rdoc' # rdoc output folder
rdoc.options << '--line-numbers'
end
CLOBBER.include %w(error-程序出错请到论坛反馈.txt log.log profile.log config.yml doc ygocore/pics) + list('replay') + list('ygocore/replay') + list('.').keep_if{|file|File.basename(file) == "Thumbs.db"} + list("graphics/avatars").reject{|file|File.basename(file) =~ /(?:error|loading)_(?:small|middle|large)\.png/} + list("ygocore/deck").keep_if{|file|File.basename(file) != 'sample.ydk'}
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
---
name: "沙沙"
field:
cardimage:
- 1
- 2
- 3
- 4
cardtext:
- 5
- 6
- 7
- 8
chat:
- 9
- 10
- 11
- 12
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
html {
font-size: 16px;
}
body {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 1rem;
line-height: 1.5;
color: #373a3c;
background-color: #fff;
margin: 0;
}
webview {
position: absolute;
top: 54px;
bottom: 0;
width: 100%;
display: none;
}
nav {
color: #eceeef;
background-color: #373a3c;
padding: .5rem 1rem;
position: fixed;
top: 0;
right: 0;
left: 0;
-webkit-user-select: none;
-webkit-app-region: drag;
}
#brand {
float: left;
padding-top: .25rem;
padding-bottom: .25rem;
margin-right: 1rem;
font-size: 1.25rem;
color: #fff;
touch-action: manipulation;
}
ul {
padding-left: 0;
margin-bottom: 0;
margin-top: 0;
list-style: none;
}
li {
float: left;
}
li + li {
margin-left: 1rem;
}
li > a {
display: block;
padding-top: .425rem;
padding-bottom: .425rem;
text-decoration: none;
color: rgba(255, 255, 255, .75);
}
li > a:hover {
color: #fff;
outline: 0;
}
li.active > a {
color: #fff;
}
.navbar-right {
float: right
}
.container {
margin-left: 100px;
margin-right: 100px;
}
</style>
</head>
<body>
<nav>
<div class="container">
<span id="brand">萌卡</span>
<ul>
<li id="nav-store">
<a href="#store">商店</a>
</li>
<li id="nav-ygopro" class="active">
<a href="#ygopro">游戏</a>
</li>
<li id="nav-forum">
<a href="#forum">社区</a>
</li>
</ul>
<div class="navbar-right">zh99998</div>
</div>
</nav>
<!--<webview id="ygopro" src="http://local.mycard.moe:3000/"></webview>-->
<webview id="store" src="http://mycard.moe/"></webview>
<webview id="ygopro" src="http://mycard.moe/lobby/"></webview> <!-- fuck https https://plus.google.com/u/0/+%E7%A5%9E%E6%A5%BD%E5%9D%82%E7%8E%B2%E5%A5%88/posts/79g2y5JRB1Z -->
<webview id="forum" src="https://forum.touhou.cc"></webview>
<script>
window.onhashchange = function (event) {
var hash = event.newURL.split('#', 2)[1];
document.getElementsByClassName('active')[0].className = "";
document.getElementById('nav-' + hash).className = "active";
document.getElementById(event.oldURL.split('#', 2)[1]).style.display = 'none';
document.getElementById(hash).style.display = 'block';
};
var hash = location.href.split('#', 2)[1];
document.getElementById('nav-' + hash).className = "active";
document.getElementById(hash).style.display = 'block';
var webviews = document.getElementsByTagName('webview');
for (var i = 0; i < webviews.length; i++) {
webviews.item(i).addEventListener('new-window', function (event) {
require('electron').shell.openExternal(event.url);
});
}
//debug
var webview = document.getElementById(hash);
webview.addEventListener("dom-ready", function () {
webview.openDevTools();
});
</script>
</body>
</html>
\ No newline at end of file
This diff is collapsed.
class Announcement
attr_accessor :title
attr_accessor :url
attr_accessor :time
def initialize(title, url, time=nil)
@title = title
@url = url
@time = time
end
end
module Association
module_function
def register
if Windows
require 'win32/registry'
path, command, icon = paths
Win32::Registry::HKEY_CLASSES_ROOT.create('mycard') { |reg| reg['URL Protocol'] = path.ljust path.bytesize }
Win32::Registry::HKEY_CLASSES_ROOT.create('mycard\shell\open\command') { |reg| reg[nil] = command.ljust command.bytesize }
Win32::Registry::HKEY_CLASSES_ROOT.create('mycard\DefaultIcon') { |reg| reg[nil] = icon.ljust icon.bytesize }
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
desktop, x_ygopro_deck, x_ygopro_replay = paths
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 desktop }
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 x_ygopro_deck }
open("#{ENV['HOME']}/.local/share/mime/packages/application-x-ygopro-replay.xml", 'w') { |f| f.write x_ygopro_replay }
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
def paths
if Windows
pwd = Dir.pwd.gsub('/', '\\')
path = '"' + pwd + '\ruby\bin\rubyw.exe" -C"' + pwd + '" -KU lib/main.rb'
command = path + ' "%1"'
icon = '"' + pwd + '\mycard.exe", 0'
[path, command, icon]
else
desktop = <<EOF
#!/usr/bin/env xdg-open
[Desktop Entry]
Name=Mycard
Name[zh_CN]=Mycard - 萌卡
Comment=a card game platform
Comment[zh_CN]=卡片游戏对战客户端
Exec=ruby -KU lib/main.rb %u
Terminal=false
Icon=#{Dir.pwd}/graphics/system/icon.png
Type=Application
Categories=Game
Path=#{Dir.pwd}
URL=https://my-card.in/
MimeType=x-scheme-handler/mycard;application/x-ygopro-deck;application/x-ygopro-replay'
EOF
x_ygopro_deck = <<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
x_ygopro_replay = <<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
[desktop, x_ygopro_deck, x_ygopro_replay]
end
end
def need?
return false if $config['no_assoc']
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
true
end
else
begin
(([IO.read("#{ENV['HOME']}/.local/share/applications/mycard.desktop"),
IO.read("#{ENV['HOME']}/.local/share/mime/packages/application-x-ygopro-deck.xml"),
IO.read("#{ENV['HOME']}/.local/share/mime/packages/application-x-ygopro-replay.xml")] != paths) or !(
File.file?("#{ENV['HOME']}/.icons/application-x-ygopro-deck.png") and
File.file?("#{ENV['HOME']}/.icons/application-x-ygopro-replay.png")))
rescue
true
end
end
end
def request
require_relative 'widget_msgbox'
Widget_Msgbox.new("mycard", "即将进行文件关联, 弹出安全警告请点允许", ok: "确定", cancel: "取消") do |clicked|
if clicked == :ok
yield
else
Widget_Msgbox.new("mycard", "未进行关联,要重新关联请删除config.yml", ok: "确定")
$config['no_assoc'] = true
Config.save
end
end
end
def start
if need?
request do
if Windows
require 'rbconfig'
register rescue Dialog.uac(File.join(RbConfig::CONFIG["bindir"], RbConfig::CONFIG["RUBY_INSTALL_NAME"] + RbConfig::CONFIG["EXEEXT"]), "-KU lib/main.rb register_association")
else
register
end
end
end
end
end
\ No newline at end of file
module Cacheable
@@all = {}
def new(id, *args)
@@all[self] ||= {}
if id and result = @@all[self][id]
result.set(id, *args)
result
else
@@all[self][id] = super(id, *args)
end
end
def find(id)
@@all[self][id]
end
end
\ No newline at end of file
#encoding: UTF-8
#==Card Model
class Card
require 'sqlite3'
@db = SQLite3::Database.new( "data/data.sqlite" )
@all = {}
@diy = {}
@count = @db.get_first_value("select COUNT(*) from `yu-gi-oh`") rescue 0
@db.results_as_hash = true
PicPath = if Windows
require 'win32/registry'
ospicpath = Win32::Registry::HKEY_CURRENT_USER.open('Software\OCGSOFT\Cards'){|reg|reg['Path']} rescue ''
ospicpath.force_encoding "GBK"
ospicpath.encode "UTF-8"
else
'' #其他操作系统卡图存放位置标准尚未制定。
end
CardBack = Surface.load("graphics/field/card.jpg").display_format rescue nil
CardBack_Small = Surface.load("graphics/field/card_small.gif").display_format rescue nil
class << self
def find(id, order_by=nil)
case id
when Integer
@all[id] || old_new(@db.get_first_row("select * from `yu-gi-oh` where id = #{id}"))
when Symbol
row = @db.get_first_row("select * from `yu-gi-oh` where name = '#{id}'")
if row
@all[row['id'].to_i] || old_new(row)
else
@diy[id] ||= Card.new('id' => 0, 'number' => :"00000000", 'name' => id, 'attribute' => :, 'level' => 1, 'card_type' => :通常怪兽, 'stats' => "", 'archettypes' => "", 'mediums' => "", 'lore' => "")
end
when Hash
old_new(id)
when nil
Card::Unknown
else
sql = "select * from `yu-gi-oh` where " << id
sql << " order by #{order_by}" if order_by
$log.debug('查询卡片执行SQL'){sql}
@db.execute(sql).collect {|row|@all[row['id'].to_i] || old_new(row)}
end
end
def all
if @all.size != @count
sql = "select * from `yu-gi-oh` where id not in (#{@all.keys.join(', ')})"
@db.execute(sql).each{|row|old_new(row)}
end
@all
end
def cache
@all
end
alias old_new new
def new(id)
find(id)
end
def load_from_ycff3(db = RUBY_PLATFORM["win"] || RUBY_PLATFORM["ming"] ? (require 'win32/registry';Win32::Registry::HKEY_CURRENT_USER.open('Software\OCGSOFT\YFCC'){|reg|reg['Path']+"YGODATA/YGODAT.dat"} rescue '') : '')
require 'win32ole'
conn = WIN32OLE.new('ADODB.Connection')
conn.open("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + db + ";Jet OLEDB:Database Password=paradisefox@sohu.com" )
records = WIN32OLE.new('ADODB.Recordset')
records.open("select EFFECT from YGOEFFECT", conn)
stats = records.GetRows.first
stats.unshift nil
records.close
records = WIN32OLE.new('ADODB.Recordset')
records.open("YGODATA", conn)
records.MoveNext #跳过首行那个空白卡
sql = ""
while !records.EOF
sql << "INSERT INTO `yu-gi-oh` VALUES(
#{records.Fields.Item("CardID").value-1},
'#{records.Fields.Item("CardPass").value}',
'#{records.Fields.Item("SCCardName").value}',
'#{records.Fields.Item("SCCardType").value == "XYZ怪兽" ? "超量怪兽" : records.Fields.Item("SCCardType").value}',
#{records.Fields.Item("SCDCardType").value == '    ' ? "NULL" : "'#{records.Fields.Item("SCDCardType").value}'"},
#{records.Fields.Item("CardATK").value || "NULL"},
#{records.Fields.Item("CardDef").value || "NULL"},
#{records.Fields.Item("SCCardAttribute").value == '    ' ? "NULL" : "'#{records.Fields.Item("SCCardAttribute").value}'"},
#{records.Fields.Item("SCCardRace").value == '    ' ? "NULL" : "'#{records.Fields.Item("SCCardRace").value}'"},
#{records.Fields.Item("CardStarNum").value || "NULL"},
'#{records.Fields.Item("SCCardDepict").value}',
#{case records.Fields.Item("ENCardBan").value; when "Normal"; 3; when "SubConfine"; 2; when "Confine"; 1; else; 0; end},
'#{records.Fields.Item("CardEfficeType").value}',
'#{records.Fields.Item("CardPhal").value.split(",").collect{|stat|stats[stat.to_i]}.join("\t")}',
'#{records.Fields.Item("CardCamp").value.gsub("、", "\t")}',
#{records.Fields.Item("CardISTKEN").value}
);"
records.MoveNext
end
@db.execute('begin transaction')
@db.execute('DROP INDEX if exists "main"."name";')
@db.execute('DROP TABLE if exists "main"."yu-gi-oh";')
@db.execute('CREATE TABLE "yu-gi-oh" (
"id" INTEGER NOT NULL,
"number" TEXT NOT NULL,
"name" TEXT NOT NULL,
"card_type" TEXT NOT NULL,
"monster_type" TEXT,
"atk" INTEGER,
"def" INTEGER,
"attribute" TEXT,
"type" TEXT,
"level" INTEGER,
"lore" TEXT NOT NULL,
"status" INTEGER NOT NULL,
"stats" TEXT NOT NULL,
"archettypes" TEXT NOT NULL,
"mediums" TEXT NOT NULL,
"tokens" INTEGER NOT NULL,
PRIMARY KEY ("id")
);')
@db.execute_batch(sql)
@db.execute('CREATE UNIQUE INDEX "main"."name" ON "yu-gi-oh" ("name");')
@db.execute('commit transaction')
@count = @db.get_first_value("select COUNT(*) from `yu-gi-oh`") #重建计数
@all.clear #清空缓存
end
end
attr_accessor :id
attr_accessor :number
attr_accessor :name
attr_accessor :card_type
attr_accessor :monster_type
attr_accessor :atk
attr_accessor :def
attr_accessor :attribute
attr_accessor :type
attr_accessor :level
attr_accessor :lore
attr_accessor :status
attr_accessor :stats
attr_accessor :archettypes
attr_accessor :mediums
attr_accessor :tokens
def initialize(hash)
@id = hash['id'].to_i
@number = hash['number'].to_sym
@name = hash['name'].to_sym
@card_type = hash['card_type'].to_sym
@monster_type = hash["monster_type"] && hash["monster_type"].to_sym
@atk = hash['atk'] && hash['atk'].to_i
@def = hash['def'] && hash['def'].to_i
@attribute = hash['attribute'] && hash['attribute'].to_sym
@type = hash['type'] && hash['type'].to_sym
@level = hash['level'] && hash['level'].to_i
@lore = hash['lore']
@status = hash['status'].to_i
@stats = hash['stats'].split("\t").collect{|stat|stat.to_i}
@archettypes = hash['archettypes'].split("\t").collect{|archettype|stat.to_sym}
@mediums = hash['mediums'].split("\t").collect{|medium|medium.to_sym}
@tokens = hash['tokens'].to_i
@token = hash['token']
Card.cache[@id] = self
end
def create_image
@image ||= Surface.load("graphics/field/card.jpg").display_format
end
def image
@image ||= Surface.load("#{PicPath}/#{@id}.jpg").display_format rescue create_image
end
def image_small
@image_small ||= image.transform_surface(0xFF000000,0,54.0/image.w, 81.0/image.h,Surface::TRANSFORM_SAFE).copy_rect(1, 1, 54, 81).display_format
end
def image_horizontal
if @image_horizontal.nil?
image_horizontal = image_small.transform_surface(0xFF000000,90,1,1,Surface::TRANSFORM_SAFE)
@image_horizontal = image_horizontal.copy_rect(1, 1, 81, 54).display_format #SDL的bug,会多出1像素的黑边
image_horizontal.destroy
end
@image_horizontal
end
def unknown?
@id == 1
end
def monster?
[:融合怪兽, :同调怪兽, :超量怪兽, :通常怪兽, :效果怪兽, :调整怪兽, :仪式怪兽].include? card_type
end
def trap?
[:通常陷阱, :反击陷阱, :永续陷阱].include? card_type
end
def spell?
[:通常魔法, :速攻魔法, :装备魔法, :场地魔法, :仪式魔法, :永续魔法].include? card_type
end
def extra?
[:融合怪兽, :同调怪兽, :超量怪兽].include? card_type
end
def token?
@token
end
def diy?
number == :"00000000"
end
def known?
self != Unknown
end
def inspect
"[#{card_type}][#{name}]"
end
Unknown = Card.new('id' => 0, 'number' => :"00000000", 'attribute' => :, 'level' => 1, 'name' => "", 'lore' => '', 'card_type' => :通常怪兽, 'stats' => "", 'archettypes' => "", 'mediums' => "")
Unknown.instance_eval{@image = CardBack; @image_small = CardBack_Small}
end
#Card.load_from_ycff3
\ No newline at end of file
class ChatMessage
attr_accessor :user, :message, :channel, :time
def initialize(user, message, channel=:lobby, time=Time.now)
@user = user
@message = message
@channel = channel
@time = time
end
def name_visible?
case channel
when Symbol
true
when Room
!channel.include?(user)
when User
false
end
end
def name_color
case user.affiliation
when :owner
[220,20,60]
when :admin
[148,43,226]
else
if user.id == :subject
[128,128,128]
else
user == $game.user ? [0, 128, 0] : [0, 0, 255]
end
end
end
def message_color
if user.id == :subject
[128,128,128]
elsif name_visible?
[0, 0, 0]
elsif user == $game.user or ($game.room and !$game.room.include?($user) and user == $game.room.player1)
[0, 128, 0]
else
[255, 0, 0]
end
end
def self.channel_name(channel)
case channel
when :lobby
"#大厅"
when Symbol
"##{channel}"
when Room
"[#{channel.name}]"
when User
"@#{channel.name}"
else
channel
end
end
def self.channel_color(channel)
case channel
when Symbol
[0x34, 0x92, 0xEA]
when Room
[0xF2, 0x83, 0xC4]
#[255,250,240]
when User
[0xFA, 0x27, 0x27]
else
[0, 0, 0]
end
end
end
require 'yaml'
require_relative 'resolution'
Config = Module.new
module Config
module_function
def load(file="config.yml")
config = YAML.load_file(file) rescue {}
config = {} unless config.is_a? Hash
config['bgm'] = true if config['bgm'].nil?
config['screen'] ||= {}
config['screen']['width'], config['screen']['height'] = Resolution.default unless Resolution.all.include? [config['screen']['width'], config['screen']['height']]
config['i18n'] ||= {}
config['i18n']['locale'] ||= "#{Locale.current.language}-#{Locale.current.region}"
I18n.locale = config['i18n']['locale']
config
end
def save(config=$config, file="config.yml")
File.open(file, "w") { |file| YAML.dump(config, file) }
end
end
\ No newline at end of file
#encoding: UTF-8
#==============================================================================
# ■ Scene_Title
#------------------------------------------------------------------------------
#  title
#==============================================================================
require_relative 'card'
class Deck
attr_accessor :main
attr_accessor :side
attr_accessor :extra
attr_accessor :temp
Key = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_="
def initialize(main, side=[], extra=[], temp=[])
@main = main
@side = side
@extra = extra
@temp = temp
end
def self.load(name)
main = []
side = []
extra = []
temp = []
now = main
open(name) do |file|
file.set_encoding "GBK", "UTF-8", :invalid => :replace, :undef => :replace
while line = file.readline.chomp!
case line
when /^\[(.+?)\](?:\#.*\#)?$/
now << Card.find($1.to_sym)
when "####"
now = side
when "===="
now = extra
when "$$$$"
now = temp
end
break if file.eof?
end
end
self.new(main, side, extra, temp)
end
def self.ygopro_deck_to_url_param(file)
card_usages = []
side = false
last_id = nil
count = 0
IO.readlines(file).each do |line|
if line[0] == '#'
next
elsif line[0, 5] == '!side'
card_usages.push({card_id: last_id, side: side, count: count}) if last_id
side = true
last_id = nil
else
card_id = line.to_i
if card_id.zero?
next
else
if card_id == last_id
count += 1
else
card_usages.push({card_id: last_id, side: side, count: count}) if last_id
last_id = card_id
count = 1
end
end
end
end
card_usages.push({card_id: last_id, side: side, count: count}) if last_id
result = ""
card_usages.each do |card_usage|
c = (card_usage[:side] ? 1 : 0) << 29 | card_usage[:count] << 27 | card_usage[:card_id]
4.downto(0) do |i|
result << Key[(c >> i * 6) & 0x3F]
end
end
require 'uri'
"name=#{URI.escape(File.basename(file, ".ydk"), Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))}&cards=#{result}"
end
#def self.decode(str)
# card_usages = []
# (0...str.length).step(5) do |i|
# decoded = 0
# str[i, 5].each do |char|
# decoded = (decoded << 6) + Key.index(char)
# side = decoded >> 29
# count = decoded >> 27 & 0x3
# card_id = decoded & 0x07FFFFFF
# card_usages.push(card_id: card_id, side: side, count: count)
# end
# end
#end
end
module Deck_Sync
require_relative 'deck'
class <<self
def start
Update.status = '正在同步卡组'
require 'open-uri'
require 'uri'
require 'net/http'
require 'json'
require 'date'
Thread.new {
just_updated = []
$log.info('下载卡组') { "https://my-card.in/decks/?user=#{URI.escape $game.user.id.bare.to_s, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]")}" }
open("https://my-card.in/decks/?user=#{URI.escape $game.user.id.bare.to_s, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]")}") { |list|
Dir.mkdir File.dirname(Ygocore.ygocore_path) if !File.directory? File.dirname(Ygocore.ygocore_path)
Dir.mkdir File.join File.dirname(Ygocore.ygocore_path), 'deck' if !File.directory? File.join File.dirname(Ygocore.ygocore_path), 'deck'
JSON.parse(list.read).each { |deck|
file = File.join(File.dirname(Ygocore.ygocore_path), 'deck', "#{deck['name']}.ydk")
if (!File.file?(file) || DateTime.parse(deck['updated_at']).to_time > File.mtime(file))
open(file, 'w') { |f|
main = []
side = []
deck['cards'].each { |card_usage|
card_usage['count'].times {
(card_usage['side'] ? side : main).push card_usage['card_id']
}
}
f.puts "#mycard deck sync #{deck['user']}"
f.puts "#main"
f.puts main.join("\n")
f.puts "!side"
f.puts side.join("\n")
}
File.utime(Time.now, DateTime.parse(deck['updated_at']).to_time, file)
end
if DateTime.parse(deck['updated_at']).to_time >= File.mtime(file)
just_updated.push file
end
}
} rescue $log.error('卡组下载') { [$!.inspect, *$!.backtrace].collect { |str| str.force_encoding("UTF-8") }.join("\n") }
Thread.new { watch } unless @watching
@watching = true
Dir.glob("#{File.dirname(Ygocore.ygocore_path)}/deck/*.ydk").each { |deck|
next if just_updated.include? deck
update(deck)
}
Update.status = nil
}
end
def watch
require 'fssm'
FSSM.monitor("#{File.dirname(Ygocore.ygocore_path)}/deck", '*.ydk') do
update { |base, relative| Deck_Sync.update "#{base}/#{relative}" }
delete { |base, relative| Deck_Sync.delete "#{base}/#{relative}" }
create { |base, relative| Deck_Sync.update "#{base}/#{relative}" }
end
end
def update(deck)
Update.status = "正在同步卡组: #{File.basename(deck, ".ydk")}"
begin
path = "/decks/?#{Deck.ygopro_deck_to_url_param(deck)}&user=#{URI.escape $game.user.id.bare.to_s, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]")}&updated_at=#{URI.escape DateTime.now.iso8601, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]")}"
$log.info("卡组上传") { path }
req = Net::HTTP::Put.new path
response = Net::HTTP.start('my-card.in', 443, use_ssl: true) { |http| http.request(req) }
rescue
$log.error('卡组上传') { [$!.inspect, *$!.backtrace].collect { |str| str.force_encoding("UTF-8") }.join("\n") }
end
Update.status = nil
end
def delete(deck)
Update.status = "正在同步卡组: #{File.basename(deck, ".ydk")}"
begin
path = "/decks/?name=#{URI.escape File.basename(deck, ".ydk"), Regexp.new("[^#{URI::PATTERN::UNRESERVED}]")}&user=#{URI.escape $game.user.id.bare.to_s, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]")}"
$log.info("卡组删除") { path }
req = Net::HTTP::Delete.new path
response = Net::HTTP.start('my-card.in', 443, use_ssl: true) { |http| http.request(req) }
rescue
$log.error('卡组删除') { [$!.inspect, *$!.backtrace].collect { |str| str.force_encoding("UTF-8") }.join("\n") }
end
Update.status = nil
end
end
end
\ No newline at end of file
module Dialog
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)
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)
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
result
else
[]
end
end
def web(url)
if Windows
Shell.ShellExecute url
else
system('xdg-open ' + url)
end
end
def uac(command, *args)
if Windows
Shell.ShellExecute File.expand_path(command), args.join(' '), Dir.pwd, "runas"
end
end
end
class FPSTimer
FPS_COUNT = 10
attr_accessor :fps
attr_reader :real_fps, :total_skip
attr_reader :count_sleep
# +fps+ is the number of frames per second that you want to keep,
# +accurary+ is the accurary of sleep/SDL.delay in milisecond
def initialize(fps = 60, accurary = 10, skip_limit = 15)
@fps = fps
@accurary = accurary / 1000.0
@skip_limit = skip_limit
reset
end
# reset timer, you should call just before starting loop
def reset
@old = get_ticks
@skip = 0
@real_fps = @fps
@frame_count = 0
@fps_old = @old
@count_sleep = 0
@total_skip = 0
end
# execute given block and wait
def wait_frame
now = get_ticks
nxt = @old + (1.0/@fps)
if nxt > now || @skip > @skip_limit
yield
@skip = 0
wait(nxt)
@old = nxt
else
@skip += 1
@total_skip += 1
@old = get_ticks
end
calc_real_fps
end
private
def wait(nxt)
#print "-"# 加了这货tk输入框不卡,原因不明=.=
sleeptime = nxt-get_ticks
sleep(sleeptime) if sleeptime > 0
end
def get_ticks
SDL.get_ticks / 1000.0
end
def calc_real_fps
@frame_count += 1
if @frame_count >= FPS_COUNT
@frame_count = 0
now = get_ticks
@real_fps = FPS_COUNT / (now - @fps_old)
@fps_old = now
end
end
end
#游戏适配器的抽象类
require_relative 'game_event'
require_relative 'action'
require_relative 'user'
require_relative 'room'
require_relative 'server'
class Game
attr_reader :users, :rooms, :servers, :filter
attr_accessor :user, :room, :player_field, :opponent_field, :turn, :turn_player, :phase
def initialize
@users = []
@rooms = []
@servers = []
@filter = {servers: [], waiting_only: false, normal_only: false}
end
def login(username, password=nil)
end
def refresh
end
def host(room_name, room_config)
end
def join(room)
end
def watch(room)
end
def leave
end
def action(action)
end
def chat(chatmessage)
end
def exit
$scene = Scene_Login.new if $scene
end
def watching?
@room and @room.include? @user
end
def self.deck_edit
require_relative 'window_deck'
@deck_window = Window_Deck.new
end
def refresh_interval
5
end
def show_chat_self
false
end
end
class Game_Card
attr_accessor :card, :position, :counters, :note
attr_writer :atk, :def
@@count = 0
def initialize(card=nil)
@@count += 1
$log.debug "创建活动卡片<#{card ? card.name : '??'}>,共计#{@@count}张"
@card = card || Card.find(nil)
reset
end
def atk
@card.atk.to_i #把"?"转为0
end
def def
@card.def.to_i #把"?"转为0
end
def reset(reset_position = true)
@position = :set if reset_position
@atk = @card.atk
@def = @card.def
@counters = 0
end
def card=(card)
return if @card == card
@card = card
@atk = @card.atk
@def = @card.def
end
def image_small
if @position == :set and !$game.player_field.hand.include?(self)
Card.find(nil).image_small
else
@card.image_small
end
end
def image_horizontal
if @position == :set and !$game.player_field.hand.include?(self)
Card.find(nil).image_horizontal
else
@card.image_horizontal
end
end
def method_missing(method, *args)
if method.to_s[0,9]== "original_"
method = method.to_s[9, method.to_s.size-9]
end
@card.send(method, *args)
end
def inspect
"<#{object_id}#{known? ? @card.inspect : '??'}>"
end
end
\ No newline at end of file
#游戏事件的抽象类
class Game_Event
@queue = []
def self.push(event)
@queue << event
end
def self.poll
@queue.shift
end
def self.parse(info, *args)
#适配器定义
end
class Login < Game_Event
attr_reader :user
def initialize(user)
@user = user
$game.user = @user
end
end
class AllUsers < Game_Event
attr_reader :users
def initialize(users)
@users = []
users.each do |user|
if user.friend?
@users.unshift user
else
@users << user
end
end
$game.users.replace @users
end
end
class AllServers < Game_Event
attr_reader :servers
def initialize(servers)
$game.servers.replace servers
end
end
class NewUser < AllUsers
attr_reader :users
def initialize(user)
@user = user
case @user.affiliation
when :owner
if index = $game.users.find_index { |user| user.affiliation != :owner }
$game.users.insert(index, @user)
else
$game.users << @user
end
when :admin
if index = $game.users.find_index { |user| user.affiliation != :owner and user.affiliation != :admin }
$game.users.insert(index, @user)
else
$game.users << @user
end
else
$game.users << @user
end
end
end
class MissingUser < AllUsers
attr_reader :users
def initialize(user)
@user = user
$game.users.delete @user
end
end
class AllRooms < Game_Event
attr_reader :rooms
def initialize(rooms)
@rooms = rooms
$game.rooms.replace @rooms
$game.rooms.sort_by! { |room| [room.status == :start ? 1 : 0, room.private ? 1 : 0, room.id] }
end
end
class RoomsUpdate < AllRooms
attr_reader :rooms
def initialize(rooms)
@rooms = rooms
$game.rooms.replace $game.rooms | @rooms
$game.rooms.delete_if { |room| room._deleted }
$game.rooms.sort_by! { |room| [room.status == :start ? 1 : 0, room.private ? 1 : 0, room.id] }
end
end
class NewRoom < AllRooms
attr_reader :room
def initialize(room)
@room = room
unless $game.rooms.include? @room
if @room.full?
$game.rooms << @room
else
$game.rooms.unshift @room
end
end
end
end
class MissingRoom < AllRooms
attr_reader :room
def initialize(room)
@room = room
$game.rooms.delete @room
end
end
class Chat < Game_Event
attr_reader :chatmessage
def initialize(chatmessage)
@chatmessage = chatmessage
end
end
class Join < Game_Event
attr_reader :room
def initialize(room)
@room = room
$game.room = @room
end
end
class Host < Join
end
class Watch < Game_Event
attr_reader :room
def initialize(room)
@room = room
$game.room = @room
end
end
class Leave < Game_Event
def initialize
end
end
class PlayerJoin < Game_Event
attr_reader :user
def initialize(user)
@user = user
$game.room.player2 = @user
end
end
class PlayerLeave < Game_Event
def initialize
$game.room.player2 = nil
end
end
class Action < Game_Event
attr_reader :action, :str
def initialize(action, str=action.escape)
@action = action
@str = str
end
end
class Error < Game_Event
attr_reader :title, :message, :fatal
def initialize(title, message, fatal=true)
@title = title
@message = message
@fatal = fatal
$log.error(@fatal ? "致命错误" : "一般错误") { "#{@title}: #{@message} #{caller}" }
end
end
class Unknown < Error
def initialize(*args)
super("unknown event", args.inspect)
end
end
end
\ No newline at end of file
#==============================================================================
# ■ Field
#------------------------------------------------------------------------------
#  Field
#==============================================================================
#英汉对照表
# field 场地
# fieldcard 场地魔法卡
# spelltrap 魔法陷阱
# spell 魔法
# trap 陷阱
# graveyard 墓地
# deck 卡组
# extra 额外卡组
# removed 除外区
class Game_Field
attr_accessor :lp
attr_accessor :deck
attr_accessor :extra
attr_accessor :field
attr_accessor :hand
attr_accessor :graveyard
attr_accessor :removed
def initialize(deck = nil)
@deck_original = deck || Deck.new(Array.new(60,Card.find(nil)), [], Array.new(15, Card.find(nil)))
reset
end
def reset
@lp = 8000
@deck = @deck_original.main.collect{|card|Game_Card.new(card)}.shuffle
@extra = @deck_original.extra.collect{|card|Game_Card.new(card)}
@field = Array.new(11)
@hand = []
@graveyard = []
@removed = []
end
def empty_monster_field
[8,7,9,6,10].each do |pos|
return pos if @field[pos].nil?
end
return
end
def empty_spelltrap_field
[3,2,4,1,5].each do |pos|
return pos if @field[pos].nil?
end
return
end
def empty_field(card)
if card.monster?
empty_monster_field
elsif card.card_type == :场地魔法
@field[0].nil? ? 0 : nil
else
empty_spelltrap_field
end
end
#def shuffle_hand
# @hand.shuffle!
# @hand.each{|card|card.card = Card::Unknown if card.position == :set}
#end
#def shuffle_deck
# @deck.shuffle!
# @deck.each{|card|card.card = Card::Unknown if card.position == set}
#end
end
\ No newline at end of file
module Graphics
module_function
Ext = ['.png', '.jpg', '.gif']
def load(directory, filename, alpha=true)
extname = File.extname(filename)
path = "graphics/#{directory}/#{File.dirname(filename)}/#{File.basename(filename, extname)}"
result = if extname.empty?
Ext.each do |ext|
result = load_file(path, ext)
break result if result
end
else
load_file(path, extname)
end
raise 'file not exist' if result.nil?
if alpha
result.display_format_alpha
else
result.display_format
end
end
def load_file(path, ext)
path_with_resolution = "#{path}-#{$config['screen']['width']}x#{$config['screen']['height']}#{ext}"
if File.file? path_with_resolution
Surface.load path_with_resolution
elsif File.file? path += ext
Surface.load path
end
end
end
\ No newline at end of file
#!/usr/bin/env ruby
begin
Windows = RUBY_PLATFORM["mswin"] || RUBY_PLATFORM["ming"]
Font = ['fonts/wqy-microhei.ttc', '/usr/share/fonts/wqy-microhei/wqy-microhei.ttc', '/usr/share/fonts/truetype/wqy/wqy-microhei.ttc', '/Library/Fonts/Hiragino Sans GB W3.otf'].find{|file|File.file? file}
#System_Encoding = Windows ? "CP#{`chcp`.scan(/\d+$/)}" : `locale |grep LANG |awk -F '=' '{print $2}'`
Dir.glob('post_update_*.rb').sort.each { |file| load file }
Thread.abort_on_exception = true
require_relative 'resolution'
require_relative 'announcement'
require_relative 'config'
require_relative 'association'
#i18n
require 'i18n'
require 'locale'
I18n.load_path += Dir['locales/*.yml']
I18n::Backend::Simple.include(I18n::Backend::Fallbacks)
#读取配置文件
$config = Config.load
Config.save
#读取命令行参数
log = "log.log"
log_level = "INFO"
profile = nil
ARGV.each do |arg|
arg = arg.dup.force_encoding("UTF-8")
arg.force_encoding("GBK") unless arg.valid_encoding?
case arg
when /--log=(.*)/
log.replace $1
when /--log-level=(.*)/
log_level.replace $1
when /--profile=(.*)/
profile = $1
when /^mycard:.*|\.ydk$|\.yrp$|\.deck$/
require_relative 'quickstart'
$scene = false
when /register_association/
Association.register
$scene = false
end
end
unless $scene == false
#加载文件
require 'openssl'
OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE #unsafe
require 'digest/sha1'
require 'digest/md5'
require 'logger'
require 'sdl'
include SDL
require_relative 'dialog'
require_relative 'graphics'
require_relative 'window'
require_relative 'widget_msgbox'
#日志
if log == "STDOUT" #调试用
log = STDOUT
end
$log = Logger.new(log, 1, 1024000)
$log.level = Logger.const_get log_level
#性能分析
if profile
if profile == "STDOUT"
profile = STDOUT
else
profile = open(profile, 'w')
end
require 'profiler'
RubyVM::InstructionSequence.compile_option = {
:trace_instruction => true,
:specialized_instruction => false
}
Profiler__::start_profile
end
SDL::Event::APPMOUSEFOCUS = 1
SDL::Event::APPINPUTFOCUS = 2
SDL::Event::APPACTIVE = 4
SDL.putenv ("SDL_VIDEO_CENTERED=1");
SDL.init(INIT_VIDEO)
WM::set_caption("MyCard", "MyCard")
WM::icon = Surface.load("graphics/system/icon.gif")
$screen = Screen.open($config['screen']['width'], $config['screen']['height'], 0, HWSURFACE | ($config['screen']['fullscreen'] ? FULLSCREEN : 0))
TTF.init
#声音
begin
SDL.init(INIT_AUDIO)
Mixer.open(Mixer::DEFAULT_FREQUENCY, Mixer::DEFAULT_FORMAT, Mixer::DEFAULT_CHANNELS, 1536)
Mixer.set_volume_music(60)
rescue
nil
end
#标题场景
require_relative 'scene_title'
$scene = Scene_Title.new
#自动更新, 加载放到SDL前面会崩, 原因不明
require_relative 'update'
Update.start
WM::set_caption("MyCard v#{Update::Version}", "MyCard")
#文件关联
Association.start
#初始化完毕
$log.info("main") { "初始化成功" }
end
rescue Exception => exception
open('error-程序出错请到论坛反馈.txt', 'w') { |f| f.write [exception.inspect, *exception.backtrace].join("\n") }
$scene = false
end
#主循环
begin
$scene.main while $scene
rescue ScriptError, StandardError => exception
exception.backtrace.each { |backtrace| break if backtrace =~ /^(.*)\.rb:\d+:in `.*'"$/ } #由于脚本是从main.rb开始执行的,总会有个能匹配成功的文件
$log.fatal($1) { [exception.inspect, *exception.backtrace].collect { |str| str.force_encoding("UTF-8") }.join("\n") }
$game.exit if $game
require_relative 'scene_error'
$scene = Scene_Error.new
retry
ensure
if profile
Profiler__::print_profile(profile)
profile.close
end
$log.close rescue nil
end
#==============================================================================
# 鈻�Scene_Title
#------------------------------------------------------------------------------
# 銆�itle
#==============================================================================
class Picture < Image
@load_path = "graphics/picture"
end
require_relative 'game'
require_relative 'user'
require_relative 'room'
require_relative 'ygocore/game'
$game = Ygocore.new
open('debug.txt', 'wb'){|f|f.write ARGV.first}
file = ARGV.first.dup.force_encoding("UTF-8")
file.force_encoding("GBK") unless file.valid_encoding?
file.encode!("UTF-8")
if ARGV.first[0, 9] == 'mycard://'
file = URI.unescape file[9, file.size-9]
uri = "http://" + URI.escape(file)
#elsif ARGV.first[0, 2] == '//'
# file = URI.unescape URI.unescape ARGV.first[2, ARGV.first.size-2]
# uri = "http://" + URI.escape(file)
else
uri = file
end
case file
when /^(.*\.yrp)$/i
require 'open-uri'
#fix File.basename
$1 =~ /(.*)(?:\\|\/)(.*?\.yrp)/
src = open(uri, 'rb') { |src| src.read }
Dir.mkdir("replay") unless File.directory?("replay")
open('replay/' + $2, 'wb') { |dest| dest.write src }
Ygocore.replay('replay/' + $2, true)
when /^(.*\.ydk)$/i
require 'open-uri'
#fix File.basename
$1 =~ /(.*)(?:\\|\/)(.*?)\.ydk/
src = open(uri, 'rb') { |src| src.read }
Dir.mkdir('ygocore/deck') unless File.directory?("ygocore/deck")
open('ygocore/deck/' + $2 + '.ydk', 'wb') { |dest| dest.write src }
Ygocore.run_ygocore($2, true)
when /^(.*)(\.txt|\.deck)$/i
require_relative 'deck'
d = $1
deck = Deck.load($&)
Dir.mkdir('ygocore/deck') unless File.directory?("ygocore/deck")
d =~ /^(.*)(?:\\|\/)(.*?)$/
open('ygocore/deck/' + $2 + '.ydk', 'w') do |dest|
dest.puts("#main")
deck.main.each { |card| dest.puts card.number }
dest.puts("#extra")
deck.extra.each { |card| dest.puts card.number }
dest.puts("!side")
deck.side.each { |card| dest.puts card.number }
end
Ygocore.run_ygocore($2, true)
when /^(?:(.+?)(?:\:(.+?))?\@)?([\d\.]+)\:(\d+)(?:\/(.*))$/
require 'uri'
require_relative 'server'
$game.user = User.new($1.to_sym, $1) if $1
$game.password = $2 if $2
room = Room.new(nil, $5.to_s)
room.server = Server.new(nil, nil, $3, $4.to_i, !!$2)
Ygocore.run_ygocore room, true
end
\ No newline at end of file
class Replay
ReplayPath = 'replay'
LastReplay = 'lastreplay.txt'
def initialize(filename=LastReplay)
@file = open(File.expand_path(filename, ReplayPath), 'w') unless filename.is_a? IO
end
def add(action)
action = action.escape if action.is_a? Action
@file.write action + "\n"
end
def save(filename="#{$game.room.player1.name}(#{$game.room.player1.id})_#{$game.room.player2.name}(#{$game.room.player2.id})_#{Time.now.strftime("%m%d%H%M")}.txt")
close
File.rename(@file.path, File.expand_path(filename, ReplayPath))
end
def close
@file.close
end
end
module Resolution
module_function
def all
[
[1024, 768],
[1024, 640]
]
end
def system
if Windows
require 'win32api'
get_system_metrics = Win32API.new "User32.dll", "GetSystemMetrics", ["L"], "L"
[get_system_metrics.call(0), get_system_metrics.call(1)]
else
`xdpyinfo`.scan(/dimensions: (\d+)x(\d+) pixels/).flatten.collect { |n| n.to_i } rescue [1440, 900]
end
end
def default
system_resolution = self.system
all.each do |width, height|
return [width, height] if system_resolution[0] > width and system_resolution[1] > height
end
all.last
end
end
\ No newline at end of file
require_relative 'cacheable'
class Room
Color = [[0,0,0], [255,0,0], [0,128,0], [0,0,255], [255, 165, 0]]
extend Cacheable
attr_accessor :id, :name, :player1, :player2, :private, :color, :forbid, :_deleted
attr_accessor :password
def initialize(id, name="等待更新", player1=nil, player2=nil, private=false, color=[0,0,0], session = nil, forbid = nil)
@id = id
@name = name
@player1 = player1
@player2 = player2
@private = private
@color = color
@session = session
@forbid = forbid
end
def set(id=:keep, name=:keep, player1=:keep, player2=:keep, private=:keep, color=:keep, session = nil, forbid=:keep)
@id = id unless id == :keep
@name = name unless name == :keep
@player1 = player1 unless player1 == :keep
@player2 = player2 unless player2 == :keep
@private = private unless private == :keep
@color = color unless color == :keep
@session = session unless session == :keep
@forbid = forbid unless forbid == :keep
end
def include?(user)
@player1 == user or @player2 == user
end
def extra
{}
end
def status
player2 ? :start : :wait
end
alias full? player2
alias private? private
end
\ No newline at end of file
#encoding: UTF-8
#==============================================================================
# ■ Scene_Base
#------------------------------------------------------------------------------
#  游戏中全部画面的超级类。
#==============================================================================
require_relative 'fpstimer'
require_relative 'game'
require_relative 'window_bgm'
require 'ogginfo'
require_relative 'widget_inputbox'
class Scene
attr_reader :windows
attr_reader :background
@@fpstimer = FPSTimer.new
@@last_bgm = @@bgm = nil
#--------------------------------------------------------------------------
# ● 主处理
#--------------------------------------------------------------------------
def initialize
@background = nil
@windows = []
@active_window = nil
@font = TTF.open(Font, 16)
end
def main
start
while $scene == self
update
@@fpstimer.wait_frame{draw}
end
terminate
end
def draw
if @background
$screen.put(@background,0,0)
else
$screen.fill_rect(0, 0, $screen.w, $screen.h, 0x000000)
end
@windows.each do |window|
window.draw($screen)
end
if Update.status
@font.draw_blended_utf8($screen, Update.status, 0, 0, 0xFF, 0xFF, 0xFF)
else
@font.draw_blended_utf8($screen, "%.1f" % @@fpstimer.real_fps, 0, 0, 0xFF, 0xFF, 0xFF)
end
$screen.update_rect(0,0,0,0)
end
#--------------------------------------------------------------------------
# ● 开始处理
#--------------------------------------------------------------------------
def start
if $config['bgm'] and @@last_bgm != bgm and SDL.inited_system(INIT_AUDIO) != 0 and File.file? "audio/bgm/#{bgm}"
@@bgm.destroy if @@bgm
@@bgm = Mixer::Music.load "audio/bgm/#{bgm}"
Mixer.fade_in_music(@@bgm, -1, 800)
title = OggInfo.new("audio/bgm/#{bgm}").tag["title"]
@bgm_window = Window_BGM.new title if title and !title.empty?
@@last_bgm = bgm
end rescue nil
end
def bgm
"title.ogg"
end
def last_bgm
@@last_bgm
end
def last_bgm=(bgm)
@@last_bgm = bgm
end
def refresh_rect(x, y, width, height, background=@background, ox=0,oy=0)
Surface.blit(background,x+ox,y+oy,width,height,$screen,x,y)
yield
$screen.update_rect(x, y, width, height)
end
#--------------------------------------------------------------------------
# ● 执行渐变
#--------------------------------------------------------------------------
def perform_transition
Graphics.transition(10)
end
#--------------------------------------------------------------------------
# ● 开始後处理
#--------------------------------------------------------------------------
def post_start
end
#--------------------------------------------------------------------------
# ● 更新画面
#--------------------------------------------------------------------------
def update
@bgm_window.update if @bgm_window and !@bgm_window.destroyed?
while event = Event.poll
handle(event)
end
#要不要放到一个Scene_Game里来处理这个?
while event = Game_Event.poll
handle_game(event)
end
end
def handle(event)
case event
when Event::MouseMotion
update_active_window(event.x, event.y)
when Event::MouseButtonDown
case event.button
when Mouse::BUTTON_LEFT
update_active_window(event.x, event.y)
@active_window.clicked if @active_window
if !(@active_window.is_a? Widget_InputBox)
Widget_InputBox.focus = false
end
when 4
@active_window.scroll_up if @active_window
when 5
@active_window.scroll_down if @active_window
end
when Event::MouseButtonUp
case event.button
when Mouse::BUTTON_LEFT
update_active_window(event.x, event.y)
@active_window.mouseleftbuttonup if @active_window
end
when Event::KeyDown
case event.sym
when Key::RETURN
if event.mod & Key::MOD_ALT != 0
$config['screen']['fullscreen'] = !$config['screen']['fullscreen']
$screen.destroy
style = HWSURFACE
style |= FULLSCREEN if $config['screen']["fullscreen"]
$screen = Screen.open($config['screen']["width"], $config['screen']["height"], 0, style)
Config.save
end
when Key::F12
$scene = Scene_Title.new
else
#$log.info('unhandled event'){event.inspect}
end
when Event::Quit
$scene = nil
when Event::Active
if (event.state & Event::APPINPUTFOCUS) != 0
Widget_InputBox.focus = event.gain
end
else
#$log.info('unhandled event'){event.inspect}
end
end
def handle_game(event)
case event
when Game_Event::Error
if event.fatal
Widget_Msgbox.new(event.title, event.message, :ok => "确定"){$game.exit if $game;$scene = Scene_Login.new}
else
Widget_Msgbox.new(event.title, event.message, :ok => "确定")
end
else
$log.debug('未处理的游戏事件'){event.inspect}
end
end
#--------------------------------------------------------------------------
# ● 结束前处理
#--------------------------------------------------------------------------
def pre_terminate
end
#--------------------------------------------------------------------------
# ● 结束处理
#--------------------------------------------------------------------------
def terminate
self.windows.each{|window|window.destroy}
end
def update_active_window(x, y)
self.windows.reverse.each do |window|
if window.include?(x, y) && window.visible
if window != @active_window
@active_window.lostfocus(window) if @active_window and !@active_window.destroyed?
@active_window = window
end
@active_window.mousemoved(x, y)
return @active_window
end
end
if @active_window and !@active_window.destroyed?
@active_window.lostfocus
@active_window = nil
end
end
end
#encoding: UTF-8
#==============================================================================
# ■ Scene_Config
#------------------------------------------------------------------------------
#  config
#==============================================================================
class Scene_Config < Scene
require_relative 'window_config'
BGM = 'title.ogg'
def start
@background = Surface.load("graphics/config/background.png").display_format
@config_window = Window_Config.new(0,0)
super
end
def handle(event)
case event
when Event::MouseMotion
self.windows.reverse.each do |window|
if window.include? event.x, event.y
@active_window = window
@active_window.mousemoved(event.x, event.y)
break
end
end
when Event::MouseButtonDown
case event.button
when Mouse::BUTTON_LEFT
@active_window.mousemoved(event.x, event.y)
@active_window.clicked
when 4
@active_window.cursor_up
when 5
@active_window.cursor_down
end
else
super
end
end
end
\ No newline at end of file
#encoding: UTF-8
#==============================================================================
# ■ Scene_Title
#------------------------------------------------------------------------------
#  title
#==============================================================================
class Scene_Deck < Scene
def start
@deck_window = Window.new(600,0,400,800)
loaddeck
@deck_window.contents.blt(@deck.main.first.pic, 200, 0)
@deck.main.each_with_index do |card, index|
@deck_window.contents.draw_text(0, index*24, card.name)
end
super
end
def loaddeck(file='/media/本地磁盘/zh99998/yu-gi-oh/token.txt')
src = IO.read(file)
src.force_encoding "GBK"
src.encode! 'UTF-8'
cards = {:main => [], :side => [], :extra => [], :temp => []}
now = :main
src.each_line do |line|
if line =~ /\[(.+)\]##(.*)\r\n/
cards[now] << Card.find($1.to_sym)
elsif line['####']
now = :side
elsif line['====']
now = :extra
elsif line['$$$$']
now = :temp
end
end
@deck = Deck.new(cards[:main], cards[:side], cards[:extra], cards[:temp])
end
def update
end
end
#encoding: UTF-8
#==============================================================================
# Scene_Duel
#------------------------------------------------------------------------------
# 决斗盘的场景
#==============================================================================
class Scene_Duel < Scene
require_relative 'window_lp'
require_relative 'window_phases'
require_relative 'window_field'
require_relative 'window_fieldback'
require_relative 'card'
require_relative 'deck'
require_relative 'action'
require_relative 'replay'
require_relative 'game_card'
require_relative 'game_field'
require_relative 'window_chat'
attr_reader :cardinfo_window
attr_reader :player_field_window
attr_reader :opponent_field_window
attr_reader :fieldback_window
def initialize(room, deck=nil)
super()
@room = room
@deck = deck
end
def start
WM::set_caption("MyCard v#{Update::Version} - #{$config['game']} - #{$game.user.name}(#{$game.user.id}) - #{@room.name}(#{@room.id})", "MyCard")
@background = Surface.load("graphics/field/main.png").display_format
Surface.blit(@background, 0, 0, 0, 0, $screen, 0, 0)
init_game
init_replay
@phases_window = Window_Phases.new(122, 356)
@fieldback_window = Window_FieldBack.new(131,173)
@cardinfo_window = Window_CardInfo.new(715, 0)
@player_field_window = Window_Field.new(2, 397, $game.player_field, true)
@opponent_field_window = Window_Field.new(2, 56, $game.opponent_field, false)
@player_lp_window = Window_LP.new(0,0, @room.player1, true)
@opponent_lp_window = Window_LP.new(360,0, @room.player2, false)
@join_se = Mixer::Wave.load("audio/se/join.ogg") if SDL.inited_system(INIT_AUDIO) != 0
create_action_window
create_chat_window
super
end
def bgm
"duel.ogg"
end
def create_action_window
@player_field_window.action_window = Window_Action.new
end
def create_chat_window
@background.fill_rect(@cardinfo_window.x, @cardinfo_window.height, 1024-@cardinfo_window.x, 768-@cardinfo_window.height,0xFFFFFFFF)
@chat_window = Window_Chat.new(@cardinfo_window.x, @cardinfo_window.height, 1024-@cardinfo_window.x, 768-@cardinfo_window.height){|text|chat(text)}
@chat_window.channel = @room
end
def chat(text)
action Action::Chat.new(true, text)
end
def init_replay
@replay = Replay.new
end
def save_replay
#@replay.save if @replay #功能尚不可用
end
def init_game
$game.player_field = Game_Field.new @deck
$game.opponent_field = Game_Field.new
$game.turn_player = true #
$game.turn = 0
end
def change_phase(phase)
action Action::ChangePhase.new(true, phase)
if phase == :EP and
action Action::TurnEnd.new(true, $game.player_field, $game.turn_player ? $game.turn : $game.turn.next)
end
end
def reset
action Action::Reset.new(true)
end
def first_to_go
action Action::FirstToGo.new(true)
end
def handle(event)
case event
when Event::MouseButtonDown
case event.button
when Mouse::BUTTON_RIGHT
if @player_field_window.action_window
@player_field_window.action_window.next
end
else
super
end
when Event::KeyDown
case event.sym
when Key::F1
action Action::Shuffle.new
@player_field_window.refresh
when Key::F2
first_to_go
@player_field_window.refresh
when Key::F3
action Action::Dice.new(true)
when Key::F5
reset
@player_field_window.refresh
when Key::F10
$game.leave
else
super
end
else
super
end
end
def action(action)
$game.action action# if @from_player
Game_Event.push Game_Event::Action.new(action)
end
def handle_game(event)
case event
when Game_Event::Chat
@chat_window.add event.chatmessage
when Game_Event::Action
if event.action.instance_of?(Action::Reset) and event.action.from_player
save_replay
init_replay
end
@replay.add event.str
str = event.str
if str =~ /^\[\d+\] (.*)$/m
str = $1
end
if str =~ /^(?:●|◎)→(.*)$/m
str = $1
end
user = if $game.room.player2 == $game.user
event.action.from_player ? $game.room.player2 : $game.room.player1
else
event.action.from_player ? $game.room.player1 : $game.room.player2
end
@chat_window.add ChatMessage.new(user, str, $game.room)
event.action.run
refresh
when Game_Event::Leave
$scene = Scene_Lobby.new
when Game_Event::Join
$game.room = event.room
@player_lp_window.player = $game.room.player1
@opponent_lp_window.player = $game.room.player2
player = $game.room.player1 == $game.user ? $game.room.player2 : $game.room.player1
if player
notify_send("对手加入房间", "#{player.name}(#{player.id})")
Mixer.play_channel(-1,@join_se,0) if SDL.inited_system(INIT_AUDIO) != 0
else
notify_send("对手离开房间", "对手离开房间")
end
else
super
end
end
def update
@cardinfo_window.update
@chat_window.update
super
end
def refresh
@fieldback_window.card = $game.player_field.field[0] && $game.player_field.field[0].card_type == :"场地魔法" && $game.player_field.field[0].position == :attack ? $game.player_field.field[0] : $game.opponent_field.field[0] && $game.opponent_field.field[0].card_type == :"场地魔法" && $game.opponent_field.field[0].position == :attack ? $game.opponent_field.field[0] : nil
@player_field_window.refresh
@opponent_field_window.refresh
@phases_window.player = $game.turn_player
@phases_window.phase = $game.phase
@player_lp_window.lp = $game.player_field.lp
@opponent_lp_window.lp = $game.opponent_field.lp
end
def terminate
unless $scene.is_a? Scene_Lobby or $scene.is_a? Scene_Duel
$game.exit
end
save_replay
super
end
def notify_send(title, msg)
command = "notify-send -i graphics/system/icon.ico #{title} #{msg}"
command = "start ruby/bin/#{command}".encode "GBK" if RUBY_PLATFORM["win"] || RUBY_PLATFORM["ming"]
system(command)
$log.info command
end
end
\ No newline at end of file
require_relative 'widget_msgbox'
class Scene_Error < Scene
def initialize(title="程序出错", text="似乎出现了一个bug,请到论坛反馈", &proc)
@title = title
@text = text
@proc = proc || proc{$scene = Scene_Title.new}
super()
end
def start
Widget_Msgbox.new(@title, @text, :ok => "确定", &@proc)
end
end
#encoding: UTF-8
#==============================================================================
# Scene_Lobby
#------------------------------------------------------------------------------
# 大厅
#==============================================================================
class Scene_Lobby < Scene
require_relative 'window_userlist'
require_relative 'window_userinfo'
require_relative 'window_roomlist'
require_relative 'window_chat'
require_relative 'window_host'
require_relative 'window_filter'
require_relative 'window_lobbybuttons'
require_relative 'chatmessage'
require_relative 'scene_duel'
require_relative 'deck_sync'
attr_reader :chat_window
def start
WM::set_caption("MyCard v#{Update::Version} - #{$config['game']} - #{$game.user.name}(#{$game.user.id})", "MyCard")
$game.refresh
@background = Graphics.load('lobby', 'background', false)
Surface.blit(@background, 0, 0, 0, 0, $screen, 0, 0)
@userlist = Window_UserList.new(24, 204, $game.users)
@roomlist = Window_RoomList.new(320, 50, $game.rooms)
@userinfo = Window_UserInfo.new(24, 24, $game.user)
@host_window = Window_LobbyButtons.new(595, 18)
@active_window = @roomlist
@chat_window = Window_Chat.new(313, $config['screen']['height'] - 225, 698, 212)
@count = 0
Deck_Sync.start
super
end
def bgm
"lobby.ogg"
end
def handle(event)
case event
when Event::KeyDown
case event.sym
when Key::UP
@active_window.cursor_up
when Key::DOWN
@active_window.cursor_down
when Key::F2
#@joinroom_msgbox = Widget_Msgbox.new("创建房间", "正在等待对手")
#$game.host Room.new(0, $game.user.name)
when Key::F3
#@joinroom_msgbox = Widget_Msgbox.new("加入房间", "正在加入房间")
#$game.join 'localhost'
when Key::F5
$game.refresh
when Key::F12
$game.exit
$scene = Scene_Login.new
end
else
super
end
end
def handle_game(event)
case event
when Game_Event::AllUsers
@userlist.items = $game.users
@userinfo.users = $game.users.size
when Game_Event::AllRooms, Game_Event::AllServers
@roomlist.items = $game.rooms.find_all { |room|
$game.filter[:servers].include?(room.server) and
$game.filter[:waiting_only] ? (room.status == :wait) : true and
$game.filter[:normal_only] ? (!room.tag? && (room.ot == 0) && (room.lp = 8000)) : true
}
@userinfo.rooms = $game.rooms.size
when Game_Event::Join
join(event.room)
when Game_Event::Watch
require_relative 'scene_watch'
$scene = Scene_Watch.new(event.room)
when Game_Event::Chat
@chat_window.add event.chatmessage
else
super
end
end
def join(room)
$scene = Scene_Duel.new(room)
end
def update
@chat_window.update
@host_window.update
@roomlist.update
if @count >= $game.refresh_interval*60
$game.refresh
@count = 0
end
@count += 1
super
end
def terminate
unless $scene.is_a? Scene_Lobby or $scene.is_a? Scene_Duel
$game.exit
end
end
end
\ No newline at end of file
#encoding: UTF-8
#==============================================================================
# ■ Scene_Login
#------------------------------------------------------------------------------
#  login
#==============================================================================
require_relative 'window_gameselect'
require_relative 'window_announcements'
require_relative 'window_login'
require_relative 'scene_replay'
require_relative 'scene_lobby'
class Scene_Login < Scene
def start
WM::set_caption("MyCard v#{Update::Version}", "MyCard")
@background = Graphics.load('login', 'background', false)
#======================================================
# We'll pay fpr that soon or later.
#======================================================
if $config['screen']['height'] == 768
@gameselect_window = Window_GameSelect.new(117,269)
elsif $config['screen']['height'] == 640
@gameselect_window = Window_GameSelect.new(117,134)
else
raise "无法分辨的分辨率"
end
#======================================================
# ENDS HERE
#======================================================
super
end
def update
@gameselect_window.update
super
end
def handle_game(event)
case event
when Game_Event::Login
require_relative 'scene_lobby'
$scene = Scene_Lobby.new
else
super
end
end
#def terminate
# @gameselect_window.destroy
#end
end
\ No newline at end of file
require_relative 'scene_watch'
class Scene_Replay < Scene_Watch
def initialize(replay)
@replay = replay
@count = 0
super(@replay.room)
$log.info('scene_reply'){'inited'}
end
def init_replay
end
def save_replay
end
def update
if @count and @count >= 60
event = @replay.get
if event
Game_Event.push event
@count = 0
else
Widget_Msgbox.new("回放", "战报回放完毕", :ok => "确定") { $scene = Scene_Login.new }
@count = nil #播放完毕标记
end
end
@count += 1 if @count
super
end
end
class Scene_Single < Scene
require 'Scene_Replay'
require_relative 'iduel/iduel'
def start
$game = Iduel.new
$scene = Scene_Replay.new Replay.load("E:/game/yu-gi-oh/test_rep.txt")
end
end
#encoding: UTF-8
#==============================================================================
# Scene_Title
#------------------------------------------------------------------------------
# title
#==============================================================================
require_relative 'scene'
require_relative 'widget_inputbox'
require_relative 'window_title'
BGM = 'title.ogg'
class Scene_Title < Scene
def start
WM::set_caption("MyCard v#{Update::Version}", "MyCard")
title = Dir.glob("graphics/titles/title_*.*")
if $config['screen']['height'] == 640
title.reject!{|t|t['full']}
else
title.reject!{|t|t['resize']}
end
title = title[rand(title.size)]
@background = Surface.load(title).display_format
Surface.blit(@background,0,0,0,0,$screen,0,0)
buttons_img = "graphics/system/titlebuttons.png"
if matched = title.match(/title_(\d+)/)
index = matched[1]
if File.exist? "graphics/titles/titlebuttons_#{index}.png"
buttons_img = "graphics/titles/titlebuttons_#{index}.png"
end
end
@command_window = Window_Title.new(title["left"] ? 200 : title["right"] ? 600 : title["special"] ? 42 : 400, title["special"] ? 321 : $config['screen']['height']/2-100,buttons_img)
(@decision_se = Mixer::Wave.load("audio/se/decision.ogg") if SDL.inited_system(INIT_AUDIO) != 0) rescue nil
super
end
def clear(x,y,width,height)
Surface.blit(@background,x,y,width,height,$screen,x,y)
end
def determine
return unless @command_window.index
Mixer.play_channel(-1,@decision_se,0) if @decision_se
case @command_window.index
when 0
require_relative 'scene_login'
$scene = Scene_Login.new
when 1
#require_relative 'scene_single'
require_relative 'widget_msgbox'
Widget_Msgbox.new("mycard", "功能未实现", :ok => "确定")
#Scene_Single.new
when 2
require_relative 'widget_msgbox'
require_relative 'scene_login'
require_relative 'deck'
load 'lib/ygocore/game.rb' #TODO:不规范啊不规范
Ygocore.deck_edit
when 3
require_relative 'scene_config'
$scene = Scene_Config.new
when 4
$scene = nil
end
end
def terminate
@command_window.destroy
@background.destroy
super
end
end
#encoding: UTF-8
#==============================================================================
# ■ Scene_Watch
#------------------------------------------------------------------------------
#  观战
#==============================================================================
require_relative 'scene_duel'
class Scene_Watch < Scene_Duel
def create_action_window
end
def chat(text)
$game.chat text, $game.room
Game_Event.push Game_Event::Action.new(Action::Chat.new(true, text), "#{$game.user}:#{text}")
end
def action(action)
end
def start
super
#$game.chat "#{$game.user.name}(#{$game.user.id})进入了观战", @room
end
def terminate
#$game.chat "#{$game.user.name}(#{$game.user.id})离开了观战", @room
end
def handle_game(event)
case event
when Game_Event::Leave
Widget_Msgbox.new("离开房间", "观战结束", :ok => "确定") { $scene = Scene_Lobby.new }
else
super
end
end
end
require_relative 'cacheable'
class Server
attr_accessor :id, :name, :ip, :port, :auth
extend Cacheable
def initialize(id, name="", ip="", port=0, auth=false)
@id = id
@name = name
@ip = ip
@port = port
@auth = auth
end
def set(id, name=:keep, ip=:keep, port=:keep, auth=:keep)
@id = id
@name = name unless name == :keep
@ip = ip unless ip == :keep
@port = port unless port == :keep
@auth = auth unless auth == :keep
end
end
\ No newline at end of file
#==============================================================================
# ■ Scene_Title
#------------------------------------------------------------------------------
#  title
#==============================================================================
class Sprite_Card < Sprite
Card_Witdh = 54
Card_Height = 81
def initialize(card, x, y)
super( card.pic ){|sprite|
sprite.x = x
sprite.y = y
#sprite.contents[0].font.size = 8
#sprite.contents[0].font.color = Color::White
sprite.zoom_x = Card_Witdh.to_f / sprite.contents[0].width
sprite.zoom_y = Card_Height.to_f / sprite.contents[0].height
#sprite.contents[0].font.smooth = true
#@font_bold = sprite.contents[0].font.dup
#@font_bold.bold = true
}
yield self if block_given?
end
end
require 'open-uri'
require "fileutils"
require_relative 'card'
module Update
Version = '1.3.8'
URL = "https://my-card.in/mycard/update.json?version=#{Version}"
class <<self
attr_reader :thumbnails, :images
attr_accessor :status
def start
Dir.glob("mycard-update-*-*.zip") do |file|
file =~ /mycard-update-(.+?)-(.+?)\.zip/
if $1 <= Version and $2 > Version
$log.info('安装更新') { file }
WM::set_caption("MyCard - 正在更新 #{Version} -> #{$2}", "MyCard")
require 'zip/zip'
Zip::ZipFile::open(file) do |zip|
zip.each do |f|
if !File.directory?(f.name)
FileUtils.mkdir_p(File.dirname(f.name))
end
f.extract { true }
end
end rescue $log.error('安装更新出错') { file+$!.inspect+$!.backtrace.inspect }
Version.replace $2
File.delete file
@updated = true
end
end
if @updated
require 'rbconfig'
spawn(File.join(RbConfig::CONFIG["bindir"],RbConfig::CONFIG[Windows ? "RUBYW_INSTALL_NAME" : "RUBY_INSTALL_NAME"] + RbConfig::CONFIG["EXEEXT"]) + " -KU lib/main.rb")
$scene = nil
end
@images = []
@thumbnails = []
@status = '正在检查更新'
@updated = false
(Thread.new do
open(URL) do |file|
require 'json'
reply = file.read
$log.info('下载更新-服务器回传') { reply }
reply = JSON.parse(reply)
$log.info('下载更新-解析后') { reply.inspect }
reply.each do |fil|
name = File.basename fil
@status = "正在下载更新#{name}"
open(fil, 'rb') do |fi|
$log.info('下载完毕') { name }
@updated = true
open(name, 'wb') do |f|
f.write fi.read
end
end rescue $log.error('下载更新') { '下载更新失败' }
end
end rescue $log.error('检查更新') { '检查更新失败' }
if @updated
require_relative 'widget_msgbox'
Widget_Msgbox.new('mycard', '下载更新完毕,点击确定重新运行mycard并安装更新', :ok => "确定") {
require 'rbconfig'
spawn(File.join(RbConfig::CONFIG["bindir"],RbConfig::CONFIG[Windows ? "RUBYW_INSTALL_NAME" : "RUBY_INSTALL_NAME"] + RbConfig::CONFIG["EXEEXT"]) + " -KU lib/main.rb")
$scene = nil
}
end
if File.file? "ygocore/cards.cdb"
require 'sqlite3'
db = SQLite3::Database.new("ygocore/cards.cdb")
db.execute("select id from datas") do |row|
@thumbnails << row[0]
end
@images.replace @thumbnails
if !File.directory?('ygocore/pics/thumbnail')
FileUtils.mkdir_p('ygocore/pics/thumbnail')
end
existed_thumbnails = []
Dir.foreach("ygocore/pics/thumbnail") do |file|
if file =~ /(\d+)\.jpg/
existed_thumbnails << $1.to_i
end
end
@thumbnails -= existed_thumbnails
existed_images = []
Dir.foreach("ygocore/pics") do |file|
if file =~ /(\d+)\.jpg/
existed_images << $1.to_i
end
end
@images -= existed_images
existed_images = []
if (!@images.empty? or !@thumbnails.empty?) and File.file?("#{Card::PicPath}/1.jpg")
db_mycard = SQLite3::Database.new("data/data.sqlite")
db_mycard.execute("select id, number from `yu-gi-oh` where number in (#{(@images+@thumbnails).uniq.collect { |number| "'%08d'" % number }.join(',')})") do |row|
id = row[0]
number = row[1].to_i
src = "#{Card::PicPath}/#{id}.jpg"
dest = "ygocore/pics/#{number}.jpg"
dest_thumb = "ygocore/pics/thumbnail/#{number}.jpg"
if File.file?(src)
@status = "检测到存在iDuel卡图 正在导入 #{id}.jpg"
existed_images << number
if !File.exist?(dest)
FileUtils.copy_file(src, dest)
FileUtils.copy_file(src, dest_thumb)
end
end
end
end
@images -= existed_images
@thumbnails -= existed_images
@thumbnails = (@thumbnails & @images) + (@thumbnails - @images)
unless @thumbnails.empty? and @images.empty?
$log.info('待下载的完整卡图') { @images.inspect }
$log.info('待下载的缩略卡图') { @thumbnails.inspect }
open('https://my-card.in/cards/image.json') do |f|
image_index = JSON.parse(f.read)
$log.info('卡图路径'){image_index}
url = image_index['url']
uri = URI(url)
image_req = uri.path
image_req += '?' + uri.query if uri.query
image_req += '#' + uri.fragment if uri.fragment
url = image_index['thumbnail_url']
uri = URI(url)
thumbnail_req = uri.path
thumbnail_req += '?' + uri.query if uri.query
thumbnail_req += '#' + uri.fragment if uri.fragment
require 'net/http/pipeline'
@thumbnails_left = @thumbnails.size
@images_left = @images.size
@error_count = 0
threads = 5.times.collect do
thread = Thread.new do
Net::HTTP.start uri.host, uri.port do |http|
http.pipelining = true
begin
list = @thumbnails
ids = []
while !@thumbnails.empty?
ids.replace @thumbnails.pop(100)
reqs = ids.reverse.collect { |id| Net::HTTP::Get.new thumbnail_req.gsub(':id', id.to_s) }
http.pipeline reqs do |res|
@status = "正在下载卡图 (剩余: 缩略#{@thumbnails_left} / 完整#{@images_left} #{"错误: #{@error_count}" if @error_count > 0})"
@thumbnails_left -= 1
id = ids.pop
if res.code[0] == '2' #http 2xx
next if File.file? "ygocore/pics/thumbnail/#{id}.jpg"
content = res.body
open("ygocore/pics/thumbnail/#{id}.jpg", 'wb') {|local|local.write content}
else
$log.warn("下载缩略卡图#{id}出错"){res}
@error_count += 1
end
end
end
list = @images
ids = []
while !@images.empty?
ids.replace @images.pop(100)
reqs = ids.reverse.collect { |id| Net::HTTP::Get.new image_req.gsub(':id', id.to_s) }
http.pipeline reqs do |res|
@status = "正在下载卡图 (剩余: 缩略#{@thumbnails_left} / 完整#{@images_left} #{"错误: #{@error_count}" if @error_count > 0})"
@images_left -= 1
id = ids.pop
if res.code[0] == '2' #http 2xx
next if File.file? "ygocore/pics/#{id}.jpg"
content = res.body
open("ygocore/pics/#{id}.jpg", 'wb') {|local|local.write content}
else
$log.warn("下载完整卡图#{id}出错"){res}
@error_count += 1
end
end
end
rescue
$log.error('卡图下载') { [$!.inspect, *$!.backtrace].collect { |str| str.force_encoding("UTF-8") }.join("\n") }
list.concat ids
end
end rescue $log.error('卡图下载线程出错') { $!.inspect.force_encoding("UTF-8") }
end
thread.priority = -1
thread
end
threads.each { |thread| thread.join }
end
end
end rescue $log.error('卡图更新') { [$!.inspect, *$!.backtrace].collect { |str| str.force_encoding("UTF-8") }.join("\n") }
@status = nil
end).priority = -1
end
end
end
require_relative 'cacheable'
class User
attr_accessor :id, :name, :friend, :affiliation
alias friend? friend
extend Cacheable
def initialize(id, name="")
@id = id
@name = name
end
def set(id, name = :keep)
@id = id
@name = name unless name == :keep
end
def avatar(size = :small)
Surface.new(SWSURFACE, 1, 1, 32, 0,0,0,0)
end
def status
room = room()
case
when room.nil?
:lobby
when room.player2
:dueling
else
:waiting
end
end
def room
$game && $game.rooms.find{|room|room.player1 == self or room.player2 == self}
end
def viewinfo
end
def color
[0,0,0]
end
def space
end
end
\ No newline at end of file
# To change this template, choose Tools | Templates
# and open the template in the editor.
class Widget_Checkbox < Window
attr_reader :checked
alias checked? checked
def initialize(window,x,y,width=window.width-x,height=24,checked=false,text="",&proc)
super(x+2,y+2,width,height,500) #+2是素材尺寸问题
@window = window
@text = text
@checked = checked
@checkbox = Surface.load('graphics/system/checkbox.png').display_format
@font = TTF.open(Font, 20)
@proc = proc
refresh
end
def checked=(checked)
@checked = checked
refresh
end
def mousemoved(x,y)
if x-@x < 24
@index = 0
else
@index = nil
end
end
def clicked
if @index
@checked = !@checked
@proc.call(@checked) if @proc
end
refresh
end
def refresh
clear
Surface.blit(@checkbox, 0, @checked ? @checkbox.h/2 : 0, @checkbox.w/3, @checkbox.h/2, self.contents, 0, 0)
@font.draw_blended_utf8(self.contents, @text, 24, 0, 0xFF, 0xFF, 0xFF)
end
#def clear(x=0,y=0,width=@width,height=@height)
# Surface.blit(@window.contents, @x-@window.x+x, @y-@window.y+y, width,height, self.contents, x, y)
#end
end
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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