Author Topic: SCI0 - Support for multiple edit controls in Print()  (Read 6279 times)

0 Members and 1 Guest are viewing this topic.

Offline gumby

SCI0 - Support for multiple edit controls in Print()
« on: November 08, 2016, 03:52:20 PM »
I had a need to input multiple values from the user and the template game out-of-the-box only supports a single edit control in the Print routine.  Here's how you can enable multiple edit boxes in a single print statement, perhaps for that RPG you always wanted to make. 

Note that this example uses the SCI Studio syntax, not the Sierra syntax.

Make a new procedure called PrintMultiEdit() based on the Print() procedure in Controls.sc.  You could just override the existing Print() procedure, but you'll need to make other changes everywhere an #edit is used in existing Print statements in the template code (shouldn't be too hard, but left out here for brevity).

Code: [Select]
(procedure public (PrintMultiEdit params)
(var hDialog, hDText, hIcon, hEdits[10], btnPressed, paramCnt, diagX, diagY,
maxWidth, newPrintDlg, hFirstEnabled, oldPort, hButtons[6], btnsWidth,
buttonCnt, btnX, msgBuf[1013], moveToX, moveToY, editCnt, leftMargin[10],fontHeight)
= diagY  -1
= diagX  -1
= buttonCnt 0
= editCnt 0
= hEdits  NULL
= hIcon  NULL
= btnsWidth 0
= maxWidth  0
= newPrintDlg  NULL
= hDialog (Dialog:new())
(send hDialog:
window(gTheWindow)
name("PrintD")
)
= hDText (DText:new())
(if(<u params[0] 1000)
GetFarText(params[0] params[1] @msgBuf)
= paramCnt 2
)(else
  (if(params[0])
  StrCpy(@msgBuf params[0])
  = paramCnt 1
)(else
= msgBuf 0
= paramCnt  0
)
)
(send hDText:
text(@msgBuf)
moveTo(4 4)
font(gDefaultFont)
setSize()
)

(send hDialog:add(hDText))


  (while(< paramCnt paramTotal)
  (switch(params[paramCnt])
  (case #mode
  ++paramCnt
  (send hDText:mode(params[paramCnt]))
)
(case #font
  ++paramCnt
  (send hDText:
  font(params[paramCnt])
  setSize(maxWidth)
  )
)
(case #width
= maxWidth params[++paramCnt]
(send hDText:setSize(maxWidth))
)
(case #time
++paramCnt
(send hDialog:time(params[paramCnt]))
)
(case #title
++paramCnt
(send hDialog:text(params[paramCnt]))
)
(case #at
= diagX params[++paramCnt]
= diagY params[++paramCnt]
)
(case #draw
Animate(
(send gCast:elements)
0
)
)
(case #edit
++paramCnt
= hEdits[editCnt] (DEdit:new())

(send hEdits[editCnt]:
text(params[paramCnt])
)

++paramCnt
(send hEdits[editCnt]:
max(params[paramCnt])
setSize()
)

= leftMargin[editCnt] params[++paramCnt]

// if this is the first edit control, get the required font height value
(if (== 0 editCnt)
  = fontHeight params[++paramCnt]
)

++editCnt
)

(case #button
    = hButtons[buttonCnt] (DButton:new())
(send hButtons[buttonCnt]:
text(params[++paramCnt])
value(params[++paramCnt])
setSize()
    )
    = btnsWidth (+ btnsWidth (+ (send hButtons[buttonCnt]:nsRight) 4))
    ++buttonCnt
)

(case #icon
(if(IsObject(params[+ paramCnt 1]))
= hIcon (send params[+ paramCnt 1]:new())
(send hIcon:setSize())
= paramCnt (+ paramCnt 1)
    )(else
    = hIcon (DIcon:new())
    (send hIcon:
    view(params[+ paramCnt 1])
    loop(params[+ paramCnt 2])
    cel(params[+ paramCnt 3])
    setSize()
    )
    = paramCnt (+ paramCnt 3)
    )
)
(case #dispose
(if(gPrintDlg)
(send gPrintDlg:dispose())
)
= newPrintDlg hDialog
)
(case #window
++paramCnt
(send hDialog:window(params[paramCnt]))
)
)
++paramCnt
)
(if(hIcon)
(send hIcon:moveTo(4 4))
(send hDText:moveTo( (+ 4 (send hIcon:nsRight)) (send hIcon:nsTop) ))
(send hDialog:add(hIcon))
)
  (send hDialog:setSize())
 
= paramCnt 0
(while(< paramCnt editCnt)
    (send hEdits[paramCnt]:moveTo(
    (+ leftMargin[paramCnt] (send hDText:nsLeft))
    (+ (- (send hDText:nsBottom) (* fontHeight editCnt)) (* fontHeight (paramCnt)))
    ))
    (send hDialog:
    add(hEdits[paramCnt])
    setSize()
    )
   
++paramCnt
)


  (if(> btnsWidth (send hDialog:nsRight))
= btnX 4
)(else
  = btnX (- (send hDialog:nsRight) btnsWidth)
        //If you wanted the button centered...
        //   = btnX / ( - (send hDialog:nsRight) btnsWidth ) 2
)

= paramCnt 0
(while(< paramCnt buttonCnt)
(send hButtons[paramCnt]:moveTo( btnX (send hDialog:nsBottom) ))
(send hDialog:add(hButtons[paramCnt]))
= btnX (+ 4 (send hButtons[paramCnt]:nsRight))
++paramCnt
)

  (send hDialog:
  setSize()
  center()
  )
  (if(hIcon and not StrLen(@msgBuf))
(send hIcon:
moveTo(
    (
    / (- (- (send hDialog:nsRight) (send hDialog:nsLeft))
    (- (send hIcon:nsRight) (send hIcon:nsLeft))) 2
    )
    4
    )
)
)

(if(== -1 diagX)
= moveToX (send hDialog:nsLeft)
)(else
= moveToX diagX
)
(if(== -1 diagY)
= moveToY (send hDialog:nsTop)
)(else
= moveToY diagY
)
  (send hDialog:moveTo( moveToX moveToY ))

= oldPort GetPort()

(if(send hDialog:text)
= moveToX nwTITLE
)(else
= moveToX nwNORMAL
)
(if(newPrintDlg)
= moveToY 15
)(else
= moveToY -1
)
(send hDialog:open(moveToX moveToY))

(if(newPrintDlg)
= gOldPort GetPort()
SetPort(oldPort)
return(= gPrintDlg newPrintDlg)
)
  (if( (= hFirstEnabled (send hDialog:firstTrue(#checkState 1)))
       and (not (send hDialog:firstTrue(#checkState 2)) ) )
    (send hFirstEnabled:state(| (send hFirstEnabled:state) 2))
)
  = btnPressed (send hDialog:doit(hFirstEnabled))
  (if(== btnPressed -1)
= btnPressed 0
)

  (for (= paramCnt 0) (< paramCnt buttonCnt) (++paramCnt)
  (if(== btnPressed hButtons[paramCnt])
    = btnPressed (send btnPressed:value)
    break
)
)
  (if(not (send hDialog:theItem) )
= btnPressed 1
)
  (send hDialog:dispose())

return(btnPressed)
)

Basically, I used the existing button code and applied it to edit controls.  Let's take it for spin:

In your room:
Code: [Select]
(instance RoomScript of Script
(properties)
(method (handleEvent pEvent)
        (var inp1[5], inp2[5], inp3[5], inp4[5], inp5[5], inp6[5], inp7[5], inp8[5], inp9[5], inp10[5], attributes[100])
        (super:handleEvent(pEvent))

            // you must initialize these or you will get garbage in your print
            = inp1 0
    = inp2 0
    = inp3 0
    = inp4 0
    = inp5 0
    = inp6 0
    = inp7 0
            = inp8 0
            = inp9 0
            = inp10 0
                   
            PrintMultiEdit("Input character attributes:\nStrength:\nConstitution:\nWisdom:\nDexterity:\nIntelligence:\nCharisma:\nSocial Standing:\nMagic Resistance:\nLuck:\nHealth:"
       #edit @inp1 3 100 12
       #edit @inp2 3 100
       #edit @inp3 3 100
       #edit @inp4 3 100
       #edit @inp5 3 100
       #edit @inp6 3 100
       #edit @inp7 3 100
       #edit @inp8 3 100
       #edit @inp9 3 100
       #edit @inp10 3 100
       #button "  OK  " 0
)
          )
)
 

Ok, let's go through this. 

First, the text to be displayed in the dialog.  For each edit control, we are going to be putting labels to the left of the edit controls.  The approach I took was to embed these into the normal text displayed when Print() is called, each edit control label separated by newlines.

Next, examine the new attributes for #edit.  There are two, the first (set to 100 for all edit controls in this example) is the left margin/padding for the edit control.  This is used to bump the edit controls to the right so that the edit labels don't get clobbered.  The 2nd, which only appears on the 1st #edit is the font height.  We only need this once because we aren't going to have mixed fonts within a single Print() call.  This value represents the vertical spacing we will use for spacing the edit controls apart.

Here's the result:



Let's show off the left margin attributes a bit and put in default values of zero:
Code: [Select]
(instance RoomScript of Script
(properties)
(method (handleEvent pEvent)
        (var inp1[5], inp2[5], inp3[5], inp4[5], inp5[5], inp6[5], inp7[5], inp8[5], inp9[5], inp10[5], attributes[100])
        (super:handleEvent(pEvent))

            // you must initialize these or you will get garbage in your print
            StrCpy(@inp1 "0")
    StrCpy(@inp2 "0")
    StrCpy(@inp3 "0")
    StrCpy(@inp4 "0")
    StrCpy(@inp5 "0")
    StrCpy(@inp6 "0")
    StrCpy(@inp7 "0")
            StrCpy(@inp8 "0")
            StrCpy(@inp9 "0")
            StrCpy(@inp10 "0")
                   
            PrintMultiEdit("Input character attributes:\nStrength:\nConstitution:\nWisdom:\nDexterity:\nIntelligence:\nCharisma:\nSocial Standing:\nMagic Resistance:\nLuck:\nHealth:"
       #edit @inp1 3 50 12
       #edit @inp2 3 73
       #edit @inp3 3 48
       #edit @inp4 3 54
       #edit @inp5 3 67
       #edit @inp6 3 56
       #edit @inp7 3 87
       #edit @inp8 3 94
       #edit @inp9 3 31
       #edit @inp10 3 40
       #button "  OK  " 0
)
          )
)



Just for fun, let's put in some default randomized attribute values:

Code: [Select]
(instance RoomScript of Script
(properties)
(method (handleEvent pEvent)
        (var inp1[5], inp2[5], inp3[5], inp4[5], inp5[5], inp6[5], inp7[5], inp8[5], inp9[5], inp10[5], attributes[100])
        (super:handleEvent(pEvent))

            // you must initialize these or you will get garbage in your print
    Format(@inp1 "%d" Random(0 20))  
            Format(@inp2 "%d" Random(0 20))
            Format(@inp3 "%d" Random(0 20))
            Format(@inp4 "%d" Random(0 20))
            Format(@inp5 "%d" Random(0 20))
            Format(@inp6 "%d" Random(0 20))
            Format(@inp7 "%d" Random(0 20))
            Format(@inp8 "%d" Random(0 20))
            Format(@inp9 "%d" Random(0 20))
            Format(@inp10 "%d" Random(0 20))
                   
            PrintMultiEdit("Input character attributes:\nStrength:\nConstitution:\nWisdom:\nDexterity:\nIntelligence:\nCharisma:\nSocial Standing:\nMagic Resistance:\nLuck:\nHealth:"
       #edit @inp1 3 50 12
       #edit @inp2 3 73
       #edit @inp3 3 48
       #edit @inp4 3 54
       #edit @inp5 3 67
       #edit @inp6 3 56
       #edit @inp7 3 87
       #edit @inp8 3 94
       #edit @inp9 3 31
       #edit @inp10 3 40
       #button "  OK  " 0
)
          )
)



I would be remiss if I didn't show that we can get these values out of our print statement - they are stored in the same input values.  This screenshot below doesn't show it, but if you change the values when in the Print() dialog, they will be reflected in the final output.

Code: [Select]
(instance RoomScript of Script
(properties)
(method (handleEvent pEvent)
        (var inp1[5], inp2[5], inp3[5], inp4[5], inp5[5], inp6[5], inp7[5], inp8[5], inp9[5], inp10[5], attributes[100])
        (super:handleEvent(pEvent))

            // you must initialize these or you will get garbage in your print
    Format(@inp1 "%d" Random(0 20))  
            Format(@inp2 "%d" Random(0 20))
            Format(@inp3 "%d" Random(0 20))
            Format(@inp4 "%d" Random(0 20))
            Format(@inp5 "%d" Random(0 20))
            Format(@inp6 "%d" Random(0 20))
            Format(@inp7 "%d" Random(0 20))
            Format(@inp8 "%d" Random(0 20))
            Format(@inp9 "%d" Random(0 20))
            Format(@inp10 "%d" Random(0 20))
                   
            PrintMultiEdit("Input character attributes:\nStrength:\nConstitution:\nWisdom:\nDexterity:\nIntelligence:\nCharisma:\nSocial Standing:\nMagic Resistance:\nLuck:\nHealth:"
       #edit @inp1 3 50 12
       #edit @inp2 3 73
       #edit @inp3 3 48
       #edit @inp4 3 54
       #edit @inp5 3 67
       #edit @inp6 3 56
       #edit @inp7 3 87
       #edit @inp8 3 94
       #edit @inp9 3 31
       #edit @inp10 3 40
       #button "  OK  " 0
)

           StrCpy(@attributes "Character attributes are:")
           StrCat(@attributes " \nStrength:")
           StrCat(@attributes @inp1)
           StrCat(@attributes " \nConstitution:")
           StrCat(@attributes @inp2)
           StrCat(@attributes " \nWisdom:")
           StrCat(@attributes @inp3)
           StrCat(@attributes " \nDexterity:")
           StrCat(@attributes @inp4)
           StrCat(@attributes " \nIntelligence:")
           StrCat(@attributes @inp5)
           StrCat(@attributes " \nCharisma:")
           StrCat(@attributes @inp6)
           StrCat(@attributes " \nSocial Standing:")
           StrCat(@attributes @inp7)        
           StrCat(@attributes " \nMagic Resistance:")
           StrCat(@attributes @inp8)    
           StrCat(@attributes " \nLuck:")
           StrCat(@attributes @inp9)    
           StrCat(@attributes " \nHeath:")
           StrCat(@attributes @inp10)        

   
   Print(@attributes)
          )
)

And the final output:


One gotcha that I ran into is sometimes the formatting/spacing of a Print() call gets messed up.  One scenario is when the header text (e.g 'Input character attributes') is shorter than the edit control label + edit control.  If you run into an issue where the edit boxes are shifted up in the dialog, add leading/trailing whitespace to the text string in the Print() call to compensate.

One last thing.  The current implementation only supports up to 10 edit controls on a single print.  There really isn't more room on the screen for that, unless additional changes are made to support two columns or possibly three columns of edit controls.
« Last Edit: November 08, 2016, 06:33:48 PM by gumby »


In the Great Underground Empire (Zork port in development)
Winter Break 2012 Rope Prop Competition

Offline Kawa

Re: SCI0 - Support for multiple edit controls in Print()
« Reply #1 on: November 08, 2016, 03:59:01 PM »
Haha, awesome.

Offline MusicallyInspired

Re: SCI0 - Support for multiple edit controls in Print()
« Reply #2 on: November 09, 2016, 10:46:18 AM »
Nice work.
Brass Lantern Prop Competition

Offline gumby

Re: SCI0 - Support for multiple edit controls in Print()
« Reply #3 on: November 10, 2016, 10:00:18 PM »
Multi column support added:

Code: [Select]
(procedure public (PrintMultiEdit params)
(var hDialog, hDText, hIcon, hEdits[25], btnPressed, paramCnt, diagX, diagY,
maxWidth, newPrintDlg, hFirstEnabled, oldPort, hButtons[6], btnsWidth,
buttonCnt, btnX, msgBuf[1013], moveToX, moveToY, editCnt, leftMargin[25], editColNum[25],
  fontHeight, xPos, yPos, columnCount)
= diagY  -1
= diagX  -1
= buttonCnt 0
= editCnt 0
= hEdits  NULL
= hIcon  NULL
= btnsWidth 0
= maxWidth  0
= newPrintDlg  NULL
= hDialog (Dialog:new())
(send hDialog:
window(gTheWindow)
name("PrintD")
)
= hDText (DText:new())
(if(<u params[0] 1000)
GetFarText(params[0] params[1] @msgBuf)
= paramCnt 2
)(else
  (if(params[0])
  StrCpy(@msgBuf params[0])
  = paramCnt 1
)(else
= msgBuf 0
= paramCnt  0
)
)
(send hDText:
text(@msgBuf)
moveTo(4 4)
font(gDefaultFont)
setSize()
)

(send hDialog:add(hDText))


  (while(< paramCnt paramTotal)
  (switch(params[paramCnt])
  (case #mode
  ++paramCnt
  (send hDText:mode(params[paramCnt]))
)
(case #font
  ++paramCnt
  (send hDText:
  font(params[paramCnt])
  setSize(maxWidth)
  )
)
(case #width
= maxWidth params[++paramCnt]
(send hDText:setSize(maxWidth))
)
(case #time
++paramCnt
(send hDialog:time(params[paramCnt]))
)
(case #title
++paramCnt
(send hDialog:text(params[paramCnt]))
)
(case #at
= diagX params[++paramCnt]
= diagY params[++paramCnt]
)
(case #draw
Animate(
(send gCast:elements)
0
)
)
(case #edit
++paramCnt
= hEdits[editCnt] (DEdit:new())

(send hEdits[editCnt]:
text(params[paramCnt])
)

++paramCnt
(send hEdits[editCnt]:
max(params[paramCnt])
setSize()
)

= leftMargin[editCnt] params[++paramCnt]
= editColNum[editCnt] params[++paramCnt]

// if this is the first edit control, extra parameters
(if (== 0 editCnt)

  = fontHeight params[++paramCnt] //get the font height value (required), spacing between edit controls vertically
  = columnCount params[++paramCnt]
)

++editCnt
)

(case #button
    = hButtons[buttonCnt] (DButton:new())
(send hButtons[buttonCnt]:
text(params[++paramCnt])
value(params[++paramCnt])
setSize()
    )
    = btnsWidth (+ btnsWidth (+ (send hButtons[buttonCnt]:nsRight) 4))
    ++buttonCnt
)

(case #icon
(if(IsObject(params[+ paramCnt 1]))
= hIcon (send params[+ paramCnt 1]:new())
(send hIcon:setSize())
= paramCnt (+ paramCnt 1)
    )(else
    = hIcon (DIcon:new())
    (send hIcon:
    view(params[+ paramCnt 1])
    loop(params[+ paramCnt 2])
    cel(params[+ paramCnt 3])
    setSize()
    )
    = paramCnt (+ paramCnt 3)
    )
)
(case #dispose
(if(gPrintDlg)
(send gPrintDlg:dispose())
)
= newPrintDlg hDialog
)
(case #window
++paramCnt
(send hDialog:window(params[paramCnt]))
)
)
++paramCnt
)
(if(hIcon)
(send hIcon:moveTo(4 4))
(send hDText:moveTo( (+ 4 (send hIcon:nsRight)) (send hIcon:nsTop) ))
(send hDialog:add(hIcon))
)
  (send hDialog:setSize())
 
= paramCnt 0
(while(< paramCnt editCnt)

    = xPos (+ (* 20 editColNum[paramCnt])   (+ leftMargin[paramCnt]  (send hDText:nsLeft)))
            = yPos (- (+ (* (* -1 fontHeight) (/ (-(- editCnt paramCnt)1) columnCount))  (send hDText:nsBottom)) fontHeight)

    (send hEdits[paramCnt]:moveTo(xPos yPos))
   
    (send hDialog:
    add(hEdits[paramCnt])
    setSize()
    )
   
++paramCnt
)


  (if(> btnsWidth (send hDialog:nsRight))
= btnX 4
)(else
  = btnX (- (send hDialog:nsRight) btnsWidth)
        //If you wanted the button centered...
        //   = btnX / ( - (send hDialog:nsRight) btnsWidth ) 2
)

= paramCnt 0
(while(< paramCnt buttonCnt)
(send hButtons[paramCnt]:moveTo( btnX (send hDialog:nsBottom) ))
(send hDialog:add(hButtons[paramCnt]))
= btnX (+ 4 (send hButtons[paramCnt]:nsRight))
++paramCnt
)

  (send hDialog:
  setSize()
  center()
  )
  (if(hIcon and not StrLen(@msgBuf))
(send hIcon:
moveTo(
    (
    / (- (- (send hDialog:nsRight) (send hDialog:nsLeft))
    (- (send hIcon:nsRight) (send hIcon:nsLeft))) 2
    )
    4
    )
)
)

(if(== -1 diagX)
= moveToX (send hDialog:nsLeft)
)(else
= moveToX diagX
)
(if(== -1 diagY)
= moveToY (send hDialog:nsTop)
)(else
= moveToY diagY
)
  (send hDialog:moveTo( moveToX moveToY ))

= oldPort GetPort()

(if(send hDialog:text)
= moveToX nwTITLE
)(else
= moveToX nwNORMAL
)
(if(newPrintDlg)
= moveToY 15
)(else
= moveToY -1
)
(send hDialog:open(moveToX moveToY))

(if(newPrintDlg)
= gOldPort GetPort()
SetPort(oldPort)
return(= gPrintDlg newPrintDlg)
)
  (if( (= hFirstEnabled (send hDialog:firstTrue(#checkState 1)))
       and (not (send hDialog:firstTrue(#checkState 2)) ) )
    (send hFirstEnabled:state(| (send hFirstEnabled:state) 2))
)
  = btnPressed (send hDialog:doit(hFirstEnabled))
  (if(== btnPressed -1)
= btnPressed 0
)

  (for (= paramCnt 0) (< paramCnt buttonCnt) (++paramCnt)
  (if(== btnPressed hButtons[paramCnt])
    = btnPressed (send btnPressed:value)
    break
)
)
  (if(not (send hDialog:theItem) )
= btnPressed 1
)
  (send hDialog:dispose())

return(btnPressed)
)

Room script:
Code: [Select]
(instance RoomScript of Script
    (properties)
    (method (handleEvent pEvent)

    (var  inp1[2],  inp2[2],  inp3[2],  inp4[2],  inp5[2],  inp6[2],  inp7[2],  inp8[2],  inp9[2], inp10[2],
    inp11[2], inp12[2], inp13[2], inp14[2], inp15[2], inp16[2], inp17[2], inp18[2], inp19[2], inp20[2],
    attributes[100])

        (super:handleEvent(pEvent))

    = inp1 0
    = inp2 0
    = inp3 0
    = inp4 0
    = inp5 0
            = inp6 0
    = inp7 0
    = inp8 0
            = inp9 0
            = inp10 0
    = inp11 0
    = inp12 0
    = inp13 0
    = inp14 0
    = inp15 0
    = inp16 0
    = inp17 0
    = inp18 0
            = inp19 0
            = inp20 0     
                       
   PrintMultiEdit("20 Inputs:\n\n       A    B    C    D    E  \n1:\n2:\n3:\n4:"
                                                                  // inputbox size, left margin, column placement, font height, column count
    #edit @inp1   2 0 1 12 5
    #edit @inp2   2 0 2
    #edit @inp3   2 0 3
    #edit @inp4   2 0 4
    #edit @inp5   2 0 5
    #edit @inp6   2 0 1
    #edit @inp7   2 0 2 
    #edit @inp8   2 0 3
    #edit @inp9   2 0 4
    #edit @inp10  2 0 5
    #edit @inp11  2 0 1
    #edit @inp12  2 0 2
    #edit @inp13  2 0 3
    #edit @inp14  2 0 4
    #edit @inp15  2 0 5
    #edit @inp16  2 0 1
    #edit @inp17  2 0 2
    #edit @inp18  2 0 3
    #edit @inp19  2 0 4
    #edit @inp20  2 0 5
    #button "  OK  " 0
   )
 

 
  )
)

Result:


Excessive?  Possibly.  I did discover that I could not go beyond 25 selectors for the Print() command, not sure where this limitation comes from (yes, I sized the input arrays to the Print procedure large enough during my testing).  Therefore, no more than 25 input boxes seem to be possible, unless I've overlooked something here.
« Last Edit: November 10, 2016, 11:25:31 PM by gumby »
In the Great Underground Empire (Zork port in development)
Winter Break 2012 Rope Prop Competition

Offline Kawa

Re: SCI0 - Support for multiple edit controls in Print()
« Reply #4 on: November 11, 2016, 05:17:51 AM »
Holy shit haha.

Offline MusicallyInspired

Re: SCI0 - Support for multiple edit controls in Print()
« Reply #5 on: November 11, 2016, 11:34:17 AM »
Sierra On-Line presents "Spreadsheet SCI!"
Brass Lantern Prop Competition


SMF 2.0.19 | SMF © 2021, Simple Machines
Simple Audio Video Embedder

Page created in 0.035 seconds with 22 queries.