|
Joined: Feb 2014
Posts: 1,135 Likes: 198
Very Senior Member
|
Very Senior Member
Joined: Feb 2014
Posts: 1,135 Likes: 198 |
Here's some routines to draw the print shop fonts (on the original disk) ![[Linked Image from i.imgur.com]](https://i.imgur.com/3c5go3r.png) ![[Linked Image from i.imgur.com]](https://i.imgur.com/AuXWGf3.png) ![[Linked Image from i.imgur.com]](https://i.imgur.com/WIK5RXd.png) ![[Linked Image from i.imgur.com]](https://i.imgur.com/pX7G3MA.png)
-- printshop_drawfont7.lua
function applemem()
if applememobject == nil then applememobject = manager:machine().devices[":maincpu"].spaces["program"] end
return applememobject
end
function calc(line,page) if line<0 then line = 0 end if line > 191 then line=191 end page=page or 0 return line % 8 * 1024 + math.floor(line / 64) * 40 + math.floor((line%64) / 8) * 128 + 8192* (page + 1) end
function calcyaddr(line,page) return calc(line,page) end
function readswitch(a)
local cpu = manager:machine().devices[":maincpu"] local mem = cpu.spaces["program"]
mem:read_u8(a)
end
function hgrfull(page)
page = page or 1
readswitch(0xC050) -- graphics
readswitch(0xC052) -- full screen
readswitch(0xC054+page-1) -- page 1
readswitch(0xC057) -- hi res
end
function hgr(page)
page = page or 1
readswitch(0xC050) -- graphics
readswitch(0xC053) -- full mixed
readswitch(0xC054+page-1) -- page 1
readswitch(0xC057) -- hi res
end
function textmode()
readswitch(0xC051) -- text
readswitch(0xC054) -- page 1
end
function text()
readswitch(0xC051) -- text
readswitch(0xC054) -- page 1
end
function hgrclr(page)
local cpu = manager:machine().devices[":maincpu"] local mem = cpu.spaces["program"]
for y=0,191 do for x=0,39 do mem:write_u8(calc(y)+x,0) end end end
function hgrwhite(page) for x=0,39 do for y=0,191 do applemem():write_u8(calcyaddr(y,page)+x,127) end end end
function getbits(a,lobit,hibit) local retval=0 for bit=lobit,hibit do retval=retval|((1<<bit)&a) end return retval end
function getbitsshift(a,lobit,hibit) return getbits(a,lobit,hibit)>>lobit end
function getfilenamepart(s)
local curpos=1
repeat
local newpos=s:find("/",curpos,true)
if newpos then curpos = newpos+1 end -- if you don't add the +1, keeps getting same match, infinite loop
until newpos == nil
return s:sub(curpos)
end
function trim2(s) return s:match "^%s*(.-)%s*$" end -- from lua users wiki
-- plot function, haven't got all the operations working yet but or,xor,store,and inverse seem to be ok
function plot(x,y,page,bit,operation) page=page or 0 x = math.max(0,x) x = math.min(x,279) y = math.max(0,y) y = math.min(y,191) mem=applemem()
local memloc=calcyaddr(y,page)+math.floor(x/7)
local readval=mem:read_u8(memloc) local bitpos=x%7
local mask=~(1<<bitpos)
local invertmask=(1<<bitpos)
local bitshifted = bit<<bitpos
local notbitshifted=(iif(bit==0,1,0) << bitpos)
if operation == nil or operation == "or" then mem:write_u8(memloc,readval | (bit<<bitpos))
elseif operation == "erase" then mem:write_u8(memloc,readval & (bit<<bitpos))
elseif operation == "color" then mem:write_u8(memloc,readval & (bit<<bitpos)) -- erase = color black
elseif operation == "xor" then mem:write_u8(memloc,readval ~ (bit<<bitpos))
elseif operation == "store" then mem:write_u8(memloc,(readval & mask) | bitshifted)
elseif operation == "inverse" then mem:write_u8(memloc,(readval & mask) | notbitshifted)
else error("PLOT OPERATION "..operation.." not recognized") end
end
function revbits(a) if a==nil then print("REV NIL") return nil end local r=0 for i=0,7 do r=(r<<1)+a%2 a=a>>1 end return r end
-- 0x3b = 59 so we can have 59 characters per font
--
-- byte offset 0x3b * 0 + c = width of character
-- byte offset 0x3b * 1 + c = height of character
-- byte offset 0x3b * 2 + c = offset of character data low byte
-- byte offset 0x3b * 3 + c = offset of character data high byte as well as some flags so AND it with 0x1f
-- fonts on the Print Shop disk are named F0 through F9, in a "hidden" directory (start at t,s=17,2)
-- fonts on Print Shop Companion have additional 12 bytes at the beginning, we're just interested
-- in drawing the bitmap so we can just "ignore" these 12 bytes by using a:sub(13) which means take
-- all the bytes to the end of the string starting at character position 13 (numbered from 1).
function getcharwidth(a,c) return a:byte((0x3b*0)+c+1) end
function getcharheight(a,c) return a:byte((0x3b*1)+c+1) end
function getcharoffset(a,c) return a:byte((0x3b*2)+c+1)+(a:byte((0x3b*3)+c+1)&0x1f)*256 end
--if we draw as bytes then we lose the high bit of the byte and we are on byte boundaries so it looks strange
-- drawing as pixels the fonts look much better
function drawpsfont(a,c0,c1,offset,doprint,xpos,ypos,lineheight,bytesorpixels,drawmode)
-- draw font characters from c0 to c1
c0 = c0 or 0
c1 = c1 or 58
offset=offset or 0
xpos,ypos=xpos or 0,ypos or 0
for c=c0,c1 do
if getcharwidth(a,c) < 128 then
local charwidth=getcharwidth(a,c)
local charheight=getcharheight(a,c)
local charoffset=getcharoffset(a,c)
local charbytewidth=math.floor((charwidth-1)/8)+1
drawmode = drawmode or "or"
if doprint then print("char="..c,"width="..getcharwidth(a,c),"height="..getcharheight(a,c),"offset="..hex(getcharoffset(a,c))) end
if charoffset>#a then print("INVALID CHAR OFFSET")
else
if charheight~=0 then
if c~=32 then
--drawblock loop by bytes
if bytesorpixels=="bytes" then
drawblockloop({"y",charheight,"x",charbytewidth},function(x,y,index) applemem():write_u8(calc(y+ypos)+x+xpos,revbits(a:sub(getcharoffset(a,c)+1):byte(index+offset+1))) end,32)
--drawblock loop by pixels
else
drawblockloop({"y",charheight,"x",charbytewidth},function(x,y,index) local bytetoplot=revbits((a:sub(charoffset+1):byte(index+offset+1))) local numpixels=math.min(8,charwidth-8*x) x=xpos+x*8 for i=0,numpixels-1 do plot(x+i,y+ypos,0,getbitsshift(bytetoplot,i,i),drawmode) end end,32)
end
else -- draw the space
-- leave space blank for now
end
-- draw the gap between characters
if bytesorpixels~="bytes" then for y=0,charheight-1 do plot(xpos+charwidth,y+ypos,0,0,drawmode) end end
end
if bytesorpixels=="bytes" then xpos = xpos+charbytewidth -- by bytes
else xpos = xpos+charwidth+1 -- by pixels
end
end
if bytesorpixels=="bytes" then if xpos>36 then xpos=0 ypos=ypos+lineheight end -- by bytes
else if xpos>240 then xpos=0 ypos=ypos+lineheight end -- by pixels
end
end
end
print("returning xpos="..xpos.." ypos="..ypos)
return xpos,ypos
end
function writepsfonttext(a,s,x,y,offset,charoffset,lineheight,drawmode) charoffset=charoffset or (65-33) for i=1,#s do x,y=drawpsfont(a,s:byte(i)-charoffset,s:byte(i)-charoffset,offset,false,x,y,lineheight,nil,drawmode) print(x) if x>255 then x=0 y=y+16 end end end
-- translate function for combo lower case/uppercase fonts
function translateps(c) -- c passed as a char number
local replacedchars=""
local translate0= "!\"#$%&'()*+,-./0123456789:;<=>?"
local translate1=string.upper("!wmnop`rsqt,k.zjabcdefghivuxly?")
for i=1,#translate0 do
if translate0:sub(i,i)~= translate1:sub(i,i) then replacedchars=replacedchars..translate0:sub(i,i)
end
end
print("REPLACED="..replacedchars)
if c>=string.byte("A") and c<=string.byte("Z") then
local cpos=string.find(translate1,string.char(c),1,true)
if cpos==nil then c=string.byte(c) end
c=string.byte(translate0:sub(cpos,cpos))
elseif c>=string.byte("a") and c<=string.byte("z") then c=c-32
elseif string.find(replacedchars,string.char(c),1,true) then c=string.byte("!")
elseif c>128 or c<32 then c=string.byte(".")
elseif c>90 or c<32 then c=string.byte(".")
end
return c
end
--for i=string.byte("a"),string.byte("z") do c=string.char(i) print(c,translateps(c)) end
--[[
loaddisk("../../PrintShop.dsk")
catalog()
getcatalog(17,2,nil,true)
-- snippet to render font f1
hgrclr() filename="F1" filelist,t,s=getcatalog(17,2,filename,nil) a=getfilefromtslist(gettslist(t,s)) print(#a.." bytes") a=stripfileheaderandextra(a) hgrclr() drawpsfont(a,32,58,0,false,0,0,38,"pixels","xor") writepsfonttext(a,filename.." 32-58",0,160)
--]]
--[[
-- snippet will loop through the namelist and render each one, but not taking any snaps
namelist={"SYSTEM","RSVP","ALEXIA","NEWS","TECH","PARTY","BLOCK","TYPEWRITER","STENCIL"}
filelist={"F0","F1","F2","F3","F4","F5","F6","F7","F8"}loaddisk("../../Print_Shop_The_1984_Broderbund_a.dsk")hgr() hgrfull() hgrclr() for i=1,#filelist do filename=filelist[i] aafilelist,t,s=getcatalog(17,2,filename,nil) a=getfilefromtslist(gettslist(t,s)) print(#a.." bytes") a=stripfileheaderandextra(a) hgrclr() drawpsfont(a,1,58,0,false,0,0,38,"pixels","xor") writepsfonttext(a,filename.." "..namelist[i],0,160)
end
-- this snippet will create snaps of all the fonts on the print shop disk
co1=coroutine.create( function()
namelist={"SYSTEM","RSVP","ALEXIA","NEWS","TECH","PARTY","BLOCK","TYPEWRITER","STENCIL"}
filelist={"F0","F1","F2","F3","F4","F5","F6","F7","F8"}
diskname="../../Print_Shop_The_1984_Broderbund_a.dsk" -- has good f5 block font, bad f1 rsvp
diskname="../../PrintShop.dsk" -- has bad f5 block font, good f1 rsvp
loaddisk(diskname)hgr() hgrfull() hgrclr() for i=1,#filelist do filename=filelist[i] aafilelist,t,s=getcatalog(17,2,filename,nil) a=getfilefromtslist(gettslist(t,s)) print(#a.." bytes") a=stripfileheaderandextra(a) hgrclr() drawpsfont(a,iif(filename=="F1",32,1),58,0,false,0,0,iif(filename=="F1",38,32),"pixels","xor") writepsfonttext(a,filename.." "..namelist[i],0,160)
emu.wait(2/60)
manager:machine():debugger():command("snap \"" .. sanefilename(getfilenamepart(diskname).."_"..trim2(filelist[i]).."_"..namelist[i])..".png\"")
end
end)
ok,error=coroutine.resume(co1)
print(ok,error)
--]] A couple of things to note about the print shop disk, the catalog is truncated, so if you start at track 17, sector 2 you can see the rest of the files. Also font F1 or F5 is corrupted depending on the disk you use. Now the PS Companion fonts seem to have 12 extra bytes at the beginning, so if you pass them as a:sub(13) instead of a those 12 bytes will be ignored.
-- just a quick test on the PS Companion disk.
loaddisk("../../PrintShop.Companion.dsk") catalog()
filename="FONT.BALLOON" hgr() hgrclr() hgrwhite() a=getfile(filename) drawpsfont(a:sub(13),iif(filename=="BALLOON",32,1),58,0,false,0,0,32,"pixels","xor") writepsfonttext(a:sub(13),filename,0,140,0,nil,20,"xor")
![[Linked Image from i.imgur.com]](https://i.imgur.com/ZiHNfyB.png)
|
|
|
|
Joined: Mar 2006
Posts: 1,080 Likes: 7
Very Senior Member
|
Very Senior Member
Joined: Mar 2006
Posts: 1,080 Likes: 7 |
Golden Child: speaking of AppleII font stuff, is the "candy apple" Hershey font editor/renderer apple2 disk preserved anywhere? The Applesoft basic listing and some of the binary and text contents are listed at https://www.govinfo.gov/content/pkg...C13-f5df264c560c0810c872edea211033cc.pdf which might be enough to re-create the disk from scratch, but I don't know of any surviving copies. Both authors of that paper have sadly passed away, so its unlikely I can get any information from that angle. EDIT: some of the fonts on the Fontrix user group disks are traced by hand from some glyphs of the herhsey fonts with some manual adjustment, but none seem to be a direct 1:1 copy. LN
Last edited by Lord Nightmare; 03/24/19 08:12 PM.
"When life gives you zombies... *CHA-CHIK!* ...you make zombie-ade!"
|
|
|
|
Joined: Feb 2014
Posts: 1,135 Likes: 198
Very Senior Member
|
Very Senior Member
Joined: Feb 2014
Posts: 1,135 Likes: 198 |
Hi LN, looking around at the "regular" places, I don't see any Hershey fonts. They're kind of interesting vector fonts, the only mention I could find was a company named Tangent 270 which sold a Hershey font product (google for "tangent 270 hershey fonts apple"). SOFTWARE/ GRAPHICS TANGENT 270 P.O. Box 38587. DspL 9281 Denver, CO ... High quality characters based on Hershey's character repertory. 14 fonts including Roman Bold, English Gothic, Greek. 7 special ... 48K Apple II+. DOS 3.3.
|
|
|
|
Joined: Feb 2014
Posts: 1,135 Likes: 198
Very Senior Member
|
Very Senior Member
Joined: Feb 2014
Posts: 1,135 Likes: 198 |
Now to draw some Fontrix fonts: ![[Linked Image from i.imgur.com]](https://i.imgur.com/VpZwYxN.png) ![[Linked Image from i.imgur.com]](https://i.imgur.com/qITuAtm.png) ![[Linked Image from i.imgur.com]](https://i.imgur.com/EsZpvnJ.png) ![[Linked Image from i.imgur.com]](https://i.imgur.com/roJVBc7.png) I was able to get some files from Printrix to draw also, which has Times 25,30,40,50,70 and Helvetica 25,30,40,50,70. Since the printrix disk was Prodos, I created a dos3.3 image in the file manager (I called it created_image.dsk and you can see the SET.HELVET25) and used COPY II+ to copy the files over so I could access them. (I haven't written routines to access Prodos disks yet -- coming soon after I can decipher Beyond Apple Prodos).
function calc(line,page) if line<0 then line = 0 end if line > 191 then line=191 end page=page or 0 return line % 8 * 1024 + math.floor(line / 64) * 40 + math.floor((line%64) / 8) * 128 + 8192* (page + 1) end
function calcyaddr(line,page) return calc(line,page) end
function plot(x,y,page,bit,operation) page=page or 0 x = math.max(0,x) x = math.min(x,279) y = math.max(0,y) y = math.min(y,191) mem=applemem()
local memloc=calcyaddr(y,page)+math.floor(x/7)
local readval=mem:read_u8(memloc) local bitpos=x%7
local mask=~(1<<bitpos)
local invertmask=(1<<bitpos)
local bitshifted = bit<<bitpos
local notbitshifted=(iif(bit==0,1,0) << bitpos)
if operation == nil or operation == "or" then mem:write_u8(memloc,readval | (bit<<bitpos))
elseif operation == "erase" then mem:write_u8(memloc,readval & (bit<<bitpos))
elseif operation == "color" then mem:write_u8(memloc,readval & (bit<<bitpos)) -- erase = color black
elseif operation == "xor" then mem:write_u8(memloc,readval ~ (bit<<bitpos))
elseif operation == "store" then mem:write_u8(memloc,(readval & mask) | bitshifted)
elseif operation == "inverse" then mem:write_u8(memloc,(readval & mask) | notbitshifted)
else error("PLOT OPERATION "..operation.." not recognized") end
end
function applemem() return manager:machine().devices[":maincpu"].spaces["program"] end
function hgrwhite(page) for x=0,39 do for y=0,191 do applemem():write_u8(calcyaddr(y,page)+x,127) end end end
function getbits(a,lobit,hibit) if a==nil then print("getbits:NIL!") return 0 end local retval=0 for bit=lobit,hibit do retval=retval|((1<<bit)&a) end return retval end
function getbitsshift(a,lobit,hibit) if a==nil then print("getbitsshift:NIL!") return 0 end return getbits(a,lobit,hibit)>>lobit end
function getcharheightfontrix(a,c) return a:byte(0x14+1) end
function getcharwidthfontrix(a,c) return a:byte((0xe2)+(c-1)+1) end
function getcharwidthfontrix(a,c) if a:byte(0x12+1)==0 then return a:byte(0x13+1) else return a:byte((0xe2)+(c-1)+1) end end
function getcharoffsetfontrix(a,c) return a:byte((0x20)+(c-1)*2+1)+a:byte((0x21)+(c-1)*2+1)*256 end
function applemem()
if applememobject == nil then applememobject = manager:machine().devices[":maincpu"].spaces["program"] end
return applememobject
end
-- subtle difference, between just catalog() and return catalog()
function cat(...) return catalog(...) end
function CAT(...) return catalog(...) end
--new version of drawfontrix font, with xpos coordinate is pixel, not byte
function drawfontrixfont2(a,c0,c1,offset,doprint,xpos,ypos,lineheight,drawmode)
-- draw font characters from c0 to c1
c0 = c0 or 0
c1 = c1 or 58
offset=offset or 0
--hgrclr()
xpos,ypos=xpos or 0,ypos or 0
for c=c0,c1 do
local charwidth=getcharwidthfontrix(a,c)
local charheight=getcharheightfontrix(a,c)
local charoffset=getcharoffsetfontrix(a,c)
local charbytewidth=math.floor((charwidth-1)/8)+1
if doprint then print("char="..c.." "..string.char(c+31),"width="..charwidth,"height="..charheight,"offset="..hex(charoffset).." vpos="..getcharvposfontrix(a,c))
end
if charoffset>#a then print("INVALID CHAR OFFSET")
else
drawblockloop({"y",charheight,"x",charbytewidth},function(x,y,index) local bytetoplot=(a:sub(charoffset+1):byte(index+offset+1)) local numpixels=math.min(8,charwidth-8*x) x=xpos+x*8 for i=0,numpixels-1 do plot(x+i,y+ypos+getcharvposfontrix(a,c),0,getbitsshift(bytetoplot,i,i),drawmode) end end,32)
xpos=xpos+charwidth+2 -- pixels now
if xpos>250 then xpos=0 ypos=ypos+lineheight end -- ypos=ypos+charheight+1
end
end
print("returning xpos="..xpos.." ypos="..ypos)
return xpos,ypos
end
function writetextfontrix2(a,s,x,y,lineheight,drawmode) for i=1,#s do c=s:byte(i) c=c-32+1 x,y=drawfontrixfont2(a,c,c,0,nil,x,y,lineheight,drawmode) if x>250 then x=0 y=y+lineheight print(y) end end end
-- for the bigger fonts
function getcharheightfontrix(a,c) return a:byte(0x200+(c-2)+1) end
function getcharheightfontrix(a,c) if a:byte(1)==0x14 then return a:byte(0x200+(c-2)+1) else return a:byte(0x14+1) end end
function getcharvposfontrix(a,c) if a:byte(1)==0x14 then return a:byte(0x200+96*1-1+(c-2)+1) else return 0 end end
--[[
function getfilenamepart(s)
local curpos=1
repeat
local newpos=s:find("/",curpos,true)
if newpos then curpos = newpos+1 end -- if you don't add the +1, keeps getting same match, infinite loop
until newpos == nil
return s:sub(curpos)
end
function trim2(s) return s:match "^%s*(.-)%s*$" end -- from lua users wiki
loaddisk("../../fontrix.dsk") setascii=getfile("SET.ASCII BOLD")
co1=coroutine.create( function()
disknamelist={"../../fontrix.dsk","../../Font Paks 1 and 2.dsk","../../fontrixfontpak14.dsk","../../created_image.dsk"}
for d=1,#disknamelist do diskname=disknamelist[d]
loaddisk(diskname)
filelist=cat()
for i=1,#filelist do print(filelist[i])
if filelist[i]:find("SET.",1,true) then
print("IT'S A FONT so let's render a sample!")
filename=filelist[i]
a=getfile(filelist[i])
hgr() hgrfull() hgrclr() xpos=0 ypos=10
drawfontrixfont2(a,1,96,0,true,0,0,30)
writetextfontrix2(setascii,diskname,0,170,20,"store")
writetextfontrix2(setascii,filename,0,180,20,"store")
emu.wait(1/60+.01)
manager:machine():debugger():command("snap \"" .. sanefilename(getfilenamepart(diskname).."_"..trim2(filelist[i]))..".png\"")
end end
end
end)
ok,error=coroutine.resume(co1)
print(ok,error)
--]]
I think the screen's too small for 50 point type. ![[Linked Image from i.imgur.com]](https://i.imgur.com/Gs4CgjH.png) ![[Linked Image from i.imgur.com]](https://i.imgur.com/mNWoSrR.png)
|
|
|
|
Joined: Feb 2014
Posts: 1,135 Likes: 198
Very Senior Member
|
Very Senior Member
Joined: Feb 2014
Posts: 1,135 Likes: 198 |
I was creating some blank apple 2 disk images to copy some Prodos files to Dos 3.3 with Copy II+ using mame's built in file manager and was getting some strange results, primarily because I was asking for filenames with .DSK in capitals as opposed to a lowercase .dsk extension. What threw me off was that it would happily create the file and give it a zero size so I could see it in Ubuntu's file manager but it contained no data. Only after a few tries did I see that there was a popup message at the bottom of the screen that said "Error: Unable to identify the image format". So be careful when you leave your caps lock on, because it doesn't like .DSK, only .dsk. ![[Linked Image from i.imgur.com]](https://i.imgur.com/RsCaGmn.png) Notice that the menu here doesn't have a default option: ![[Linked Image from i.imgur.com]](https://i.imgur.com/63jvBOg.png) and we get a popup error message: (which I didn't see the first couple of times I did this) ![[Linked Image from i.imgur.com]](https://i.imgur.com/sb5AyI5.png) and when using lowercase .dsk extension the menu is slightly different with a bar separating the first option from the rest. ![[Linked Image from i.imgur.com]](https://i.imgur.com/XrzIWMT.png)
|
|
|
|
Joined: Mar 2001
Posts: 17,239 Likes: 263
Very Senior Member
|
Very Senior Member
Joined: Mar 2001
Posts: 17,239 Likes: 263 |
With the Apple II SCSI card solidified, the next step was getting the CD-ROM drive to work. Didn't take much work, and here you see the IIgs Finder browsing a PlayStation game disc. ![[Linked Image from rbelmont.mameworld.info]](http://rbelmont.mameworld.info/wp-content/uploads/2019/03/0019.png)
|
|
|
|
Joined: Mar 2001
Posts: 17,239 Likes: 263
Very Senior Member
|
Very Senior Member
Joined: Mar 2001
Posts: 17,239 Likes: 263 |
MAME is now the first and only Apple IIgs emulator able to use the Golden Orchard CD-ROM .iso. ![[Linked Image from rbelmont.mameworld.info]](http://rbelmont.mameworld.info/wp-content/uploads/2019/03/0020.png) And, it can even boot from the CD-ROM: ![[Linked Image from rbelmont.mameworld.info]](http://rbelmont.mameworld.info/wp-content/uploads/2019/03/0021.png)
|
|
|
|
Joined: May 2004
Posts: 1,009 Likes: 118
Very Senior Member
|
Very Senior Member
Joined: May 2004
Posts: 1,009 Likes: 118 |
That's awesome 
|
|
|
|
Joined: Feb 2014
Posts: 1,135 Likes: 198
Very Senior Member
|
Very Senior Member
Joined: Feb 2014
Posts: 1,135 Likes: 198 |
Something I've been fiddling with (and the emulation is probably horribly incorrect since I have no idea what I'm doing) Bonus points if you know what this is: ![[Linked Image from i.imgur.com]](https://i.imgur.com/dwRnzvI.png)
|
|
|
|
Joined: Feb 2014
Posts: 1,135 Likes: 198
Very Senior Member
|
Very Senior Member
Joined: Feb 2014
Posts: 1,135 Likes: 198 |
|
|
|
0 members (),
80
guests, and
6
robots. |
Key:
Admin,
Global Mod,
Mod
|
|
Forums9
Topics9,331
Posts122,197
Members5,077
|
Most Online1,283 Dec 21st, 2022
|
|
These forums are sponsored by Superior Solitaire, an ad-free card game collection for macOS and iOS. Download it today!
|
|
|
|