DVD Screensaver
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © SamRecio

//@version=5
indicator("DVD Screensaver", shorttitle = "DVD", overlay = true, max_bars_back = 1)

//Uset Inputs///////////////////////////////////////////////////////////////////
columns = input.int(10, minval = 1, maxval = 100, title = "Window Ratio ➡", inline = "0")
rows = input.int(12, minval = 1, maxval = 50,title = "⬆", inline = "0")
c_hight = 2
c_width = 1.5 
tl1 = input.string("bottom", title = "Table Location", options = ["top", "middle", "bottom"], group = "Table Settings", inline = "1")
tl2 = input.string("right", title = "", options = ["left", "center", "right"], group = "Table Settings", inline = "1")
bg_color = input.color(color.rgb(0,0,0), title = "Background Color", group = "Table Settings", inline = "2")
//There are alot more possible customizabilities to this, but they seemed unneccesary for a public release. 
//These are the settings I thought was enough.


//Pulling and plotting crypto to force update the indicator.
btc = request.security("COINBASE:BTCUSD","",close)
plot(btc, display = display.none, editable = false)
eth = request.security("COINBASE:ETHUSD","",close)
plot(eth, display = display.none, editable = false)

//Initializing Table////////////////////////////////////////////////////////////

var table screen = table.new(tl1 +"_" + tl2,columns + 1,rows + 1)
//Filling every cell to take up space and form the background.
/////////////////////////////////////////////
//Only need to do this on the last bar for speed. ;)
/////////////////////////////////////////////
if barstate.islast
    for e = 0 to rows
        for i = 0 to columns
            table.cell(screen, i,e, text = "", height = c_hight, width = c_width, bgcolor = bg_color)

//Initializing the Moving Box///////////////////////////////////////////////////

varip r = math.round(math.random(0,rows))    //"varip" is required to update the variable inside bars.
varip c = math.round(math.random(0,columns)) // This means every time the script ticks the variable can be updated.
varip move = math.round(math.random(0,3))    // Setting these variables initially at a random number to make the movement random.
varip int r_num = 0                          // Otherwise it would take the same path every time
rng = math.round(math.random(1,14)) //generating random number for color picking

colorpicker(_num) =>                         // Color picking function
    _num == 1? color.aqua:                   // Picks color from a universe of colors.
     _num == 2? color.blue:                  // I could set the colors to generate with color.rgb() and 3 random numbers, however, that results in some ugly colors most of the time.
     _num == 3? color.fuchsia:               // This allows me to make sure the colors are nice.
     _num == 4? color.green :
     _num == 5? color.lime :
     _num == 6? color.maroon: 
     _num == 7? color.navy :
     _num == 8? color.olive :
     _num == 9? color.orange :
     _num == 10? color.purple :
     _num == 11? color.red :
     _num == 12? color.teal :
     _num == 13? color.white:
     _num == 14? color.yellow :
     color.white

//Bumping Logic/////////////////////////////////////////////////////////////////

//Bottom Wall Bump
if r == rows and barstate.islast and move == 0   // r and c values can tell us where the box is,
    move := 1                                    // each wall bump can result in 1 of 2 different moves depending on the direction the box is coming from.
    r_num := rng                                 // we can tell where its coming from by saying "if move == X", this will tell us the direction its currently moving.
if r == rows and barstate.islast and move == 3   // When it hits a boundary we check update the direction of movement an change the color.
    move := 2
    r_num := rng

//Right Wall Bump
if c == columns and barstate.islast and move == 0
    move := 3
    r_num := rng
if c == columns and barstate.islast and move == 1
    move := 2
    r_num := rng
    
//Top Wall Bump
if r == 0 and barstate.islast and move == 1
    move := 0
    r_num := rng
if r == 0 and barstate.islast and move == 2
    move := 3
    r_num := rng
   
//Left Wall Bump
if c == 0 and barstate.islast and move == 2
    move := 1
    r_num := rng
if c == 0 and barstate.islast and move == 3
    move := 0
    r_num := rng


//Moving Logic//////////////////////////////////////////////////////////////////
//Move 0 | Down-Right
//
if r < rows and c < columns and barstate.islast and move == 0                                  //Checking rows and colums is redundant. I have it in here to stop the box if something were to go wrong. 
    table.cell(screen,c,r, text = "", height = c_hight, width = c_width, bgcolor = bg_color)   //All that really matters is the move, since it only moves diagonally we are always moving it up or down 1 and left or right 1.
    r := r + 1                                                                                 //We delete the current box at the current values and then update our location, we do this until one of our bump conditions is met, and so on.
    c := c + 1

//Move 1 | Up-Right
//
if r > 0 and c < columns and barstate.islast and move == 1
    table.cell(screen,c,r, text = "", height = c_hight, width = c_width, bgcolor = bg_color)
    r := r - 1
    c := c + 1
    
//Move 2 | Up-Left
//
if r > 0 and c > 0 and barstate.islast and move == 2
    table.cell(screen,c,r, text = "", height = c_hight, width = c_width, bgcolor = bg_color)
    r := r - 1
    c := c - 1
//Move 3  | Down-Left
//
if r < rows and c > 0 and barstate.islast and move == 3
    table.cell(screen,c,r, text = "", height = c_hight, width = c_width, bgcolor = bg_color)
    r := r + 1
    c := c - 1

table.cell(screen,c,r, text = "DVD", text_size = "normal", height = c_hight, width = c_width, text_color = colorpicker(r_num), bgcolor = bg_color) //Drawing the box at the current location, this is not in any scope so it updates every tick.

