Merge branch 'master' into master

This commit is contained in:
Wyst3r 2017-02-22 19:51:13 +01:00 committed by GitHub
commit d665bad4c5
379 changed files with 18374 additions and 12981 deletions

View File

@ -1,251 +1,371 @@
-- Gargoyles, Genesis
-- feos, 2015
-- Gargoyles, Genesis (BizHawk)
-- feos, 2015-2016
--== Shortcuts ==--
local rb = memory.read_u8
local rw = memory.read_u16_be
local rws = memory.read_s16_be
local rl = memory.read_u32_be
local box = gui.drawBox
local text = gui.pixelText
local line = gui.drawLine
local AND = bit.band
local SHIFT= bit.rshift
rb = memory.read_u8
rw = memory.read_u16_be
rws = memory.read_s16_be
r24 = memory.read_u24_be
rl = memory.read_u32_be
box = gui.drawBox
text = gui.pixelText
line = gui.drawLine
AND = bit.band
SHIFT = bit.rshift
--== RAM addresses ==--
local GlobalBase = 0x1c76
local GolBase = 0x2c76
local MapA_Buff = 0x4af0
local mapline_tab = 0x0244
local LevelFlr = 0x00c0
local LevelCon = 0x00c4
local levnum = 0x00ba
levnum = 0xff00ba
LevelFlr = 0xff00c0
LevelCon = 0xff00c4
mapline_tab = 0xff0244
GlobalBase = 0xff1c76
GolBase = 0xff2c76
MapA_Buff = 0xff4af0
--== Camera Hack ==--
local camhack = false
local div = 1 -- scale
local size = 16/div -- block size
camhack = false
div = 1 -- scale
size = 16/div -- block size
--== Block cache ==--
col = 0 -- block color
opout = 0x33000000 -- outer opacity
opin = 0x66000000 -- inner opacity
op = 0xff000000
cache = {}
--== Other stuff ==--
local XposLast = 0
local YposLast = 0
XposLast = 0
YposLast = 0
room = 0
workinglast = 0
lagcount = emu.lagcount()
gui.defaultPixelFont("fceux")
function main()
camx = (rws(0x010c)+16)
camy = (rws(0x010e)+16)
backx = camx
backy = camy
mapw = rw(0x00d4)*8
maph = rw(0x00d6)*8
-- text(100,0,mapw.." "..maph)
Xpos = rws(0x0106)
Ypos = rws(0x0108)
health = rws(0x2cc6)
facing = AND(rb(GolBase+0x48),2) -- object flag 1
working= rb(0x0073)
if camhack then
camx = Xpos-320/2*div
camy = Ypos-224/2*div
rnd1 = rl (0xff001c)
rnd2 = rw (0xff0020)
working = rb (0xff0073)
xblocks = rw (0xff00d4)
mapw = rw (0xff00d4)*8
maph = rw (0xff00d6)*8
Xpos = rws(0xff0106)
Ypos = rws(0xff0108)
camx = rws(0xff010c)+16
camy = rws(0xff010e)+16
run = rb (0xff1699)
inv = rw (0xff16d2)
health = rws(0xff2cc6)
backx = camx
backy = camy
Xspd = Xpos-XposLast
Yspd = Ypos-YposLast
facing = AND(rb(GolBase+0x48),2) -- object flag 1
Background()
CamhackHUD()
Objects()
PlayerBoxes()
HUD()
RoomTime()
Input()
end
function RoomTime()
local start11 = 894--767
local start12 = 2294
local start13 = 4101
local startl4 = 6000
timer = emu.framecount()
if timer < start11 then room = timer
elseif timer < start12 then room = timer - start11
elseif timer < start13 then room = timer - start12
elseif timer < startl4 then room = timer - start13
end
run = rb(0x1699)
inv = rw(0x16d2)
rnd1 = rl(0x001c)
rnd2 = rw(0x0020)
Xspd = Xpos-XposLast
Yspd = Ypos-YposLast
XposLast = Xpos
YposLast = Ypos
rndlast = rnd1
--[ [--
if camhack then box(0,0,320,240,0,0x66000000) end
text(160,214,"room cnt: "..room, "white")
end
function HUD()
text(1, 0,emu.framecount(), framecol)
text(1,20,emu.lagcount(), "red")
text(1,30,movie.rerecordcount(),"orange")
if working>0 then return end
if rndlast ~= rnd1 then rndcol = "red" else rndcol = "white" end
text( 0,214,"rnd: ","yellow")
text( 26,214,string.format("%08X %04X",rnd1,rnd2),rndcol)
text(277, 0,string.format(
"x: %4d\ny: %4d\ndx: %3d\ndy: %3d\nhp: %3d\nrun:%3d\ninv:%3d",
Xpos,Ypos,Xspd,Yspd,health,run,inv)
)
end
function CamhackHUD()
if working==0 then
box(
(backx-camx- 1)/div,
-- screen edge
box((backx-camx- 1)/div,
(backy-camy- 1)/div,
(backx-camx+320)/div,
(backy-camy+224)/div,
0x0000ffff)
0xff0000ff)
-- map edge
box( 0-camx/div+size,
0-camy/div+size,
mapw/div-camx/div,
maph/div-camy/div,
0xff0000ff)
end
for i=0,20*div do
for j=0,14*div do
GetBlock(i,j)
end
end
--]]--
Objects()
PlayerBoxes()
HUD()
RoomTime()
text(260,206,string.format("cHack: %s\nscale: %d",ch,div))
end
function RoomTime()
local start11 = 767
local start12 = 2294
local start13 = 4101
local startl4 = 6000
timer = emu.framecount()
if timer < start11 then room = timer
elseif timer < start12 then room = timer - start11
elseif timer < start13 then room = timer - start12
elseif timer < startl4 then room = timer - start13
function Background()
if working>0 then
cache = {}
return
end
if camhack then
camx = Xpos-320/2*div
camy = Ypos-224/2*div
box(0,0,320,240,0,0x66000000)
ch = "on"
else
ch = "off"
end
local border = 0
local offset = 32
local basex = camx+border
local basey = camy+border
local basei = PosToIndex(basex-offset,basey-offset)
local boundx = 320*div-border
local boundy = 224*div-border
local xblockstockeck = ((camx+boundx+offset)-(basex-offset))/size/div
local yblockstockeck = ((camy+boundy+offset)-(basey-offset))/size/div
for yblock = 0,yblockstockeck do
for xblock = 0,xblockstockeck do
local i = yblock*xblocks+xblock+basei
local x = basex+xblock*size*div
local y = basey+yblock*size*div
if InBounds(x,basex-offset,camx+boundx+offset) then
local unit = cache[i]
if unit == nil or workinglast>0 then
if InBounds(x,basex,camx+boundx)
and InBounds(y,basey,camy+boundy)
then cache[i] = GetBlock(x,y)
end
else
if not InBounds(x,basex,camx+boundx)
and not InBounds(y,basey,camy+boundy)
then cache[i] = nil
end
end
if unit ~= nil then
DrawBG(unit,x,y)
end
elseif cache[i] ~= nil
then cache[i] = nil
end
end
end
end
function DrawBG(unit, x, y)
local val= 0
local x1 = x/div-camx/div-(camx%16)/div
local x2 = x1+size-1
local y1 = y/div-camy/div-(camy%16)/div
local y2 = y1+size-1
if unit.contour ~= nil then
box(x1,y1,x2,y2,0x5500ff00,0x5500ff00)
for pixel=0,15 do
val = unit.contour[pixel]
if val>0 then
gui.drawPixel(
x1+pixel/div,
y1+val/div-1/div,
0xffffff00)
end
end
end
if unit.block>0 then
local Fn = DrawBlock[unit.block] or DrawBlockDefault
Fn(x1,y1,x2,y2)
box(x1,y1,x2,y2,col+opin,col+opout)
end
text(100,217,"room cnt: "..room)
end
function GetBlock(x,y)
if working>0 then return end
x = camx+x*size*div-AND(camx,0xF)
y = camy+y*size*div-AND(camy,0xF)
if x>0 and x<mapw and y>0 and y<maph then
local x1 = x/div-camx/div
local x2 = x1+size-1
local y1 = y/div-camy/div
local y2 = y1+size-1
local d4 = rw(mapline_tab+SHIFT(y,4)*2)
local a1 = AND(rl(LevelFlr),0xffff)
local d1 = SHIFT(rw(MapA_Buff+d4+SHIFT(x,4)*2),1)
local ret = rb(a1+d1+2) -- block
local col = 0 -- block color
local opout = 0x33000000 -- outer opacity
local opin = 0x66000000 -- inner opacity
local op = 0xff000000
if working>0 then return nil end
local final = { contour={}, block=0 }
if x>0 and x<mapw
and y>0 and y<maph then
local pixels = 0
local x1 = x/div-camx/div
local x2 = x1+size-1
local y1 = y/div-camy/div
local y2 = y1+size-1
local d4 = rw(mapline_tab+SHIFT(y,4)*2)
local a1 = r24(LevelFlr+1)
local d1 = SHIFT(rw(MapA_Buff+d4+SHIFT(x,4)*2),1)
final.block = rb(a1+d1+2)
d1 = rw(a1+d1)
a1 = AND(rl(LevelCon),0xffffff)+d1
if rb(a1,"MD CART")>0 or rb(a1+8,"MD CART")>0 then
box(x1,y1,x2,y2,0x5500ff00,0x5500ff00)
a1 = r24(LevelCon+1)+d1
if rb(a1)>0 or rb(a1+8)>0 then
for pixel=0,15 do
retc = rb(a1+pixel,"MD CART") -- contour
if retc>0 then
gui.drawPixel(x1+pixel/div,y1+retc/div-1/div,0xffffff00)
-- text(x1,y1,string.format("%X",retc))
end
final.contour[pixel] = rb(a1+pixel)
end
else
final.contour = nil
end
local lol = 0
--if lol==0 then return end
if ret>0 then
if ret==0x80 then -- WALL
col = 0x00ffffff -- white
line(x1,y1,x1,y2,col+op) -- left
line(x2,y1,x2,y2,col+op) -- right
elseif ret==0x81 then -- CEILING
col = 0x00ffffff -- white
line(x1,y2,x2,y2,col+op) -- bottom
elseif ret==0x82 then -- CLIMB_U
col = 0x0000ffff -- cyan
line(x1,y2,x2,y2,col+op) -- bottom
elseif ret==0x83 then -- CLIMB_R
-- col = 0x00ffffff -- white
-- line(x2,y1,x2,y2,col+op) -- right
col = 0x0000ffff -- cyan
line(x1,y1,x1,y2,col+op) -- left
elseif ret==0x84 then -- CLIMB_L
-- col = 0x00ffffff -- white
-- line(x1,y1,x1,y2,col+op) -- left
col = 0x0000ffff -- cyan
line(x2,y1,x2,y2,col+op) -- right
elseif ret==0x85 then -- CLIMB_LR
col = 0x0000ffff -- cyan
line(x1,y1,x1,y2,col+op) -- left
line(x2,y1,x2,y2,col+op) -- right
elseif ret==0x86 then -- CLIMB_R_STAND_R
col = 0x00ffffff -- white
line(x1,y1,x2,y1,col+op) -- top
col = 0x0000ffff -- cyan
line(x1,y1,x1,y2,col+op) -- left
elseif ret==0x87 then -- CLIMB_L_STAND_L
col = 0x00ffffff -- white
line(x1,y1,x2,y1,col+op) -- top
col = 0x0000ffff -- cyan
line(x2,y1,x2,y2,col+op) -- right
elseif ret==0x87 then -- CLIMB_LR_STAND_LR
col = 0x00ffffff -- white
line(x1,y1,x2,y1,col+op) -- top
col = 0x00ff00ff -- cyan
line(x1,y1,x1,y2,col+op) -- left
col = 0x0000ffff -- cyan
line(x2,y1,x2,y2,col+op) -- right
elseif ret==0x70 then -- GRAB_SWING
col = 0x0000ff00 -- green
box(x1,y1,x2,y2,col,col+opout)
-- elseif ret==0x72 then -- FORCE_TURN (for enemies)
-- col = 0x0088ff00 -- green
-- box(x1,y1,x2,y2,col,col+opout)
elseif ret==0x7f then -- EXIT
col = 0x00ffff00 -- yellow
elseif ret==0xd0 or ret==0xd1 then -- SPIKES
col = 0x00ff0000 -- red
box(x1,y1,x2,y2,col,col+opout)
else -- LEVEL_SPECIFIC
col = 0x00ff8800 -- orange
box(x1,y1,x2,y2,col+opin,col+opout)
end
box(x1,y1,x2,y2,col+opin,col+opout)
-- text(x1,y1,string.format("%X",ret))
end
else
return nil
end
return final
end
function PosToIndex(x,y)
return math.floor(x/16)+math.floor(y/16)*xblocks
end
function IndexToPos(i)
return { x=(i%xblocks)*16, y=math.floor(i/xblocks)*16 }
end
function InBounds(x,minimum,maximum)
if x>=minimum and x<=maximum
then return true
else return false
end
end
function HUD()
if working>0 then return end
if camhack then ch = "on" else ch = "off" end
if rndlast~= rnd1 then rndcol = "red" else rndcol = "white" end
if memory.readbyte(0xF6D4)==0 then text(170,217,"LAG","red") end
text(280,210,string.format("cHack: %s\nscale: %d",ch,div))
text( 0,217,"rnd: ","yellow")
text( 20,217,string.format("%08X %04X",rnd1,rnd2),rndcol)
text(290, 0,string.format(
"x: %4d\ny: %4d\ndx: %3d\ndy: %3d\nhp: %3d\nrun:%3d\ninv:%3d",
Xpos,Ypos,Xspd,Yspd,health,run,inv),"yellow"
)
DrawBlock = {
[0x80] = function(x1,y1,x2,y2) -- WALL
col = 0x00ffffff -- white
line(x1,y1,x1,y2,col+op) -- left
line(x2,y1,x2,y2,col+op) -- right
end,
[0x81] = function(x1,y1,x2,y2) -- CEILING
col = 0x00ffffff -- white
line(x1,y2,x2,y2,col+op) -- bottom
end,
[0x82] = function(x1,y1,x2,y2) -- CLIMB_U
col = 0x0000ffff -- cyan
line(x1,y2,x2,y2,col+op) -- bottom
end,
[0x83] = function(x1,y1,x2,y2) -- CLIMB_R
col = 0x0000ffff -- cyan
line(x1,y1,x1,y2,col+op) -- left
end,
[0x84] = function(x1,y1,x2,y2) -- CLIMB_L
col = 0x0000ffff -- cyan
line(x2,y1,x2,y2,col+op) -- right
end,
[0x85] = function(x1,y1,x2,y2) -- CLIMB_LR
col = 0x0000ffff -- cyan
line(x1,y1,x1,y2,col+op) -- left
line(x2,y1,x2,y2,col+op) -- right
end,
[0x86] = function(x1,y1,x2,y2) -- CLIMB_R_STAND_R
col = 0x00ffffff -- white
line(x1,y1,x2,y1,col+op) -- top
col = 0x0000ffff -- cyan
line(x1,y1,x1,y2,col+op) -- left
end,
[0x87] = function(x1,y1,x2,y2) -- CLIMB_L_STAND_L
col = 0x00ffffff -- white
line(x1,y1,x2,y1,col+op) -- top
col = 0x0000ffff -- cyan
line(x2,y1,x2,y2,col+op) -- right
end,
[0x88] = function(x1,y1,x2,y2) -- CLIMB_LR_STAND_LR
col = 0x00ffffff -- white
line(x1,y1,x2,y1,col+op) -- top
col = 0x00ff00ff -- cyan
line(x1,y1,x1,y2,col+op) -- left
col = 0x0000ffff -- cyan
line(x2,y1,x2,y2,col+op) -- right
end,
[0x70] = function(x1,y1,x2,y2) -- GRAB_SWING
col = 0x0000ff00 -- green
box(x1,y1,x2,y2,col,col+opout)
end,
[0x7f] = function(x1,y1,x2,y2) -- EXIT
col = 0x00ffff00 -- yellow
end,
[0xd0] = function(x1,y1,x2,y2) -- SPIKES
col = 0x00ff0000 -- red
box(x1,y1,x2,y2,col,col+opout)
end,
[0xd1] = function(x1,y1,x2,y2) -- SPIKES
col = 0x00ff0000 -- red
box(x1,y1,x2,y2,col,col+opout)
end
}
function DrawBlockDefault(x1,y1,x2,y2)-- LEVEL_SPECIFIC
col = 0x00ff8800 -- orange
box(x1,y1,x2,y2,col+opin,col+opout)
end
function Objects()
if working>0 then return end
for i=0,63 do
local base = GlobalBase+i*128
local flag2 = AND(rb(base+0x49),0x10) -- active
if flag2==0x10 then
local xpos = rw(base+0x00)
local ypos = rw(base+0x02)
-- local anm = rl(base+0x20)
local dmg = rb(base+0x10)
local type = rw(base+0x40)
local hp = rw(base+0x50)
local cRAM = rw(base+0x76) -- pointer to 4 collision boxes per object
local col = 0 -- collision color
local xpos = rw (base+0x00)
local ypos = rw (base+0x02)
local dmg = rb (base+0x10)
local type = rw (base+0x40)
local hp = rw (base+0x50)
local cRAM = r24(base+0x75) -- pointer to 4 collision boxes per object
local col = 0 -- collision color
local xscr = (xpos-camx)/div
local yscr = (ypos-camy)/div
if type==0 then
-- gui.text(xscr,yscr,string.format("%X",anm))
end
for boxx=0,4 do
local x1 = (rws(cRAM+boxx*8+0)-camx)/div
local y1 = (rws(cRAM+boxx*8+2)-camy)/div
local x2 = (rws(cRAM+boxx*8+4)-camx)/div
local y2 = (rws(cRAM+boxx*8+6)-camy)/div
if boxx==0 then
col = 0xff00ff00 -- body
col = 0xff00ff00 -- body
if type==282 or type==258 then hp = 1 end -- archer hp doesn't matter
if hp>0 and type>0 then
text(x1+2,y1+1,string.format("%d",hp),col)
text(x1+2,y1+1,string.format("%d",hp),col,0x88000000,"gens")
end
elseif boxx==1 then
col = 0xffffff00 -- floor
elseif boxx==1 then
col = 0xffffff00 -- floor
elseif boxx==2 then
if dmg>0 then
col = 0xffff0000 -- projectile
else
col = 0xff8800ff -- item
if dmg>0
then col = 0xffff0000 -- projectile
else col = 0xff8800ff -- item
end
if dmg>0 then
text(x1+2,y2+1,string.format("%d",dmg),col)
text(x1+2,y2+1,string.format("%d",dmg),col,0x88000000,"gens")
end
else
col = 0xffffffff -- other
col = 0xffffffff -- other
end
if x1~=0x8888 and x2<320 and x1>0 and y2<224 and y1>0 then
box(x1,y1,x2,y2,col)
end
@ -256,20 +376,24 @@ end
function PlayerBoxes()
if working>0 then return end
xx = (Xpos-camx)/div
yy = (Ypos-camy)/div
local xx = (Xpos-camx)/div
local yy = (Ypos-camy)/div
local col = 0xff00ffff
local swcol = col -- usual detection
if Yspd>0 then -- gimme swings to grab!!!
local swcol = col -- usual detection
if Yspd>0 then -- gimme swings to grab!
swcol = 0xff00ff00
elseif Yspd==0 then -- can tell that too
elseif Yspd==0 then -- can tell that too
swcol = 0xffffffff
end
if facing==2 then
box(xx-0xf /div-2,yy-0x2c/div-1,xx-0xf /div+0,yy-0x2c/div+1,swcol) -- lefttop
else
box(xx+0xf /div-1,yy-0x2c/div-1,xx+0xf /div+1,yy-0x2c/div+1,swcol) -- rightttop
end
box(xx -1,yy-0x2c/div-1,xx +1,yy-0x2c/div+1,col) -- top
box(xx-0xf /div-2,yy-0x1f/div-1,xx-0xf /div+0,yy-0x1f/div+1,col) -- left
box(xx+0x10/div-1,yy-0x1f/div-1,xx+0x10/div+1,yy-0x1f/div+1,col) -- right
@ -279,7 +403,44 @@ function PlayerBoxes()
-- box(xx -1,yy+0x10/div-1,xx +1,yy+0x10/div+1,col) -- ground
end
--event.onframeend(main)
function Input()
local i,u,d,l,r,a,b,c,s
if movie.isloaded() then
i = movie.getinput(emu.framecount()-1)
else
i = joypad.getimmediate()
end
if i["P1 Up" ] then u = "U" else u = " " end
if i["P1 Down" ] then d = "D" else d = " " end
if i["P1 Left" ] then l = "L" else l = " " end
if i["P1 Right"] then r = "R" else r = " " end
if i["P1 A" ] then a = "A" else a = " " end
if i["P1 B" ] then b = "B" else b = " " end
if i["P1 C" ] then c = "C" else c = " " end
if i["P1 Start"] then s = "S" else s = " " end
text(1,10,u..d..l..r..a..b..c..s,"yellow")
end
event.onframeend(function()
emu.setislagged(rb(0xfff6d4)==0)
if rb(0xfff6d4)==0 then
lagcount = lagcount+1
framecol = "red"
else
framecol = "white"
end
emu.setlagcount(lagcount)
rndlast = rnd1
workinglast = working
XposLast = Xpos
YposLast = Ypos
end)
while true do
main()

View File

@ -238,14 +238,14 @@
"P4 R": ""
},
"Nintento 64 Controller": {
"P1 A Up": "UpArrow, J1 DpadUp, X1 LStickUp",
"P1 A Down": "DownArrow, J1 POV1D, X1 DpadDown, X1 LStickDown",
"P1 A Left": "LeftArrow, J1 POV1L, X1 DpadLeft, X1 LStickLeft",
"P1 A Right": "RightArrow, J1 POV1R, X1 DpadRight, X1 LStickRight",
"P1 DPad U": "",
"P1 DPad D": "",
"P1 DPad L": "",
"P1 DPad R": "",
"P1 A Up": "UpArrow, J1 POV1U",
"P1 A Down": "DownArrow, J1 POV1D",
"P1 A Left": "LeftArrow, J1 POV1L",
"P1 A Right": "RightArrow, J1 POV1R",
"P1 DPad U": "X1 DpadUp",
"P1 DPad D": "X1 DpadDown",
"P1 DPad L": "X1 DpadLeft",
"P1 DPad R": "X1 DpadRight",
"P1 Start": "Return, J1 B10, X1 Start",
"P1 Z": "D, J1 B3, X1 B",
"P1 B": "S, J1 B1, X1 X",
@ -1192,12 +1192,12 @@
},
"Nintento 64 Controller": {
"P1 X Axis": {
"Value": "J1 X",
"Value": "X1 LeftThumbX",
"Mult": 1.0,
"Deadzone": 0.1
},
"P1 Y Axis": {
"Value": "J1 Y",
"Value": "X1 LeftThumbY",
"Mult": 1.0,
"Deadzone": 0.1
},

File diff suppressed because it is too large Load Diff

View File

@ -29,6 +29,7 @@
#include gamedb_msx1.txt
#include gamedb_msx2.txt
#include gamedb_vs.txt
#include gamedb_intv.txt
; ************ NES / Famicom ************
@ -311,6 +312,7 @@ sha1:35C157A921156E47FD3F6573D150F54108D0EDFC Blargg's 5.MMC3_rev_A.nes NES bo
sha1:0E971E2CCAD1DEE51A0C305ED38FAFD2E6CA3B41 Blargg's 6.MMC3_rev_B.nes NES board=MAPPER004;MMC3=MMC3B
sha1:F794FDA12D34E611D58E652319ED583AE61B81E0 Blargg's 6-MMC6.nes NES board=MAPPER004_MMC6
sha1:2F29F3DC724027FAD926BC9D4470A481884E42A5 Blargg's 6-MMC6.nes (newer) NES board=MAPPER004_MMC6
sha1:6F3184ACDC7333683D459C7613CA1C235CEAFD3F Aladdin (SuperGame) (Mapper 4) [!] NES board=MAPPER004;MMC3=MMC3A
;;;;;;;;;;;;;;;;;;;-----------------------------------------------------------------------
;datach stuff
@ -324,6 +326,9 @@ EDD7A45A7F27E396B6D686F1861642D509863132 Datach SD Gundam Gundam Wars NES boar
6F3C65BD945FE13305A7A39D8CD884A5BF314A8F Datach Crayon Shin Chan Ora to Poi Poi NES board=MAPPER157
1218C891DEE878C18D31D38D07CAD5FB06B3B2CE Datach Yuu Yuu akusho Baktutou NES board=MAPPER157
;testrom
sha1:E925A172C29DD46BA385D526F3C317DB039FA2BF mmc1_a12 NES board=NES-SNROM
; ArcadePit hacks
; Why does this one need NesHawk?
sha1:90acbbdfad1465032dfff77175320bab8aa4adb7 H Mike Tyson's Punch-Out!! [Buck Edit] (USA) NES NesHawk
@ -349,7 +354,6 @@ C94257E7 B Looney Tunes - Sheep Raider (STATiC Dump) PSX dh=00000000
829A295C B Monster Rancher 2 (U) (EXE Patched) PSX dh=00000000
#include gamedb_neshomebrew.txt
#include gamedb_vs.txt
#include gamedb_user.txt
#include gamedb_ws.txt
#include gamedb_wsc.txt

View File

@ -137,7 +137,7 @@ sha1:5DE3BD9B7234A0EEA7551DDBEDD7F55CD47AA9F7 Kevtris by Kevin Horton (1996) (P
sha1:77CD01E29071DECE70D18CF9E7E2D2CE455D001F Keystone Kapers (1983-84) (Activision) Coleco
sha1:50A1BE08F8CD5445EE32C1702A3D3607948867B6 Kill Barney in Tokyo by Daniel Bienvenu (1997) (PD) Coleco
sha1:40324590797F32915021CFD0D6EB4112020939BF Killer Instinct by Daniel Bienvenu (1997) (PD) Coleco
sha1:AFA8E2F119D63463DBDD0C88BE6873B0C6A27594 Lady Bug (1982) (Universal) Coleco
sha1:AFA8E2F119D63463DBDD0C88BE6873B0C6A27594 Lady Bug (1982) (Universal) Coleco NoSkip
sha1:0CE165B3C2A9E60964D33F37E8AEC7CBF9E9D00F Learning With Leeper (1983) (Sierravision) [!] Coleco
sha1:198767E1C8794F974F3434674CB0E542108D0011 Linking Logic (1984) (Fisher-Price) Coleco
sha1:C5A4D39C1AA5A643DAABC9A163F366F9BA5AFEF2 Logic Levels (1984) (Fisher-Price) Coleco
@ -235,8 +235,8 @@ sha1:F828B172ED3B51CC5F65843032BD2F4E2BF5C418 Space Invasion Demo by John Dondz
sha1:530870501F322F1D72E820A722790D300F43A6DE Space Panic (1983) (Universal) Coleco NoSkip
sha1:5A1E9E8CFE6D6E1CD685EC4AFD0FC159E20A69FF Spectank Demo by Daniel Bienvenu (2000) (PD) Coleco
sha1:8C83391F512D20CBBB4F36B0ADD06A6CF0BD8E65 Spectron (1983) (Spectravideo) Coleco
sha1:E9814F694FAD5548E9CE7295DDC9F8B9EEE29332 B Spy Hunter (1983-84) (Midway) [b1] Coleco
sha1:97865D067BD531209857C3C8502C1260E0A30366 Spy Hunter (1983-84) (Midway) Coleco
sha1:E9814F694FAD5548E9CE7295DDC9F8B9EEE29332 B Spy Hunter (1983-84) (Midway) [b1] Coleco NoSkip
sha1:97865D067BD531209857C3C8502C1260E0A30366 Spy Hunter (1983-84) (Midway) Coleco NoSkip
sha1:D4C1A98A35DC79727B6E8838B1B0815919496601 Squish 'Em Sam! (1983) (Interphase) Coleco
sha1:870D1A39AA85AC1D0E270348B56944BA47170557 St-Valentine's Day (2002) (PD) Coleco
sha1:003F07FA755F632348694E7C6E6AC0DE10E1B3E7 St-Valentine's Day (No Alien Head) (2002) (PD) Coleco
@ -264,7 +264,7 @@ sha1:EFA3B89899839E062E072921148716E8B82923CE Super Cross Force (1983) (Spectra
sha1:B1AC18780E36821A8D41FC4410E14AB0CE80AC91 Super DK! (1983) (Prototype) Coleco
sha1:44A22E508002A069F7953668F2E8A3C901C677D6 Super DK! Junior (1983) (Prototype) Coleco
sha1:FF8F73F9BF16BB67799BBE8E52C541D727F501F4 Superpong Demo (2000) (PD) Coleco
sha1:A79CBE906A6DF960F790C3139704F534B09A378B Tank Wars (1983) (Bit Corp) [!] Coleco
sha1:A79CBE906A6DF960F790C3139704F534B09A378B Tank Wars (1983) (Bit Corp) [!] Coleco NoSkip
sha1:459393F07792EE1B2C878E1257A21C6C351D5C29 B Tapper (1984) (Midway) [b1] Coleco
sha1:BBB25E64AEFA3ADAFF9F864713ECABE3B6F0316B Tapper (1984) (Midway) Coleco
sha1:2D61D96FD15C614BDE450813AA88092CF814E60A Tarzan (1984) (Coleco) Coleco

View File

@ -0,0 +1,31 @@
; NOTE: games not in this database will default to mapper 0
sha1:AAD9D2691F63A993B984143D8457FC4A86CFC472 Atlantis INTV board=7
sha1:280A14898F1AB2C26209D3B28AD67054504C0856 Beauty and the Beast (1982) (Imagic) [!] INTV board=7
sha1:A27144195AE123FA4FC9F9848B77B7B5208D5FFC Body Slam - Super Pro Wrestling (1988) (Intv Corp) INTV board=2
sha1:C50B818CB1E5041BAD1087A03BF8B6E021579BC5 Centipede (1983) (Atarisoft) INTV board=6
sha1:39BF9C38E1A9F0472A6254A4700FC0D2695E8A71 Championship Tennis (1985) (Mattel) INTV board=1
sha1:C7146409D4791F45C517475FC5068038E388EDA2 Chip Shot - Super Pro Golf (1987) (Intv Corp) INTV board=2
sha1:059A73EC21E71985A6724974F864AE8A82041AA8 Commando (1987) (Mattel) INTV board=2
sha1:E8E3DCB80ED8273D079DEF0793BEB1D6070C9A08 Congo Bongo (1983) (Sega) INTV board=5
sha1:D41F0B32703A15A8406901905224205451D7B59C Defender (1983) (Atarisoft) INTV board=5
sha1:E27310C6C26C07D9FF59E723AFFA8E48BEE7D820 Demon Attack (1982) (Imagic) [!] INTV board=7
sha1:997846CEE15A81E51255CBE378379216B01DE0F2 Dig Dug (1987) (Intv Corp) INTV board=5
sha1:C649D6A822062B3DD7151E27005979ACF1C6FDFD Diner (1987) (Intv Corp) INTV board=2
sha1:B883C75D3ABCB9638E8ED3D4E11CFCC1322462A8 Game Factory (Prototype) (1983) (Mattel) [!] INTV board=9
sha1:208147F393AF35ECE134D2CD056214E4A4DCCA5E Hover Force (1986) (Intv Corp) INTV board=2
sha1:9800325E3C8A82BBEE66FE0402C9F76A5D996AB0 King of the Mountain (1982) (Mattel) INTV board=1
sha1:8E28A7AD0DB9CB0E7D7DA008A16C0F8654810826 Land Battle (1982) (Mattel) INTV board=4
sha1:18AE3B7BC158B7FFCDFCFA84AF86D16B1545769C Learning Fun I - Math Master Factor Fun (1987) (Intv Corp) INTV board=2
sha1:A01DB79795CCB7F20B45D3C44791F52065600DEB Learning Fun II - Word Wizard Memory Fun (1987) (Intv Corp) INTV board=2
sha1:13BDECAF48094920F257C8A25686EEC91C0ADADC Microsurgeon (1982) (Imagic) [!] INTV board=7
sha1:21F6AABE3462594EA5E20EEED7AEF493BE427911 Ms PcaMan INTV board=10
sha1:350313B04570F0F30B8E6730C999B5DA8EE26ABE MTE201 Intellivision Test Cartridge (1978) (Mattel) INTV board=8
sha1:68AC0AE38753D0F3EDC69E004954B0575DF85DD6 Pac-Man (1983) (Atarisoft) INTV board=5
sha1:7E44A63186C66A80DF20DF26036F48E5A309256F Pac-Man (1983) (Intv Corp) INTV board=5
sha1:FB32AE847476A5BC7625100D85985E99A377CE39 Pole Position (1986) (Intv Corp) INTV board=2
sha1:30399A9B4AAA0B4E0D8C7987AEF56D0AB7AE4B09 Stadium Mud Buggies (1988) (Intv Corp) INTV board=2
sha1:004ABB06C3C5A4641EAE488DD78858C10C9F0A42 Super Pro Decathlon (1988) (Intv Corp) INTV board=2
sha1:6E1261F456070F3EBBE124B6DCEC2A31C5BCC0EE Super Pro Football (1986) (Intv Corp) INTV board=2
sha1:57B8BFAD43CD7F0CC0E30029870CA6BA0454AE38 Tower of Doom (1986) (Intv Corp) INTV board=3
sha1:307D7DF3EE36000D1BE8C1151EA6484245602C5D USCF Chess (1981) (Mattel) INTV board=4

View File

@ -349,8 +349,8 @@ EA608A53121D0C905DCFE6544248C275 Shaq Fu (UE) GG USA;Europe
A952A843A123092AAFBEB37B428EF6FF Shikinjou (J) GG Japan
8EAFD80D35251B5D3F07D5CAE27241C1 Shining Force Gaiden - Ensei, Jashin no Kuni e (J) GG Strategy;RPG SRAM=16384 Japan
35EF27F6B4B4DDC4A6AD6C78DB8C890B Shining Force Gaiden - Final Conflict (J) GG Strategy;RPG SRAM=32768 Japan
8857422E565412A59C77CB29550715E4 Shining Force Gaiden II - Jashin no Kakusei (J) GG Strategy;RPG SRAM=24576 Japan
0A0FA9CBCC3DB467191E907794C8C02B Shining Force II - The Sword of Hajya (U) GG Strategy;RPG SRAM=24576 USA
8857422E565412A59C77CB29550715E4 Shining Force Gaiden II - Jashin no Kakusei (J) GG Strategy;RPG SRAM=32768 Japan
0A0FA9CBCC3DB467191E907794C8C02B Shining Force II - The Sword of Hajya (U) GG Strategy;RPG SRAM=32768 USA
48D741774004EAB9C19C1DD43758BF2B Shinobi II - The Silent Fury (W) (Ja) GG World
8FA7438DEC1403F2E9D7B1CA60B29F1A Shinobi (UE) GG USA;Europe
21D2E4E7C508E6ABBB12BB96C7AAC868 Shinobi (J) GG Japan

View File

@ -340,8 +340,8 @@ namespace BizHawk.Client.ApiHawk
{
AutoFireStickyXorAdapter joypadAdaptor = Global.AutofireStickyXORAdapter;
IEnumerable<string> pressedButtons = from button in joypadAdaptor.Type.BoolButtons
where joypadAdaptor[button]
IEnumerable<string> pressedButtons = from button in joypadAdaptor.Definition.BoolButtons
where joypadAdaptor.IsPressed(button)
select button;
foreach (Joypad j in allJoypads)

View File

@ -83,7 +83,8 @@ namespace BizHawk.Client.ApiHawk
ToolStripMenuItem item = null;
try
{
{
BizHawk.Common.Win32Hacks.RemoveMOTW(fileName);
externalToolFile = Assembly.LoadFrom(fileName);
object[] attributes = externalToolFile.GetCustomAttributes(typeof(BizHawkExternalToolAttribute), false);
if (attributes != null && attributes.Count() == 1)

View File

@ -154,9 +154,14 @@
<Compile Include="Global.cs" />
<Compile Include="inputAdapters\AutoPattern.cs" />
<Compile Include="inputAdapters\BitwiseAdapters.cs" />
<Compile Include="inputAdapters\ClickyVirtualPadController.cs" />
<Compile Include="inputAdapters\CopyController.cs" />
<Compile Include="inputAdapters\InputAdapterExtensions.cs" />
<Compile Include="inputAdapters\InputAdapters.cs" />
<Compile Include="inputAdapters\StickyAdapters.cs" />
<Compile Include="inputAdapters\InputManager.cs" />
<Compile Include="inputAdapters\OverrideAdaptor.cs" />
<Compile Include="inputAdapters\SimpleController.cs" />
<Compile Include="inputAdapters\UDLRController.cs" />
<Compile Include="IonicZipWriter.cs" />
<Compile Include="IPS.cs" />
<Compile Include="IZipWriter.cs" />

View File

@ -9,14 +9,6 @@ namespace BizHawk.Client.Common
{
public class Controller : IController
{
private readonly WorkingDictionary<string, List<string>> _bindings = new WorkingDictionary<string, List<string>>();
private readonly WorkingDictionary<string, bool> _buttons = new WorkingDictionary<string, bool>();
private readonly WorkingDictionary<string, float> _floatButtons = new WorkingDictionary<string, float>();
private readonly Dictionary<string, ControllerDefinition.FloatRange> _floatRanges = new WorkingDictionary<string, ControllerDefinition.FloatRange>();
private readonly Dictionary<string, Config.AnalogBind> _floatBinds = new Dictionary<string, Config.AnalogBind>();
private ControllerDefinition _type;
public Controller(ControllerDefinition definition)
{
_type = definition;
@ -27,16 +19,37 @@ namespace BizHawk.Client.Common
}
}
public ControllerDefinition Type { get { return _type; } }
public ControllerDefinition Definition
{
get { return _type; }
}
/// <summary>don't do this</summary>
public void ForceType(ControllerDefinition newtype) { _type = newtype; }
public bool this[string button] { get { return IsPressed(button); } }
public bool IsPressed(string button)
{
return _buttons[button];
}
public float GetFloat(string name)
{
return _floatButtons[name];
}
private readonly WorkingDictionary<string, List<string>> _bindings = new WorkingDictionary<string, List<string>>();
private readonly WorkingDictionary<string, bool> _buttons = new WorkingDictionary<string, bool>();
private readonly WorkingDictionary<string, float> _floatButtons = new WorkingDictionary<string, float>();
private readonly Dictionary<string, ControllerDefinition.FloatRange> _floatRanges = new WorkingDictionary<string, ControllerDefinition.FloatRange>();
private readonly Dictionary<string, Config.AnalogBind> _floatBinds = new Dictionary<string, Config.AnalogBind>();
private ControllerDefinition _type;
/// <summary>don't do this</summary>
public void ForceType(ControllerDefinition newtype) { _type = newtype; }
public bool this[string button]
{
get { return IsPressed(button); }
}
public bool AnyPressed
{
get
@ -50,8 +63,6 @@ namespace BizHawk.Client.Common
}
}
public float GetFloat(string name) { return _floatButtons[name]; }
// Looks for bindings which are activated by the supplied physical button.
public List<string> SearchBindings(string button)
{
@ -132,7 +143,7 @@ namespace BizHawk.Client.Common
_buttons[kvp.Key] = false;
foreach (var bound_button in kvp.Value)
{
if (controller[bound_button])
if (controller.IsPressed(bound_button))
{
_buttons[kvp.Key] = true;
}
@ -165,9 +176,9 @@ namespace BizHawk.Client.Common
{
// change: or from each button that the other input controller has
// foreach (string button in type.BoolButtons)
if (controller.Type != null)
if (controller.Definition != null)
{
foreach (var button in controller.Type.BoolButtons)
foreach (var button in controller.Definition.BoolButtons)
{
if (controller.IsPressed(button))
{
@ -181,7 +192,7 @@ namespace BizHawk.Client.Common
{
foreach (var button in controller.Overrides)
{
_buttons[button] = controller[button];
_buttons[button] = controller.IsPressed(button);
}
foreach (var button in controller.FloatOverrides)
@ -259,8 +270,8 @@ namespace BizHawk.Client.Common
public int On { get; set; }
public int Off { get; set; }
public ControllerDefinition Type { get { return _type; } }
public bool this[string button] { get { return IsPressed(button); } }
public ControllerDefinition Definition { get { return _type; } }
public bool IsPressed(string button)
{
if (_autofire)
@ -295,7 +306,7 @@ namespace BizHawk.Client.Common
{
foreach (var bound_button in kvp.Value)
{
if (_buttons[kvp.Key] == false && controller[bound_button])
if (_buttons[kvp.Key] == false && controller.IsPressed(bound_button))
{
_buttonStarts[kvp.Key] = _emulator.Frame;
}
@ -308,7 +319,7 @@ namespace BizHawk.Client.Common
_buttons[kvp.Key] = false;
foreach (var bound_button in kvp.Value)
{
if (controller[bound_button])
if (controller.IsPressed(bound_button))
{
_buttons[kvp.Key] = true;
}

View File

@ -12,6 +12,7 @@ using BizHawk.Emulation.Cores.ColecoVision;
using BizHawk.Emulation.Cores.Computers.Commodore64;
using BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES;
using BizHawk.Emulation.Cores.Consoles.Sega.gpgx;
using GPGX64=BizHawk.Emulation.Cores.Consoles.Sega.gpgx64;
using BizHawk.Emulation.Cores.Intellivision;
using BizHawk.Emulation.Cores.Nintendo.Gameboy;
using BizHawk.Emulation.Cores.Nintendo.GBA;
@ -474,9 +475,16 @@ namespace BizHawk.Client.Common
switch (game.System)
{
case "GEN":
var genesis = new GPGX(
nextComm, null, disc, GetCoreSettings<GPGX>(), GetCoreSyncSettings<GPGX>());
nextEmulator = genesis;
if (Environment.Is64BitProcess)
{
var genesis = new GPGX64.GPGX(nextComm, null, disc, GetCoreSettings<GPGX64.GPGX>(), GetCoreSyncSettings<GPGX64.GPGX>());
nextEmulator = genesis;
}
else
{
var genesis = new GPGX(nextComm, null, disc, GetCoreSettings<GPGX>(), GetCoreSyncSettings<GPGX>());
nextEmulator = genesis;
}
break;
case "SAT":
nextEmulator = new Yabause(nextComm, disc, GetCoreSyncSettings<Yabause>());
@ -750,7 +758,7 @@ namespace BizHawk.Client.Common
if(Global.Config.NES_InQuickNES) preference = "quicknes";
//if user has saw fit to override in gamedb, apply that
if(Global.Config.CoreForcingViaGameDB)
if (Global.Config.CoreForcingViaGameDB && !string.IsNullOrEmpty(game.ForcedCore))
preference = game.ForcedCore;
//but only neshawk is accurate
@ -816,8 +824,11 @@ namespace BizHawk.Client.Common
nextEmulator.CoreComm.RomStatusDetails = "PSX etc.";
break;
case "GEN":
// discard "Genplus-gx64", auto-added due to implementing IEmulator
core = CoreInventory.Instance["GEN", "Genplus-gx"];
// discard "Genplus-gx64", auto-added due to implementing IEmulator // HUH?
//core = CoreInventory.Instance["GEN", "Genplus-gx"];
if (Environment.Is64BitProcess)
core = CoreInventory.Instance["GEN", "Genplus-gx64"];
else core = CoreInventory.Instance["GEN", "Genplus-gx"];
break;
}

View File

@ -34,9 +34,9 @@ namespace BizHawk.Client.Common
bs.PutLump(BinaryStateLump.Corestate, bw => core.SaveStateBinary(bw));
}
if (Global.Config.SaveScreenshotWithStates)
if (Global.Config.SaveScreenshotWithStates && Global.Emulator.HasVideoProvider())
{
var vp = Global.Emulator.VideoProvider();
var vp = Global.Emulator.AsVideoProvider();
var buff = vp.GetVideoBuffer();
if (buff.Length == 1)
{
@ -58,7 +58,7 @@ namespace BizHawk.Client.Common
out_h /= 2;
}
using (new SimpleTime("Save Framebuffer"))
bs.PutLump(BinaryStateLump.Framebuffer, (s) => QuickBmpFile.Save(Global.Emulator.VideoProvider(), s, out_w, out_h));
bs.PutLump(BinaryStateLump.Framebuffer, (s) => QuickBmpFile.Save(Global.Emulator.AsVideoProvider(), s, out_w, out_h));
}
}
@ -96,14 +96,19 @@ namespace BizHawk.Client.Common
public static void PopulateFramebuffer(BinaryReader br)
{
if (!Global.Emulator.HasVideoProvider())
{
return;
}
try
{
using (new SimpleTime("Load Framebuffer"))
QuickBmpFile.Load(Global.Emulator.VideoProvider(), br.BaseStream);
QuickBmpFile.Load(Global.Emulator.AsVideoProvider(), br.BaseStream);
}
catch
{
var buff = Global.Emulator.VideoProvider().GetVideoBuffer();
var buff = Global.Emulator.AsVideoProvider().GetVideoBuffer();
try
{
for (int i = 0; i < buff.Length; i++)
@ -219,9 +224,9 @@ namespace BizHawk.Client.Common
}
var args = str.Split(' ');
if (args[0] == "Framebuffer")
if (args[0] == "Framebuffer" && Global.Emulator.HasVideoProvider())
{
Global.Emulator.VideoProvider().GetVideoBuffer().ReadFromHex(args[1]);
Global.Emulator.AsVideoProvider().GetVideoBuffer().ReadFromHex(args[1]);
}
}
}

View File

@ -152,6 +152,7 @@ namespace BizHawk.Client.Common
Bind("General", "Exit Program"),
Bind("General", "Screen Raw to Clipboard", "Ctrl+C"),
Bind("General", "Screen Client to Clipboard", "Ctrl+Shift+C"),
Bind("General", "Toggle Skip Lag Frame"),
Bind("Save States", "Save State 0", "Shift+F10"),
Bind("Save States", "Save State 1", "Shift+F1"),
@ -229,6 +230,12 @@ namespace BizHawk.Client.Common
Bind("TAStudio", "Insert Frame", "Insert"),
Bind("TAStudio", "Delete Frames", "Ctrl+Delete"),
Bind("TAStudio", "Clone Frames", "Ctrl+Insert"),
Bind("TAStudio", "Analog Increment", "UpArrow"),
Bind("TAStudio", "Analog Decrement", "DownArrow"),
Bind("TAStudio", "Analog Incr. by 10", "Shift+UpArrow"),
Bind("TAStudio", "Analog Decr. by 10", "Shift+DownArrow"),
Bind("TAStudio", "Analog Maximum", "RightArrow"),
Bind("TAStudio", "Analog Minimum", "LeftArrow"),
Bind("SNES", "Toggle BG 1"),
Bind("SNES", "Toggle BG 2"),

View File

@ -83,7 +83,7 @@ namespace BizHawk.Client.Common
public int TargetScanlineFilterIntensity = 128; // choose between 0 and 256
public int TargetDisplayFilter = 0;
public int DispFinalFilter = 1; //bilinear
public int DispFinalFilter = 0; //None
public string DispUserFilterPath = "";
public RecentFiles RecentRoms = new RecentFiles(10);
public RecentFiles RecentRomSessions = new RecentFiles(8); // Only used for MultiHawk

View File

@ -1,6 +1,8 @@
using System.Drawing;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using Newtonsoft.Json;
namespace BizHawk.Client.Common
@ -56,6 +58,25 @@ namespace BizHawk.Client.Common
}
}
/// <summary>
/// Represents the top left corner coordinate, if Wndx and Wndy form a valid point
/// Throws an InvalidOperationException if Wndx or Wndy is null
/// It is expected to check for this before using this property
/// </summary>
[JsonIgnore]
public Point TopLeft
{
get
{
if (_wndx.HasValue && _wndy.HasValue)
{
return new Point(_wndx.Value, _wndy.Value);
}
throw new InvalidOperationException("TopLeft can not be used when one of the coordinates is null");
}
}
public int? Width { get; set; }
public int? Height { get; set; }

View File

@ -1,9 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BizHawk.Client.Common
namespace BizHawk.Client.Common
{
public class AutoPatternBool
{

View File

@ -1,74 +1,56 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BizHawk.Common;
using BizHawk.Emulation.Common;
using BizHawk.Emulation.Common;
namespace BizHawk.Client.Common
{
public class AndAdapter : IController
{
public ControllerDefinition Definition
{
get { return Source.Definition; }
}
public bool IsPressed(string button)
{
return this[button];
if (Source != null && SourceAnd != null)
{
return Source.IsPressed(button) & SourceAnd.IsPressed(button);
}
return false;
}
// pass floats solely from the original source
// this works in the code because SourceOr is the autofire controller
public float GetFloat(string name) { return Source.GetFloat(name); }
public IController Source { get; set; }
public IController SourceAnd { get; set; }
public ControllerDefinition Type { get { return Source.Type; } set { throw new InvalidOperationException(); } }
public bool this[string button]
public float GetFloat(string name)
{
get
{
if (Source != null && SourceAnd != null)
{
return Source[button] & SourceAnd[button];
}
return false;
}
set
{
throw new InvalidOperationException();
}
return Source.GetFloat(name);
}
internal IController Source { get; set; }
internal IController SourceAnd { get; set; }
}
public class ORAdapter : IController
{
public ControllerDefinition Definition
{
get { return Source.Definition; }
}
public bool IsPressed(string button)
{
return this[button];
return (Source != null ? Source.IsPressed(button) : false)
| (SourceOr != null ? SourceOr.IsPressed(button) : false);
}
// pass floats solely from the original source
// this works in the code because SourceOr is the autofire controller
public float GetFloat(string name) { return Source.GetFloat(name); }
public IController Source { get; set; }
public IController SourceOr { get; set; }
public ControllerDefinition Type { get { return Source.Type; } set { throw new InvalidOperationException(); } }
public bool this[string button]
public float GetFloat(string name)
{
get
{
return (Source != null ? Source[button] : false) |
(SourceOr != null ? SourceOr[button] : false);
}
set
{
throw new InvalidOperationException();
}
return Source.GetFloat(name);
}
internal IController Source { get; set; }
internal IController SourceOr { get; set; }
}
}

View File

@ -0,0 +1,73 @@
using System.Collections.Generic;
using BizHawk.Emulation.Common;
namespace BizHawk.Client.Common
{
/// <summary>
/// Will hold buttons for 1 frame and then release them.
/// (Calling Click() from your button click is what you want to do)
/// TODO - should the duration be controllable?
/// </summary>
public class ClickyVirtualPadController : IController
{
public ControllerDefinition Definition { get; set; }
public bool IsPressed(string button)
{
return _pressed.Contains(button);
}
public float GetFloat(string name)
{
return 0.0f;
}
/// <summary>
/// Call this once per frame to do the timekeeping for the hold and release
/// </summary>
public void FrameTick()
{
_pressed.Clear();
}
/// <summary>
/// Call this to hold the button down for one frame
/// </summary>
public void Click(string button)
{
_pressed.Add(button);
}
public void Unclick(string button)
{
_pressed.Remove(button);
}
public void Toggle(string button)
{
if (IsPressed(button))
{
_pressed.Remove(button);
}
else
{
_pressed.Add(button);
}
}
public void SetBool(string button, bool value)
{
if (value)
{
_pressed.Remove(button);
}
else
{
_pressed.Add(button);
}
}
private readonly HashSet<string> _pressed = new HashSet<string>();
}
}

View File

@ -0,0 +1,37 @@
using BizHawk.Emulation.Common;
namespace BizHawk.Client.Common
{
/// <summary>
/// Just copies source to sink, or returns whatever a NullController would if it is disconnected. useful for immovable hardpoints.
/// </summary>
public class CopyControllerAdapter : IController
{
public ControllerDefinition Definition
{
get { return Curr.Definition; }
}
public bool IsPressed(string button)
{
return Curr.IsPressed(button);
}
public float GetFloat(string name)
{
return Curr.GetFloat(name);
}
public IController Source { get; set; }
private IController Curr
{
get
{
return Source == null
? NullController.Instance
: Source;
}
}
}
}

View File

@ -1,10 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BizHawk.Emulation.Common;
using BizHawk.Client.Common;
using BizHawk.Emulation.Common;
namespace BizHawk.Client.Common.InputAdapterExtensions
{

View File

@ -1,889 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using BizHawk.Common;
using BizHawk.Common.StringExtensions;
using BizHawk.Emulation.Common;
using BizHawk.Emulation.Common.IEmulatorExtensions;
namespace BizHawk.Client.Common
{
/// <summary>
/// will hold buttons for 1 frame and then release them. (Calling Click() from your button click is what you want to do)
/// TODO - should the duration be controllable?
/// </summary>
public class ClickyVirtualPadController : IController
{
public ControllerDefinition Type { get; set; }
public bool this[string button]
{
get { return IsPressed(button); }
}
public float GetFloat(string name)
{
return 0.0f;
}
// TODO
public bool IsPressed(string button)
{
return _pressed.Contains(button);
}
/// <summary>
/// call this once per frame to do the timekeeping for the hold and release
/// </summary>
public void FrameTick()
{
_pressed.Clear();
}
/// <summary>
/// call this to hold the button down for one frame
/// </summary>
public void Click(string button)
{
_pressed.Add(button);
}
public void Unclick(string button)
{
_pressed.Remove(button);
}
public void Toggle(string button)
{
if (IsPressed(button))
{
_pressed.Remove(button);
}
else
{
_pressed.Add(button);
}
}
public void SetBool(string button, bool value)
{
if (value)
{
_pressed.Remove(button);
}
else
{
_pressed.Add(button);
}
}
private readonly HashSet<string> _pressed = new HashSet<string>();
}
/// <summary>
/// Filters input for things called Up and Down while considering the client's AllowUD_LR option.
/// This is a bit gross but it is unclear how to do it more nicely
/// </summary>
public class UD_LR_ControllerAdapter : IController
{
public ControllerDefinition Type
{
get { return Source.Type; }
}
public bool this[string button]
{
get { return IsPressed(button); }
}
public IController Source { get; set; }
// The float format implies no U+D and no L+R no matter what, so just passthru
public float GetFloat(string name)
{
return Source.GetFloat(name);
}
HashSet<string> Unpresses = new HashSet<string>();
public bool IsPressed(string button)
{
bool PriorityUD_LR = !Global.Config.AllowUD_LR && !Global.Config.ForbidUD_LR; //implied by neither of the others being set (left as non-enum for back-compatibility)
if (Global.Config.AllowUD_LR)
{
return Source.IsPressed(button);
}
string prefix;
//" C " is for N64 "P1 C Up" and the like, which should not be subject to mutexing
//regarding the unpressing and UDLR logic...... don't think about it. don't question it. don't look at it.
if (button.Contains("Down") && !button.Contains(" C "))
{
if (!Source.IsPressed(button)) Unpresses.Remove(button);
prefix = button.GetPrecedingString("Down");
string other = prefix + "Up";
if (Source.IsPressed(other))
{
if (Unpresses.Contains(button)) return false;
if (Global.Config.ForbidUD_LR) return false;
Unpresses.Add(other);
}
else Unpresses.Remove(button);
}
if (button.Contains("Up") && !button.Contains(" C "))
{
if (!Source.IsPressed(button)) Unpresses.Remove(button);
prefix = button.GetPrecedingString("Up");
string other = prefix + "Down";
if (Source.IsPressed(other))
{
if (Unpresses.Contains(button)) return false;
if (Global.Config.ForbidUD_LR) return false;
Unpresses.Add(other);
}
else Unpresses.Remove(button);
}
if (button.Contains("Right") && !button.Contains(" C "))
{
if (!Source.IsPressed(button)) Unpresses.Remove(button);
prefix = button.GetPrecedingString("Right");
string other = prefix + "Left";
if (Source.IsPressed(other))
{
if (Unpresses.Contains(button)) return false;
if (Global.Config.ForbidUD_LR) return false;
Unpresses.Add(other);
}
else Unpresses.Remove(button);
}
if (button.Contains("Left") && !button.Contains(" C "))
{
if (!Source.IsPressed(button)) Unpresses.Remove(button);
prefix = button.GetPrecedingString("Left");
string other = prefix + "Right";
if (Source.IsPressed(other))
{
if (Unpresses.Contains(button)) return false;
if (Global.Config.ForbidUD_LR) return false;
Unpresses.Add(other);
}
else Unpresses.Remove(button);
}
return Source.IsPressed(button);
}
}
public class SimpleController : IController
{
public ControllerDefinition Type { get; set; }
protected WorkingDictionary<string, bool> Buttons = new WorkingDictionary<string, bool>();
protected WorkingDictionary<string, float> Floats = new WorkingDictionary<string, float>();
public virtual void Clear()
{
Buttons = new WorkingDictionary<string, bool>();
Floats = new WorkingDictionary<string, float>();
}
public virtual bool this[string button]
{
get { return Buttons[button]; }
set { Buttons[button] = value; }
}
public virtual bool IsPressed(string button)
{
return this[button];
}
public float GetFloat(string name)
{
return Floats[name];
}
public IEnumerable<KeyValuePair<string, bool>> BoolButtons()
{
return Buttons;
}
public virtual void LatchFrom(IController source)
{
foreach (var button in source.Type.BoolButtons)
{
Buttons[button] = source[button];
}
}
public void AcceptNewFloats(IEnumerable<Tuple<string, float>> newValues)
{
foreach (var sv in newValues)
{
Floats[sv.Item1] = sv.Item2;
}
}
}
// Used by input display, to determine if either autofire or regular stickies are "in effect" because we color this scenario differently
public class StickyOrAdapter : IController
{
public bool IsPressed(string button)
{
return this[button];
}
// pass floats solely from the original source
// this works in the code because SourceOr is the autofire controller
public float GetFloat(string name) { return 0.0F; } // Floats don't make sense in sticky land
public ISticky Source { get; set; }
public ISticky SourceStickyOr { get; set; }
public ControllerDefinition Type { get { return Source.Type; } set { throw new InvalidOperationException(); } }
public bool this[string button]
{
get
{
return Source.StickyIsInEffect(button) ||
SourceStickyOr.StickyIsInEffect(button);
}
set
{
throw new InvalidOperationException();
}
}
}
public interface ISticky : IController
{
bool StickyIsInEffect(string button);
}
public class StickyXorAdapter : IController, ISticky
{
protected HashSet<string> stickySet = new HashSet<string>();
public IController Source { get; set; }
public ControllerDefinition Type
{
get { return Source.Type; }
set { throw new InvalidOperationException(); }
}
public bool Locked { get; set; } // Pretty much a hack,
public bool IsPressed(string button)
{
return this[button];
}
// if SetFloat() is called (typically virtual pads), then that float will entirely override the Source input
// otherwise, the source is passed thru.
protected readonly WorkingDictionary<string, float?> _floatSet = new WorkingDictionary<string, float?>();
public void SetFloat(string name, float? value)
{
if (value.HasValue)
{
_floatSet[name] = value;
}
else
{
_floatSet.Remove(name);
}
}
public float GetFloat(string name)
{
var val = _floatSet[name];
if (val.HasValue)
{
return val.Value;
}
if (Source == null)
{
return 0;
}
return Source.GetFloat(name);
}
public void ClearStickyFloats()
{
_floatSet.Clear();
}
public bool this[string button]
{
get
{
var source = Source[button];
source ^= stickySet.Contains(button);
return source;
}
set
{
throw new InvalidOperationException();
}
}
/// <summary>
/// Determines if a sticky is current mashing the button itself,
/// If sticky is not set then false, if set, it returns true if the Source is not pressed, else false
/// </summary>
public bool StickyIsInEffect(string button)
{
if (IsSticky(button))
{
return !Source.IsPressed(button);
}
return false;
}
public void SetSticky(string button, bool isSticky)
{
if (isSticky)
{
stickySet.Add(button);
}
else
{
stickySet.Remove(button);
}
}
public void Unset(string button)
{
stickySet.Remove(button);
_floatSet.Remove(button);
}
public bool IsSticky(string button)
{
return stickySet.Contains(button);
}
public HashSet<string> CurrentStickies
{
get
{
return stickySet;
}
}
public void ClearStickies()
{
stickySet.Clear();
_floatSet.Clear();
}
public void MassToggleStickyState(List<string> buttons)
{
foreach (var button in buttons.Where(button => !_justPressed.Contains(button)))
{
if (stickySet.Contains(button))
{
stickySet.Remove(button);
}
else
{
stickySet.Add(button);
}
}
_justPressed = buttons;
}
private List<string> _justPressed = new List<string>();
}
///// SuuperW: I'm leaving the old class in case I accidentally screwed something up
//public class AutoFireStickyXorAdapter : IController, ISticky
//{
// public int On { get; set; }
// public int Off { get; set; }
// public WorkingDictionary<string, int> buttonStarts = new WorkingDictionary<string, int>();
// public WorkingDictionary<string, int> lagStarts = new WorkingDictionary<string, int>(); // TODO: need a data structure not misc dictionaries
// private readonly HashSet<string> _stickySet = new HashSet<string>();
// public IController Source { get; set; }
// public void SetOnOffPatternFromConfig()
// {
// On = Global.Config.AutofireOn < 1 ? 0 : Global.Config.AutofireOn;
// Off = Global.Config.AutofireOff < 1 ? 0 : Global.Config.AutofireOff;
// }
// public AutoFireStickyXorAdapter()
// {
// //On = Global.Config.AutofireOn < 1 ? 0 : Global.Config.AutofireOn;
// //Off = Global.Config.AutofireOff < 1 ? 0 : Global.Config.AutofireOff;
// On = 1;
// Off = 1;
// }
// public bool IsPressed(string button)
// {
// return this[button];
// }
// public bool this[string button]
// {
// get
// {
// var source = Source[button];
// if (_stickySet.Contains(button))
// {
// var lagcount = 0;
// if (Global.Emulator.CanPollInput() && Global.Config.AutofireLagFrames)
// {
// lagcount = Global.Emulator.AsInputPollable().LagCount;
// }
// var a = ((Global.Emulator.Frame - lagcount) - (buttonStarts[button] - lagStarts[button])) % (On + Off);
// if (a < On)
// {
// return source ^= true;
// }
// else
// {
// return source ^= false;
// }
// }
// return source;
// }
// set
// {
// throw new InvalidOperationException();
// }
// }
// public ControllerDefinition Type { get { return Source.Type; } set { throw new InvalidOperationException(); } }
// public bool Locked { get; set; } // Pretty much a hack,
// // dumb passthrough for floats, because autofire doesn't care about them
// public float GetFloat(string name)
// {
// return Source.GetFloat(name);
// }
// public void SetSticky(string button, bool isSticky)
// {
// if (isSticky)
// {
// _stickySet.Add(button);
// buttonStarts.Add(button, Global.Emulator.Frame);
// if (Global.Emulator.CanPollInput())
// {
// lagStarts.Add(button, Global.Emulator.AsInputPollable().LagCount);
// }
// else
// {
// lagStarts.Add(button, 0);
// }
// }
// else
// {
// _stickySet.Remove(button);
// buttonStarts.Remove(button);
// lagStarts.Remove(button);
// }
// }
// public bool IsSticky(string button)
// {
// return this._stickySet.Contains(button);
// }
// public HashSet<string> CurrentStickies
// {
// get
// {
// return this._stickySet;
// }
// }
// public void ClearStickies()
// {
// _stickySet.Clear();
// buttonStarts.Clear();
// lagStarts.Clear();
// }
// public void MassToggleStickyState(List<string> buttons)
// {
// foreach (var button in buttons.Where(button => !_justPressed.Contains(button)))
// {
// if (_stickySet.Contains(button))
// {
// _stickySet.Remove(button);
// }
// else
// {
// _stickySet.Add(button);
// }
// }
// _justPressed = buttons;
// }
// /// <summary>
// /// Determines if a sticky is current mashing the button itself,
// /// If sticky is not set then false, if set, it returns true if the Source is not pressed, else false
// /// </summary>
// public bool StickyIsInEffect(string button)
// {
// if (Source.IsPressed(button))
// {
// return false;
// }
// return (IsPressed(button)); // Shortcut logic since we know the Source isn't pressed, Ispressed can only return true if the autofire sticky is in effect for this frame
// }
// private List<string> _justPressed = new List<string>();
//}
// commenting this out, it breaks the autofire hotkey
public class AutoFireStickyXorAdapter : IController, ISticky
{
// TODO: Change the AutoHold adapter to be one of these, with an 'Off' value of 0?
// Probably would have slightly lower performance, but it seems weird to have such a similar class that is only used once.
private int On;
private int Off;
public void SetOnOffPatternFromConfig()
{
On = Global.Config.AutofireOn < 1 ? 0 : Global.Config.AutofireOn;
Off = Global.Config.AutofireOff < 1 ? 0 : Global.Config.AutofireOff;
}
private WorkingDictionary<string, AutoPatternBool> _boolPatterns = new WorkingDictionary<string, AutoPatternBool>();
private WorkingDictionary<string, AutoPatternFloat> _floatPatterns = new WorkingDictionary<string, AutoPatternFloat>();
public AutoFireStickyXorAdapter()
{
On = 1; Off = 1;
}
public IController Source { get; set; }
public ControllerDefinition Type
{
get { return Source.Type; }
}
public bool Locked { get; set; } // Pretty much a hack,
public bool IsPressed(string button)
{
return this[button];
}
public void SetFloat(string name, float? value, AutoPatternFloat pattern = null)
{
if (value.HasValue)
{
if (pattern == null)
pattern = new AutoPatternFloat(value.Value, On, 0, Off);
_floatPatterns[name] = pattern;
}
else
{
_floatPatterns.Remove(name);
}
}
public float GetFloat(string name)
{
if (_floatPatterns.ContainsKey(name))
return _floatPatterns[name].PeekNextValue();
if (Source == null)
return 0;
return Source.GetFloat(name);
}
public void ClearStickyFloats()
{
_floatPatterns.Clear();
}
public bool this[string button]
{
get
{
var source = Source[button];
bool patternValue = false;
if (_boolPatterns.ContainsKey(button))
{ // I can't figure a way to determine right here if it should Peek or Get.
patternValue = _boolPatterns[button].PeekNextValue();
}
source ^= patternValue;
return source;
}
}
/// <summary>
/// Determines if a sticky is current mashing the button itself,
/// If sticky is not set then false, if set, it returns true if the Source is not pressed, else false
/// </summary>
public bool StickyIsInEffect(string button)
{
if (IsSticky(button))
{
return !Source.IsPressed(button);
}
return false;
}
public void SetSticky(string button, bool isSticky, AutoPatternBool pattern = null)
{
if (isSticky)
{
if (pattern == null)
pattern = new AutoPatternBool(On, Off);
_boolPatterns[button] = pattern;
}
else
{
_boolPatterns.Remove(button);
}
}
public void Unset(string button)
{
_boolPatterns.Remove(button);
_floatPatterns.Remove(button);
}
public bool IsSticky(string button)
{
return _boolPatterns.ContainsKey(button) || _floatPatterns.ContainsKey(button);
}
public HashSet<string> CurrentStickies
{
get
{
return new HashSet<string>(_boolPatterns.Keys);
}
}
public void ClearStickies()
{
_boolPatterns.Clear();
_floatPatterns.Clear();
}
public void IncrementLoops(bool lagged)
{
for (int i = 0; i < _boolPatterns.Count; i++)
_boolPatterns.ElementAt(i).Value.GetNextValue(lagged);
for (int i = 0; i < _floatPatterns.Count; i++)
_floatPatterns.ElementAt(i).Value.GetNextValue(lagged);
}
private List<string> _justPressed = new List<string>();
public void MassToggleStickyState(List<string> buttons)
{
foreach (var button in buttons.Where(button => !_justPressed.Contains(button)))
{
if (_boolPatterns.ContainsKey(button))
SetSticky(button, false);
else
SetSticky(button, true);
}
_justPressed = buttons;
}
}
/// <summary>
/// Just copies source to sink, or returns whatever a NullController would if it is disconnected. useful for immovable hardpoints.
/// </summary>
public class CopyControllerAdapter : IController
{
public IController Source { get; set; }
private readonly NullController _null = new NullController();
private IController Curr
{
get
{
if (Source == null)
{
return _null;
}
else
{
return Source;
}
}
}
public ControllerDefinition Type
{
get { return Curr.Type; }
}
public bool this[string button]
{
get { return Curr[button]; }
}
public bool IsPressed(string button)
{
return Curr.IsPressed(button);
}
public float GetFloat(string name)
{
return Curr.GetFloat(name);
}
}
/// <summary>
/// Used to pass into an Override method to manage the logic overriding input
/// This only works with bool buttons!
/// </summary>
public class OverrideAdaptor : IController
{
private readonly Dictionary<string, bool> _overrides = new Dictionary<string, bool>();
private readonly Dictionary<string, float> _floatOverrides = new Dictionary<string, float>();
private readonly List<string> _inverses = new List<string>();
public bool this[string button]
{
get
{
if (_overrides.ContainsKey(button))
{
return _overrides[button];
}
throw new InvalidOperationException();
}
set
{
if (_overrides.ContainsKey(button))
{
_overrides[button] = value;
}
else
{
_overrides.Add(button, value);
}
}
}
public ControllerDefinition Type { get; set; }
public IEnumerable<string> Overrides
{
get
{
foreach (var kvp in _overrides)
{
yield return kvp.Key;
}
}
}
public IEnumerable<string> FloatOverrides
{
get
{
foreach (var kvp in _floatOverrides)
{
yield return kvp.Key;
}
}
}
public IEnumerable<string> InversedButtons
{
get
{
foreach (var name in _inverses)
{
yield return name;
}
}
}
public void SetFloat(string name, float value)
{
if (_floatOverrides.ContainsKey(name))
{
_floatOverrides[name] = value;
}
else
{
_floatOverrides.Add(name, value);
}
}
public float GetFloat(string name)
{
if (_floatOverrides.ContainsKey(name))
{
return _floatOverrides[name];
}
return 0.0F;
}
public bool IsPressed(string button) { return this[button]; }
public void SetButton(string button, bool value)
{
this[button] = value;
_inverses.Remove(button);
}
public void UnSet(string button)
{
_overrides.Remove(button);
_inverses.Remove(button);
}
public void SetInverse(string button)
{
_inverses.Add(button);
}
public void FrameTick()
{
_overrides.Clear();
_floatOverrides.Clear();
_inverses.Clear();
}
}
}

View File

@ -9,7 +9,7 @@ namespace BizHawk.Client.Common
public static void RewireInputChain()
{
Global.ControllerInputCoalescer.Clear();
Global.ControllerInputCoalescer.Type = Global.ActiveController.Type;
Global.ControllerInputCoalescer.Definition = Global.ActiveController.Definition;
Global.UD_LR_ControllerAdapter.Source = Global.ActiveController.Or(Global.AutoFireController);
@ -21,7 +21,7 @@ namespace BizHawk.Client.Common
Global.ControllerOutput.Source = Global.MovieOutputHardpoint;
Global.Emulator.Controller = Global.ControllerOutput;
Global.MovieSession.MovieControllerAdapter.Type = Global.MovieInputSourceAdapter.Type;
Global.MovieSession.MovieControllerAdapter.Definition = Global.MovieInputSourceAdapter.Definition;
// connect the movie session before MovieOutputHardpoint if it is doing anything
// otherwise connect the MovieInputSourceAdapter to it, effectively bypassing the movie session
@ -45,7 +45,7 @@ namespace BizHawk.Client.Common
// allow propogating controls that are in the current controller definition but not in the prebaked one
// these two lines shouldn't be required anymore under the new system?
Global.ActiveController.ForceType(new ControllerDefinition(def));
Global.ClickyVirtualPadController.Type = new ControllerDefinition(def);
Global.ClickyVirtualPadController.Definition = new ControllerDefinition(def);
RewireInputChain();
}

View File

@ -0,0 +1,117 @@
using System;
using System.Collections.Generic;
using BizHawk.Emulation.Common;
namespace BizHawk.Client.Common
{
/// <summary>
/// Used to pass into an Override method to manage the logic overriding input
/// This only works with bool buttons!
/// </summary>
public class OverrideAdaptor : IController
{
public ControllerDefinition Definition { get; private set; }
private readonly Dictionary<string, bool> _overrides = new Dictionary<string, bool>();
private readonly Dictionary<string, float> _floatOverrides = new Dictionary<string, float>();
private readonly List<string> _inverses = new List<string>();
public bool IsPressed(string button)
{
if (_overrides.ContainsKey(button))
{
return _overrides[button];
}
throw new InvalidOperationException();
}
public float GetFloat(string name)
{
if (_floatOverrides.ContainsKey(name))
{
return _floatOverrides[name];
}
return 0.0F;
}
public IEnumerable<string> Overrides
{
get
{
foreach (var kvp in _overrides)
{
yield return kvp.Key;
}
}
}
public IEnumerable<string> FloatOverrides
{
get
{
foreach (var kvp in _floatOverrides)
{
yield return kvp.Key;
}
}
}
public IEnumerable<string> InversedButtons
{
get
{
foreach (var name in _inverses)
{
yield return name;
}
}
}
public void SetFloat(string name, float value)
{
if (_floatOverrides.ContainsKey(name))
{
_floatOverrides[name] = value;
}
else
{
_floatOverrides.Add(name, value);
}
}
public void SetButton(string button, bool value)
{
if (_overrides.ContainsKey(button))
{
_overrides[button] = value;
}
else
{
_overrides.Add(button, value);
}
_inverses.Remove(button);
}
public void UnSet(string button)
{
_overrides.Remove(button);
_inverses.Remove(button);
}
public void SetInverse(string button)
{
_inverses.Add(button);
}
public void FrameTick()
{
_overrides.Clear();
_floatOverrides.Clear();
_inverses.Clear();
}
}
}

View File

@ -0,0 +1,62 @@
using System;
using System.Collections.Generic;
using BizHawk.Common;
using BizHawk.Emulation.Common;
namespace BizHawk.Client.Common
{
/// <summary>
/// A basic implementation of IController
/// </summary>
public class SimpleController : IController
{
public ControllerDefinition Definition { get; set; }
protected WorkingDictionary<string, bool> Buttons = new WorkingDictionary<string, bool>();
protected WorkingDictionary<string, float> Floats = new WorkingDictionary<string, float>();
public virtual void Clear()
{
Buttons = new WorkingDictionary<string, bool>();
Floats = new WorkingDictionary<string, float>();
}
public virtual bool this[string button]
{
get { return Buttons[button]; }
set { Buttons[button] = value; }
}
public virtual bool IsPressed(string button)
{
return this[button];
}
public float GetFloat(string name)
{
return Floats[name];
}
public IEnumerable<KeyValuePair<string, bool>> BoolButtons()
{
return Buttons;
}
public virtual void LatchFrom(IController source)
{
foreach (var button in source.Definition.BoolButtons)
{
Buttons[button] = source.IsPressed(button);
}
}
public void AcceptNewFloats(IEnumerable<Tuple<string, float>> newValues)
{
foreach (var sv in newValues)
{
Floats[sv.Item1] = sv.Item2;
}
}
}
}

View File

@ -0,0 +1,325 @@
using System.Collections.Generic;
using System.Linq;
using BizHawk.Common;
using BizHawk.Emulation.Common;
namespace BizHawk.Client.Common
{
public interface ISticky : IController
{
bool StickyIsInEffect(string button);
}
/// <summary>
/// Used by input display, to determine if either autofire or regular stickies
/// are "in effect" because we color this scenario differently
/// </summary>
public class StickyOrAdapter : IController
{
public ControllerDefinition Definition
{
get { return Source.Definition; }
}
public bool IsPressed(string button)
{
return Source.StickyIsInEffect(button)
|| SourceStickyOr.StickyIsInEffect(button);
}
// pass floats solely from the original source
// this works in the code because SourceOr is the autofire controller
public float GetFloat(string name)
{
int i = Source.Definition.FloatControls.IndexOf(name);
return Source.Definition.FloatRanges[i].Mid; // Floats don't make sense in sticky land
}
public ISticky Source { get; set; }
public ISticky SourceStickyOr { get; set; }
}
public class StickyXorAdapter : ISticky, IController
{
/// <summary>
/// Determines if a sticky is current mashing the button itself,
/// If sticky is not set then false, if set, it returns true if the Source is not pressed, else false
/// </summary>
public bool StickyIsInEffect(string button)
{
if (IsSticky(button))
{
return !Source.IsPressed(button);
}
return false;
}
public ControllerDefinition Definition
{
get { return Source.Definition; }
}
public bool IsPressed(string button)
{
var source = Source.IsPressed(button);
source ^= stickySet.Contains(button);
return source;
}
public float GetFloat(string name)
{
var val = _floatSet[name];
if (val.HasValue)
{
return val.Value;
}
if (Source == null)
{
return 0;
}
return Source.GetFloat(name);
}
public IController Source { get; set; }
public bool Locked { get; set; } // Pretty much a hack,
private List<string> _justPressed = new List<string>();
protected readonly HashSet<string> stickySet = new HashSet<string>();
// if SetFloat() is called (typically virtual pads), then that float will entirely override the Source input
// otherwise, the source is passed thru.
protected readonly WorkingDictionary<string, float?> _floatSet = new WorkingDictionary<string, float?>();
public void SetFloat(string name, float? value)
{
if (value.HasValue)
{
_floatSet[name] = value;
}
else
{
_floatSet.Remove(name);
}
}
public void ClearStickyFloats()
{
_floatSet.Clear();
}
public void SetSticky(string button, bool isSticky)
{
if (isSticky)
{
stickySet.Add(button);
}
else
{
stickySet.Remove(button);
}
}
public void Unset(string button)
{
stickySet.Remove(button);
_floatSet.Remove(button);
}
public bool IsSticky(string button)
{
return stickySet.Contains(button);
}
public HashSet<string> CurrentStickies
{
get
{
return stickySet;
}
}
public void ClearStickies()
{
stickySet.Clear();
_floatSet.Clear();
}
public void MassToggleStickyState(List<string> buttons)
{
foreach (var button in buttons.Where(button => !_justPressed.Contains(button)))
{
if (stickySet.Contains(button))
{
stickySet.Remove(button);
}
else
{
stickySet.Add(button);
}
}
_justPressed = buttons;
}
}
public class AutoFireStickyXorAdapter : ISticky, IController
{
/// <summary>
/// Determines if a sticky is current mashing the button itself,
/// If sticky is not set then false, if set, it returns true if the Source is not pressed, else false
/// </summary>
public bool StickyIsInEffect(string button)
{
if (IsSticky(button))
{
return !Source.IsPressed(button);
}
return false;
}
public ControllerDefinition Definition
{
get { return Source.Definition; }
}
public bool IsPressed(string button)
{
var source = Source.IsPressed(button);
bool patternValue = false;
if (_boolPatterns.ContainsKey(button))
{ // I can't figure a way to determine right here if it should Peek or Get.
patternValue = _boolPatterns[button].PeekNextValue();
}
source ^= patternValue;
return source;
}
public float GetFloat(string name)
{
if (_floatPatterns.ContainsKey(name))
{
return _floatPatterns[name].PeekNextValue();
}
if (Source == null)
{
return 0;
}
return Source.GetFloat(name);
}
// TODO: Change the AutoHold adapter to be one of these, with an 'Off' value of 0?
// Probably would have slightly lower performance, but it seems weird to have such a similar class that is only used once.
private int On;
private int Off;
public void SetOnOffPatternFromConfig()
{
On = Global.Config.AutofireOn < 1 ? 0 : Global.Config.AutofireOn;
Off = Global.Config.AutofireOff < 1 ? 0 : Global.Config.AutofireOff;
}
private WorkingDictionary<string, AutoPatternBool> _boolPatterns = new WorkingDictionary<string, AutoPatternBool>();
private WorkingDictionary<string, AutoPatternFloat> _floatPatterns = new WorkingDictionary<string, AutoPatternFloat>();
public AutoFireStickyXorAdapter()
{
On = 1; Off = 1;
}
public IController Source { get; set; }
public bool Locked { get; set; } // Pretty much a hack,
public void SetFloat(string name, float? value, AutoPatternFloat pattern = null)
{
if (value.HasValue)
{
if (pattern == null)
pattern = new AutoPatternFloat(value.Value, On, 0, Off);
_floatPatterns[name] = pattern;
}
else
{
_floatPatterns.Remove(name);
}
}
public void ClearStickyFloats()
{
_floatPatterns.Clear();
}
public void SetSticky(string button, bool isSticky, AutoPatternBool pattern = null)
{
if (isSticky)
{
if (pattern == null)
pattern = new AutoPatternBool(On, Off);
_boolPatterns[button] = pattern;
}
else
{
_boolPatterns.Remove(button);
}
}
public void Unset(string button)
{
_boolPatterns.Remove(button);
_floatPatterns.Remove(button);
}
public bool IsSticky(string button)
{
return _boolPatterns.ContainsKey(button) || _floatPatterns.ContainsKey(button);
}
public HashSet<string> CurrentStickies
{
get
{
return new HashSet<string>(_boolPatterns.Keys);
}
}
public void ClearStickies()
{
_boolPatterns.Clear();
_floatPatterns.Clear();
}
public void IncrementLoops(bool lagged)
{
for (int i = 0; i < _boolPatterns.Count; i++)
_boolPatterns.ElementAt(i).Value.GetNextValue(lagged);
for (int i = 0; i < _floatPatterns.Count; i++)
_floatPatterns.ElementAt(i).Value.GetNextValue(lagged);
}
private List<string> _justPressed = new List<string>();
public void MassToggleStickyState(List<string> buttons)
{
foreach (var button in buttons.Where(button => !_justPressed.Contains(button)))
{
if (_boolPatterns.ContainsKey(button))
SetSticky(button, false);
else
SetSticky(button, true);
}
_justPressed = buttons;
}
}
}

View File

@ -0,0 +1,163 @@
using System.Collections.Generic;
using BizHawk.Common.StringExtensions;
using BizHawk.Emulation.Common;
namespace BizHawk.Client.Common
{
/// <summary>
/// Filters input for things called Up and Down while considering the client's AllowUD_LR option.
/// This is a bit gross but it is unclear how to do it more nicely
/// </summary>
public class UD_LR_ControllerAdapter : IController
{
public ControllerDefinition Definition
{
get { return Source.Definition; }
}
public bool IsPressed(string button)
{
bool PriorityUD_LR = !Global.Config.AllowUD_LR && !Global.Config.ForbidUD_LR; // implied by neither of the others being set (left as non-enum for back-compatibility)
if (Global.Config.AllowUD_LR)
{
return Source.IsPressed(button);
}
string prefix;
//" C " is for N64 "P1 C Up" and the like, which should not be subject to mutexing
//regarding the unpressing and UDLR logic...... don't think about it. don't question it. don't look at it.
if (button.Contains("Down") && !button.Contains(" C "))
{
if (!Source.IsPressed(button))
{
Unpresses.Remove(button);
}
prefix = button.GetPrecedingString("Down");
string other = prefix + "Up";
if (Source.IsPressed(other))
{
if (Unpresses.Contains(button))
{
return false;
}
if (Global.Config.ForbidUD_LR)
{
return false;
}
Unpresses.Add(other);
}
else
{
Unpresses.Remove(button);
}
}
if (button.Contains("Up") && !button.Contains(" C "))
{
if (!Source.IsPressed(button))
{
Unpresses.Remove(button);
}
prefix = button.GetPrecedingString("Up");
string other = prefix + "Down";
if (Source.IsPressed(other))
{
if (Unpresses.Contains(button))
{
return false;
}
if (Global.Config.ForbidUD_LR)
{
return false;
}
Unpresses.Add(other);
}
else
{
Unpresses.Remove(button);
}
}
if (button.Contains("Right") && !button.Contains(" C "))
{
if (!Source.IsPressed(button))
{
Unpresses.Remove(button);
}
prefix = button.GetPrecedingString("Right");
string other = prefix + "Left";
if (Source.IsPressed(other))
{
if (Unpresses.Contains(button))
{
return false;
}
if (Global.Config.ForbidUD_LR)
{
return false;
}
Unpresses.Add(other);
}
else
{
Unpresses.Remove(button);
}
}
if (button.Contains("Left") && !button.Contains(" C "))
{
if (!Source.IsPressed(button))
{
Unpresses.Remove(button);
}
prefix = button.GetPrecedingString("Left");
string other = prefix + "Right";
if (Source.IsPressed(other))
{
if (Unpresses.Contains(button))
{
return false;
}
if (Global.Config.ForbidUD_LR)
{
return false;
}
Unpresses.Add(other);
}
else
{
Unpresses.Remove(button);
}
}
return Source.IsPressed(button);
}
// The float format implies no U+D and no L+R no matter what, so just passthru
public float GetFloat(string name)
{
return Source.GetFloat(name);
}
private readonly HashSet<string> Unpresses = new HashSet<string>();
public IController Source { get; set; }
}
}

View File

@ -34,6 +34,9 @@ namespace BizHawk.Client.Common
[OptionalService]
public IInputPollable InputPollableCore { get; set; }
[OptionalService]
public IRegionable RegionableCore { get; set; }
public Action FrameAdvanceCallback { get; set; }
public Action YieldCallback { get; set; }
@ -185,6 +188,31 @@ namespace BizHawk.Client.Common
}
}
[LuaMethodAttributes(
"totalexecutedcycles",
"gets the total number of executed cpu cycles"
)]
public int TotalExecutedycles()
{
try
{
if (DebuggableCore == null)
{
throw new NotImplementedException();
}
return DebuggableCore.TotalExecutedCycles;
}
catch (NotImplementedException)
{
Log(string.Format(
"Error: {0} does not yet implement totalexecutedcycles()",
Emulator.Attributes().CoreName));
return 0;
}
}
[LuaMethodAttributes(
"getsystemid",
"Returns the ID string of the current core loaded. Note: No ROM loaded will return the string NULL"
@ -364,13 +392,9 @@ namespace BizHawk.Client.Common
)]
public string GetDisplayType()
{
if (Global.Game != null)
if (RegionableCore != null)
{
var displaytype = Emulator.GetType().GetProperty("DisplayType");
if (displaytype != null)
{
return displaytype.GetValue(Emulator, null).ToString();
}
return RegionableCore.Region.ToString();
}
return string.Empty;

View File

@ -21,19 +21,19 @@ namespace BizHawk.Client.Common
{
var buttons = Lua.NewTable();
var adaptor = Global.AutofireStickyXORAdapter;
foreach (var button in adaptor.Source.Type.BoolButtons)
foreach (var button in adaptor.Source.Definition.BoolButtons)
{
if (!controller.HasValue)
{
buttons[button] = adaptor[button];
buttons[button] = adaptor.IsPressed(button);
}
else if (button.Length >= 3 && button.Substring(0, 2) == "P" + controller)
{
buttons[button.Substring(3)] = adaptor["P" + controller + " " + button.Substring(3)];
buttons[button.Substring(3)] = adaptor.IsPressed("P" + controller + " " + button.Substring(3));
}
}
foreach (var button in adaptor.Source.Type.FloatControls)
foreach (var button in adaptor.Source.Definition.FloatControls)
{
if (controller == null)
{
@ -52,6 +52,7 @@ namespace BizHawk.Client.Common
return buttons;
}
// TODO: what about float controls?
[LuaMethodAttributes(
"getimmediate",
"returns a lua table of any controller buttons currently pressed by the user"
@ -59,9 +60,9 @@ namespace BizHawk.Client.Common
public LuaTable GetImmediate()
{
var buttons = Lua.NewTable();
foreach (var button in Global.ActiveController.Type.BoolButtons)
foreach (var button in Global.ActiveController.Definition.BoolButtons)
{
buttons[button] = Global.ActiveController[button];
buttons[button] = Global.ActiveController.IsPressed(button);
}
return buttons;
@ -78,12 +79,12 @@ namespace BizHawk.Client.Common
var lg = Global.MovieSession.MovieControllerInstance();
lg.SetControllersAsMnemonic(inputLogEntry);
foreach (var button in lg.Type.BoolButtons)
foreach (var button in lg.Definition.BoolButtons)
{
Global.LuaAndAdaptor.SetButton(button, lg.IsPressed(button));
}
foreach (var floatButton in lg.Type.FloatControls)
foreach (var floatButton in lg.Definition.FloatControls)
{
Global.LuaAndAdaptor.SetFloat(floatButton, lg.GetFloat(floatButton));
}

View File

@ -3,8 +3,9 @@ using System.Collections.Generic;
using System.IO;
using LuaInterface;
using BizHawk.Emulation.Common.IEmulatorExtensions;
using BizHawk.Emulation.Common;
using BizHawk.Emulation.Common.IEmulatorExtensions;
namespace BizHawk.Client.Common
{
@ -20,26 +21,21 @@ namespace BizHawk.Client.Common
private readonly Dictionary<Guid, byte[]> MemorySavestates = new Dictionary<Guid, byte[]>();
[RequiredService]
private IStatable _statableCore { get; set; }
[LuaMethodAttributes(
"savecorestate",
"creates a core savestate and stores it in memory. Note: a core savestate is only the raw data from the core, and not extras such as movie input logs, or framebuffers. Returns a unique identifer for the savestate"
)]
public string SaveCoreStateToMemory()
{
if (Global.Emulator.HasSavestates())
{
var guid = Guid.NewGuid();
var bytes = (byte[])Global.Emulator.AsStatable().SaveStateBinary().Clone();
var guid = Guid.NewGuid();
var bytes = (byte[])_statableCore.SaveStateBinary().Clone();
MemorySavestates.Add(guid, bytes);
MemorySavestates.Add(guid, bytes);
return guid.ToString();
}
else
{
Log("Savestates not supported on this core");
return Guid.Empty.ToString();
}
return guid.ToString();
}
[LuaMethodAttributes(
@ -50,27 +46,19 @@ namespace BizHawk.Client.Common
{
var guid = new Guid(identifier);
if (Global.Emulator.HasSavestates())
try
{
try
{
var statableCore = Global.Emulator.AsStatable();
var state = MemorySavestates[guid];
var state = MemorySavestates[guid];
using (MemoryStream ms = new MemoryStream(state))
using (BinaryReader br = new BinaryReader(ms))
{
statableCore.LoadStateBinary(br);
}
}
catch
using (MemoryStream ms = new MemoryStream(state))
using (BinaryReader br = new BinaryReader(ms))
{
Log("Unable to find the given savestate in memory");
_statableCore.LoadStateBinary(br);
}
}
else
catch
{
Log("Savestates not supported on this core");
Log("Unable to find the given savestate in memory");
}
}

View File

@ -63,14 +63,14 @@ namespace BizHawk.Client.Common
return null;
}
foreach (var button in adapter.Type.BoolButtons)
foreach (var button in adapter.Definition.BoolButtons)
{
input[button] = adapter[button];
input[button] = adapter.IsPressed(button);
}
foreach (var button in adapter.Type.FloatControls)
foreach (var button in adapter.Definition.FloatControls)
{
input[button] = adapter[button];
input[button] = adapter.GetFloat(button);
}
return input;
@ -199,10 +199,6 @@ namespace BizHawk.Client.Common
)]
public static void SetReadOnly(bool readOnly)
{
int x = 0;
x++;
int y = x;
Global.MovieSession.ReadOnly = readOnly;
}

View File

@ -3,8 +3,8 @@ using System.ComponentModel;
using System.Linq;
using LuaInterface;
using BizHawk.Emulation.Common;
using BizHawk.Emulation.Common.IEmulatorExtensions;
using BizHawk.Emulation.Cores.Nintendo.NES;
using BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES;
@ -22,11 +22,17 @@ namespace BizHawk.Client.Common
[OptionalService]
private NES _neshawk { get; set; }
[OptionalService]
private QuickNES _quicknes { get; set; }
[OptionalService]
private IMemoryDomains _memoryDomains { get; set; }
private bool NESAvailable { get { return _neshawk != null || _quicknes != null; } }
private bool HasMemoryDOmains { get { return _memoryDomains != null; } }
public NesLuaLibrary(Lua lua, Action<string> logOutputCallback)
: base(lua, logOutputCallback) { }
@ -38,11 +44,11 @@ namespace BizHawk.Client.Common
)]
public void AddGameGenie(string code)
{
if (NESAvailable)
if (NESAvailable && HasMemoryDOmains)
{
var decoder = new NESGameGenieDecoder(code);
var watch = Watch.GenerateWatch(
Global.Emulator.AsMemoryDomains()["System Bus"],
_memoryDomains["System Bus"],
decoder.Address,
WatchSize.Byte,
DisplayType.Hex,

View File

@ -61,10 +61,18 @@ namespace BizHawk.Client.Common
public void Toggle()
{
if (State == RunState.Paused)
{
State = RunState.Running;
}
else if (State == RunState.Disabled)
{
State = RunState.Running;
else State = RunState.Disabled;
FrameWaiting = false;
}
else
{
State = RunState.Disabled;
}
}
public void TogglePause()

View File

@ -65,7 +65,7 @@ namespace BizHawk.Client.Common
public IMovieController MovieControllerInstance()
{
var adapter = Movie.LogGeneratorInstance().MovieControllerAdapter;
adapter.Type = MovieControllerAdapter.Type;
adapter.Definition = MovieControllerAdapter.Definition;
return adapter;
}
@ -263,7 +263,7 @@ namespace BizHawk.Client.Common
// Movie may go into finished mode as a result from latching
if (!Movie.IsFinished)
{
if (Global.ClientControls["Scrub Input"])
if (Global.ClientControls.IsPressed("Scrub Input"))
{
LatchInputFromPlayer(Global.MovieInputSourceAdapter);
ClearFrame();
@ -294,13 +294,17 @@ namespace BizHawk.Client.Common
private void HandleFrameLoopForRecordMode()
{
if (MultiTrack.IsActive)
// tasmovie is appended via recording frames, but we don't want it to latch input outside its inetrnal recording mode
if (!(Movie is TasMovie) || !Movie.IsPlaying)
{
LatchMultitrackPlayerInput(Global.MovieInputSourceAdapter, Global.MultitrackRewiringAdapter);
}
else
{
LatchInputFromPlayer(Global.MovieInputSourceAdapter);
if (MultiTrack.IsActive)
{
LatchMultitrackPlayerInput(Global.MovieInputSourceAdapter, Global.MultitrackRewiringAdapter);
}
else
{
LatchInputFromPlayer(Global.MovieInputSourceAdapter);
}
}
// the movie session makes sure that the correct input has been read and merged to its MovieControllerAdapter;

View File

@ -94,7 +94,7 @@ namespace BizHawk.Client.Common
public int PlayerSource { get; set; }
public int PlayerTargetMask { get; set; }
public ControllerDefinition Type { get { return Source.Type; } }
public ControllerDefinition Definition { get { return Source.Definition; } }
public bool this[string button]
{

View File

@ -58,6 +58,8 @@ namespace BizHawk.Client.Common
{"C64_NTSC", NTSC_CARRIER*2/7/263/65},
{"C64_NTSC_OLD", NTSC_CARRIER*2/7/262/64},
{"C64_DREAN", PAL_N_CARRIER*2/7/312/65},
{"INTV", 59.92 }
//according to ryphecha, using
//clocks[2] = { 53.693182e06, 53.203425e06 }; //ntsc console, pal console

View File

@ -37,8 +37,7 @@ namespace BizHawk.Client.Common
}
}
#region IController Implementation
// TODO: get rid of this, add a SetBool() method or something for the set access, replace get wtih IsPressed
public bool this[string button]
{
get
@ -55,6 +54,8 @@ namespace BizHawk.Client.Common
}
}
#region IController Implementation
public bool IsPressed(string button)
{
return MyBoolButtons[button];
@ -71,7 +72,7 @@ namespace BizHawk.Client.Common
private Bk2ControllerDefinition _type = new Bk2ControllerDefinition();
public ControllerDefinition Type
public ControllerDefinition Definition
{
get
{
@ -90,7 +91,7 @@ namespace BizHawk.Client.Common
/// </summary>
public void LatchPlayerFromSource(IController playerSource, int playerNum)
{
foreach (var button in playerSource.Type.BoolButtons)
foreach (var button in playerSource.Definition.BoolButtons)
{
var bnp = ButtonNameParser.Parse(button);
if (bnp == null)
@ -103,11 +104,11 @@ namespace BizHawk.Client.Common
continue;
}
var val = playerSource[button];
var val = playerSource.IsPressed(button);
MyBoolButtons[button] = val;
}
foreach (var button in Type.FloatControls)
foreach (var button in Definition.FloatControls)
{
var bnp = ButtonNameParser.Parse(button);
if (bnp == null)
@ -131,12 +132,12 @@ namespace BizHawk.Client.Common
/// </summary>
public void LatchFromSource(IController source)
{
foreach (var button in Type.BoolButtons)
foreach (var button in Definition.BoolButtons)
{
MyBoolButtons[button] = source.IsPressed(button);
}
foreach (var name in Type.FloatControls)
foreach (var name in Definition.FloatControls)
{
MyFloatControls[name] = source.GetFloat(name);
}
@ -151,7 +152,7 @@ namespace BizHawk.Client.Common
{
var def = Global.Emulator.ControllerDefinition;
var trimmed = mnemonic.Replace("|", "");
var buttons = Type.ControlsOrdered.SelectMany(x => x).ToList();
var buttons = Definition.ControlsOrdered.SelectMany(x => x).ToList();
var iterator = 0;
foreach (var key in buttons)

View File

@ -44,7 +44,8 @@ namespace BizHawk.Client.Common
{ "LStick X", "lsX" },
{ "LStick Y", "lsY" },
{ "RStick X", "rsX" },
{ "RStick Y", "rsY" }
{ "RStick Y", "rsY" },
{ "Disc Select", "Disc" }
};
private readonly Dictionary<string, Dictionary<string, string>> SystemOverrides = new Dictionary<string, Dictionary<string, string>>

View File

@ -36,16 +36,7 @@ namespace BizHawk.Client.Common
public string GenerateInputDisplay()
{
var le = GenerateLogEntry();
if (le == EmptyEntry)
{
return string.Empty;
}
return le
.Replace(".", " ")
.Replace("|", "")
.Replace(" 0,", " "); //zero 04-aug-2015 - changed from a 2-dimensional type string to support emptying out the one-dimensional PSX disc select control
return CreateLogEntry(forInputDisplay: true);
}
public bool IsEmpty
@ -76,7 +67,7 @@ namespace BizHawk.Client.Common
var sb = new StringBuilder();
sb.Append("LogKey:");
foreach (var group in _source.Type.ControlsOrdered.Where(c => c.Any()))
foreach (var group in _source.Definition.ControlsOrdered.Where(c => c.Any()))
{
sb.Append("#");
foreach (var button in group)
@ -93,15 +84,15 @@ namespace BizHawk.Client.Common
public Dictionary<string, string> Map()
{
var dict = new Dictionary<string, string>();
foreach (var group in _source.Type.ControlsOrdered.Where(c => c.Any()))
foreach (var group in _source.Definition.ControlsOrdered.Where(c => c.Any()))
{
foreach (var button in group)
{
if (_source.Type.BoolButtons.Contains(button))
if (_source.Definition.BoolButtons.Contains(button))
{
dict.Add(button, Mnemonics[button].ToString());
}
else if (_source.Type.FloatControls.Contains(button))
else if (_source.Definition.FloatControls.Contains(button))
{
dict.Add(button, FloatLookup[button]);
}
@ -111,30 +102,40 @@ namespace BizHawk.Client.Common
return dict;
}
private string CreateLogEntry(bool createEmpty = false)
private string CreateLogEntry(bool createEmpty = false, bool forInputDisplay = false)
{
var sb = new StringBuilder();
sb.Append('|');
foreach (var group in _source.Type.ControlsOrdered)
if (!forInputDisplay)
sb.Append('|');
foreach (var group in _source.Definition.ControlsOrdered)
{
if (group.Any())
{
foreach (var button in group)
{
if (_source.Type.FloatControls.Contains(button))
if (_source.Definition.FloatControls.Contains(button))
{
int val;
int i = _source.Definition.FloatControls.IndexOf(button);
int mid = (int)_source.Definition.FloatRanges[i].Mid;
if (createEmpty)
{
sb.Append(" 0,");
val = mid;
}
else
{
var val = (int)_source.GetFloat(button);
sb.Append(val.ToString().PadLeft(5, ' ')).Append(',');
val = (int)_source.GetFloat(button);
}
if (forInputDisplay && val == mid)
sb.Append(" ");
else
sb.Append(val.ToString().PadLeft(5, ' ')).Append(',');
}
else if (_source.Type.BoolButtons.Contains(button))
else if (_source.Definition.BoolButtons.Contains(button))
{
if (createEmpty)
{
@ -142,12 +143,13 @@ namespace BizHawk.Client.Common
}
else
{
sb.Append(_source.IsPressed(button) ? Mnemonics[button] : '.');
sb.Append(_source.IsPressed(button) ? Mnemonics[button] : forInputDisplay ? ' ' : '.');
}
}
}
sb.Append('|');
if (!forInputDisplay)
sb.Append('|');
}
}

View File

@ -107,7 +107,10 @@ namespace BizHawk.Client.Common
{ "Square", 'Q' },
{ "Toggle Left Difficulty", 'l' },
{ "Toggle Right Difficulty", 'r' }
{ "Toggle Right Difficulty", 'r' },
{ "Open", 'O' },
{ "Close", 'C' }
};
private readonly Dictionary<string, Dictionary<string, char>> SystemOverrides = new Dictionary<string, Dictionary<string, char>>
@ -279,6 +282,27 @@ namespace BizHawk.Client.Common
{ "L", 'L' },
{ "R", 'R' }
}
},
{
"INTV",
new Dictionary<string, char>
{
{ "Clear", 'C' },
{ "Enter", 'E' },
{ "Top", 'T' },
{ "NNE", 'n' },
{ "NE", '/' },
{ "ENE", 'e' },
{ "ESE", 'e' },
{ "SE", '\\' },
{ "SSE", 's' },
{ "SSW", 's' },
{ "SW", '/' },
{ "WSW", 'w' },
{ "WNW", 'w' },
{ "NW", '\\' },
{ "NNW", 'n' }
}
}
};
}

View File

@ -321,7 +321,7 @@ namespace BizHawk.Client.Common
private string ConvertLogEntryFromFile(string line, string logKey)
{
var adapter = new Bk2LogEntryGenerator(logKey).MovieControllerAdapter;
adapter.Type = Global.MovieSession.MovieControllerAdapter.Type;
adapter.Definition = Global.MovieSession.MovieControllerAdapter.Definition;
adapter.SetControllersAsMnemonic(line);
var lg = LogGeneratorInstance();

View File

@ -143,7 +143,7 @@ namespace BizHawk.Client.Common
var adapter = new Bk2ControllerAdapter
{
Type = Global.MovieSession.MovieControllerAdapter.Type
Definition = Global.MovieSession.MovieControllerAdapter.Definition
};
adapter.SetControllersAsMnemonic(_log[getframe]);

View File

@ -9,10 +9,7 @@ namespace BizHawk.Client.Common
{
#region IController Implementation
public bool this[string button]
{
get { return MyBoolButtons[button]; }
}
public ControllerDefinition Definition { get; set; }
public bool IsPressed(string button)
{
@ -28,14 +25,12 @@ namespace BizHawk.Client.Common
#region IMovieController Implementation
public ControllerDefinition Type { get; set; }
/// <summary>
/// latches one player from the source
/// </summary>
public void LatchPlayerFromSource(IController playerSource, int playerNum)
{
foreach (var button in playerSource.Type.BoolButtons)
foreach (var button in playerSource.Definition.BoolButtons)
{
var bnp = ButtonNameParser.Parse(button);
if (bnp == null)
@ -48,7 +43,7 @@ namespace BizHawk.Client.Common
continue;
}
var val = playerSource[button];
var val = playerSource.IsPressed(button);
MyBoolButtons[button] = val;
}
}
@ -58,12 +53,12 @@ namespace BizHawk.Client.Common
/// </summary>
public void LatchFromSource(IController source)
{
foreach (var button in Type.BoolButtons)
foreach (var button in Definition.BoolButtons)
{
MyBoolButtons[button] = source[button];
MyBoolButtons[button] = source.IsPressed(button);
}
foreach (var name in Type.FloatControls)
foreach (var name in Definition.FloatControls)
{
MyFloatControls[name] = source.GetFloat(name);
}
@ -258,7 +253,7 @@ namespace BizHawk.Client.Common
private bool IsGenesis6Button()
{
return this.Type.BoolButtons.Contains("P1 X");
return this.Definition.BoolButtons.Contains("P1 X");
}
private void Force(string button, bool state)
@ -271,7 +266,7 @@ namespace BizHawk.Client.Common
MyFloatControls[name] = state;
}
private string ControlType { get { return Type.Name; } }
private string ControlType { get { return Definition.Name; } }
private void SetGBAControllersAsMnemonic(string mnemonic)
{

View File

@ -12,7 +12,7 @@ namespace BizHawk.Client.Common
public void SetSource(IController source)
{
_source = source;
_controlType = source.Type.Name;
_controlType = source.Definition.Name;
}
public string GenerateLogEntry()

View File

@ -100,7 +100,7 @@ namespace BizHawk.Client.Common
var adapter = new BkmControllerAdapter
{
Type = Global.MovieSession.MovieControllerAdapter.Type
Definition = Global.MovieSession.MovieControllerAdapter.Definition
};
adapter.SetControllersAsMnemonic(_log[getframe]);
return adapter;

View File

@ -241,7 +241,7 @@ namespace BizHawk.Client.Common
private static IController EmptyLmsvFrame(string line)
{
var emptyController = new SimpleController { Type = new ControllerDefinition { Name = "SNES Controller" } };
var emptyController = new SimpleController { Definition = new ControllerDefinition { Name = "SNES Controller" } };
emptyController["Reset"] = false;
emptyController["Power"] = false;
@ -294,7 +294,7 @@ namespace BizHawk.Client.Common
controller = "Saturn Controller";
break;
}
var controllers = new SimpleController { Type = new ControllerDefinition { Name = controller } };
var controllers = new SimpleController { Definition = new ControllerDefinition { Name = controller } };
// Split up the sections of the frame.
string[] sections = line.Split('|');
if (ext == ".FM2" && sections.Length >= 2 && sections[1].Length != 0)
@ -373,14 +373,14 @@ namespace BizHawk.Client.Common
int player = section + player_offset;
string prefix = "P" + (player) + " ";
// Gameboy doesn't currently have a prefix saying which player the input is for.
if (controllers.Type.Name == "Gameboy Controller")
if (controllers.Definition.Name == "Gameboy Controller")
{
prefix = "";
}
// Only count lines with that have the right number of buttons and are for valid players.
if (
sections[section].Length == buttons.Length &&
player <= BkmMnemonicConstants.PLAYERS[controllers.Type.Name]
player <= BkmMnemonicConstants.PLAYERS[controllers.Definition.Name]
)
{
for (int button = 0; button < buttons.Length; button++)
@ -724,7 +724,7 @@ namespace BizHawk.Client.Common
m.Header[HeaderKeys.AUTHOR] = author;
// Advance to first byte of input data.
r.BaseStream.Position = firstFrameOffset;
SimpleController controllers = new SimpleController { Type = new ControllerDefinition { Name = "NES Controller" } };
SimpleController controllers = new SimpleController { Definition = new ControllerDefinition { Name = "NES Controller" } };
string[] buttons = { "A", "B", "Select", "Start", "Up", "Down", "Left", "Right" };
bool fds = false;
bool fourscore = false;
@ -955,7 +955,7 @@ namespace BizHawk.Client.Common
*/
m.Header[HeaderKeys.PAL] = "False";
// 090 frame data begins here
SimpleController controllers = new SimpleController { Type = new ControllerDefinition { Name = "NES Controller" } };
SimpleController controllers = new SimpleController { Definition = new ControllerDefinition { Name = "NES Controller" } };
/*
* 01 Right
* 02 Left
@ -1042,14 +1042,14 @@ namespace BizHawk.Client.Common
string player1Config = r.ReadStringFixedAscii(1);
// 015 ASCII-encoded controller config for player 2. '3' or '6'.
string player2Config = r.ReadStringFixedAscii(1);
SimpleController controllers = new SimpleController { Type = new ControllerDefinition() };
SimpleController controllers = new SimpleController { Definition = new ControllerDefinition() };
if (player1Config == "6" || player2Config == "6")
{
controllers.Type.Name = "GPGX Genesis Controller";
controllers.Definition.Name = "GPGX Genesis Controller";
}
else
{
controllers.Type.Name = "GPGX 3-Button Controller";
controllers.Definition.Name = "GPGX 3-Button Controller";
}
// 016 special flags (Version A and up only)
byte flags = r.ReadByte();
@ -1474,7 +1474,7 @@ namespace BizHawk.Client.Common
r.ReadBytes(103);
// TODO: Verify if NTSC/"PAL" mode used for the movie can be detected or not.
// 100 variable Input data
SimpleController controllers = new SimpleController { Type = new ControllerDefinition { Name = name + " Controller" } };
SimpleController controllers = new SimpleController { Definition = new ControllerDefinition { Name = name + " Controller" } };
int bytes = 256;
// The input stream consists of 1 byte for power-on and reset, and then X bytes per each input port per frame.
if (platform == "nes")
@ -1595,7 +1595,7 @@ namespace BizHawk.Client.Common
// 00e4-00f3: binary: rom MD5 digest
byte[] md5 = r.ReadBytes(16);
m.Header[MD5] = string.Format("{0:x8}", md5.BytesToHexString().ToLower());
var controllers = new SimpleController { Type = new ControllerDefinition { Name = "SMS Controller" } };
var controllers = new SimpleController { Definition = new ControllerDefinition { Name = "SMS Controller" } };
/*
76543210
* bit 0 (0x01): up
@ -1820,7 +1820,7 @@ namespace BizHawk.Client.Common
// ... 4-byte little-endian unsigned int: length of controller data in bytes
uint length = r.ReadUInt32();
// ... (variable) controller data
SimpleController controllers = new SimpleController { Type = new ControllerDefinition { Name = "NES Controller" } };
SimpleController controllers = new SimpleController { Definition = new ControllerDefinition { Name = "NES Controller" } };
/*
Standard controllers store data in the following format:
* 01: A
@ -1923,7 +1923,7 @@ namespace BizHawk.Client.Common
* bit 4: controller 5 in use
* other: reserved, set to 0
*/
SimpleController controllers = new SimpleController { Type = new ControllerDefinition { Name = "SNES Controller" } };
SimpleController controllers = new SimpleController { Definition = new ControllerDefinition { Name = "SNES Controller" } };
bool[] controllersUsed = new bool[5];
for (int controller = 1; controller <= controllersUsed.Length; controller++)
{
@ -2109,7 +2109,7 @@ namespace BizHawk.Client.Common
}
}
ushort controllerState = (ushort)(((controllerState1 << 4) & 0x0F00) | controllerState2);
if (player <= BkmMnemonicConstants.PLAYERS[controllers.Type.Name])
if (player <= BkmMnemonicConstants.PLAYERS[controllers.Definition.Name])
{
for (int button = 0; button < buttons.Length; button++)
{
@ -2334,14 +2334,14 @@ namespace BizHawk.Client.Common
string movieDescription = NullTerminated(r.ReadStringFixedAscii(128));
m.Comments.Add(COMMENT + " " + movieDescription);
r.BaseStream.Position = firstFrameOffset;
SimpleController controllers = new SimpleController { Type = new ControllerDefinition() };
SimpleController controllers = new SimpleController { Definition = new ControllerDefinition() };
if (platform != "GBA")
{
controllers.Type.Name = "Gameboy Controller";
controllers.Definition.Name = "Gameboy Controller";
}
else
{
controllers.Type.Name = "GBA Controller";
controllers.Definition.Name = "GBA Controller";
}
/*
* 01 00 A
@ -2512,7 +2512,7 @@ namespace BizHawk.Client.Common
return m;
}
r.BaseStream.Position = firstFrameOffset;
SimpleController controllers = new SimpleController { Type = new ControllerDefinition { Name = "NES Controller" } };
SimpleController controllers = new SimpleController { Definition = new ControllerDefinition { Name = "NES Controller" } };
/*
* 01 A
* 02 B
@ -2749,7 +2749,7 @@ namespace BizHawk.Client.Common
uint savestateSize = (uint)((r.ReadByte() | (r.ReadByte() << 8) | (r.ReadByte() << 16)) & 0x7FFFFF);
// Next follows a ZST format savestate.
r.ReadBytes((int)savestateSize);
SimpleController controllers = new SimpleController { Type = new ControllerDefinition { Name = "SNES Controller" } };
SimpleController controllers = new SimpleController { Definition = new ControllerDefinition { Name = "SNES Controller" } };
/*
* bit 11: A
* bit 10: X
@ -2903,7 +2903,7 @@ namespace BizHawk.Client.Common
}
}
leftOver = !leftOver;
if (player <= BkmMnemonicConstants.PLAYERS[controllers.Type.Name])
if (player <= BkmMnemonicConstants.PLAYERS[controllers.Definition.Name])
{
if (player != 2 || !superScope)
{

View File

@ -183,7 +183,7 @@ namespace BizHawk.Client.Common
info.player2Type,
OctoshockDll.ePeripheralType.None,OctoshockDll.ePeripheralType.None,OctoshockDll.ePeripheralType.None
};
controllers.Type = Octoshock.CreateControllerDefinition(settings);
controllers.Definition = Octoshock.CreateControllerDefinition(settings);
string[] buttons = { "Select", "L3", "R3", "Start", "Up", "Right", "Down", "Left",
"L2", "R2", "L1", "R1", "Triangle", "Circle", "Cross", "Square"};
@ -290,7 +290,7 @@ namespace BizHawk.Client.Common
info.player2Type,
OctoshockDll.ePeripheralType.None,OctoshockDll.ePeripheralType.None,OctoshockDll.ePeripheralType.None
};
controllers.Type = Octoshock.CreateControllerDefinition(settings);
controllers.Definition = Octoshock.CreateControllerDefinition(settings);
string[] buttons = { "Select", "L3", "R3", "Start", "Up", "Right", "Down", "Left",
"L2", "R2", "L1", "R1", "Triangle", "Circle", "Cross", "Square"};

View File

@ -4,7 +4,7 @@ namespace BizHawk.Client.Common
{
public interface IMovieController: IController
{
new ControllerDefinition Type { get; set; }
new ControllerDefinition Definition { get; set; }
void LatchPlayerFromSource(IController playerSource, int playerNum);

View File

@ -125,7 +125,8 @@ namespace BizHawk.Client.Common
foreach (var frame in frames.OrderByDescending(x => x)) // Removin them in reverse order allows us to remove by index;
{
_log.RemoveAt(frame);
if (frame < _log.Count)
_log.RemoveAt(frame);
if (BindMarkersToInput) // TODO: This is slow, is there a better way to do it?
{
bool wasRecording = ChangeLog.IsRecording;
@ -370,7 +371,7 @@ namespace BizHawk.Client.Common
Changes = true;
InvalidateAfter(frame);
ChangeLog.AddBoolToggle(frame, buttonName, !adapter[buttonName], "Toggle " + buttonName + ": " + frame);
ChangeLog.AddBoolToggle(frame, buttonName, !adapter.IsPressed(buttonName), "Toggle " + buttonName + ": " + frame);
}
public void SetBoolState(int frame, string buttonName, bool val)
@ -379,7 +380,7 @@ namespace BizHawk.Client.Common
ExtendMovieForEdit(frame - _log.Count + 1);
var adapter = GetInputState(frame) as Bk2ControllerAdapter;
var old = adapter[buttonName];
var old = adapter.IsPressed(buttonName);
adapter[buttonName] = val;
var lg = LogGeneratorInstance();
@ -405,7 +406,7 @@ namespace BizHawk.Client.Common
for (int i = 0; i < count; i++)
{
var adapter = GetInputState(frame + i) as Bk2ControllerAdapter;
bool old = adapter[buttonName];
bool old = adapter.IsPressed(buttonName);
adapter[buttonName] = val;
var lg = LogGeneratorInstance();

View File

@ -36,11 +36,6 @@ namespace BizHawk.Client.Common
// TasProj extras
bs.PutLump(BinaryStateLump.StateHistorySettings, tw => tw.WriteLine(StateManager.Settings.ToString()));
if (StateManager.Settings.SaveStateHistory)
{
bs.PutLump(BinaryStateLump.StateHistory, (BinaryWriter bw) => StateManager.Save(bw));
}
bs.PutLump(BinaryStateLump.LagLog, (BinaryWriter bw) => LagLog.Save(bw));
bs.PutLump(BinaryStateLump.Markers, tw => tw.WriteLine(Markers.ToString()));
@ -81,6 +76,11 @@ namespace BizHawk.Client.Common
}
bs.PutLump(BinaryStateLump.Session, tw => tw.WriteLine(Session.ToString()));
if (StateManager.Settings.SaveStateHistory)
{
bs.PutLump(BinaryStateLump.StateHistory, (BinaryWriter bw) => StateManager.Save(bw));
}
}
if (!backup)
@ -201,21 +201,6 @@ namespace BizHawk.Client.Common
StateManager.Settings.PopulateFromString(tr.ReadToEnd());
});
if(!preload)
{
if (StateManager.Settings.SaveStateHistory)
{
bl.GetLump(BinaryStateLump.StateHistory, false, delegate(BinaryReader br, long length)
{
StateManager.Load(br);
});
}
// Movie should always have a state at frame 0.
if (!this.StartsFromSavestate && Global.Emulator.Frame == 0)
StateManager.Capture();
}
bl.GetLump(BinaryStateLump.Markers, false, delegate(TextReader tr)
{
string line;
@ -280,6 +265,21 @@ namespace BizHawk.Client.Common
{
Session.PopulateFromString(tr.ReadToEnd());
});
if (!preload)
{
if (StateManager.Settings.SaveStateHistory)
{
bl.GetLump(BinaryStateLump.StateHistory, false, delegate(BinaryReader br, long length)
{
StateManager.Load(br);
});
}
// Movie should always have a state at frame 0.
if (!this.StartsFromSavestate && Global.Emulator.Frame == 0)
StateManager.Capture();
}
}
Changes = false;

View File

@ -268,14 +268,14 @@ namespace BizHawk.Client.Common
public string CreateDisplayValueForButton(IController adapter, string buttonName)
{
if (adapter.Type.BoolButtons.Contains(buttonName))
if (adapter.Definition.BoolButtons.Contains(buttonName))
{
return adapter.IsPressed(buttonName) ?
Mnemonics[buttonName].ToString() :
string.Empty;
}
if (adapter.Type.FloatControls.Contains(buttonName))
if (adapter.Definition.FloatControls.Contains(buttonName))
{
return adapter.GetFloat(buttonName).ToString();
}
@ -543,7 +543,9 @@ namespace BizHawk.Client.Common
StateManager.SetState(branch.Frame, branch.CoreData);
//ChangeLog = branch.ChangeLog;
Markers = branch.Markers;
if (BindMarkersToInput) // pretty critical not to erase them
Markers = branch.Markers;
Changes = true;
}

View File

@ -282,6 +282,11 @@ namespace BizHawk.Client.Common
.FirstOrDefault();
}
public int FindIndex(string markerName)
{
return this.FindIndex(m => m.Message == markerName);
}
public bool IsMarker(int frame)
{
return this.Any(m => m == frame);

View File

@ -773,7 +773,7 @@ namespace BizHawk.Client.Common
}
// Check if there are any branch states for the given frame.
if (!BranchStates.ContainsKey(frame) || BranchStates[frame] == null)
if (!BranchStates.ContainsKey(frame) || BranchStates[frame] == null || branchHash == -1)
return -2;
// Loop through branch states for the given frame.

View File

@ -524,20 +524,28 @@ namespace BizHawk.Client.Common
_history.Clear();
}
public void Undo()
public int Undo()
{
int origCount = _watchList.Count;
if (_keepHistory)
{
_watchList = _history.Undo().ToList();
return _watchList.Count - origCount;
}
return _watchList.Count;
}
public void Redo()
public int Redo()
{
int origCount = _watchList.Count;
if (_keepHistory)
{
_watchList = _history.Redo().ToList();
return origCount - _watchList.Count;
}
return _watchList.Count;
}
#endregion

View File

@ -17,8 +17,14 @@ namespace BizHawk.Client.EmuHawk
private long _soundRemainder; // audio timekeeping for video dumping
public void DumpAV(IVideoProvider v, ISoundProvider s, out short[] samples, out int samplesprovided)
public void DumpAV(IVideoProvider v, ISoundProvider asyncSoundProvider, out short[] samples, out int samplesprovided)
{
// Sound refactor TODO: we could try set it here, but we want the client to be responsible for mode switching? There may be non-trivial complications with when to switch modes that we don't want this object worrying about
if (asyncSoundProvider.SyncMode != SyncSoundMode.Async)
{
throw new InvalidOperationException("Only async mode is supported, set async mode before passing in the sound provider");
}
if (!aset || !vset)
throw new InvalidOperationException("Must set params first!");
@ -29,7 +35,7 @@ namespace BizHawk.Client.EmuHawk
_soundRemainder = nsampnum % fpsnum;
samples = new short[nsamp * channels];
s.GetSamples(samples);
asyncSoundProvider.GetSamplesAsync(samples);
samplesprovided = (int)nsamp;
w.AddFrame(v);
@ -73,10 +79,16 @@ namespace BizHawk.Client.EmuHawk
}
}
public void DumpAV(IVideoProvider v, ISyncSoundProvider s, out short[] samples, out int samplesprovided)
public void DumpAV(IVideoProvider v, ISoundProvider syncSoundProvider, out short[] samples, out int samplesprovided)
{
// Sound refactor TODO: we could just set it here, but we want the client to be responsible for mode switching? There may be non-trivial complications with when to switch modes that we don't want this object worrying about
if (syncSoundProvider.SyncMode != SyncSoundMode.Sync)
{
throw new InvalidOperationException("Only sync mode is supported, set sync mode before passing in the sound provider");
}
VerifyParams();
s.GetSamples(out samples, out samplesprovided);
syncSoundProvider.GetSamplesSync(out samples, out samplesprovided);
exaudio_num += samplesprovided * (long)fpsnum;
// todo: scan for duplicate frames (ie, video content exactly matches previous frame) and for them, skip the threshone step

View File

@ -367,6 +367,12 @@
<Compile Include="config\InputWidget.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="config\INTV\IntvControllerSettings.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="config\INTV\IntvControllerSettings.Designer.cs">
<DependentUpon>IntvControllerSettings.cs</DependentUpon>
</Compile>
<Compile Include="config\MessageConfig.cs">
<SubType>Form</SubType>
</Compile>
@ -711,11 +717,14 @@
<Compile Include="RomStatusPicker.Designer.cs">
<DependentUpon>RomStatusPicker.cs</DependentUpon>
</Compile>
<Compile Include="Sound\Interfaces\IBufferedSoundProvider.cs" />
<Compile Include="Sound\Interfaces\ISoundOutput.cs" />
<Compile Include="Sound\Output\DirectSoundSoundOutput.cs" />
<Compile Include="Sound\Output\DummySoundOutput.cs" />
<Compile Include="Sound\Output\OpenALSoundOutput.cs" />
<Compile Include="Sound\Output\XAudio2SoundOutput.cs" />
<Compile Include="Sound\Sound.cs" />
<Compile Include="Sound\Utilities\BufferedAsync.cs" />
<Compile Include="Sound\Utilities\SoundOutputProvider.cs" />
<Compile Include="Throttle.cs" />
<Compile Include="ToolAttributes.cs" />
@ -1073,12 +1082,7 @@
<Compile Include="tools\TAStudio\PatternsForm.Designer.cs">
<DependentUpon>PatternsForm.cs</DependentUpon>
</Compile>
<Compile Include="tools\TAStudio\ScreenshotPopupControl.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Include="tools\TAStudio\ScreenshotPopupControl.Designer.cs">
<DependentUpon>ScreenshotPopupControl.cs</DependentUpon>
</Compile>
<Compile Include="tools\TAStudio\ScreenshotPopup.cs" />
<Compile Include="tools\TAStudio\TAStudio.Callbacks.cs">
<DependentUpon>TAStudio.cs</DependentUpon>
<SubType>Form</SubType>
@ -1184,6 +1188,7 @@
<Compile Include="tools\VirtualPads\schema\GBASchema.cs" />
<Compile Include="tools\VirtualPads\schema\GBSchema.cs" />
<Compile Include="tools\VirtualPads\schema\GenSchema.cs" />
<Compile Include="tools\VirtualPads\schema\IntvSchema.cs" />
<Compile Include="tools\VirtualPads\schema\LynxSchema.cs" />
<Compile Include="tools\VirtualPads\schema\PSXSchema.cs" />
<Compile Include="tools\VirtualPads\schema\SatSchema.cs" />
@ -1315,6 +1320,9 @@
<EmbeddedResource Include="config\InputCompositeWidget.resx">
<DependentUpon>InputCompositeWidget.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="config\INTV\IntvControllerSettings.resx">
<DependentUpon>IntvControllerSettings.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="config\N64\N64ControllerSettingControl.resx">
<DependentUpon>N64ControllerSettingControl.cs</DependentUpon>
</EmbeddedResource>
@ -1566,6 +1574,7 @@
</EmbeddedResource>
<EmbeddedResource Include="tools\TAStudio\BookmarksBranchesBox.resx">
<DependentUpon>BookmarksBranchesBox.cs</DependentUpon>
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="tools\TAStudio\DefaultGreenzoneSettings.resx">
<DependentUpon>DefaultGreenzoneSettings.cs</DependentUpon>
@ -1588,9 +1597,6 @@
<EmbeddedResource Include="tools\TAStudio\PlaybackBox.resx">
<DependentUpon>PlaybackBox.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="tools\TAStudio\ScreenshotPopupControl.resx">
<DependentUpon>ScreenshotPopupControl.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="tools\TAStudio\TAStudio.resx">
<DependentUpon>TAStudio.cs</DependentUpon>
</EmbeddedResource>
@ -1767,6 +1773,16 @@
<None Include="config\ControllerImages\GENController.png" />
</ItemGroup>
<ItemGroup>
<None Include="images\WSW.png" />
<None Include="images\WNW.png" />
<None Include="images\SW.png" />
<None Include="images\SSW.png" />
<None Include="images\SSE.png" />
<None Include="images\SE.png" />
<None Include="images\NW.png" />
<None Include="images\NNW.png" />
<None Include="images\NNE.png" />
<None Include="images\NE.png" />
<None Include="images\Shark.ico" />
<None Include="images\Shark.png" />
<None Include="images\ScrollTo.png" />
@ -2081,6 +2097,9 @@
<None Include="images\cdlogger.ico" />
<None Include="images\AddEdit.png" />
<None Include="images\JumpTo.png" />
<None Include="images\ENE.png" />
<None Include="images\ESE.png" />
<None Include="images\5757344.png" />
<Content Include="images\logo.ico" />
<None Include="images\Paste.png" />
<None Include="images\reboot.png" />

View File

@ -37,12 +37,8 @@ namespace BizHawk.Client.EmuHawk
// Hiding lag frames (Mainly intended for < 60fps play.)
public int LagFramesToHide { get; set; }
public bool HideWasLagFrames { get; set; }
private byte[] lagFrames = new byte[100]; // Large enough value that it shouldn't ever need resizing.
private byte[] lagFrames = new byte[256]; // Large enough value that it shouldn't ever need resizing. // apparently not large enough for 4K
public bool denoteStatesWithIcons { get; set; }
public bool denoteStatesWithBGColor { get; set; }
public bool denoteMarkersWithIcons { get; set; }
public bool denoteMarkersWithBGColor { get; set; }
public bool allowRightClickSelecton { get; set; }
public bool letKeysModifySelection { get; set; }
public bool suspendHotkeys { get; set; }
@ -618,6 +614,7 @@ namespace BizHawk.Client.EmuHawk
{
var rollSettings = settings as InputRollSettings;
_columns = rollSettings.Columns;
_columns.ChangedCallback = ColumnChangedCallback;
HorizontalOrientation = rollSettings.HorizontalOrientation;
LagFramesToHide = rollSettings.LagFramesToHide;
HideWasLagFrames = rollSettings.HideWasLagFrames;
@ -1155,19 +1152,14 @@ namespace BizHawk.Client.EmuHawk
var hadIndex = SelectedItems.Any();
SelectedItems.Clear();
SelectCell(CurrentCell);
// In this case the SelectCell did not invoke the change event since there was nothing to select
// But we went from selected to unselected, that is a change, so catch it here
if (hadIndex && CurrentCell.RowIndex.HasValue && CurrentCell.RowIndex > RowCount)
{
if (SelectedIndexChanged != null)
{
SelectedIndexChanged(this, new EventArgs());
}
}
}
Refresh();
if (SelectedIndexChanged != null)
{
SelectedIndexChanged(this, new EventArgs());
}
}
}
@ -1682,11 +1674,6 @@ namespace BizHawk.Client.EmuHawk
SelectedItems.Add(CurrentCell);
}
}
if (SelectedIndexChanged != null)
{
SelectedIndexChanged(this, new EventArgs());
}
}
}
@ -2021,10 +2008,11 @@ namespace BizHawk.Client.EmuHawk
private void DoChangeCallback()
{
if (ChangedCallback != null)
{
// no check will make it crash for user too, not sure which way of alarm we prefer. no alarm at all will cause all sorts of subtle bugs
if (ChangedCallback == null)
System.Diagnostics.Debug.Fail("ColumnChangedCallback has died!");
else
ChangedCallback();
}
}
// TODO: this shouldn't be exposed. But in order to not expose it, each RollColumn must have a change callback, and all property changes must call it, it is quicker and easier to just call this when needed

View File

@ -333,7 +333,7 @@ namespace BizHawk.Client.EmuHawk
}
/// <summary>
/// Using the current filter program, turn a emulator screen space coordinat to a window coordinate (suitable for lua layer drawing)
/// Using the current filter program, turn a emulator screen space coordinate to a window coordinate (suitable for lua layer drawing)
/// </summary>
public Point TransformPoint(Point p)
{

View File

@ -157,9 +157,14 @@ namespace BizHawk.Client.EmuHawk.WinFormExtensions
/// <summary>
/// Handles EmuHawk specific issues before showing a modal dialog
/// </summary>
public static DialogResult ShowHawkDialog(this Form form, IWin32Window owner = null)
public static DialogResult ShowHawkDialog(this Form form, IWin32Window owner = null, Point position = default(Point))
{
GlobalWin.Sound.StopSound();
if (position != default(Point))
{
form.StartPosition = FormStartPosition.Manual;
form.Location = position;
}
var result = (owner == null ? form.ShowDialog() : form.ShowDialog(owner));
GlobalWin.Sound.StartSound();
return result;

View File

@ -21,46 +21,46 @@ namespace BizHawk.Client.EmuHawk.CoreExtensions
{
public static Bitmap Icon(this IEmulator core)
{
var attributes = Global.Emulator.Attributes();
var attributes = core.Attributes();
if (!attributes.Ported)
{
return Properties.Resources.CorpHawkSmall;
}
if (Global.Emulator is QuickNES)
if (core is QuickNES)
{
return Properties.Resources.QuickNes;
}
else if (Global.Emulator is LibsnesCore)
else if (core is LibsnesCore)
{
return Properties.Resources.bsnes;
}
else if (Global.Emulator is Yabause)
else if (core is Yabause)
{
return Properties.Resources.yabause;
}
else if (Global.Emulator is Atari7800)
else if (core is Atari7800)
{
return Properties.Resources.emu7800;
}
else if (Global.Emulator is GBA)
else if (core is GBA)
{
return Properties.Resources.meteor;
}
else if (Global.Emulator is GPGX)
else if (core is GPGX)
{
return Properties.Resources.genplus;
}
else if (Global.Emulator is PSP)
else if (core is PSP)
{
return Properties.Resources.ppsspp;
}
else if (Global.Emulator is Gameboy)
else if (core is Gameboy)
{
return Properties.Resources.gambatte;
}
else if (Global.Emulator is Snes9x)
else if (core is Snes9x)
{
return Properties.Resources.snes9x;
}
@ -72,14 +72,14 @@ namespace BizHawk.Client.EmuHawk.CoreExtensions
public static string DisplayName(this IEmulator core)
{
var attributes = Global.Emulator.Attributes();
var attributes = core.Attributes();
var str = (!attributes.Released ? "(Experimental) " : string.Empty) +
attributes.CoreName;
if (Global.Emulator is LibsnesCore)
if (core is LibsnesCore)
{
str += " (" + ((LibsnesCore)Global.Emulator).CurrentProfile + ")";
str += " (" + ((LibsnesCore)core).CurrentProfile + ")";
}
return str;

View File

@ -5,11 +5,10 @@ using System.IO;
using System.Text;
using System.Windows.Forms;
using BizHawk.Common;
using BizHawk.Client.Common;
using BizHawk.Emulation.Common;
using BizHawk.Common.ReflectionExtensions;
using BizHawk.Emulation.Common;
using BizHawk.Emulation.Common.IEmulatorExtensions;
using BizHawk.Client.Common;
//todo - perks - pause, copy to clipboard, backlog length limiting
@ -138,7 +137,7 @@ namespace BizHawk.Client.EmuHawk
private void HideShowGameDbButton()
{
AddToGameDbBtn.Visible = Global.Emulator.HasExposedMethod("GenerateGameDbEntry")
AddToGameDbBtn.Visible = Global.Emulator.CanGenerateGameDBEntries()
&& (Global.Game.Status == RomStatus.Unknown || Global.Game.Status == RomStatus.NotInDatabase);
}
@ -148,10 +147,10 @@ namespace BizHawk.Client.EmuHawk
var result = picker.ShowDialog();
if (result == DialogResult.OK)
{
var entryObj = (CompactGameInfo)Global.Emulator.InvokeMethod("GenerateGameDbEntry", null);
var gameDbEntry = Global.Emulator.AsGameDBEntryGenerator().GenerateGameDbEntry();
var userDb = Path.Combine(PathManager.GetExeDirectoryAbsolute(), "gamedb", "gamedb_user.txt");
Global.Game.Status = entryObj.Status = picker.PickedStatus;
Database.SaveDatabaseEntry(userDb, entryObj);
Global.Game.Status = gameDbEntry.Status = picker.PickedStatus;
Database.SaveDatabaseEntry(userDb, gameDbEntry);
GlobalWin.MainForm.UpdateDumpIcon();
HideShowGameDbButton();
}

File diff suppressed because it is too large Load Diff

View File

@ -35,17 +35,17 @@ namespace BizHawk.Client.EmuHawk
SaveStateSubMenu.Enabled =
LoadStateSubMenu.Enabled =
SaveSlotSubMenu.Enabled =
Global.Emulator.HasSavestates();
Emulator.HasSavestates();
OpenRomMenuItem.ShortcutKeyDisplayString = Global.Config.HotkeyBindings["Open ROM"].Bindings;
CloseRomMenuItem.ShortcutKeyDisplayString = Global.Config.HotkeyBindings["Close ROM"].Bindings;
MovieSubMenu.Enabled =
CloseRomMenuItem.Enabled =
!Global.Emulator.IsNull();
!Emulator.IsNull();
var hasSaveRam = Global.Emulator.HasSaveRam();
bool needBold = hasSaveRam && Global.Emulator.AsSaveRam().SaveRamModified;
var hasSaveRam = Emulator.HasSaveRam();
bool needBold = hasSaveRam && Emulator.AsSaveRam().SaveRamModified;
SaveRAMSubMenu.Enabled = hasSaveRam;
if (SaveRAMSubMenu.Font.Bold != needBold)
@ -53,6 +53,10 @@ namespace BizHawk.Client.EmuHawk
var font = new System.Drawing.Font(SaveRAMSubMenu.Font, needBold ? FontStyle.Bold : FontStyle.Regular);
SaveRAMSubMenu.Font = font;
}
AVSubMenu.Enabled =
ScreenshotSubMenu.Enabled =
Emulator.HasVideoProvider();
}
private void RecentRomMenuItem_DropDownOpened(object sender, EventArgs e)
@ -338,7 +342,7 @@ namespace BizHawk.Client.EmuHawk
//CLONE OF CODE FROM OpenRom (mostly)
var ofd = new OpenFileDialog
{
InitialDirectory = PathManager.GetRomsPath(Global.Emulator.SystemId),
InitialDirectory = PathManager.GetRomsPath(Emulator.SystemId),
Filter = filter,
RestoreDirectory = false,
FilterIndex = _lastOpenRomFilter,
@ -447,7 +451,7 @@ namespace BizHawk.Client.EmuHawk
private void RecordMovieMenuItem_Click(object sender, EventArgs e)
{
if (!Global.Emulator.Attributes().Released)
if (!Emulator.Attributes().Released)
{
var result = MessageBox.Show
(this, "Thanks for using Bizhawk! The emulation core you have selected " +
@ -460,9 +464,9 @@ namespace BizHawk.Client.EmuHawk
return;
}
}
else if (Global.Emulator is LibsnesCore)
else if (Emulator is LibsnesCore)
{
var snes = (LibsnesCore)Global.Emulator;
var snes = (LibsnesCore)Emulator;
if (snes.CurrentProfile == "Performance")
{
var box = new MsgBox(
@ -491,7 +495,7 @@ namespace BizHawk.Client.EmuHawk
}
}
new RecordMovie().ShowDialog();
new RecordMovie(Emulator).ShowDialog();
}
private void PlayMovieMenuItem_Click(object sender, EventArgs e)
@ -513,7 +517,7 @@ namespace BizHawk.Client.EmuHawk
{
var ofd = new OpenFileDialog
{
InitialDirectory = PathManager.GetRomsPath(Global.Emulator.SystemId),
InitialDirectory = PathManager.GetRomsPath(Emulator.SystemId),
Multiselect = true,
Filter = FormatFilter(
"Movie Files", "*.fm2;*.mc2;*.mcm;*.mmv;*.gmv;*.vbm;*.lsmv;*.fcm;*.fmv;*.vmv;*.nmv;*.smv;*.ymv;*.zmv;*.bkm;*.pjm;*.pxm",
@ -701,10 +705,10 @@ namespace BizHawk.Client.EmuHawk
{
PauseMenuItem.Checked = _didMenuPause ? _wasPaused : EmulatorPaused;
SoftResetMenuItem.Enabled = Global.Emulator.ControllerDefinition.BoolButtons.Contains("Reset") &&
SoftResetMenuItem.Enabled = Emulator.ControllerDefinition.BoolButtons.Contains("Reset") &&
(!Global.MovieSession.Movie.IsPlaying || Global.MovieSession.Movie.IsFinished);
HardResetMenuItem.Enabled = Global.Emulator.ControllerDefinition.BoolButtons.Contains("Power") &&
HardResetMenuItem.Enabled = Emulator.ControllerDefinition.BoolButtons.Contains("Power") &&
(!Global.MovieSession.Movie.IsPlaying || Global.MovieSession.Movie.IsFinished);
PauseMenuItem.ShortcutKeyDisplayString = Global.Config.HotkeyBindings["Pause"].Bindings;
@ -766,7 +770,7 @@ namespace BizHawk.Client.EmuHawk
DisplayStatusBarMenuItem.Checked = Global.Config.DispChrome_StatusBarWindowed;
DisplayLogWindowMenuItem.Checked = Global.Config.ShowLogWindow;
DisplayLagCounterMenuItem.Enabled = Global.Emulator.CanPollInput();
DisplayLagCounterMenuItem.Enabled = Emulator.CanPollInput();
DisplayMessagesMenuItem.Checked = Global.Config.DisplayMessages;
}
@ -779,7 +783,7 @@ namespace BizHawk.Client.EmuHawk
x4MenuItem.Checked =
x5MenuItem.Checked = false;
switch (Global.Config.TargetZoomFactors[Global.Emulator.SystemId])
switch (Global.Config.TargetZoomFactors[Emulator.SystemId])
{
case 1: x1MenuItem.Checked = true; break;
case 2: x2MenuItem.Checked = true; break;
@ -792,12 +796,12 @@ namespace BizHawk.Client.EmuHawk
private void WindowSize_Click(object sender, EventArgs e)
{
if (sender == x1MenuItem) Global.Config.TargetZoomFactors[Global.Emulator.SystemId] = 1;
if (sender == x2MenuItem) Global.Config.TargetZoomFactors[Global.Emulator.SystemId] = 2;
if (sender == x3MenuItem) Global.Config.TargetZoomFactors[Global.Emulator.SystemId] = 3;
if (sender == x4MenuItem) Global.Config.TargetZoomFactors[Global.Emulator.SystemId] = 4;
if (sender == x5MenuItem) Global.Config.TargetZoomFactors[Global.Emulator.SystemId] = 5;
if (sender == mzMenuItem) Global.Config.TargetZoomFactors[Global.Emulator.SystemId] = 10;
if (sender == x1MenuItem) Global.Config.TargetZoomFactors[Emulator.SystemId] = 1;
if (sender == x2MenuItem) Global.Config.TargetZoomFactors[Emulator.SystemId] = 2;
if (sender == x3MenuItem) Global.Config.TargetZoomFactors[Emulator.SystemId] = 3;
if (sender == x4MenuItem) Global.Config.TargetZoomFactors[Emulator.SystemId] = 4;
if (sender == x5MenuItem) Global.Config.TargetZoomFactors[Emulator.SystemId] = 5;
if (sender == mzMenuItem) Global.Config.TargetZoomFactors[Emulator.SystemId] = 10;
FrameBufferResized();
}
@ -873,8 +877,8 @@ namespace BizHawk.Client.EmuHawk
private void ConfigSubMenu_DropDownOpened(object sender, EventArgs e)
{
ControllersMenuItem.Enabled = Global.Emulator.ControllerDefinition.Any();
RewindOptionsMenuItem.Enabled = Global.Emulator.HasSavestates();
ControllersMenuItem.Enabled = Emulator.ControllerDefinition.Any();
RewindOptionsMenuItem.Enabled = Emulator.HasSavestates();
}
private void FrameSkipMenuItem_DropDownOpened(object sender, EventArgs e)
@ -947,7 +951,7 @@ namespace BizHawk.Client.EmuHawk
private void ControllersMenuItem_Click(object sender, EventArgs e)
{
var controller = new ControllerConfig(Global.Emulator.ControllerDefinition);
var controller = new ControllerConfig(Emulator.ControllerDefinition);
if (controller.ShowDialog() == DialogResult.OK)
{
InitControls();
@ -1152,7 +1156,7 @@ namespace BizHawk.Client.EmuHawk
{
Global.Config.GB_AsSGB ^= true;
if (!Global.Emulator.IsNull())
if (!Emulator.IsNull())
{
FlagNeedsReboot();
}
@ -1162,7 +1166,7 @@ namespace BizHawk.Client.EmuHawk
{
Global.Config.NES_InQuickNES ^= true;
if (!Global.Emulator.IsNull())
if (!Emulator.IsNull())
{
FlagNeedsReboot();
}
@ -1181,7 +1185,12 @@ namespace BizHawk.Client.EmuHawk
Coresnes9xMenuItem.Checked = Global.Config.SNES_InSnes9x;
Coresnes9xMenuItem.Visible = VersionInfo.DeveloperBuild;
var sss = (LibsnesCore.SnesSyncSettings)Global.Config.GetCoreSyncSettings<LibsnesCore>();
LibsnesCore.SnesSyncSettings sss = (LibsnesCore.SnesSyncSettings)Global.Config.GetCoreSyncSettings<LibsnesCore>();
if (sss == null)
{
sss = new LibsnesCore.SnesSyncSettings();
}
CorebsnesPerformanceMenuItem.Checked = sss.Profile == "Performance";
CorebsnesCompatibilityMenuItem.Checked = sss.Profile == "Compatibility";
}
@ -1199,7 +1208,7 @@ namespace BizHawk.Client.EmuHawk
sss.Profile = "Performance";
Global.Config.PutCoreSyncSettings<LibsnesCore>(sss);
if (Global.Emulator is LibsnesCore && orig != sss.Profile)
if (Emulator is LibsnesCore && orig != sss.Profile)
{
FlagNeedsReboot();
}
@ -1218,7 +1227,7 @@ namespace BizHawk.Client.EmuHawk
sss.Profile = "Compatibility";
Global.Config.PutCoreSyncSettings<LibsnesCore>(sss);
if (Global.Emulator is LibsnesCore && orig != sss.Profile)
if (Emulator is LibsnesCore && orig != sss.Profile)
{
FlagNeedsReboot();
}
@ -1228,7 +1237,7 @@ namespace BizHawk.Client.EmuHawk
{
Global.Config.SNES_InSnes9x ^= true;
if (Global.Emulator is Snes9x || Global.Emulator is LibsnesCore)
if (Emulator is Snes9x || Emulator is LibsnesCore)
{
FlagNeedsReboot();
}
@ -1430,7 +1439,7 @@ namespace BizHawk.Client.EmuHawk
private void TAStudioMenuItem_Click(object sender, EventArgs e)
{
if (!Global.Emulator.CanPollInput())
if (!Emulator.CanPollInput())
{
MessageBox.Show("Current core does not support input polling. TAStudio can't be used.");
return;
@ -1486,25 +1495,26 @@ namespace BizHawk.Client.EmuHawk
private void NESSubMenu_DropDownOpened(object sender, EventArgs e)
{
FDSControlsMenuItem.Enabled = Global.Emulator.BoardName == "FDS";
FDSControlsMenuItem.Enabled = Emulator.BoardName == "FDS";
VSControlsMenuItem.Enabled = (Global.Emulator is NES) && (Global.Emulator as NES).IsVS;
VSControlsMenuItem.Enabled =
VSSettingsMenuItem.Enabled =
((Emulator is NES) && (Emulator as NES).IsVS);
NESSoundChannelsMenuItem.Enabled = GlobalWin.Tools.IsAvailable<NESSoundConfig>();
MovieSettingsMenuItem.Enabled = Global.Emulator is NES && !Global.MovieSession.Movie.IsActive;
MovieSettingsMenuItem.Enabled = Emulator is NES && !Global.MovieSession.Movie.IsActive;
NesControllerSettingsMenuItem.Enabled = GlobalWin.Tools.IsAvailable<NesControllerSettings>()
&& !Global.MovieSession.Movie.IsActive;
barcodeReaderToolStripMenuItem.Enabled = ServiceInjector.IsAvailable(Global.Emulator.ServiceProvider, typeof(BarcodeEntry));
barcodeReaderToolStripMenuItem.Enabled = ServiceInjector.IsAvailable(Emulator.ServiceProvider, typeof(BarcodeEntry));
musicRipperToolStripMenuItem.Enabled = GlobalWin.Tools.IsAvailable<NESMusicRipper>();
}
private void FdsControlsMenuItem_DropDownOpened(object sender, EventArgs e)
{
FdsEjectDiskMenuItem.Enabled = Global.Emulator.BoardName == "FDS";
FdsEjectDiskMenuItem.Enabled = Emulator.BoardName == "FDS";
while (FDSControlsMenuItem.DropDownItems.Count > 1)
{
@ -1514,7 +1524,7 @@ namespace BizHawk.Client.EmuHawk
for (int i = 0; i < 16; i++)
{
var str = "FDS Insert " + i;
if (Global.Emulator.ControllerDefinition.BoolButtons.Contains(str))
if (Emulator.ControllerDefinition.BoolButtons.Contains(str))
{
FdsInsertDiskMenuAdd("Insert Disk " + i, str, "FDS Disk " + i + " inserted.");
}
@ -1543,9 +1553,9 @@ namespace BizHawk.Client.EmuHawk
private void NESGraphicSettingsMenuItem_Click(object sender, EventArgs e)
{
if (Global.Emulator is NES)
if (Emulator is NES)
new NESGraphicsConfig().ShowDialog(this);
else if (Global.Emulator is QuickNES)
else if (Emulator is QuickNES)
new QuickNesConfig().ShowDialog(this);
}
@ -1556,7 +1566,10 @@ namespace BizHawk.Client.EmuHawk
private void VSSettingsMenuItem_Click(object sender, EventArgs e)
{
new NESVSSettings().ShowHawkDialog();
if (Emulator is NES && (Emulator as NES).IsVS)
{
new NESVSSettings().ShowHawkDialog();
}
}
private void FdsEjectDiskMenuItem_Click(object sender, EventArgs e)
@ -1570,7 +1583,7 @@ namespace BizHawk.Client.EmuHawk
private void VSInsertCoinP1MenuItem_Click(object sender, EventArgs e)
{
if (Global.Emulator is NES && (Global.Emulator as NES).IsVS)
if (Emulator is NES && (Emulator as NES).IsVS)
{
if (!Global.MovieSession.Movie.IsPlaying || Global.MovieSession.Movie.IsFinished)
{
@ -1582,7 +1595,7 @@ namespace BizHawk.Client.EmuHawk
private void VSInsertCoinP2MenuItem_Click(object sender, EventArgs e)
{
if (Global.Emulator is NES && (Global.Emulator as NES).IsVS)
if (Emulator is NES && (Emulator as NES).IsVS)
{
if (!Global.MovieSession.Movie.IsPlaying || Global.MovieSession.Movie.IsFinished)
{
@ -1594,7 +1607,7 @@ namespace BizHawk.Client.EmuHawk
private void VSServiceSwitchMenuItem_Click(object sender, EventArgs e)
{
if (Global.Emulator is NES && (Global.Emulator as NES).IsVS)
if (Emulator is NES && (Emulator as NES).IsVS)
{
if (!Global.MovieSession.Movie.IsPlaying || Global.MovieSession.Movie.IsFinished)
{
@ -1606,9 +1619,9 @@ namespace BizHawk.Client.EmuHawk
private void NesControllerSettingsMenuItem_Click(object sender, EventArgs e)
{
if (Global.Emulator is NES)
if (Emulator is NES)
new NesControllerSettings().ShowDialog();
else if (Global.Emulator is QuickNES)
else if (Emulator is QuickNES)
GenericCoreConfig.DoDialog(this, "QuickNES Controller Settings", true, false);
}
@ -1631,7 +1644,7 @@ namespace BizHawk.Client.EmuHawk
private void PCESubMenu_DropDownOpened(object sender, EventArgs e)
{
var s = ((PCEngine)Global.Emulator).GetSettings();
var s = ((PCEngine)Emulator).GetSettings();
PceControllerSettingsMenuItem.Enabled = !Global.MovieSession.Movie.IsActive;
@ -1675,21 +1688,21 @@ namespace BizHawk.Client.EmuHawk
private void PCEAlwaysPerformSpriteLimitMenuItem_Click(object sender, EventArgs e)
{
var s = ((PCEngine)Global.Emulator).GetSettings();
var s = ((PCEngine)Emulator).GetSettings();
s.SpriteLimit ^= true;
PutCoreSettings(s);
}
private void PCEAlwaysEqualizeVolumesMenuItem_Click(object sender, EventArgs e)
{
var s = ((PCEngine)Global.Emulator).GetSettings();
var s = ((PCEngine)Emulator).GetSettings();
s.EqualizeVolume ^= true;
PutCoreSettings(s);
}
private void PCEArcadeCardRewindEnableMenuItem_Click(object sender, EventArgs e)
{
var s = ((PCEngine)Global.Emulator).GetSettings();
var s = ((PCEngine)Emulator).GetSettings();
s.ArcadeCardRewindHack ^= true;
PutCoreSettings(s);
}
@ -1700,8 +1713,8 @@ namespace BizHawk.Client.EmuHawk
private void SMSSubMenu_DropDownOpened(object sender, EventArgs e)
{
var s = ((SMS)Global.Emulator).GetSettings();
var ss = ((SMS)Global.Emulator).GetSyncSettings();
var s = ((SMS)Emulator).GetSettings();
var ss = ((SMS)Emulator).GetSyncSettings();
SMSregionExportToolStripMenuItem.Checked = ss.ConsoleRegion == "Export";
SMSregionJapanToolStripMenuItem.Checked = ss.ConsoleRegion == "Japan";
SMSregionAutoToolStripMenuItem.Checked = ss.ConsoleRegion == "Auto";
@ -1742,105 +1755,105 @@ namespace BizHawk.Client.EmuHawk
private void SMS_RegionExport_Click(object sender, EventArgs e)
{
var ss = ((SMS)Global.Emulator).GetSyncSettings();
var ss = ((SMS)Emulator).GetSyncSettings();
ss.ConsoleRegion = "Export";
PutCoreSyncSettings(ss);
}
private void SMS_RegionJapan_Click(object sender, EventArgs e)
{
var ss = ((SMS)Global.Emulator).GetSyncSettings();
var ss = ((SMS)Emulator).GetSyncSettings();
ss.ConsoleRegion = "Japan";
PutCoreSyncSettings(ss);
}
private void SMS_RegionAuto_Click(object sender, EventArgs e)
{
var ss = ((SMS)Global.Emulator).GetSyncSettings();
var ss = ((SMS)Emulator).GetSyncSettings();
ss.ConsoleRegion = "Auto";
PutCoreSyncSettings(ss);
}
private void SMS_DisplayNTSC_Click(object sender, EventArgs e)
{
var ss = ((SMS)Global.Emulator).GetSyncSettings();
var ss = ((SMS)Emulator).GetSyncSettings();
ss.DisplayType = "NTSC";
PutCoreSyncSettings(ss);
}
private void SMS_DisplayPAL_Click(object sender, EventArgs e)
{
var ss = ((SMS)Global.Emulator).GetSyncSettings();
var ss = ((SMS)Emulator).GetSyncSettings();
ss.DisplayType = "PAL";
PutCoreSyncSettings(ss);
}
private void SMS_DisplayAuto_Click(object sender, EventArgs e)
{
var ss = ((SMS)Global.Emulator).GetSyncSettings();
var ss = ((SMS)Emulator).GetSyncSettings();
ss.DisplayType = "Auto";
PutCoreSyncSettings(ss);
}
private void SMS_BIOS_Click(object sender, EventArgs e)
{
var ss = ((SMS)Global.Emulator).GetSyncSettings();
var ss = ((SMS)Emulator).GetSyncSettings();
ss.UseBIOS ^= true;
PutCoreSyncSettings(ss);
}
private void SMSEnableFMChipMenuItem_Click(object sender, EventArgs e)
{
var ss = ((SMS)Global.Emulator).GetSyncSettings();
var ss = ((SMS)Emulator).GetSyncSettings();
ss.EnableFM ^= true;
PutCoreSyncSettings(ss);
}
private void SMSOverclockMenuItem_Click(object sender, EventArgs e)
{
var ss = ((SMS)Global.Emulator).GetSyncSettings();
var ss = ((SMS)Emulator).GetSyncSettings();
ss.AllowOverlock ^= true;
PutCoreSyncSettings(ss);
}
private void SMSForceStereoMenuItem_Click(object sender, EventArgs e)
{
var s = ((SMS)Global.Emulator).GetSettings();
var s = ((SMS)Emulator).GetSettings();
s.ForceStereoSeparation ^= true;
PutCoreSettings(s);
}
private void SMSSpriteLimitMenuItem_Click(object sender, EventArgs e)
{
var s = ((SMS)Global.Emulator).GetSettings();
var s = ((SMS)Emulator).GetSettings();
s.SpriteLimit ^= true;
PutCoreSettings(s);
}
private void SMSDisplayOverscanMenuItem_Click(object sender, EventArgs e)
{
var s = ((SMS)Global.Emulator).GetSettings();
var s = ((SMS)Emulator).GetSettings();
s.DisplayOverscan ^= true;
PutCoreSettings(s);
}
private void SMSFix3DDisplayMenuItem_Click(object sender, EventArgs e)
{
var s = ((SMS)Global.Emulator).GetSettings();
var s = ((SMS)Emulator).GetSettings();
s.Fix3D ^= true;
PutCoreSettings(s);
}
private void ShowClippedRegionsMenuItem_Click(object sender, EventArgs e)
{
var s = ((SMS)Global.Emulator).GetSettings();
var s = ((SMS)Emulator).GetSettings();
s.ShowClippedRegions ^= true;
PutCoreSettings(s);
}
private void HighlightActiveDisplayRegionMenuItem_Click(object sender, EventArgs e)
{
var s = ((SMS)Global.Emulator).GetSettings();
var s = ((SMS)Emulator).GetSettings();
s.HighlightActiveDisplayRegion ^= true;
PutCoreSettings(s);
}
@ -1883,7 +1896,7 @@ namespace BizHawk.Client.EmuHawk
{
var ofd = new OpenFileDialog
{
InitialDirectory = PathManager.GetRomsPath(Global.Emulator.SystemId),
InitialDirectory = PathManager.GetRomsPath(Emulator.SystemId),
Filter = "TI-83 Program Files (*.83p,*.8xp)|*.83P;*.8xp|All Files|*.*",
RestoreDirectory = true
};
@ -1892,7 +1905,7 @@ namespace BizHawk.Client.EmuHawk
{
try
{
(Global.Emulator as TI83).LinkPort.SendFileToCalc(File.OpenRead(ofd.FileName), true);
(Emulator as TI83).LinkPort.SendFileToCalc(File.OpenRead(ofd.FileName), true);
}
catch (IOException ex)
{
@ -1900,7 +1913,7 @@ namespace BizHawk.Client.EmuHawk
if (MessageBox.Show(Message, "Upload Failed", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question) == DialogResult.Yes)
{
(Global.Emulator as TI83).LinkPort.SendFileToCalc(File.OpenRead(ofd.FileName), false);
(Emulator as TI83).LinkPort.SendFileToCalc(File.OpenRead(ofd.FileName), false);
}
}
}
@ -1948,28 +1961,28 @@ namespace BizHawk.Client.EmuHawk
private void GBForceDMGMenuItem_Click(object sender, EventArgs e)
{
var s = ((Gameboy)Global.Emulator).GetSyncSettings();
var s = ((Gameboy)Emulator).GetSyncSettings();
s.ForceDMG ^= true;
PutCoreSyncSettings(s);
}
private void GBAInCGBModeMenuItem_Click(object sender, EventArgs e)
{
var s = ((Gameboy)Global.Emulator).GetSyncSettings();
var s = ((Gameboy)Emulator).GetSyncSettings();
s.GBACGB ^= true;
PutCoreSyncSettings(s);
}
private void GBMulticartCompatibilityMenuItem_Click(object sender, EventArgs e)
{
var s = ((Gameboy)Global.Emulator).GetSyncSettings();
var s = ((Gameboy)Emulator).GetSyncSettings();
s.MulticartCompat ^= true;
PutCoreSyncSettings(s);
}
private void GBPaletteConfigMenuItem_Click(object sender, EventArgs e)
{
var gb = Global.Emulator as Gameboy;
var gb = Emulator as Gameboy;
if (gb.IsCGBMode())
CGBColorChooserForm.DoCGBColorChooserFormDialog(this);
else
@ -2049,7 +2062,7 @@ namespace BizHawk.Client.EmuHawk
private void SNESSubMenu_DropDownOpened(object sender, EventArgs e)
{
if ((Global.Emulator as LibsnesCore).IsSGB)
if ((Emulator as LibsnesCore).IsSGB)
{
SnesGBInSGBMenuItem.Visible = true;
SnesGBInSGBMenuItem.Checked = Global.Config.GB_AsSGB;
@ -2062,7 +2075,7 @@ namespace BizHawk.Client.EmuHawk
private void SNESDisplayMenuItem_DropDownOpened(object sender, EventArgs e)
{
var s = ((LibsnesCore)Global.Emulator).GetSettings();
var s = ((LibsnesCore)Emulator).GetSettings();
SnesBg1MenuItem.Checked = s.ShowBG1_1;
SnesBg2MenuItem.Checked = s.ShowBG2_1;
@ -2171,13 +2184,13 @@ namespace BizHawk.Client.EmuHawk
private void ColecoSubMenu_DropDownOpened(object sender, EventArgs e)
{
var ss = ((ColecoVision)Global.Emulator).GetSyncSettings();
var ss = ((ColecoVision)Emulator).GetSyncSettings();
ColecoSkipBiosMenuItem.Checked = ss.SkipBiosIntro;
}
private void ColecoSkipBiosMenuItem_Click(object sender, EventArgs e)
{
var ss = ((ColecoVision)Global.Emulator).GetSyncSettings();
var ss = ((ColecoVision)Emulator).GetSyncSettings();
ss.SkipBiosIntro ^= true;
PutCoreSyncSettings(ss);
}
@ -2195,21 +2208,21 @@ namespace BizHawk.Client.EmuHawk
N64CircularAnalogRangeMenuItem.Checked = Global.Config.N64UseCircularAnalogConstraint;
var s = ((N64)Global.Emulator).GetSettings();
var s = ((N64)Emulator).GetSettings();
MupenStyleLagMenuItem.Checked = s.UseMupenStyleLag;
//var ss = (N64SyncSettings)Global.Emulator.GetSyncSettings();
//var ss = (N64SyncSettings)Emulator.GetSyncSettings();
//N64ExpansionSlotMenuItem.Checked = !ss.DisableExpansionSlot;
N64ExpansionSlotMenuItem.Checked = (Global.Emulator as N64).UsingExpansionSlot;
N64ExpansionSlotMenuItem.Enabled = !(Global.Emulator as N64).IsOverridingUserExpansionSlotSetting;
N64ExpansionSlotMenuItem.Checked = (Emulator as N64).UsingExpansionSlot;
N64ExpansionSlotMenuItem.Enabled = !(Emulator as N64).IsOverridingUserExpansionSlotSetting;
}
private void N64PluginSettingsMenuItem_Click(object sender, EventArgs e)
{
if (new N64VideoPluginconfig().ShowDialog() == DialogResult.OK)
{
if (Global.Emulator.IsNull())
if (Emulator.IsNull())
{
GlobalWin.OSD.AddMessage("Plugin settings saved");
}
@ -2244,7 +2257,7 @@ namespace BizHawk.Client.EmuHawk
private void MupenStyleLagMenuItem_Click(object sender, EventArgs e)
{
var n64 = (N64)Global.Emulator;
var n64 = (N64)Emulator;
var s = n64.GetSettings();
s.UseMupenStyleLag ^= true;
n64.PutSettings(s);
@ -2252,7 +2265,7 @@ namespace BizHawk.Client.EmuHawk
private void N64ExpansionSlotMenuItem_Click(object sender, EventArgs e)
{
var n64 = (N64)Global.Emulator;
var n64 = (N64)Emulator;
var ss = n64.GetSyncSettings();
ss.DisableExpansionSlot ^= true;
n64.PutSyncSettings(ss);
@ -2322,9 +2335,9 @@ namespace BizHawk.Client.EmuHawk
private void AppleSubMenu_DropDownOpened(object sender, EventArgs e)
{
if (Global.Emulator is AppleII)
if (Emulator is AppleII)
{
AppleDisksSubMenu.Enabled = (Global.Emulator as AppleII).DiskCount > 1;
AppleDisksSubMenu.Enabled = (Emulator as AppleII).DiskCount > 1;
}
}
@ -2332,9 +2345,9 @@ namespace BizHawk.Client.EmuHawk
{
AppleDisksSubMenu.DropDownItems.Clear();
if (Global.Emulator is AppleII)
if (Emulator is AppleII)
{
var appleII = Global.Emulator as AppleII;
var appleII = Emulator as AppleII;
for (int i = 0; i < appleII.DiskCount; i++)
{
var menuItem = new ToolStripMenuItem
@ -2366,6 +2379,15 @@ namespace BizHawk.Client.EmuHawk
#endregion
#region Intv
private void IntVControllerSettingsMenuItem_Click(object sender, EventArgs e)
{
new IntvControllerSettings().ShowDialog();
}
#endregion
#region Help
private void OnlineHelpMenuItem_Click(object sender, EventArgs e)
@ -2400,7 +2422,7 @@ namespace BizHawk.Client.EmuHawk
_didMenuPause = true;
PauseEmulator();
OpenRomContextMenuItem.Visible = Global.Emulator.IsNull() || _inFullscreen;
OpenRomContextMenuItem.Visible = Emulator.IsNull() || _inFullscreen;
bool showMenuVisible = _inFullscreen;
if (!MainMenuStrip.Visible) showMenuVisible = true; //need to always be able to restore this as an emergency measure
@ -2409,7 +2431,7 @@ namespace BizHawk.Client.EmuHawk
ShowMenuContextMenuSeparator.Visible =
showMenuVisible;
LoadLastRomContextMenuItem.Visible = Global.Emulator.IsNull();
LoadLastRomContextMenuItem.Visible = Emulator.IsNull();
StopAVContextMenuItem.Visible = _currAviWriter != null;
@ -2418,12 +2440,12 @@ namespace BizHawk.Client.EmuHawk
ScreenshotContextMenuItem.Visible =
CloseRomContextMenuItem.Visible =
UndoSavestateContextMenuItem.Visible =
!Global.Emulator.IsNull();
!Emulator.IsNull();
RecordMovieContextMenuItem.Visible =
PlayMovieContextMenuItem.Visible =
LoadLastMovieContextMenuItem.Visible =
!Global.Emulator.IsNull() && !Global.MovieSession.Movie.IsActive;
!Emulator.IsNull() && !Global.MovieSession.Movie.IsActive;
RestartMovieContextMenuItem.Visible =
StopMovieContextMenuItem.Visible =
@ -2437,7 +2459,7 @@ namespace BizHawk.Client.EmuHawk
StopNoSaveContextMenuItem.Visible = Global.MovieSession.Movie.IsActive && Global.MovieSession.Movie.Changes;
AddSubtitleContextMenuItem.Visible = !Global.Emulator.IsNull() && Global.MovieSession.Movie.IsActive && !Global.MovieSession.ReadOnly;
AddSubtitleContextMenuItem.Visible = !Emulator.IsNull() && Global.MovieSession.Movie.IsActive && !Global.MovieSession.ReadOnly;
ConfigContextMenuItem.Visible = _inFullscreen;
@ -2572,7 +2594,7 @@ namespace BizHawk.Client.EmuHawk
for (int x = 0; x < Global.MovieSession.Movie.Subtitles.Count; x++)
{
sub = Global.MovieSession.Movie.Subtitles[x];
if (Global.Emulator.Frame == sub.Frame)
if (Emulator.Frame == sub.Frame)
{
index = x;
break;
@ -2581,7 +2603,7 @@ namespace BizHawk.Client.EmuHawk
if (index < 0)
{
sub = new Subtitle { Frame = Global.Emulator.Frame };
sub = new Subtitle { Frame = Emulator.Frame };
}
subForm.Sub = sub;
@ -2636,7 +2658,7 @@ namespace BizHawk.Client.EmuHawk
private void DumpStatusButton_Click(object sender, EventArgs e)
{
string details = Global.Emulator.CoreComm.RomStatusDetails;
string details = Emulator.CoreComm.RomStatusDetails;
if (!String.IsNullOrEmpty(details))
{
GlobalWin.Sound.StopSound();
@ -2766,6 +2788,11 @@ namespace BizHawk.Client.EmuHawk
AutohideCursor(false);
}
public void MainForm_MouseWheel(object sender, MouseEventArgs e)
{
MouseWheelTracker += e.Delta;
}
public void MainForm_MouseMove(object sender, MouseEventArgs e)
{
AutohideCursor(false);
@ -2873,12 +2900,12 @@ namespace BizHawk.Client.EmuHawk
}
else if (MovieService.IsValidMovieExtension(ext))
{
if (Global.Emulator.IsNull())
if (Emulator.IsNull())
{
OpenRom();
}
if (Global.Emulator.IsNull())
if (Emulator.IsNull())
{
return;
}
@ -2900,7 +2927,7 @@ namespace BizHawk.Client.EmuHawk
(GlobalWin.Tools.Get<RamWatch>() as RamWatch).LoadWatchFile(new FileInfo(filePaths[0]), false);
}
else if (ext.ToUpper() == ".CDL" && Global.Emulator is PCEngine)
else if (ext.ToUpper() == ".CDL" && Emulator is PCEngine)
{
GlobalWin.Tools.Load<CDL>();
(GlobalWin.Tools.Get<CDL>() as CDL).LoadFile(filePaths[0]);
@ -2908,12 +2935,12 @@ namespace BizHawk.Client.EmuHawk
else if (MovieImport.IsValidMovieExtension(Path.GetExtension(filePaths[0])))
{
if (Global.Emulator.IsNull())
if (Emulator.IsNull())
{
OpenRom();
}
if (Global.Emulator.IsNull())
if (Emulator.IsNull())
{
return;
}

View File

@ -68,7 +68,7 @@ namespace BizHawk.Client.EmuHawk
ToggleFrameCounter();
break;
case "Lag Counter":
if (Global.Emulator.CanPollInput())
if (Emulator.CanPollInput())
{
ToggleLagCounter();
}
@ -115,6 +115,10 @@ namespace BizHawk.Client.EmuHawk
case "Reboot Core":
RebootCore();
break;
case "Toggle Skip Lag Frame":
Global.Config.SkipLagFrame ^= true;
GlobalWin.OSD.AddMessage("Skip Lag Frames toggled " + (Global.Config.SkipLagFrame ? "On" : "Off"));
break;
// Save States
case "Save State 0":
@ -397,6 +401,30 @@ namespace BizHawk.Client.EmuHawk
if (GlobalWin.Tools.IsLoaded<TAStudio>())
GlobalWin.Tools.TAStudio.CloneFramesExternal();
break;
case "Analog Increment":
if (GlobalWin.Tools.IsLoaded<TAStudio>())
GlobalWin.Tools.TAStudio.AnalogIncrementByOne();
break;
case "Analog Decrement":
if (GlobalWin.Tools.IsLoaded<TAStudio>())
GlobalWin.Tools.TAStudio.AnalogDecrementByOne();
break;
case "Analog Incr. by 10":
if (GlobalWin.Tools.IsLoaded<TAStudio>())
GlobalWin.Tools.TAStudio.AnalogIncrementByTen();
break;
case "Analog Decr. by 10":
if (GlobalWin.Tools.IsLoaded<TAStudio>())
GlobalWin.Tools.TAStudio.AnalogDecrementByTen();
break;
case "Analog Maximum":
if (GlobalWin.Tools.IsLoaded<TAStudio>())
GlobalWin.Tools.TAStudio.AnalogMax();
break;
case "Analog Minimum":
if (GlobalWin.Tools.IsLoaded<TAStudio>())
GlobalWin.Tools.TAStudio.AnalogMin();
break;
// SNES
case "Toggle BG 1":

View File

@ -33,11 +33,11 @@ namespace BizHawk.Client.EmuHawk
var tasmovie = (movie as TasMovie);
if (tasmovie != null)
tasmovie.TasStateManager.MountWriteAccess();
Global.MovieSession.QueueNewMovie(movie, record, Global.Emulator);
Global.MovieSession.QueueNewMovie(movie, record, Emulator);
}
catch (MoviePlatformMismatchException ex)
{
MessageBox.Show(this, ex.Message, "Movie/Platform Mismatch", MessageBoxButtons.OK, MessageBoxIcon.Error);
MessageBox.Show(new Form(){TopMost = true}, ex.Message, "Movie/Platform Mismatch", MessageBoxButtons.OK, MessageBoxIcon.Error);
return false;
}
@ -63,31 +63,33 @@ namespace BizHawk.Client.EmuHawk
Global.Config.RecentMovies.Add(movie.Filename);
if (Global.Emulator.HasSavestates() && movie.StartsFromSavestate)
if (Emulator.HasSavestates() && movie.StartsFromSavestate)
{
if (movie.TextSavestate != null)
{
Global.Emulator.AsStatable().LoadStateText(new StringReader(movie.TextSavestate));
Emulator.AsStatable().LoadStateText(new StringReader(movie.TextSavestate));
}
else
{
Global.Emulator.AsStatable().LoadStateBinary(new BinaryReader(new MemoryStream(movie.BinarySavestate, false)));
Emulator.AsStatable().LoadStateBinary(new BinaryReader(new MemoryStream(movie.BinarySavestate, false)));
}
if (movie.SavestateFramebuffer != null)
if (movie.SavestateFramebuffer != null && Emulator.HasVideoProvider())
{
var b1 = movie.SavestateFramebuffer;
var b2 = Global.Emulator.VideoProvider().GetVideoBuffer();
var b2 = Emulator.AsVideoProvider().GetVideoBuffer();
int len = Math.Min(b1.Length, b2.Length);
for (int i = 0; i < len; i++)
{
b2[i] = b1[i];
}
}
Global.Emulator.ResetCounters();
Emulator.ResetCounters();
}
else if (Global.Emulator.HasSaveRam() && movie.StartsFromSaveRam)
else if (Emulator.HasSaveRam() && movie.StartsFromSaveRam)
{
Global.Emulator.AsSaveRam().StoreSaveRam(movie.SaveRam);
Emulator.AsSaveRam().StoreSaveRam(movie.SaveRam);
}
Global.MovieSession.RunQueuedMovie(record);

File diff suppressed because it is too large Load Diff

View File

@ -28,142 +28,143 @@
/// </summary>
private void InitializeComponent()
{
this.label3 = new System.Windows.Forms.Label();
this.label2 = new System.Windows.Forms.Label();
this.btnLibretroLaunchNoGame = new System.Windows.Forms.Button();
this.btnCancel = new System.Windows.Forms.Button();
this.groupBox2 = new System.Windows.Forms.GroupBox();
this.txtLibretroCore = new System.Windows.Forms.TextBox();
this.btnLibretroLaunchGame = new System.Windows.Forms.Button();
this.btnSetLibretroCore = new System.Windows.Forms.Button();
this.groupBox3 = new System.Windows.Forms.GroupBox();
this.btnClassicLaunchGame = new System.Windows.Forms.Button();
this.groupBox2.SuspendLayout();
this.groupBox3.SuspendLayout();
this.SuspendLayout();
//
// label3
//
this.label3.Location = new System.Drawing.Point(6, 25);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(250, 29);
this.label3.TabIndex = 5;
this.label3.Text = "Load a rom with the classic BizHawk autodetection method. But why not just use Op" +
this.label3 = new System.Windows.Forms.Label();
this.label2 = new System.Windows.Forms.Label();
this.btnLibretroLaunchNoGame = new System.Windows.Forms.Button();
this.btnCancel = new System.Windows.Forms.Button();
this.groupBox2 = new System.Windows.Forms.GroupBox();
this.txtLibretroCore = new System.Windows.Forms.TextBox();
this.btnLibretroLaunchGame = new System.Windows.Forms.Button();
this.btnSetLibretroCore = new System.Windows.Forms.Button();
this.groupBox3 = new System.Windows.Forms.GroupBox();
this.btnClassicLaunchGame = new System.Windows.Forms.Button();
this.groupBox2.SuspendLayout();
this.groupBox3.SuspendLayout();
this.SuspendLayout();
//
// label3
//
this.label3.Location = new System.Drawing.Point(6, 25);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(250, 29);
this.label3.TabIndex = 5;
this.label3.Text = "Load a rom with the classic BizHawk autodetection method. But why not just use Op" +
"en Rom?";
//
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(6, 26);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(69, 13);
this.label2.TabIndex = 3;
this.label2.Text = "Current Core:";
//
// btnLibretroLaunchNoGame
//
this.btnLibretroLaunchNoGame.Location = new System.Drawing.Point(217, 50);
this.btnLibretroLaunchNoGame.Name = "btnLibretroLaunchNoGame";
this.btnLibretroLaunchNoGame.Size = new System.Drawing.Size(102, 23);
this.btnLibretroLaunchNoGame.TabIndex = 1;
this.btnLibretroLaunchNoGame.Text = "Launch No Game";
this.btnLibretroLaunchNoGame.UseVisualStyleBackColor = true;
this.btnLibretroLaunchNoGame.Click += new System.EventHandler(this.btnLibretroLaunchNoGame_Click);
//
// btnCancel
//
this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.btnCancel.Location = new System.Drawing.Point(370, 176);
this.btnCancel.Name = "btnCancel";
this.btnCancel.Size = new System.Drawing.Size(75, 23);
this.btnCancel.TabIndex = 2;
this.btnCancel.Text = "Cancel";
this.btnCancel.UseVisualStyleBackColor = true;
this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
//
// groupBox2
//
this.groupBox2.Controls.Add(this.txtLibretroCore);
this.groupBox2.Controls.Add(this.btnLibretroLaunchGame);
this.groupBox2.Controls.Add(this.btnSetLibretroCore);
this.groupBox2.Controls.Add(this.label2);
this.groupBox2.Controls.Add(this.btnLibretroLaunchNoGame);
this.groupBox2.Location = new System.Drawing.Point(12, 12);
this.groupBox2.Name = "groupBox2";
this.groupBox2.Size = new System.Drawing.Size(433, 81);
this.groupBox2.TabIndex = 3;
this.groupBox2.TabStop = false;
this.groupBox2.Text = "Libretro";
//
// txtLibretroCore
//
this.txtLibretroCore.Location = new System.Drawing.Point(81, 23);
this.txtLibretroCore.Name = "txtLibretroCore";
this.txtLibretroCore.ReadOnly = true;
this.txtLibretroCore.Size = new System.Drawing.Size(314, 20);
this.txtLibretroCore.TabIndex = 6;
//
// btnLibretroLaunchGame
//
this.btnLibretroLaunchGame.Location = new System.Drawing.Point(325, 50);
this.btnLibretroLaunchGame.Name = "btnLibretroLaunchGame";
this.btnLibretroLaunchGame.Size = new System.Drawing.Size(102, 23);
this.btnLibretroLaunchGame.TabIndex = 5;
this.btnLibretroLaunchGame.Text = "Launch Game";
this.btnLibretroLaunchGame.UseVisualStyleBackColor = true;
this.btnLibretroLaunchGame.Click += new System.EventHandler(this.btnLibretroLaunchGame_Click);
//
// btnSetLibretroCore
//
this.btnSetLibretroCore.AutoSize = true;
this.btnSetLibretroCore.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.btnSetLibretroCore.Location = new System.Drawing.Point(401, 21);
this.btnSetLibretroCore.Name = "btnSetLibretroCore";
this.btnSetLibretroCore.Size = new System.Drawing.Size(26, 23);
this.btnSetLibretroCore.TabIndex = 4;
this.btnSetLibretroCore.Text = "...";
this.btnSetLibretroCore.UseVisualStyleBackColor = true;
this.btnSetLibretroCore.Click += new System.EventHandler(this.btnSetLibretroCore_Click);
//
// groupBox3
//
this.groupBox3.Controls.Add(this.btnClassicLaunchGame);
this.groupBox3.Controls.Add(this.label3);
this.groupBox3.Location = new System.Drawing.Point(12, 99);
this.groupBox3.Name = "groupBox3";
this.groupBox3.Size = new System.Drawing.Size(277, 100);
this.groupBox3.TabIndex = 6;
this.groupBox3.TabStop = false;
this.groupBox3.Text = "BizHawk Classic";
//
// btnClassicLaunchGame
//
this.btnClassicLaunchGame.Location = new System.Drawing.Point(169, 71);
this.btnClassicLaunchGame.Name = "btnClassicLaunchGame";
this.btnClassicLaunchGame.Size = new System.Drawing.Size(102, 23);
this.btnClassicLaunchGame.TabIndex = 6;
this.btnClassicLaunchGame.Text = "Launch Game";
this.btnClassicLaunchGame.UseVisualStyleBackColor = true;
this.btnClassicLaunchGame.Click += new System.EventHandler(this.btnClassicLaunchGame_Click);
//
// OpenAdvancedChooser
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.CancelButton = this.btnCancel;
this.ClientSize = new System.Drawing.Size(457, 208);
this.Controls.Add(this.groupBox3);
this.Controls.Add(this.groupBox2);
this.Controls.Add(this.btnCancel);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "OpenAdvancedChooser";
this.Text = "Open Advanced";
this.groupBox2.ResumeLayout(false);
this.groupBox2.PerformLayout();
this.groupBox3.ResumeLayout(false);
this.ResumeLayout(false);
//
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(6, 26);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(69, 13);
this.label2.TabIndex = 3;
this.label2.Text = "Current Core:";
//
// btnLibretroLaunchNoGame
//
this.btnLibretroLaunchNoGame.Location = new System.Drawing.Point(217, 50);
this.btnLibretroLaunchNoGame.Name = "btnLibretroLaunchNoGame";
this.btnLibretroLaunchNoGame.Size = new System.Drawing.Size(102, 23);
this.btnLibretroLaunchNoGame.TabIndex = 1;
this.btnLibretroLaunchNoGame.Text = "Launch No Game";
this.btnLibretroLaunchNoGame.UseVisualStyleBackColor = true;
this.btnLibretroLaunchNoGame.Click += new System.EventHandler(this.btnLibretroLaunchNoGame_Click);
//
// btnCancel
//
this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.btnCancel.Location = new System.Drawing.Point(370, 176);
this.btnCancel.Name = "btnCancel";
this.btnCancel.Size = new System.Drawing.Size(75, 23);
this.btnCancel.TabIndex = 2;
this.btnCancel.Text = "Cancel";
this.btnCancel.UseVisualStyleBackColor = true;
this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
//
// groupBox2
//
this.groupBox2.Controls.Add(this.txtLibretroCore);
this.groupBox2.Controls.Add(this.btnLibretroLaunchGame);
this.groupBox2.Controls.Add(this.btnSetLibretroCore);
this.groupBox2.Controls.Add(this.label2);
this.groupBox2.Controls.Add(this.btnLibretroLaunchNoGame);
this.groupBox2.Location = new System.Drawing.Point(12, 12);
this.groupBox2.Name = "groupBox2";
this.groupBox2.Size = new System.Drawing.Size(433, 81);
this.groupBox2.TabIndex = 3;
this.groupBox2.TabStop = false;
this.groupBox2.Text = "Libretro";
//
// txtLibretroCore
//
this.txtLibretroCore.Location = new System.Drawing.Point(81, 23);
this.txtLibretroCore.Name = "txtLibretroCore";
this.txtLibretroCore.ReadOnly = true;
this.txtLibretroCore.Size = new System.Drawing.Size(314, 20);
this.txtLibretroCore.TabIndex = 6;
//
// btnLibretroLaunchGame
//
this.btnLibretroLaunchGame.Location = new System.Drawing.Point(325, 50);
this.btnLibretroLaunchGame.Name = "btnLibretroLaunchGame";
this.btnLibretroLaunchGame.Size = new System.Drawing.Size(102, 23);
this.btnLibretroLaunchGame.TabIndex = 5;
this.btnLibretroLaunchGame.Text = "Launch Game";
this.btnLibretroLaunchGame.UseVisualStyleBackColor = true;
this.btnLibretroLaunchGame.Click += new System.EventHandler(this.btnLibretroLaunchGame_Click);
//
// btnSetLibretroCore
//
this.btnSetLibretroCore.AutoSize = true;
this.btnSetLibretroCore.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
this.btnSetLibretroCore.Location = new System.Drawing.Point(401, 21);
this.btnSetLibretroCore.Name = "btnSetLibretroCore";
this.btnSetLibretroCore.Size = new System.Drawing.Size(26, 23);
this.btnSetLibretroCore.TabIndex = 4;
this.btnSetLibretroCore.Text = "...";
this.btnSetLibretroCore.UseVisualStyleBackColor = true;
this.btnSetLibretroCore.Click += new System.EventHandler(this.btnSetLibretroCore_Click);
//
// groupBox3
//
this.groupBox3.Controls.Add(this.btnClassicLaunchGame);
this.groupBox3.Controls.Add(this.label3);
this.groupBox3.Location = new System.Drawing.Point(12, 99);
this.groupBox3.Name = "groupBox3";
this.groupBox3.Size = new System.Drawing.Size(277, 100);
this.groupBox3.TabIndex = 6;
this.groupBox3.TabStop = false;
this.groupBox3.Text = "BizHawk Classic";
//
// btnClassicLaunchGame
//
this.btnClassicLaunchGame.Location = new System.Drawing.Point(169, 71);
this.btnClassicLaunchGame.Name = "btnClassicLaunchGame";
this.btnClassicLaunchGame.Size = new System.Drawing.Size(102, 23);
this.btnClassicLaunchGame.TabIndex = 6;
this.btnClassicLaunchGame.Text = "Launch Game";
this.btnClassicLaunchGame.UseVisualStyleBackColor = true;
this.btnClassicLaunchGame.Click += new System.EventHandler(this.btnClassicLaunchGame_Click);
//
// OpenAdvancedChooser
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.CancelButton = this.btnCancel;
this.ClientSize = new System.Drawing.Size(457, 208);
this.Controls.Add(this.groupBox3);
this.Controls.Add(this.groupBox2);
this.Controls.Add(this.btnCancel);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "OpenAdvancedChooser";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Open Advanced";
this.groupBox2.ResumeLayout(false);
this.groupBox2.PerformLayout();
this.groupBox3.ResumeLayout(false);
this.ResumeLayout(false);
}

View File

@ -35,6 +35,7 @@ namespace BizHawk.Client.EmuHawk
GraphicsControl.MouseDoubleClick += (o, e) => HandleFullscreenToggle(o, e);
GraphicsControl.MouseClick += (o, e) => GlobalWin.MainForm.MainForm_MouseClick(o, e);
GraphicsControl.MouseMove += (o, e) => GlobalWin.MainForm.MainForm_MouseMove(o, e);
GraphicsControl.MouseWheel += (o, e) => GlobalWin.MainForm.MainForm_MouseWheel(o, e);
}
bool IsDisposed = false;

View File

@ -65,6 +65,8 @@ namespace BizHawk.Client.EmuHawk
//some people are getting MOTW through a combination of browser used to download bizhawk, and program used to dearchive it
WhackAllMOTW(dllDir);
//We need to do it here too... otherwise people get exceptions when externaltools we distribute try to startup
//in case assembly resolution fails, such as if we moved them into the dll subdiretory, this event handler can reroute to them
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
@ -265,7 +267,7 @@ namespace BizHawk.Client.EmuHawk
if (!VersionInfo.DeveloperBuild && Global.MovieSession.Movie.IsActive)
{
var result = MessageBox.Show(
"EmuHawk has thrown a fatal exception and is about to close.\nA movie has been detected. Would you like to try to save?\n(Note: Depending on what caused this error, this may or may succeed)",
"EmuHawk has thrown a fatal exception and is about to close.\nA movie has been detected. Would you like to try to save?\n(Note: Depending on what caused this error, this may or may not succeed)",
"Fatal error: " + e.GetType().Name,
MessageBoxButtons.YesNo,
MessageBoxIcon.Exclamation
@ -318,13 +320,6 @@ namespace BizHawk.Client.EmuHawk
[DllImport("kernel32.dll", SetLastError = true)]
static extern uint SetDllDirectory(string lpPathName);
[DllImport("kernel32.dll", EntryPoint = "DeleteFileW", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true)]
static extern bool DeleteFileW([MarshalAs(UnmanagedType.LPWStr)]string lpFileName);
static void RemoveMOTW(string path)
{
DeleteFileW(path + ":Zone.Identifier");
}
static void WhackAllMOTW(string dllDir)
{
var todo = new Queue<DirectoryInfo>(new[] { new DirectoryInfo(dllDir) });
@ -333,9 +328,9 @@ namespace BizHawk.Client.EmuHawk
var di = todo.Dequeue();
foreach (var disub in di.GetDirectories()) todo.Enqueue(disub);
foreach (var fi in di.GetFiles("*.dll"))
RemoveMOTW(fi.FullName);
Win32Hacks.RemoveMOTW(fi.FullName);
foreach (var fi in di.GetFiles("*.exe"))
RemoveMOTW(fi.FullName);
Win32Hacks.RemoveMOTW(fi.FullName);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1524,4 +1524,40 @@
<data name="whiteTriUp" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\images\whiteTriUp.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="ENE" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\images\ENE.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="ESE" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\images\ESE.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="NE" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\images\NE.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="NNE" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\images\NNE.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="NNW" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\images\NNW.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="NW" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\images\NW.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="SE" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\images\SE.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="SSE" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\images\SSE.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="SSW" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\images\SSW.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="SW" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\images\SW.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="WNW" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\images\WNW.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="WSW" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\images\WSW.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
</root>

View File

@ -0,0 +1,17 @@
using BizHawk.Emulation.Common;
namespace BizHawk.Client.EmuHawk
{
public interface IBufferedSoundProvider
{
/// <summary>
/// The source audio provider.
/// </summary>
ISoundProvider BaseSoundProvider { get; set; }
/// <summary>
/// Clears any internally buffered samples, and discards samples from the base provider (if set).
/// </summary>
void DiscardSamples();
}
}

View File

@ -0,0 +1,14 @@
using System;
namespace BizHawk.Client.EmuHawk
{
public interface ISoundOutput : IDisposable
{
void StartSound();
void StopSound();
void ApplyVolumeSettings(double volume);
int MaxSamplesDeficit { get; }
int CalculateSamplesNeeded();
void WriteSamples(short[] samples, int sampleCount);
}
}

View File

@ -129,11 +129,7 @@ namespace BizHawk.Client.EmuHawk
int cursorDelta = CircularDistance(_lastWriteCursor, writeCursor, BufferSizeBytes);
cursorDelta += BufferSizeBytes * (int)Math.Round((elapsedSeconds - (cursorDelta / (double)(Sound.SampleRate * Sound.BlockAlign))) / bufferSizeSeconds);
_filledBufferSizeBytes -= cursorDelta;
if (_filledBufferSizeBytes < 0)
{
_sound.OnUnderrun();
detectedUnderrun = true;
}
detectedUnderrun = _filledBufferSizeBytes < 0;
}
if (isInitializing || detectedUnderrun)
{

View File

@ -56,7 +56,6 @@ namespace BizHawk.Client.EmuHawk
if (_remainingSamples < 0)
{
_remainingSamples = 0;
_sound.OnUnderrun();
detectedUnderrun = true;
}
_lastWriteTime = currentWriteTime;

View File

@ -81,7 +81,6 @@ namespace BizHawk.Client.EmuHawk
bool detectedUnderrun = sourceState == ALSourceState.Stopped;
if (detectedUnderrun)
{
_sound.OnUnderrun();
// SampleOffset should reset to 0 when stopped; update the queued sample count to match
UnqueueProcessedBuffers();
currentSamplesPlayed = 0;

View File

@ -102,10 +102,6 @@ namespace BizHawk.Client.EmuHawk
{
bool isInitializing = _runningSamplesQueued == 0;
bool detectedUnderrun = !isInitializing && _sourceVoice.State.BuffersQueued == 0;
if (detectedUnderrun)
{
_sound.OnUnderrun();
}
long samplesAwaitingPlayback = _runningSamplesQueued - _sourceVoice.State.SamplesPlayed;
int samplesNeeded = (int)Math.Max(BufferSizeSamples - samplesAwaitingPlayback, 0);
if (isInitializing || detectedUnderrun)

View File

@ -14,27 +14,26 @@ namespace BizHawk.Client.EmuHawk
public const int BlockAlign = BytesPerSample * ChannelCount;
private bool _disposed;
private ISoundOutput _soundOutput;
private ISyncSoundProvider _syncSoundProvider;
private ISoundProvider _asyncSoundProvider;
private SoundOutputProvider _outputProvider;
private readonly BufferedAsync _semiSync = new BufferedAsync();
private readonly ISoundOutput _outputDevice;
private readonly SoundOutputProvider _outputProvider = new SoundOutputProvider(); // Buffer for Sync sources
private readonly BufferedAsync _bufferedAsync = new BufferedAsync(); // Buffer for Async sources
private IBufferedSoundProvider _bufferedProvider; // One of the preceding buffers, or null if no source is set
public Sound(IntPtr mainWindowHandle)
{
#if WINDOWS
if (Global.Config.SoundOutputMethod == Config.ESoundOutputMethod.DirectSound)
_soundOutput = new DirectSoundSoundOutput(this, mainWindowHandle);
_outputDevice = new DirectSoundSoundOutput(this, mainWindowHandle);
if (Global.Config.SoundOutputMethod == Config.ESoundOutputMethod.XAudio2)
_soundOutput = new XAudio2SoundOutput(this);
_outputDevice = new XAudio2SoundOutput(this);
#endif
if (Global.Config.SoundOutputMethod == Config.ESoundOutputMethod.OpenAL)
_soundOutput = new OpenALSoundOutput(this);
_outputDevice = new OpenALSoundOutput(this);
if (_soundOutput == null)
_soundOutput = new DummySoundOutput(this);
if (_outputDevice == null)
_outputDevice = new DummySoundOutput(this);
}
public void Dispose()
@ -43,8 +42,7 @@ namespace BizHawk.Client.EmuHawk
StopSound();
_soundOutput.Dispose();
_soundOutput = null;
_outputDevice.Dispose();
_disposed = true;
}
@ -57,151 +55,113 @@ namespace BizHawk.Client.EmuHawk
if (!Global.Config.SoundEnabled) return;
if (IsStarted) return;
_soundOutput.StartSound();
_outputDevice.StartSound();
_outputProvider = new SoundOutputProvider();
_outputProvider.MaxSamplesDeficit = _soundOutput.MaxSamplesDeficit;
_outputProvider.BaseSoundProvider = _syncSoundProvider;
_outputProvider.MaxSamplesDeficit = _outputDevice.MaxSamplesDeficit;
Global.SoundMaxBufferDeficitMs = (int)Math.Ceiling(SamplesToMilliseconds(_soundOutput.MaxSamplesDeficit));
Global.SoundMaxBufferDeficitMs = (int)Math.Ceiling(SamplesToMilliseconds(_outputDevice.MaxSamplesDeficit));
IsStarted = true;
//ApplyVolumeSettings();
//LogUnderruns = true;
//_outputProvider.LogDebug = true;
}
public void StopSound()
{
if (!IsStarted) return;
_soundOutput.StopSound();
_outputDevice.StopSound();
_outputProvider = null;
if (_bufferedProvider != null) _bufferedProvider.DiscardSamples();
Global.SoundMaxBufferDeficitMs = 0;
IsStarted = false;
}
//public void ApplyVolumeSettings()
//{
// if (!IsStarted) return;
// double volume = Global.Config.SoundVolume / 100.0;
// if (volume < 0.0) volume = 0.0;
// if (volume > 1.0) volume = 1.0;
// _soundOutput.ApplyVolumeSettings(volume);
//}
public void SetSyncInputPin(ISyncSoundProvider source)
/// <summary>
/// Attaches a new input pin which will run either in sync or async mode depending
/// on its SyncMode property. Once attached, the sync mode must not change unless
/// the pin is re-attached.
/// </summary>
public void SetInputPin(ISoundProvider source)
{
if (_asyncSoundProvider != null)
if (_bufferedProvider != null)
{
_asyncSoundProvider.DiscardSamples();
_asyncSoundProvider = null;
_bufferedProvider.BaseSoundProvider = null;
_bufferedProvider.DiscardSamples();
_bufferedProvider = null;
}
_semiSync.DiscardSamples();
_semiSync.BaseSoundProvider = null;
_syncSoundProvider = source;
if (_outputProvider != null)
{
_outputProvider.BaseSoundProvider = source;
}
}
public void SetAsyncInputPin(ISoundProvider source)
{
if (_syncSoundProvider != null)
if (source == null) return;
if (source.SyncMode == SyncSoundMode.Sync)
{
_syncSoundProvider.DiscardSamples();
_syncSoundProvider = null;
_bufferedProvider = _outputProvider;
}
if (_outputProvider != null)
else if (source.SyncMode == SyncSoundMode.Async)
{
_outputProvider.DiscardSamples();
_outputProvider.BaseSoundProvider = null;
_bufferedAsync.RecalculateMagic(Global.Emulator.CoreComm.VsyncRate);
_bufferedProvider = _bufferedAsync;
}
_asyncSoundProvider = source;
_semiSync.BaseSoundProvider = source;
_semiSync.RecalculateMagic(Global.Emulator.CoreComm.VsyncRate);
else throw new InvalidOperationException("Unsupported sync mode.");
_bufferedProvider.BaseSoundProvider = source;
}
public bool LogUnderruns { get; set; }
private bool InitializeBufferWithSilence
{
get { return true; }
}
private bool RecoverFromUnderrunsWithSilence
{
get { return true; }
}
private int SilenceLeaveRoomForFrameCount
{
get { return Global.Config.SoundThrottle ? 1 : 2; } // Why 2? I don't know, but it seems to work well with the clock throttle's behavior.
}
internal void HandleInitializationOrUnderrun(bool isUnderrun, ref int samplesNeeded)
{
if ((!isUnderrun && InitializeBufferWithSilence) || (isUnderrun && RecoverFromUnderrunsWithSilence))
// Fill device buffer with silence but leave enough room for one frame
int samplesPerFrame = (int)Math.Round(SampleRate / Global.Emulator.CoreComm.VsyncRate);
int silenceSamples = Math.Max(samplesNeeded - samplesPerFrame, 0);
_outputDevice.WriteSamples(new short[silenceSamples * 2], silenceSamples);
samplesNeeded -= silenceSamples;
if (isUnderrun)
{
int samplesPerFrame = (int)Math.Round(Sound.SampleRate / Global.Emulator.CoreComm.VsyncRate);
int silenceSamples = Math.Max(samplesNeeded - (SilenceLeaveRoomForFrameCount * samplesPerFrame), 0);
_soundOutput.WriteSamples(new short[silenceSamples * 2], silenceSamples);
samplesNeeded -= silenceSamples;
if (LogUnderruns) Console.WriteLine("Sound underrun detected!");
_outputProvider.OnVolatility();
}
}
internal void OnUnderrun()
{
if (!IsStarted) return;
if (LogUnderruns) Console.WriteLine("Sound underrun detected!");
_outputProvider.OnVolatility();
}
public void UpdateSound(float atten)
{
if (!Global.Config.SoundEnabled || !IsStarted || _disposed)
if (!Global.Config.SoundEnabled || !IsStarted || _bufferedProvider == null || _disposed)
{
if (_asyncSoundProvider != null) _asyncSoundProvider.DiscardSamples();
if (_syncSoundProvider != null) _syncSoundProvider.DiscardSamples();
if (_outputProvider != null) _outputProvider.DiscardSamples();
if (_bufferedProvider != null) _bufferedProvider.DiscardSamples();
return;
}
if (atten < 0) atten = 0;
if (atten > 1) atten = 1;
_soundOutput.ApplyVolumeSettings(atten);
_outputDevice.ApplyVolumeSettings(atten);
short[] samples;
int samplesNeeded = _soundOutput.CalculateSamplesNeeded();
int samplesNeeded = _outputDevice.CalculateSamplesNeeded();
int samplesProvided;
if (atten==0)
if (atten == 0)
{
samples = new short[samplesNeeded * ChannelCount];
samplesProvided = samplesNeeded;
if (_asyncSoundProvider != null) _asyncSoundProvider.DiscardSamples();
if (_syncSoundProvider != null) _syncSoundProvider.DiscardSamples();
if (_outputProvider != null) _outputProvider.DiscardSamples();
_bufferedProvider.DiscardSamples();
}
else if (_syncSoundProvider != null)
else if (_bufferedProvider == _outputProvider)
{
if (Global.Config.SoundThrottle)
{
_syncSoundProvider.GetSamples(out samples, out samplesProvided);
_outputProvider.BaseSoundProvider.GetSamplesSync(out samples, out samplesProvided);
while (samplesNeeded < samplesProvided && !Global.DisableSecondaryThrottling)
if (Global.DisableSecondaryThrottling && samplesProvided > samplesNeeded)
{
return;
}
while (samplesProvided > samplesNeeded)
{
Thread.Sleep((samplesProvided - samplesNeeded) / (SampleRate / 1000)); // Let the audio clock control sleep time
samplesNeeded = _soundOutput.CalculateSamplesNeeded();
samplesNeeded = _outputDevice.CalculateSamplesNeeded();
}
}
else
@ -213,11 +173,11 @@ namespace BizHawk.Client.EmuHawk
_outputProvider.GetSamples(samplesNeeded, out samples, out samplesProvided);
}
}
else if (_asyncSoundProvider != null)
else if (_bufferedProvider == _bufferedAsync)
{
samples = new short[samplesNeeded * ChannelCount];
_semiSync.GetSamples(samples);
_bufferedAsync.GetSamplesAsync(samples);
samplesProvided = samplesNeeded;
}
@ -226,7 +186,7 @@ namespace BizHawk.Client.EmuHawk
return;
}
_soundOutput.WriteSamples(samples, samplesProvided);
_outputDevice.WriteSamples(samples, samplesProvided);
}
public static int MillisecondsToSamples(int milliseconds)
@ -239,14 +199,4 @@ namespace BizHawk.Client.EmuHawk
return samples * 1000.0 / SampleRate;
}
}
public interface ISoundOutput : IDisposable
{
void StartSound();
void StopSound();
void ApplyVolumeSettings(double volume);
int MaxSamplesDeficit { get; }
int CalculateSamplesNeeded();
void WriteSamples(short[] samples, int sampleCount);
}
}

View File

@ -1,6 +1,9 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
namespace BizHawk.Emulation.Common
using BizHawk.Emulation.Common;
namespace BizHawk.Client.EmuHawk
{
// Generates SEMI-synchronous sound, or "buffered asynchronous" sound.
@ -27,16 +30,15 @@ namespace BizHawk.Emulation.Common
* TODO: For systems that _really_ don't need BufferedAsync (pce not turbocd, sms), make a way to signal
* that and then bypass the BufferedAsync.
*/
public sealed class BufferedAsync : ISoundProvider
public sealed class BufferedAsync : ISoundProvider, IBufferedSoundProvider
{
public ISoundProvider BaseSoundProvider;
public ISoundProvider BaseSoundProvider { get; set; }
readonly Queue<short> buffer = new Queue<short>(4096);
private readonly Queue<short> buffer = new Queue<short>(MaxExcessSamples);
private int SamplesInOneFrame = 1470;
private int TargetExtraSamples = 882;
const int MaxExcessSamples = 4096;
private const int MaxExcessSamples = 4096;
/// <summary>
/// recalculates some internal parameters based on the IEmulator's framerate
@ -50,13 +52,13 @@ namespace BizHawk.Emulation.Common
public void DiscardSamples()
{
buffer.Clear();
if (BaseSoundProvider != null)
BaseSoundProvider.DiscardSamples();
}
public int MaxVolume { get; set; }
public void GetSamples(short[] samples)
public void GetSamplesAsync(short[] samples)
{
int samplesToGenerate = SamplesInOneFrame;
if (buffer.Count > samples.Length + MaxExcessSamples)
@ -68,7 +70,11 @@ namespace BizHawk.Emulation.Common
var mySamples = new short[samplesToGenerate];
BaseSoundProvider.GetSamples(mySamples);
if (BaseSoundProvider.SyncMode != SyncSoundMode.Async)
{
throw new InvalidOperationException("Base sound provider must be in async mode.");
}
BaseSoundProvider.GetSamplesAsync(mySamples);
foreach (short s in mySamples)
{
@ -80,5 +86,28 @@ namespace BizHawk.Emulation.Common
samples[i] = buffer.Dequeue();
}
}
public bool CanProvideAsync
{
get { return true; }
}
public SyncSoundMode SyncMode
{
get { return SyncSoundMode.Async; }
}
public void SetSyncMode(SyncSoundMode mode)
{
if (mode != SyncSoundMode.Async)
{
throw new NotSupportedException("Sync mode is not supported.");
}
}
public void GetSamplesSync(out short[] samples, out int nsamp)
{
throw new InvalidOperationException("Sync mode is not supported.");
}
}
}

View File

@ -16,7 +16,7 @@ namespace BizHawk.Client.EmuHawk
// perform a "soft" correction by resampling it to hopefully get back inside our
// window shortly. If it ends up going too low or too high, we will perform a
// "hard" correction by generating silence or discarding samples.
public class SoundOutputProvider
public class SoundOutputProvider : IBufferedSoundProvider
{
private const int SampleRate = 44100;
private const int ChannelCount = 2;
@ -54,7 +54,7 @@ namespace BizHawk.Client.EmuHawk
public int MaxSamplesDeficit { get; set; }
public ISyncSoundProvider BaseSoundProvider { get; set; }
public ISoundProvider BaseSoundProvider { get; set; }
public void DiscardSamples()
{
@ -164,7 +164,11 @@ namespace BizHawk.Client.EmuHawk
short[] samples;
int count;
BaseSoundProvider.GetSamples(out samples, out count);
if (BaseSoundProvider.SyncMode != SyncSoundMode.Sync)
{
throw new InvalidOperationException("Base sound provider must be in sync mode.");
}
BaseSoundProvider.GetSamplesSync(out samples, out count);
bool correctedEmptyFrame = false;
if (count == 0)

View File

@ -245,7 +245,7 @@ namespace BizHawk.Client.EmuHawk
endticks = GetCurTime();
// calculate time since last frame
ulong diffticks = endticks - beginticks;
ulong diffticks = Math.Max(endticks - beginticks, 1);
float diff = (float)diffticks / afsfreq;
// calculate time since last frame not including throttle sleep time

View File

@ -473,32 +473,42 @@ namespace BizHawk.Client.EmuHawk
using(var ofd = new OpenFileDialog())
{
ofd.Multiselect = true;
if (ofd.ShowDialog() != System.Windows.Forms.DialogResult.OK)
if (ofd.ShowDialog() != DialogResult.OK)
{
return;
}
RunImportJob(ofd.FileNames);
}
}
bool RunImportJobSingle(string basepath, string f, ref string errors)
private bool RunImportJobSingle(string basepath, string f, ref string errors)
{
try
{
var fi = new FileInfo(f);
if (!fi.Exists) return false;
if (!fi.Exists)
{
return false;
}
string target = Path.Combine(basepath, fi.Name);
if (new FileInfo(target).Exists)
{
//compare the files, if theyre the same. dont do anything
// compare the files, if theyre the same. dont do anything
if (File.ReadAllBytes(target).SequenceEqual(File.ReadAllBytes(f)))
{
return false;
//hmm theyre different. import but rename it
}
// hmm theyre different. import but rename it
string dir = Path.GetDirectoryName(target);
string ext = Path.GetExtension(target);
string name = Path.GetFileNameWithoutExtension(target);
name += " (variant)";
target = Path.Combine(dir, name) + ext;
}
Directory.CreateDirectory(Path.GetDirectoryName(target));
fi.CopyTo(target, false);
return true;
@ -511,7 +521,7 @@ namespace BizHawk.Client.EmuHawk
}
}
void RunImportJob(IEnumerable<string> files)
private void RunImportJob(IEnumerable<string> files)
{
bool didSomething = false;
var basepath = PathManager.MakeAbsolutePath(Global.Config.PathEntries.FirmwaresPathFragment, null);
@ -523,9 +533,8 @@ namespace BizHawk.Client.EmuHawk
if (hf.IsArchive)
{
//blech. the worst extraction code in the universe.
string extractpath = System.IO.Path.GetTempFileName() + ".dir";
DirectoryInfo di = null;
di = System.IO.Directory.CreateDirectory(extractpath);
string extractpath = Path.GetTempFileName() + ".dir";
DirectoryInfo di = Directory.CreateDirectory(extractpath);
try
{
@ -549,23 +558,31 @@ namespace BizHawk.Client.EmuHawk
}
}
else
{
didSomething |= RunImportJobSingle(basepath, f, ref errors);
}
}
}
if (errors != "")
System.Windows.Forms.MessageBox.Show(errors, "Error importing these files");
if (!string.IsNullOrEmpty(errors))
{
MessageBox.Show(errors, "Error importing these files");
}
if (didSomething) DoScan();
if (didSomething)
{
DoScan();
}
}
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == Keys.Escape)
{
this.Close();
Close();
return true;
}
return base.ProcessCmdKey(ref msg, keyData);
}

View File

@ -0,0 +1,147 @@
namespace BizHawk.Client.EmuHawk
{
partial class IntvControllerSettings
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(IntvControllerSettings));
this.OkBtn = new System.Windows.Forms.Button();
this.CancelBtn = new System.Windows.Forms.Button();
this.label5 = new System.Windows.Forms.Label();
this.label4 = new System.Windows.Forms.Label();
this.Port2ComboBox = new System.Windows.Forms.ComboBox();
this.Port1ComboBox = new System.Windows.Forms.ComboBox();
this.label1 = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// OkBtn
//
this.OkBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.OkBtn.Location = new System.Drawing.Point(170, 249);
this.OkBtn.Name = "OkBtn";
this.OkBtn.Size = new System.Drawing.Size(60, 23);
this.OkBtn.TabIndex = 3;
this.OkBtn.Text = "&OK";
this.OkBtn.UseVisualStyleBackColor = true;
this.OkBtn.Click += new System.EventHandler(this.OkBtn_Click);
//
// CancelBtn
//
this.CancelBtn.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.CancelBtn.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.CancelBtn.Location = new System.Drawing.Point(236, 249);
this.CancelBtn.Name = "CancelBtn";
this.CancelBtn.Size = new System.Drawing.Size(60, 23);
this.CancelBtn.TabIndex = 4;
this.CancelBtn.Text = "&Cancel";
this.CancelBtn.UseVisualStyleBackColor = true;
this.CancelBtn.Click += new System.EventHandler(this.CancelBtn_Click);
//
// label5
//
this.label5.AutoSize = true;
this.label5.Location = new System.Drawing.Point(9, 94);
this.label5.Name = "label5";
this.label5.Size = new System.Drawing.Size(38, 13);
this.label5.TabIndex = 16;
this.label5.Text = "Port 2:";
//
// label4
//
this.label4.AutoSize = true;
this.label4.Location = new System.Drawing.Point(12, 44);
this.label4.Name = "label4";
this.label4.Size = new System.Drawing.Size(38, 13);
this.label4.TabIndex = 15;
this.label4.Text = "Port 1:";
//
// Port2ComboBox
//
this.Port2ComboBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.Port2ComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.Port2ComboBox.FormattingEnabled = true;
this.Port2ComboBox.Location = new System.Drawing.Point(12, 110);
this.Port2ComboBox.Name = "Port2ComboBox";
this.Port2ComboBox.Size = new System.Drawing.Size(284, 21);
this.Port2ComboBox.TabIndex = 14;
//
// Port1ComboBox
//
this.Port1ComboBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.Port1ComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.Port1ComboBox.FormattingEnabled = true;
this.Port1ComboBox.Location = new System.Drawing.Point(12, 60);
this.Port1ComboBox.Name = "Port1ComboBox";
this.Port1ComboBox.Size = new System.Drawing.Size(284, 21);
this.Port1ComboBox.TabIndex = 13;
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(12, 14);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(146, 13);
this.label1.TabIndex = 17;
this.label1.Text = "Intellivision Controller Settings";
//
// IntvControllerSettings
//
this.AcceptButton = this.OkBtn;
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.CancelButton = this.CancelBtn;
this.ClientSize = new System.Drawing.Size(308, 284);
this.Controls.Add(this.label1);
this.Controls.Add(this.label5);
this.Controls.Add(this.label4);
this.Controls.Add(this.Port2ComboBox);
this.Controls.Add(this.Port1ComboBox);
this.Controls.Add(this.CancelBtn);
this.Controls.Add(this.OkBtn);
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.Name = "IntvControllerSettings";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Controller Settings";
this.Load += new System.EventHandler(this.IntvControllerSettings_Load);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Button OkBtn;
private System.Windows.Forms.Button CancelBtn;
private System.Windows.Forms.Label label5;
private System.Windows.Forms.Label label4;
private System.Windows.Forms.ComboBox Port2ComboBox;
private System.Windows.Forms.ComboBox Port1ComboBox;
private System.Windows.Forms.Label label1;
}
}

View File

@ -0,0 +1,61 @@
using System;
using System.Data;
using System.Linq;
using System.Windows.Forms;
using BizHawk.Client.Common;
using BizHawk.Emulation.Cores.Intellivision;
namespace BizHawk.Client.EmuHawk
{
public partial class IntvControllerSettings : Form
{
private Intellivision.IntvSyncSettings _syncSettings;
public IntvControllerSettings()
{
InitializeComponent();
}
private void IntvControllerSettings_Load(object sender, EventArgs e)
{
_syncSettings = (Global.Emulator as Intellivision).SyncSettings.Clone();
var possibleControllers = IntellivisionControllerDeck.ValidControllerTypes.Select(t => t.Key);
foreach (var val in possibleControllers)
{
Port1ComboBox.Items.Add(val);
Port2ComboBox.Items.Add(val);
}
Port1ComboBox.SelectedItem = _syncSettings.Port1;
Port2ComboBox.SelectedItem = _syncSettings.Port2;
}
private void OkBtn_Click(object sender, EventArgs e)
{
bool changed =
_syncSettings.Port1 != Port1ComboBox.SelectedItem.ToString()
|| _syncSettings.Port2 != Port2ComboBox.SelectedItem.ToString();
if (changed)
{
_syncSettings.Port1 = Port1ComboBox.SelectedItem.ToString();
_syncSettings.Port2 = Port2ComboBox.SelectedItem.ToString();
GlobalWin.MainForm.PutCoreSyncSettings(_syncSettings);
}
DialogResult = DialogResult.OK;
Close();
}
private void CancelBtn_Click(object sender, EventArgs e)
{
GlobalWin.OSD.AddMessage("Controller settings aborted");
DialogResult = DialogResult.Cancel;
Close();
}
}
}

View File

@ -0,0 +1,624 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
AAABAAwAMDAQAAAABABoBgAAxgAAACAgEAAAAAQA6AIAAC4HAAAYGBAAAAAEAOgBAAAWCgAAEBAQAAAA
BAAoAQAA/gsAADAwAAAAAAgAqA4AACYNAAAgIAAAAAAIAKgIAADOGwAAGBgAAAAACADIBgAAdiQAABAQ
AAAAAAgAaAUAAD4rAAAwMAAAAAAgAKglAACmMAAAICAAAAAAIACoEAAATlYAABgYAAAAACAAiAkAAPZm
AAAQEAAAAAAgAGgEAAB+cAAAKAAAADAAAABgAAAAAQAEAAAAAACABAAAAAAAAAAAAAAQAAAAEAAAAAAA
AAAAAIAAAIAAAACAgACAAAAAgACAAICAAACAgIAAwMDAAAAA/wAA/wAAAP//AP8AAAD/AP8A//8AAP//
/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAHR3AAAAAAAAAAAAAAAAAAAAAAAAAAAAdHdEcAAAAAAAAAAAAAAAAA
AAAAAAAAAHd0d3QAAAAAAAAAAAAAAAAAAAAAAAAAAEd8d3UAAAAAAAAAAAAAAAAAAAAAAAAAB3yHfHZw
AAAAAAAAAAAAAAAAAAAAAAAAd3fIyHVwAAAAAAAAAAAAAAAAAAAAAAAAfHh3jIxwAAAAAAAAAAAAAAAA
AAAAAAAHd8jIyHdgAAAAAAAAAAAAAAAAAAAAAAAHd4yHfIdAAAAAAAAAAAAAAAAAAAAAAAAHyMjIyMhQ
AAAAAAAAAAAAAAAAAAAAAAB3d3eMh4dgAAAAAAAAAAAAAAAAAAAAAAB8jIyIfIdQAAAAAAAAAAAAAAAA
AAAAAAB3h4jIiMh3AAAAAAAAAAAAAAAAAAAAAAB8jIeHeIjHAAAAAAAAAAAAAAAAAAAAAAeIiHh4eMiE
AAAAAAAAAAAAB0dHcAAAAAd8h4eIiIiHcAAAAAAAAAB0d3d3RwAAAAeIeIiIiIh3RwAAAAAAAHR3d8h3
dAAAAAfIh4iIiHiIx0cAAAAAdHh3eIeHhwAAAAeHiIiIiIiId3R3dHR0eHd4h4eHhAAAAAd4eIiIiIiH
x3d2d3eId4iIiIiIhwAAAAd4eIiI+IiIh3d3eHh3iIiIiIeHwAAAAAfIjHeIiIiIyIeHh4iIiIiIiIiI
cAAAAAeIQ0R3h3iIiMiIiIiIiIiIiIiEAAAAAAfIR3d3d0iIiIh4iIeIiIiIiHhAAAAAAAB4d3d3SHiI
h4fTiIi3iIiIeIwAAAAAAAB3h4d3eIeIiHiJiIuIiIh4jHAAAAAAAAAHyId3h3h4iIh4iIiIiIiHeAAA
AAAAAAAAB8iMiMjIiIiIh4h3aMjHAAAAAAAAAAAAAAdYyIeIiIiMjId6d4eAAAAAAAAAAAAAAAAHdsjH
eIeH6MiId3AAAAAAAAAAAAAAAIiIh4V8jIh4eIfHcAAAAAAAAAAAAACIiIh3AAAHd3h3fHcAAAAAAAAA
AAAAAAiIjHgAAAAAAHx8eAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAD///////8AAP///////wAA////////AAD///////8AAP///////wAA////////
AAD///////8AAP///////wAA//h/////AAD/4D////8AAP/AP////wAA/8A/////AAD/gB////8AAP8A
H////wAA/wAf////AAD+AB////8AAP4AH////wAA/gAf////AAD8AB////8AAPwAH////wAA/AAP////
AAD8AA////8AAPgAD//+BwAA+AAH//ADAAD4AAP/wAMAAPgAAP8AAwAA+AAAAAADAAD4AAAAAAMAAPgA
AAAABwAA+AAAAAAHAAD4AAAAAA8AAPgAAAAAHwAA/AAAAAA/AAD8AAAAAH8AAP4AAAAA/wAA/4AAAAP/
AAD/4AAAB/8AAP/4AAAf/wAA/8AAAH//AAD8A+AD//8AAPgP/A///wAA////////AAD///////8AAP//
/////wAA////////AAD///////8AAP///////wAA////////AAAoAAAAIAAAAEAAAAABAAQAAAAAAAAC
AAAAAAAAAAAAABAAAAAQAAAAAAAAAAAAgAAAgAAAAICAAIAAAACAAIAAgIAAAICAgADAwMAAAAD/AAD/
AAAA//8A/wAAAP8A/wD//wAA////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdwAAAAAAAAAAAAAAAA
AAd0dAAAAAAAAAAAAAAAAAB3x3cAAAAAAAAAAAAAAAAAd3fHcAAAAAAAAAAAAAAAB3yMh3AAAAAAAAAA
AAAAAAfIeMdwAAAAAAAAAAAAAAAHjIyHQAAAAAAAAAAAAAAAfId4yHAAAAAAAAAAAAAAAHjIyIdQAAAA
AAAAAAAAAAB3iId4YAAAAAAAAAdwAAAAjIiIiIUAAAAAAHd3dAAAB4iIiHh8cAAAAHd3x4dwAAd4iIiI
h3Z3d3R3yIh4cAAHh4iIiIfHd3d4iIiIh3AAB3jHiIiIiHeHiIiIiIwAAAh3dXh4iMiIiIiIiIhwAAAA
yGd0d4iIeIi4iIiMAAAAAIeHd4iIh32IiIiIcAAAAAAAd4jIyIiIiHeHyAAAAAAAAAB3h4iIh8h3dwAA
AAAAAAAIh8fIh4eIaAAAAAAAAACIiHAAB8jIyAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////////
////////////////////n////g////wP///8B///+Af///gH///4B///8Af///AH///wB//n8AP/A+AB
/AHgAAAB4AAAAeAAAAPgAAAH8AAAD/AAAB/8AAA//wAA//4AA//weA//////////////////////////
//8oAAAAGAAAADAAAAABAAQAAAAAACABAAAAAAAAAAAAABAAAAAQAAAAAAAAAAAAgAAAgAAAAICAAIAA
AACAAIAAgIAAAICAgADAwMAAAAD/AAD/AAAA//8A/wAAAP8A/wD//wAA////AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHRwAAAAAAAAAAAAB3dAAAAAAAAAAAAA
d8dwAAAAAAAAAAAAfId3AAAAAAAAAAAHeMjHAAAAAAAAAAAHyHh3AAAAAAAAAAAHh3eEAAAAAAAAAAAI
yIiHAAAAAHd2cAAIiIiIQAAAd3d4UACHiIiId3d3eHiIcACHh4iIyHeHiIiIcAAIR3d4iIiIiIiMAAAH
d3eIh3iIiIhwAAAAeMh4iIiHiMAAAAAAAHfIiMh4aAAAAAAAiIgHyIfIAAAAAAAIgAAAAIAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wD///8A////AP///wD8f/8A+H//APB/
/wDwP/8A4D//AOA//wDgP/8A4D/BAOAfAQDAAAEAwAABAOAAAwDgAAcA8AAfAPwAPwDwgP8A5/f/AP//
/wD///8A////ACgAAAAQAAAAIAAAAAEABAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAACA
AAAAgIAAgAAAAIAAgACAgAAAgICAAMDAwAAAAP8AAP8AAAD//wD/AAAA/wD/AP//AAD///8AAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAd1AAAAAAAAB8cAAAAAAAB4eAAAAAAAAHyMgAAAAAAAiIhwAAAHcACI
iHcAd3hwAIz4jIeIiIAAd3eIiIiIAACHeIiIiHAAAACMeMh4AAAAiAAIgAAAAAAAAAAAAAAAAAAAAAAA
AAD//wAA//8AAP//AADj/wAA4/8AAMP/AADB/wAAwfkAAMDBAADAAQAAwAMAAMAHAADwDwAAzn8AAP//
AAD//wAAKAAAADAAAABgAAAAAQAIAAAAAAAACQAAAAAAAAAAAAAAAQAAAAEAAAAAAAA9OzsAZD8/AGg8
PABtPj4AQkNDAEZIRwBWQkIAV0REAF5AQABbRkYAVklJAFxPTwBTU1MAXFJSAF5ZWQBkQEAAYUREAGZF
RQBqQkEAYEtLAGNPTwBwQUEAfUZGAHJKSgB2SUkAfU9PAGBRUQBgVFQAZlZWAGZYWABqWVkAclZWAHpU
VAB9W1oAbmJiAGtoaABtaWkAcWdnAHdnZwB8Y2MAe2pqAHJxcQB+dHQAd3l5AHl6egCGT08AiU9PAIFP
UACGU1MAjVFRAIlWVgCMV1cAg1xbAIxaWQCQUlIAlVJSAJFXVgCXVVUAmVVVAJZaWQCSXV0AlV9eAJpZ
WgCeW1sAml5eAKBZWgCgXFwAql9fAIRmZQCIZWQAhWtrAI5ragCTYmEAnGBhAJ9kYwCaZmYAk25uAJ1s
awCFdHQAiXd3AIt+fgCWd3cAmHR0AJV5eQCbfHwAo2JhAKZhYQChZWUApGVkAKplZACsZGQAqmhnAKZr
agCnbGsAqmloAKlubQCsbW0AtGZnALhsbACxb3AAv29wAKVxcACrc3IAr35+ALN0cwC5c3MAvXBxALR4
dgC1fHsAunt6AMNtbgDGb3AAw3FyAMZwcQDGdXUAyHR1AMp3eADBeXkAxnt7AMB/fgDLensANLBSAEWf
TgBBtFwAPMdnADHkdgDciiIAvoF/AISrdwDln0sA35lhAN2XfADgmmEA8LdlAO61cAArWPIALWT+AEh5
+gDOf4AAfoCAAHiA1ABZv9wAZrnUAGK+2ABxnv4Ad6P/ADPX/QBw0OcAW+D7AIKEgwCPgoIAjI2NAJuC
ggCUiIgAmYqKAJGSkgCjhIQAqoKCAKKLiwC+hIMAsoqKALaSgQCum5sAsZubALqqlQCdgr4Ar6ytALGh
oAC6pKQAwoSDAMyBggDGiIYAyYiHAMWMigDMjIoA0ISFANKHiADUjIwA2Y6NAMCUjQDIk44A0JCPANaP
kADHlZQAzpSSAMScmwDUkpIA2ZSVANWYlgDampcA2ZeYANWcnADam5sA4p2cAMChjwDeoJ4A5aCFAOaj
jQDlpJoA2p6hAMOkowDOoaEAy62tANegoADdoqEA2aGpANGsrwDdq6kAwbG4ANGysQDdtLQA2ri3AOGk
owDjqKYA66ylAOGnqADjq6oA6a2rAOOwrwDssK4A5K+wAOaztADttLIA57i2AO24tgDmurgA6rq6APC1
swDyuLYA9Ly5APi+uwD1wL0A+cC9AKKMwACkk8QAqprMALSayACptsEAlaDkAOy/wACRxtQAgOv9AJnr
9wDEwsoA5sbGAOzCwgDuyMcA7MzMAPPEwgDxy8oA9dPTAPja2gAAAAAAAAAAAP///wAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFAoIJQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAACYXODs4BCUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
KTNDQ0M7OAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALllbYmJZQBcAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYYWNwcHBwWy8mAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAFFLanBwcHBwYz0eAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAABpqcHBwcHBwZVkUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAl11w
cHBwcHBwcGcSAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIXdwcHBwcHBwcGkSAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPXBwcHBwcHBwd2wYAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAACXbnBwdXB5dXl0eW4hAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAid3R5eXl5eXl5q6wzAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9eXV5
i7CxsbGxsblLKgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABndYuwsbm8uby5vMFnHgAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJt3q7G3vMHB1cLBwdWuEgAAAAAAAAAAAAAAAAAA
AAAAAAAeEhMSCiUAAAAAAAAAAEexsbm/1dXZ2dnZ1da5ZgwAAAAAAAAAAAAAAAAAAAAjEjNZaW5qXRMl
AAAAAAAAADW5s7/V2N7i4uLi3dzZrQQPAAAAAAAAAAAAAAAAHxhZbm5uaWltd6ASAAAAAAAAAEmzvMLZ
3uP29/fw4uTkuUAWCy0AAAAAAAAAAB4YYXd3gG13vbm5vb8zAAAAAAAAAE6xwdXd4/b6+/r38OTl1Vlc
OAMIFAweFBQSM2mtrYB3vdXT0NXExNU1AAAAAAAAAE65wtXe8Pr7/Pz79+fn1WphZ25pXV1mbHetrXd3
tdXT4vXw49nZ3NYgAAAAAAAAAEu3wdje9vv7/Pz79+fn34B3d2xtoHeud66uudXT4vD39/Dj49zk5G0A
AAAAAAAAAD2xwcwoH0/L/Pukyenp5K27u7m5uczM0Nve4vb3+vr56OPl5eXl1igAAAAAAAAAADWxwQgB
BQYNmveZK/Dp6cG/wcTV2eP3+vr6+/r6+ejm5ufn5+nkIgAAAAAAAAAAAJmruR4sjC2WLFCdDd3p6dXW
1tXI3vn67pCO9Ojp6efo5+fm59wiAAAAAAAAAAAAAABLsZ0FmC0qKgHMRcjp6dzc1Y2KiO3RlfKTj+np
5ubm5eXk1SIAAAAAAAAAAAAAAACdab/Lp5aWnEfV1cHm6ebk6pGSiabZ8fOU0uXl5eTk3NyuRQAAAAAA
AAAAAAAAAAAAn0ux0KFTaMHBv7nC6efp3Ovv7OTm3OPl3Nzc3NfW1U6fAAAAAAAAAAAAAAAAAAAAAABF
Wa25t7yxs7Gw5+fn5Obk18XG3NyBfHvD1cSgNQAAAAAAAAAAAAAAAAAAAAAAAAAAAFUzarGwsHl5sefn
39zEgoZ/hL19fnqirj2jAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATj09ZXV0cLzn3NXChYeDub+1pbQ9
VQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0rXj+rpInTBDcHCz5NW/ucG5u7GAM1QAAAAAAAAAAAAAAAAA
AAAAAAAAAADLytDi9tOemQAAAAAAUy9EecLEsa1uPTUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPj11Mme
VakAAAAAAAAAAAAATS84M0akAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAD///////8AAP///////wAA////////AAD///////8AAP///////wAA////////
AAD///////8AAP///////wAA//h/////AAD/4D////8AAP/AP////wAA/8A/////AAD/gB////8AAP8A
H////wAA/wAf////AAD+AB////8AAP4AH////wAA/gAf////AAD8AB////8AAPwAH////wAA/AAP////
AAD8AA////8AAPgAD//+BwAA+AAH//ADAAD4AAP/wAMAAPgAAP8AAwAA+AAAAAADAAD4AAAAAAMAAPgA
AAAABwAA+AAAAAAHAAD4AAAAAA8AAPgAAAAAHwAA/AAAAAA/AAD8AAAAAH8AAP4AAAAA/wAA/4AAAAP/
AAD/4AAAB/8AAP/4AAAf/wAA/8AAAH//AAD8A+AD//8AAPgP/A///wAA////////AAD///////8AAP//
/////wAA////////AAD///////8AAP///////wAA////////AAAoAAAAIAAAAEAAAAABAAgAAAAAAAAE
AAAAAAAAAAAAAAABAAAAAQAAAAAAAFFNTQBRUlIAU1RUAGJHRwBiT08Aa0lIAGJTUwBrVlYAYllZAGZc
XABpWloAb1xbAHNTUwB7V1YAc1hXAHFbWwBkZWUAaWFhAG5kZABpamkAcGFhAHlubgB2cHAAf3V1AH55
eQB8fX0AgUpKAI1PTwCLWFcAhlhYAI9ZWQCKXFsAm1ZWAJJZWQCWWVgAmlpbAJtcWwCiXFwAl2BfAIBg
YACAZ2YAgG9vAI9oaACWZWQAmGBhAJ5kZACcaWoAmm9vAIV0dACNcHAAiXZ2AIB8fACac3IAm3V0AJ51
dQCZfHwAnHx8AKNmZgCnZmYAqmJiAK5jYwCvb24AtWVmALBtbgC5bW0AvmxtAKx+fQCxcnIAtHBwALZz
dACydXQAtnd2ALlwcAC5dnYAt3p5ALh5eAC8fHsAun18ALx+fQDGb3AAxnBxAMdzdADAd3YAyHJzAMlz
dADJdXYAynd4AMd/fwDMe3wAzXx9AHunbwBhvHIAYsN4ANuLOwC2hn4A4Zt5APC3ZABte9sAX47+AHWM
5QAl0foAY+P8AIeDgwCFhoYAioSEAJOIiACWi4sAmpKRAKGCgQCmhYUAqYGBAKuDhACniooApYyMAKiO
jQCyhYMAvoWEALeNjQCrj5AAr5eXALSVlAC9lJMAmbCEAK6RugDBgYAAwoSCAMWDhADChoQAxYeFAM6A
gQDFiIYAxoqIAMqIiQDMi4oAy4yKAMiPjQDPj44A0ISFANKJigDUi4wA04+NANWNjgDKkY8A0JCOANud
iQDWj5AAzJSTAM2XlgDGm5oA1pGSANOUkgDVl5EA1pOUANiVlgDYmJUA2ZeYANKenADbmpsA3pmYANuc
mgDbn5wA1aacAN6gngDqqZoA3Z+gAMyjowDCra0AxqysAMqpqQDboaAA3qKiAN6logDbp6UA3aWkANer
qgDWsbMA0rW0ANe0tADfs7IA4aSiAOGlpQDkp6UA46imAOWopgDsraIA6qimAOGoqADhrqwA6a2rAOqv
rADpsK4A7LGuAOGzswDlsbEA7bKxAO+1sgDotrYA5rm3AO+4twDot7sA6bq5AOu9uwDrv70A8bazAPG2
tADxuLUA9Lm2APC9uwD2vboA9L+9APi+uwD4v7wA8sC+APXAvgD5wL0AkILJAKqXzACsu8cAqr/LALLV
3QDawMIA48XFAOvDwQDswMAA7cTDAO/ExQDgxsgA8cbEAPTGxADwyskA9MvJAPLNzQD21dYA+NjZAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAA////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAMEwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAqHCEcBQAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAayU9PSYbAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdQlBSQiJpAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAM0pSUlJQPRcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnUlJSUlJGFQAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAFJSUlJSUkoQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzUlJSWVJZfxAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAC5XWYqKioqGDgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAASoqMkpqa
mqAsAAAAAAAAAAAAAAAAAABoNAAAAAAAAACMjJyuvLy2toYHAAAAAAAAAAAAABcOIDouBgAAAAAAc4yc
tsHKysPAriIKAAAAAAAAABYgRk1LTX+DEAAAAABukqXB4ejo4dHPQCIEChcXEwggTXV/k66unKMpAAAA
AG6Srsro6ero0dN/Rk1NRk2Dg4STrsbh4cHAt2sAAAAAbpKuOXPe6ajW15KGg4OGk528yuHo5eHPz882
AAAAAAB4jCkDAxSoMabXt5yjt8ro3ePo5dbT09HTdAAAAAAAAABGcBFoGgFwdtfDwHxi2dpmZcrX09HP
z0MAAAAAAAAAAHh/qWwaOa6cz9PNZGPYsdzbzc3DwLk2AAAAAAAAAAAAAAAvhpKakoyg19HNyKS5wHtb
orZ/cwAAAAAAAAAAAAAAAAAANkaKWVm5zb1gYV6cXVxfNgAAAAAAAAAAAAAAAAAAALGvlTIuP1K5tqCR
l4xfLwAAAAAAAAAAAAAAAAAAsbPBenkAAAAAcCVYjE0scwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///////////////////////////+f///+D////A////wH
///4B///+Af///gH///wB///8Af///AH/+fwA/8D4AH8AeAAAAHgAAAB4AAAA+AAAAfwAAAP8AAAH/wA
AD//AAD//gAD//B4D////////////////////////////ygAAAAYAAAAMAAAAAEACAAAAAAAQAIAAAAA
AAAAAAAAAAEAAAABAAAAAAAAWlJSAHBJSQB1SEgAe1dXAHdYWAB5WlkAel1dAGBiYgB1bGwAfWtrAHh2
dgB9fn4Ag01NAIRXVwCIV1cAhV9eAItbWgCgX14ApV1dAJhgXwCNYGAAnWtqAJhtbQCCdnYAh3x8AI15
eACeensAqGBgAKhoZwCga2oArGpqALNqagCzb28AtG1tALltbQCxb3AApnVzAKlzcwCqdHMApnp6AKd+
fgCpensAq3x7ALZ3dgC8dHQAvH59AMZvcADGcHEAxXN0AMhycwDJdncAynh5AMx5egDNfn8Ajo1wAOek
VgDGgH8A4p53AEZ2+gB8u4AAd8PaAIuEhACOh4cAjo6OAJ+DggCejo4Ao4SEAKSIiACsi4sAqo2MAK6P
jgC+gYAAvoaGAL+KiACskJAAtJeXALWenQC5np4At6iOAKmyjgC9nroAwYSDAMaGhADOhoYAxomHAMiK
iQDJjYwA0oeIANOOjwDUjY0A2ZiPANaPkADGkZEAx5eXAMySkADGnZwA1ZOSANeTlADWl5YA2JSVANGZ
mADan50A3J6dAOCcmwDVoJ8A7K2fAMOtrQDXo6IA3aCgAN+kpADVq6oA3ay3AMu0tADPtrYA3L+/AOCi
oQDhpqUA5KelAOinpgDlq6gA46usAOOvrQDqrqwA7LGuAOayswDjtrQA5re1AOqysQDts7EA57y6AO+8
ugDrvL0A8LOwAPC1sgDwtrQA87q3APS6twD2vboA8b69APi/vAD2wb4A+cC9AJmTzwDHqMMAu8PMAIHf
8QDByNAA7cLCAO3FwwDvxsQA5cjIAOzOzgDwxcQA9cbEAPPP0AD10tIAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAD///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
BQMJAAAAAAAAAAAAAAAAAAAAAAAAAAAPHBMNAAAAAAAAAAAAAAAAAAAAAAAAABojLy8TAAAAAAAAAAAA
AAAAAAAAAAAAAB0wMDAiPgAAAAAAAAAAAAAAAAAAAAAAQjAwMDAtGAAAAAAAAAAAAAAAAAAAAAAAFzIy
NTU5CgAAAAAAAAAAAAAAAAAAAAAAIjZYWFxcBwAAAAAAAAAAAAAAAAAAAAAANlxtdW11JQAAAAAAAAAA
PgcRDgkAAAAAXG1/lISAZgMAAAAAABkVLC5SVhcAAABNY3WWnJuLfB8UBAcQHkhWaX91dSsAAABNY2BM
mJeCiVJSVl9laX+WloSJgEIAAAAAXAEIC0tGjnR0dJaRk5qNjIyJQwAAAAAAJkNADBtdjIaPO1GSPYuJ
hnVEAAAAAAAAAClISWRcd4xwkGp8UE90VwAAAAAAAAAAAAAAKSQ1NYZ7OjhbPDdGAAAAAAAAAAAAAHNv
YGsAKyJoXFYmRwAAAAAAAAAAAAAAcnIAAAAAAAAATgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AP//
/wD///8A////APx//wD4f/8A8H//APA//wDgP/8A4D//AOA//wDgP8EA4B8BAMAAAQDAAAEA4AADAOAA
BwDwAB8A/AA/APCA/wDn9/8A////AP///wD///8AKAAAABAAAAAgAAAAAQAIAAAAAAAAAQAAAAAAAAAA
AAAAAQAAAAEAAAAAAABjZGQAdmRjAHtpaQB/eHgAgU9PAKBaWgCFbm0AlWtqAKptbgCwZ2cAsGhoAKxw
cACteHkAvnJyAMZvcADGcHEAy3l5AMx9fgCFmXQAwIB/ANeUfQDhoX8AlIqJAJWMjACYiIgAoIaGAK2K
igCxh4cAvoGAALKKigC4iYgAuJWVAL2cnACss50AuqKhAL+mpgDLgoIAxImHAMeNjADLkI8AxpWTANCS
kQDYlZUA1J6dANqZmgDdnp4A1J+oAMaiogDOr68AzLKyANi5uADhpaIA4qypAOWtqADrrqsA4bKwAOay
sgDtuLYA57++AOy4uADxtLIA8be0APa9ugDswL4A9sG+ALCcxwC5ncIA06zBALnH0QC2ytQA7sPDAPLS
0gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAZBgUAAAAAAAAAAAAAAAAACw8KAAAAAAAAAAAAAAAAGhAQDgAAAAAAAAAAAAAAAAkRESUYAAAA
AAAAAAAAAAAlKy4uBwAAAAAAAAcDAAAAKzlHPCYCAAAYCB0oKgAAAC0wSDs0FB0nLDlAOiwAAAANAQQb
Pi9DRkVBPzUAAAAAJB4cKz5EQjMiNSkAAAAAAAAAHwwRNxYVEyQAAAAAAAAxMgAAACEgAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//8AAP//AAD//wAA4/8AAOP/AADD/wAAwf8AAMH5
AADAwQAAwAEAAMADAADABwAA8A8AAM5/AAD//wAA//8AACgAAAAwAAAAYAAAAAEAIAAAAAAAgCUAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAkAAAAJAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAUAAAAOAEBAVUAAABUAAAANQAAABAAAAABAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAkFBSUvGRl5TCkpwlYuLtxDJCTQFw0NmQAA
AEkAAAAPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACGAwMKE8rK6V6RET2klJR/5ZS
U/+OT0//ZDc38B0QEJoAAAAyAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYDAwYVzAwoopP
T/ygXVz/oFtb/55ZWf+bWFf/k1NT/1UvL9wGAwNcAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AARNKipxhk5O+adkY/+uZWX/tWdo/7VmZ/+qYWH/nltb/3hERPcfERGCAAAAFgAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAADEZGS1zQ0LXqGdm/7ptbf/Fb3D/x3Bx/8hwcf/BbW7/q2Vl/4hPT/82HR2gAAAAIAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAB1gxMYyYXl3/vXFx/8Zwcf/HcHH/x3Bx/8dwcf/HcHH/uG1t/5NY
V/9EJia2AAAAKQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPB8fNH1MS+K4cnH/x3Fy/8dwcf/HcHH/x3Bx/8dw
cf/HcHH/wHBx/51gX/9PLCzGAAAAMwAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACXjU1h6NnZv/Fc3T/x3Bx/8dw
cf/HcHH/x3Bx/8dwcf/HcHH/w3Jz/6ZoZ/9ZMzPTAQAAPQAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAyFxccektK0b12
dv/HcHH/x3Bx/8dwcf/HcHH/x3Bx/8dwcf/HcHH/xXR0/69wb/9jOjneBwMDSQAAAAUAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AABNKSlNlmBf9sh3d//HcHH/x3Bx/8dwcf/HcHH/x3Bx/8dwcf/HcHH/xnd3/7Z4d/9sQUDnDgcHVQAA
AAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAABkOjqKsXFw/8lyc//HcXL/yHJz/8l0df/JdXb/yXV2/8l1dv/JdHX/ynt7/7+B
f/94SknvFgsLZQAAAAsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAACILCxB7TUzDwXd3/8lyc//KdXb/y3h5/8x7fP/NfX7/zX5+/819
fv/NfH3/zoOC/8iJiP+GVVX3Hg8QegAAABIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEMiIi+SXl3oynp7/8t4ef/NfX7/z4GC/9GE
hf/Sh4j/04iJ/9KIiP/Rhof/04uK/8+RkP+XY2L9KxcXlwAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAABwAA
AA0AAAAPAAAACwAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFUvL1enbW37zn5+/85/
gP/Rhob/1IuM/9aPkP/XkpP/2JOU/9iTlP/XkZH/15OT/9eZl/+rdHP/QSUlvAAAADwAAAAFAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAACQAA
ABgAAAAvAgEBSwcDA2EFAgJoAAAAWAAAADYAAAARAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGU8
O4W5eXn/0IKD/9KIif/Wj5D/2ZWW/9ubm//dnp//3qCg/92foP/cnZ3/3Jyc/9+in//CiYf/Zj8/4wYC
AnAAAAAbAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAA
AA4AAAAnCQQEUCISEoQ+IiKzVzEx1mU6OuZiOTnmRigo0hgNDZsAAABMAAAAEAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAABnVJSK/HhIP/04eI/9aQkf/amJn/3qCh/+Gmp//jq6v/5Kyt/+OsrP/iqan/4aal/+ap
p//Umpj/nmxr/C8ZGboAAABXAAAAGAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAIAAAAOAQAALRkNDWY+IiKpZDo63YZRUfigZGP/sHBv/7V0c/+xcnH/oWZm/2k+PvEfEBCcAAAAMQAA
AAMAAAAAAAAAAAAAAAAAAAAALhAQFIZXVs/RjIz/1Y2O/9qYmP/eoaL/46qr/+aysv/ot7f/6rm5/+m4
uf/otbX/5q+v/+uvrf/jqab/wYeF/28/P/QhEhKvAAAAXwAAACgAAAANAAAABQAAAAMAAAACAAAAAwAA
AAUAAAAKAAAAFQAAADAdDg9oSSkptHZHRu2dYmL+t3Z1/758e/+6enn/tnh3/7d5eP+8fn3/w4SD/7Z6
ef9eODfbBgICTgAAAAgAAAAAAAAAAAAAAAAAAAAAPhwcJJVjYuPXkZH/2JOU/92fn//iqqr/57O0/+u8
vP/uwsL/78XG/+/Exf/twMD/67i4/+60sv/wtrP/zZKQ/5taWv9xQED2MRsaxAgEBIcAAABaAAAAQQAA
ADcAAAA2AAAAOwAAAEUEAgJZHA4OfUcnJ7l5SkntqGxr/8CAfv/DgoH/vH59/7p+ff/DiIb/zZGP/9GT
kf/UlJP/1peV/9eZl/+GVlbuGQsLVwAAAAcAAAAAAAAAAAAAAAAAAAAARiIiLZ9rauvZk5P/2peY/+Ck
pP/lsLD/6ru7/+/Fxf/yzMz/9NDQ//PPz//xycr/7sDA//K5tv/1u7j/36Kg/6dmZf+mZWX/j1ZW/WM6
OutDJSXQNBwcvDAaGrQ0HBy1PiIivUwsLMtkPDzfh1VU9a1xcP/EhIP/xIWE/7+Cgf/Ch4b/zZST/9mk
ov/grq3/4a6t/96lo//eoJ7/36Kg/+Cjof+IWVjnGwwMQwAAAAIAAAAAAAAAAAAAAAAAAAAARyQkL6Br
auzZk5P/25qb/+GnqP/ntLT/7cDA//LLy//209T/+NjY//fX1//00ND/8cbG//W9u//4vrz/46ak/7d0
c/+vb27/s3Jy/7d2df+ucXD/pWpp/6Npaf+nbWz/sHVz/7p9fP/EhYT/yImI/8WIhv/DiIb/ypGP/9eg
n//hr63/57q5/+rCwP/rwsD/6bq4/+evrf/nq6n/6q6r/9qgnv9wRkbDBwAAHgAAAAAAAAAAAAAAAAAA
AAAAAAAASCQkLZ1nZuvYkpP/25uc/+Opqv/qtrf/7cHB//TOzv/52Nj/+tzc//na2v/xz9D/8MfH//fA
vv/6wb7/6a6r/8OBgP/DgoD/vX58/7h7ev+8fn3/woOC/8aHhv/HiYj/xoqJ/8aLif/Ijoz/zZST/9eg
nv/hrav/6Lm3/+zCwf/uyMf/78nH/+/Dwf/uvLr/7ba0/+60sf/vtLL/8ri1/7J+fflMKSltAAAABAAA
AAAAAAAAAAAAAAAAAAAAAAAAQyEhI5JcXOPWj5D/3Juc/8qVlf+BZmb/bl5e/4l4eP/AqKj/8tPT//LO
zv+5p6b/w6qq//fBv//7wr//8LWy/86Ojf/Ojoz/0ZGP/9GSkP/OkY//zpOR/9GamP/VoJ//2qel/+Gv
rf/nt7X/6727/+3Dwf/wycf/8czL//LLyf/yxsT/8cC+//G7uf/yubf/87m3//S7uP/4vrv/1J6c/3JH
RrAdCgsWAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANRcXEYJNTcvPiIn/15aW/2VNTf85Ojr/Q0VF/0JF
RP9dXFz/n5GR/+S/v/+bh4f/hXp6/+25uP/7wr//9bu4/9qcmv/Zmpj/252b/96gnf/ipKH/5q+s/+u+
vP/vycf/8srI/+3Hxv/wysj/9c7M//TNy//0ysj/9MbE//TBv//1vrz/9r26//e9u//4vrv/+L+8//vB
vv/hqqf/g1ZVzDwcHC4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAW4+Ppq/env/05OT/2ZX
V/9rbm7/fX9//3l6ev99f3//cHJy/5F9ff+ff3//XFhY/9eop//8wr//+L+8/+Wppv/ipaP/5qil/96i
pP/Kmaz/1qi1//LGxP/tyMf/qb3J/23E3P9kw9//vMTN//jDwP/3wb//+MC9//i/vf/5v73/+b+8//i/
vP/3vrv/+L68/92mo/+IWlnRRSMjOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFcv
L0mbX1/y15GS/6GAgP9XV1b/iYuL/4CBgf98fX3/cnR0/1dPT/++j4//km9w/9Sfnv/6wL3/+cC9/+6z
sP/ssK3/0Z+u/4OH1P9YffD/QGPs/7KYyv/Ct7z/Ytrz/3Ts//8s2f//cbvU//m+u//4v7z/+L67//e9
uv/1vLn/9Lq3//O5tv/zuLX/0puZ/4RVVctGIyM4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAADIXFwdrPDySq2ts/diZmf/ApKT/sKur/4CBgP95enr/iYiI/49zdP/do6P/36Ch/96e
nv/zuLX/+sK///W7uP/1ubT/qZC//2qY+/9tnf//MGT6/56FxP/esK//nMbS/57n8/9+z+T/ybG3//a6
t//zubb/8re0//C1s//utLH/7rKw/+qvrP++iIb9dklJtkMgISoAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABHIyMSazw8kZ5hYvXNjI3/2aSk/7OMjP+bd3f/sIKC/9KV
lv/cnJz/2peY/9aRkf/koqL/+sG+//nAvf/5v7z/4amw/6qZx/+aouP/qpvP/+mxtv/2urj/6rGv/+S6
u//ptrX/466n/+Ovqf/ssK7/6q6s/+isqv/oq6n/2J2b/6JubfFoPT2NOxoaFwAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOBoaCFowMFd7SEjAomZm9sWC
gv/XkZL/25SV/9iSk//Wj5D/1IyN/9KHiP/UiIj/8bOx//rCv//3vbv/9ru4//O3s//xuLX/7q6e/+ej
hf/npIn/7bCp/+Otp/+KsX3/ULdm/1WjWv+7oYz/5KWk/9uenP+4gH79glJRzVYuLlQgCAkGAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAA8HBwQVy4uS3FBQaCPV1fjsG5v/cmAgf/ShYb/0YKD/85+f//LeXr/2I2M//e8uf/1vLn/7rOx/+2y
sP/lpJX/5qFY/+6xXP/djS3/35h9/86gl/9SwW7/Nd90/0WxXP+vlH//wYSE/49cW+VlOTmBQR4eHAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAGk7OhqIWFd8oG5u8J5qav+eX2D/tmts/8Z0df/KdHX/yXJz/92T
k//3vLn/7LGu/+Snpf/dm5L/4Z1q/+61dP/fmmX/15WM/9eYlv/Bm43/r6uR/6uNgP+WYWDtbkBAnUwn
JzQVAQECAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAiFJSBnhC
QgpqNDQJWSUlB08dHQdfKisKfENDFJJWViinbGtRvYOCjtOcm8/pt7X157y6/7eOjfhxRUW7aTk5m4RK
StehWlr6uGdo/8Zwcf/dkpH/8bSx/+OnpP/YmZj/1ZWT/9ealP/Vl5X/0JCP/8eIhv+zdnb/lFtc6nA/
QKRSKio/JQwNBgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AADTn6AB2qioDMuUlCHBhYU8voCAWcCBgXTEhoaLzZGQqdeensngrKvn47Sz/NOop/+yiIfyi2Bgs2k+
PlZXKysPAAAAAUYlJRxcMTFYcj4+pYpMTeWmXF3+xnl5/9+Zl//dnJr/z46M/8KCgf+vc3L/ll9e831L
S8hlOTl/TigoMy0REQYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAABzQUIDnmprDriGhifHlpZMzp6eeNCgoZ7On5+2yJqaybuPj9WnfHzVj2RkunVJ
SYNbLy8/PRQUCgAAAAAAAAAAAAAAAAAAAAAAAAAAKRUVBU0pKSphNDRtd0BAsotNTd2ZW1vrkVlY4HtJ
Sb5lOTmCUysrQTsbGxEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWCwsA2Y4OA5xQkImdkhIRHhKSll0R0dibUBAWWI2
NkNUKCgoOhISDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMhkZB0km
Jh5LJiYsRSEhITATFAsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///////8AAP//
/////wAA////////AAD///////8AAP///////wAA////////AAD/+H////8AAP/gH////wAA/8Af////
AAD/gA////8AAP+AD////wAA/wAP////AAD/AA////8AAP4AB////wAA/gAH////AAD8AAf///8AAPwA
B////wAA/AAH////AAD8AAf///8AAPgAB////wAA+AAH//4HAAD4AAP/8AEAAPgAAf/AAQAA8AAA/wAA
AADwAAAAAAAAAPAAAAAAAAAA8AAAAAAAAADwAAAAAAEAAPAAAAAAAQAA8AAAAAADAADwAAAAAAcAAPAA
AAAADwAA+AAAAAAfAAD4AAAAAD8AAPwAAAAAfwAA/gAAAAD/AAD/gAAAA/8AAP/gAAAH/wAAgAAAAB//
AAAAAAAAf/8AAAAD4AP//wAAgB/8H///AAD///////8AAP///////wAA////////AAD///////8AAP//
/////wAA////////AAAoAAAAIAAAAEAAAAABACAAAAAAAIAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAYAAAAZAAAAGQAAAAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAARCQkYOh8fb0ooKK80HByiCQUFTAAAAAkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAIhERFmA2Np2ITUz3lVNT/4dLS/5IKCi9AAAALwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAANjODiBllhY+61kZP+vY2P/pV5e/3xHRvEhEhJfAAAAAgAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAASSgoN41VVeS6bW3/xW9w/8dwcf+9bG3/klZW/jogIIEAAAAGAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZ1RkWcs2xs/8dxcv/HcHH/x3Bx/8Zwcf+iYWH/SSkpmAAA
AAsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUC0tMZtgX+fGcnP/x3Bx/8dwcf/HcHH/x3Fy/61q
av9UMTGqAAAAEQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABxRER1tm9v/8hxcv/HcHH/x3Bx/8dw
cf/HcnP/tnRz/185OboAAAAZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABwAACIxXV7TEdHT/yHJz/8l1
dv/Kd3j/ynd4/8p4eP/Bf37/bURDywAAACQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABNKysjo2Zm4Mt4
ef/NfH3/z4GC/9GFhf/RhYb/0YWF/82Mi/9+UVHeCAICOwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAJAAAACwAAAAUAAAAAAAAAAAAAAAAAAAAAAAAAAGc+
Pkm1c3P30IGC/9OJiv/XkZL/2ZaW/9mWl//YlJX/2JmY/5hnZfMeEBBrAAAABwAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAA0FAgItHhAQWzAbG4IqFxeHDQcHWwAAABkAAAAAAAAAAAAA
AAAAAAAAek1MdMN/f//VjI3/2piZ/9+io//hqKn/4qmp/+Clpf/jpqT/wImH/04xMLwAAAA6AAAABQAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAABEbDg5GRygokW5CQs+MVlbxnGJh/JdfXvxnPz7hHA8PbgAA
AAwAAAAAAAAAAAAAAACMW1qbz4qK/9qXl//gpqb/5rKz/+q6u//rvLz/6La2/+qxr//epKL/j1lZ+DUc
HLACAQFPAAAAHQAAAA8AAAAPAAAAEwAAACIbDg5MVDExnYZUU+SpbWz+uXl4/7x+fP/AgoD/xoeF/72A
f/9fOzu1AAAAHAAAAAAAAAAAAAAABJhkZK/VkZH/3Z+g/+axsf/twMD/8svL//LNzf/vxcX/8Lq4/+6z
sf+1dHP/j1VU+144N9g7IiKqMhwclDcfH5RGKSmiYTw7v4tZWOiydXT+woOC/8aKiP/Ol5X/2aWj/9ui
of/cnpz/2pyb/35TUrgAAAAVAAAAAAAAAAAAAAAFmmVkstaTk//hpaX/7Lm6//TLy//419f/+NnZ//TP
z//1wb//9Lq3/8aGhP+1dHP/s3Rz/6xwb/+pb27+rnNy/7Z7ev/BhIL/yY2L/8+WlP/apqT/5be2/+vB
v//rvrz/6bKw/+uvrf/Um5n/bUVEgAAAAAMAAAAAAAAAAAAAAAOTXV2q1ZGR/9CYmP+dfX7/o4yM/9e8
vP/z0tL/zLOz/+u8u//5v7z/1peV/8uLif/Ki4r/yoyL/86Ukv/TnJv/2qSi/+Gtq//nuLb/7cPB//DJ
x//xxsT/8b+9//G6t//zubf/77az/6d1dM89Hx8lAAAAAAAAAAAAAAAAAAAAAIJOTojNiIn/jGlp/01O
Tv9UVlb/dnNz/7uhof+Pfn7/xJ+e//zCv//lqKb/3J2b/+Chnv/hpaT/7Ly5/+vHxv/MxMn/0MjN//LK
yf/1x8X/9sLA//a/vP/3vrv/+L+8//S7uP+5hoXhYTo5RwAAAAAAAAAAAAAAAAAAAAAAAAAAaTs7RrVz
dPKmfn7/cXJx/4SGhv97fX3/b2Zm/516ev+7kJD/+sG+//C2s//lqqr/rpbA/3aB2/+ql83/tMHK/2jc
9P9OzOz/2r3B//q/vP/3vrv/9ry6//a8uf/ss7D/tYGA32c+Pk0AAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAvEhIHg01Njbp9fvrCn5//nI+P/4R7ev+fgID/2Jyd/9ybnP/ytrT/+b+8/+ewtf+Mld3/ZI36/5eI
zv/Ttrn/sNLc/6/Czv/stLT/8re0/++0sf/tsq//2qCe/6Rxb8phODg+AAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAABCIB8MeUZGbqRpata8gYH8x4mJ/9eTk//YkpP/04qL/+Cbmv/5wL3/9726/+Sw
t//Zrrn/56qY/+2smf/lr6n/nLWJ/4Gtdf/Pppn/3qGf/7yEg/KJWViYTyoqIAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQh0dGXJAQGOXXl7NtnR1/8V7fP/MfH3/znt8/+il
o//0urj/7LCu/+Whg//rq13/35VX/9Kek/9yvXz/ZbNv/6iCdfqYY2O/aj4+TCUJCgcAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAACcamsBjFRVB4FERAh9PT0JjU1ND6VnZx+/hINF0JqZiNOjoty0iIf2hFBQw5lX
V8+wY2P4xXR0/+aioP/oq6j/2pqT/92fif/Vlor/yYqJ/7N8efiVZmPGdERFYkEfHxIAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAALiFhgXFkJEdx5CQSMqSknbNlZWbz5uaws2cnOXBlJPnqH18r4dc
XFFULy8OSCUlFm07O0+FSUmeoV1d3sF9fPrGhoX/snZ295xkZNiFUlKbbD4+T0UdHxIAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAc0JDA5FgYRKdbm46onR0Zp9ycnuWampzhFlZVmY6
OikvDAwHAAAAAAAAAAAAAAAAAAAAAB0ODgRULCwhbjo7UXhERGVrPDxHTCYmGxAAAQMAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAACAAAAAgAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAP//////////////////////D////gf///wH///4A///+AP///AD///wA///8AP//+AD
///gA//D4AH+AeAA+ADgAAAAwAAAAMAAAADAAAAB4AAAA+AAAAfgAAAP8AAAH/wAAD8AAAD/AAAD/wB4
D//H////////////////////KAAAABgAAAAwAAAAAQAgAAAAAABgCQAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAABMAAAAtAAAAEQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAgIO1cwMM1qOjrsHhAQmwAA
ABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAATCgogfUhI6ahgYP6lXV3+f0hI9wIBAT0AAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAsGBgFPLy6kuW1t/sZv
cP/Gb3D/oF9e/hMKCmgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAB4QECynZmX7xnBx/sdwcf/HcHH/tG1t/h8REYMAAAABAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFAx
MIzFc3T+xm9w/sdwcf7HcHH+vHR0/jAcHJkAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGQ4OAYVSUtfIcnP/yXZ3/st5ef/LeHn/xoB//kQq
KrEAAAAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAJxYWGrNvb/7Nfn//0oeI/tSNjf/UjI3/1ZOS/mE+PtQAAAAXAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAIAAAARAAAALQAAADUAAAARAAAAAAAAAAAAAAAAQyYmUM6Ghv/Wj5D/3J2e/uCl
pf/fpKT/4KOi/qRycPkHBARlAAAABQAAAAAAAAAAAAAAAAAAAAAAAAADAQAAJh8REYBYNTXMhVJR8XxM
TO8gEhKeAAAAEAAAAAAAAAAAbUVEe9aPkP7doKD+5rKz/uu9vv7rvLz+6rKx/tqfnf5iNzfnCAQEcwAA
ACoAAAAbAAAAIQIBATorGBiQhFNT67Z3dv68fn3+wYSD/siKiP6aZmX2AQAAKQAAAAAAAAAAd05Ni9eT
lP/jq6z/7cLC/vXS0v/zz9D/8b69/uyxrv+samr/l15d+2tDQ+NkPz7bdkxL451nZve+gYD/yY2M/tWg
n//jtrT/46+t/uOmpP+mdHPwBQMDFAAAAAAAAAAAdkpJh9iUlf7Hl5f+tJeX/uzOzv7lyMj+57y6/vS6
t/7HhoX+xYaE/saJh/7MkpD+0ZmY/tejov7mt7X+7cXD/vDFxP7vvLr+8Le0/u2zsf5PMzOMDQcHAQAA
AAAAAAAAYTg4X9OOj/9aUlL/YGJi/nh2dv+skJD/qo2M/vnAvf/dn53/4KKg/+Cnp/7vxsT/u8PM/sHI
0P/1xsT/9sG+/ve+u//3vrv/87q3/ntVVLkkFhYIAAAAAAAAAAAAAAAAVC8wD6BkZOWjhIT/jo6O/n1+
fv+eenv/xpGR/vi/vP/wtbL/mZPP/0Z2+v69nrr/gd/x/nfD2v/2vLr/9Lq3/vG2tP/lq6j/elJRrjQg
IAoAAAAAAAAAAAAAAAAAAAAAAAAAAGc7OyeOWVnGv4eH/r2Fhf7YlZb+1Y6P/uinpv74v7z+3ay3/seo
w/7srZ/+7LGv/qmyjv63qI7+5Kel/r2GhPZ1S0p1QCcmAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAd0pKOpReXtKxb3D/yXl6/sx5ev/ws7D/6q6s/+Ked/7npFb/2ZiP/ny7gP+OjW/9h1dWr2I7
OiMAAAAAAAAAAAAAAAAAAAAAAAAAALSCggSqcXIbo2dnN61xcVS/h4eIzp2c2cKWle2OY2OGbz4+Y4xN
Tr6zaWn84Jyb/9aXlv7Ji4r/p25t9INTUqZlPDw3AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJJg
YASjcnMorH9/a6h7e4yabm6Df1NTU3VKSgwAAAAAAAAAAAAAAABgNDQgcj8/bntHR4ZnPDxTVTExDQAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAP///wD///8A////APx//wD4P/8A8D//AOA//wDgH/8A4B//AMAf
/wDAH8EAwA8AAMAAAADAAAAAwAAAAMAAAQDAAAMA4AAHAPgAHwAAAH8AAcH/AP///wD///8A////ACgA
AAAQAAAAIAAAAAEAIAAAAAAAQAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADQc
HA5LKSlUNBwcSAAAAAUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABsO
DgV/SkqHm1hY+X5HR90tGRkuAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAB4SEhCr2Zm7sZwcf+oYWL5UC8vUwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAACnl9fnMRwcf/IcXL/tmxs/mI8PGgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAa0NCGbRsbdbMenv/zn5//8R9ff9ySkmCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAA
AAkAAAAAAAAAAItYWDvFfn/y2ZWW/92fn//anJv/jWFgvwAAAB0AAAAAAAAAAAAAAAIzHBwiYjs7a3pM
S6pqQkKjLBoaMwAAAACeZ2dZ05KS/em0tP/vxMT/77u6/8CHhfpmPDyvRysqYlExMV1ySEiGnWdn07qB
gPzLkI//w4iG/HJLS3YAAAAAomloXsyRkf/DoKD/48bG/+jAv//hpKL/vX17/7h/fPu/iYj7z5qZ/+Gw
rv/rvLr/77q3/9ScmuR9U1I+AAAAAJZbWz2ndnbxdG9v/4yCgv+4lJP/77Wy/86erP+6nsH/tsXR/8PH
0P/4wsD/9b26/+Cppu2peXdiAAAAAQAAAABYKCgHn2lqe6eCguSsgoL90pKS//Cxrv/TrcP/s5y+/8i3
s/+quab/26mh/82UktSgbm1TBAAAAwAAAACud3cEvYGBC7N6ehyyfHtyt39+3bNub9vLgYH05qak/+Kg
g//OlH39jZR04Zd0aYmDT1EiAAAAAAAAAAAAAAAAr3t7D7aCgki5h4Z8uImJgah+fUltPz8ajU1ORq1s
bI6vdHOgm2RkaYxJUiZgCygCAAAAAAAAAAAAAAAAAAAAAGo9PQF9UVEHcEdHCTodHQIAAAAAAAAAAAAA
AAAAAAABAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//8AAP//AADh/wAAwf8AAMH/
AACB/wAAgfkAAIDAAACAAAAAgAAAAIAAAACAAQAAAAcAAAAPAAAOfwAA//8AAA==
</value>
</data>
</root>

View File

@ -2,6 +2,7 @@
using System.Drawing;
using System.Windows.Forms;
using BizHawk.Emulation.Common.IEmulatorExtensions;
using BizHawk.Client.Common;
namespace BizHawk.Client.EmuHawk
@ -66,7 +67,7 @@ namespace BizHawk.Client.EmuHawk
private void SetMaxXY()
{
var video = BizHawk.Emulation.Common.VideoProviderGlue.VideoProvider(Global.Emulator);
var video = Global.Emulator.AsVideoProvider(); // TODO: this is objectively wrong, these are core agnostic settings, why is the current core used here? Also this will crash on a core without a video provider
XNumeric.Maximum = video.BufferWidth - 12;
YNumeric.Maximum = video.BufferHeight - 12;
PositionPanel.Size = new Size(video.BufferWidth + 2, video.BufferHeight + 2);

View File

@ -21,7 +21,7 @@ namespace BizHawk.Client.EmuHawk
return;
}
string[] coresToHide = { "INTV", "C64" };
string[] coresToHide = { "C64" };
foreach (var core in coresToHide)
{

Binary file not shown.

After

Width:  |  Height:  |  Size: 567 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 628 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 586 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 549 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 827 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 546 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 623 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 663 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 723 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 642 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 785 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 771 B

View File

@ -13,14 +13,18 @@ using BizHawk.Client.EmuHawk.WinFormExtensions;
namespace BizHawk.Client.EmuHawk
{
// TODO - Allow relative paths in record textbox
public partial class RecordMovie : Form
{
// TODO - Allow relative paths in record textbox
public RecordMovie()
private IEmulator Emulator;
public RecordMovie(IEmulator core)
{
InitializeComponent();
if (!Global.Emulator.HasSavestates())
Emulator = core;
if (!Emulator.HasSavestates())
{
StartFromCombo.Items.Remove(
StartFromCombo.Items
@ -29,7 +33,7 @@ namespace BizHawk.Client.EmuHawk
.ToLower() == "now"));
}
if (!Global.Emulator.HasSaveRam())
if (!Emulator.HasSaveRam())
{
StartFromCombo.Items.Remove(
StartFromCombo.Items
@ -88,9 +92,9 @@ namespace BizHawk.Client.EmuHawk
Directory.CreateDirectory(fileInfo.DirectoryName);
}
if (StartFromCombo.SelectedItem.ToString() == "Now" && Global.Emulator.HasSavestates())
if (StartFromCombo.SelectedItem.ToString() == "Now" && Emulator.HasSavestates())
{
var core = Global.Emulator.AsStatable();
var core = Emulator.AsStatable();
movieToRecord.StartsFromSavestate = true;
movieToRecord.StartsFromSaveRam = false;
@ -112,15 +116,15 @@ namespace BizHawk.Client.EmuHawk
{
// hack: some IMovies eat the framebuffer, so don't bother with them
movieToRecord.SavestateFramebuffer = new int[0];
if (movieToRecord.SavestateFramebuffer != null)
if (movieToRecord.SavestateFramebuffer != null && Emulator.HasVideoProvider())
{
movieToRecord.SavestateFramebuffer = (int[])Global.Emulator.VideoProvider().GetVideoBuffer().Clone();
movieToRecord.SavestateFramebuffer = (int[])Emulator.AsVideoProvider().GetVideoBuffer().Clone();
}
}
}
else if (StartFromCombo.SelectedItem.ToString() == "SaveRam" && Global.Emulator.HasSaveRam())
else if (StartFromCombo.SelectedItem.ToString() == "SaveRam" && Emulator.HasSaveRam())
{
var core = Global.Emulator.AsSaveRam();
var core = Emulator.AsSaveRam();
movieToRecord.StartsFromSavestate = false;
movieToRecord.StartsFromSaveRam = true;
movieToRecord.SaveRam = core.CloneSaveRam();

Some files were not shown because too many files have changed in this diff Show More