------------------------------------------------------------------------------
-- This is a script file for U61 by U-Foot (www.ufoot.org ufoot@ufoot.org)  --
-- It is free software, protected by the GPL (www.fsf.org)                  --
--                                                                          --
-- Do not hesitate to modify this file to change the behavior of U61,       --
-- that's exactly what it's done for!                                       --
------------------------------------------------------------------------------


------------------------------------------------------------------------------
--                                                                          --
-- U U    6   1            U U   FFF  O   O  TTT                            --
-- U U   6   11   b        U U   F   O O O O  T                             --
-- U U - 66   1   bb  y y  U U - FF  O O O O  T                             --
-- U U   6 6  1   b b  y   U U   F   O O O O  T                             --
--  U     6   1   bb   y    U    F    O   O   T                             --
--                                                                          --
-- U61 is another block based game                                          --
-- Copyright (C) 2000 Christian Mauduit (ufoot@ufoot.org / www.ufoot.org)   --
--                                                                          --
-- This program is free software; you can redistribute it and/or            --
-- modify it under the terms of the GNU General Public License              --
-- as published by the Free Software Foundation; either version 2           --
-- of the License, or (at your option) any later version.                   --
--                                                                          --
-- This program is distributed in the hope that it will be useful,          --
-- but WITHOUT ANY WARRANTY; without even the implied warranty of           --
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            --
-- GNU General Public License for more details.                             --
--                                                                          --
-- You should have received a copy of the GNU General Public License        --
-- along with this program; if not, write to the Free Software              --
-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA--
--                                                                          --
-- This project is also available on SourceForge  (http://sourceforge.net)  --
------------------------------------------------------------------------------

-- tetramino game, the goal is to have an horizontal line filled with
-- squares of any color. possible movements include translation & rotation
-- colors do not have any purpose except make the game look nicer


-- shape definition ----------------------------------------------------------

function user_new_shape(num)
    num=mod(num,100)

    return num
end

function user_do_shape(num)
    if num>=80 then
        tetramino_bar()
    elseif num>=70 then
        tetramino_square()
    elseif num>=60 then
        tetramino_pyramid()
    elseif num>=45 then
        tetramino_s1()
    elseif num>=30 then
        tetramino_s2()
    elseif num>=15 then
        tetramino_l1()
    else
        tetramino_l2()
    end

    fiftytwo_do_shape(num)
end


-- actions -------------------------------------------------------------------

function user_rotate_left()
    rotation_left()    
end

function user_rotate_right()
    rotation_right()    
end

function user_move_left()
    goofy_left()
end

function user_move_right()
    goofy_right()
end

function user_move_down()
    translation_y(1)
end

function user_use_antidote()
    u61_cancel_curse(u61_get_oldest_curse())
end

-- pattern match -------------------------------------------------------------

function user_match_pattern(match_count)
    local matched

    matched=line_match_pattern(match_count)

    if matched>0 and match_count>=2 then
        u61_send_curse(ID_CURSE_HOLEDLINE)
    end

    return matched
end

function user_land()

end

function user_square_blown_up(x,y)
    utils_shift_column_down(x,y)
end

-- curse functions  ----------------------------------------------------------

function user_new_curse(num)
    num=mod(num,100)

    if num<10 then
        num=ID_CURSE_ANTIDOTE
    elseif num<30 then
        num=ID_CURSE_HOLEDLINE
    elseif num<40 then
        num=ID_CURSE_GOOFY
    elseif num<50 then
        num=ID_CURSE_CLEAR
    elseif num<60 then 
        num=ID_CURSE_DROP
    elseif num<65 then 
        num=ID_CURSE_STAIRS
    elseif num<70 then 
        num=ID_CURSE_BOOST
    elseif num<75 then 
        num=ID_CURSE_SHUFFLE
    elseif num<80 then 
        num=ID_CURSE_WIND
    elseif num<84 then 
        num=ID_CURSE_FIFTYTWO
    elseif num<88 then 
        num=ID_CURSE_BIGX
    elseif num<92 then 
        num=ID_CURSE_TOPHOLEDLINE
    elseif num<96 then 
        num=ID_CURSE_TOPDOWN
    elseif num<100 then 
        num=ID_CURSE_HAHA
    end

    return num
end

function user_do_curse(num,sent)
    if (num==ID_CURSE_ANTIDOTE) then
        antidote_do_curse()
    elseif (num==ID_CURSE_HOLEDLINE) then
        holedline_do_curse(sent)
    elseif (num==ID_CURSE_GOOFY) then
        goofy_do_curse(sent)
    elseif (num==ID_CURSE_CLEAR) then
        clear_do_curse()
    elseif (num==ID_CURSE_SHUFFLE) then
        shuffle_do_curse(sent)
    elseif (num==ID_CURSE_WIND) then
        wind_do_curse(sent)
    elseif (num==ID_CURSE_FIFTYTWO) then
        fiftytwo_do_curse(sent)
    elseif (num==ID_CURSE_BIGX) then
        bigx_do_curse(sent)
    elseif (num==ID_CURSE_BOOST) then
        boost_do_curse(sent)
    elseif (num==ID_CURSE_DROP) then
        drop_do_curse(sent)
    elseif (num==ID_CURSE_TOPDOWN) then
        topdown_do_curse(sent)
    elseif (num==ID_CURSE_TOPHOLEDLINE) then
        topholedline_do_curse(sent)
    elseif (num==ID_CURSE_STAIRS) then
        stairs_do_curse(sent)
    elseif (num==ID_CURSE_HAHA) then
        haha_do_curse(sent)
    end    
end

function user_get_curse_name(num)
    name="surprise"

    if (num==ID_CURSE_ANTIDOTE) then
        name="antidote"
    elseif (num==ID_CURSE_HOLEDLINE) then
        name="line"
    elseif (num==ID_CURSE_GOOFY) then
        name="goofy"
    elseif (num==ID_CURSE_CLEAR) then
        name="clear"
    elseif (num==ID_CURSE_SHUFFLE) then
        name="shuffle"
    elseif (num==ID_CURSE_WIND) then
        name="wind"
    elseif (num==ID_CURSE_FIFTYTWO) then
        name="52"
    elseif (num==ID_CURSE_BIGX) then
        name="X"
    elseif (num==ID_CURSE_BOOST) then
        name="boost"
    elseif (num==ID_CURSE_DROP) then
        name="drop"
    elseif (num==ID_CURSE_TOPDOWN) then
        name="topdown"
    elseif (num==ID_CURSE_TOPHOLEDLINE) then
        name="toper"
    elseif (num==ID_CURSE_STAIRS) then
        name="stairs"
    elseif (num==ID_CURSE_HAHA) then
        name="haha"
    end

    return name
end 

-- other functions -----------------------------------------------------------

function user_time_callback()
    u61_add_score(10)
    shuffle_time_callback()
    wind_time_callback()
    boost_time_callback()
end



-- various functions used for pattern matching -------------------------------

function utils_shift_column_down(x_col,y_bottom)
    local y
    local color

    y=y_bottom
    while y>=1 do
        color=u61_get_square_color(x_col,y-1)
        u61_set_square_color(x_col,y,color)
        y=y-1
    end
    u61_set_square_color(x_col,0,-1)

    if u61_get_curse_x()==x_col and u61_get_curse_y()<y_bottom then
        u61_set_curse_y(u61_get_curse_y()+1)
    end
end


-- Functions used in many curse scripts --------------------------------------

function utils_shift_map_up()
    local x
    local y
    local width
    local height
    local color

    width=u61_get_width()
    height=u61_get_height() 
    y=0
    while y<height-1 do
        x=0
        while x<width do
            color=u61_get_square_color(x,y+1)
            u61_set_square_color(x,y,color)
            x=x+1
        end
        y=y+1
    end

    u61_set_curse_y(u61_get_curse_y()-1)
end

function utils_clear_map()
    local x
    local y
    local width
    local height

    width=u61_get_width()
    height=u61_get_height() 
    y=0
    while y<height do
        x=0
        while x<width do
            u61_set_square_color(x,y,-1)
            x=x+1
        end
        y=y+1
    end
end

function utils_switch_lines(y1,y2)
    local x
    local color

    x=u61_get_width()-1
    while x>=0 do
        color=u61_get_square_color(x,y1)
        u61_set_square_color(x,y1,u61_get_square_color(x,y2))
        u61_set_square_color(x,y2,color)
        x=x-1
    end
end

function utils_get_highest_square_y()
    local x
    local y
    local width
    local height
    local min_y	

    width=u61_get_width()
    height=u61_get_height()
    min_y=height 
    y=0
    while y<height do
        x=0
        while x<width do
            if u61_get_square_color(x,y)>=0 then
                min_y=y
                x=width
                y=height
            end
            x=x+1
        end
        y=y+1
    end 

    return min_y   
end
-- defines tetraminos --------------------------------------------------------

function tetramino_bar()
    u61_add_item(0,0,0)
    u61_add_item(0,1,0)
    u61_add_item(0,2,0)
    u61_add_item(0,3,0)
end

function tetramino_s1()
    u61_add_item(0,0,1)
    u61_add_item(1,0,1)
    u61_add_item(1,1,1)
    u61_add_item(2,1,1)
end

function tetramino_s2()
    u61_add_item(0,1,2)
    u61_add_item(1,1,2)
    u61_add_item(1,0,2)
    u61_add_item(2,0,2)
end

function tetramino_square()
    u61_add_item(0,0,3)
    u61_add_item(0,1,3)
    u61_add_item(1,0,3)
    u61_add_item(1,1,3)
end

function tetramino_l1()
    u61_add_item(0,1,4)
    u61_add_item(1,1,4)
    u61_add_item(2,1,4)
    u61_add_item(2,0,4)
end

function tetramino_l2()
    u61_add_item(0,0,5)
    u61_add_item(0,1,5)
    u61_add_item(1,1,5)
    u61_add_item(2,1,5)
end

function tetramino_pyramid()
    u61_add_item(0,1,6)
    u61_add_item(1,1,6)
    u61_add_item(2,1,6)
    u61_add_item(1,0,6)
end



-- defines translations ------------------------------------------------------

function translation_x(x)
    u61_set_block_x(u61_get_block_x()+x)
end

function translation_y(y)
    u61_set_block_y(u61_get_block_y()+y)
end

function translation_x_check(x)
    local i
    local dx
	
    if x>0 then
        dx=1
    else
        x=-x
        dx=-1
    end

    i=x
    while i>0 do
        translation_x(dx)
        if u61_is_block_ok()==0 then
            translation_x(-dx)
            i=0
        end
        i=i-1	          
    end
end

function translation_y_check(y)
    local i
    local dy
	
    if y>0 then
        dy=1
    else
        y=-y
        dy=-1
    end

    i=y
    while i>0 do
        translation_y(dy)
        if u61_is_block_ok()==0 then
            translation_y(-dy)
            i=0
        end
        i=i-1		          
    end
end


-- defines geometrical rotations ---------------------------------------------

function rotation_left()
    local x
    local y
    local i 

    i = u61_get_nb_items()-1
    while i>=0 do
        x = u61_get_item_x(i) 
        y = u61_get_item_y(i) 
        x,y = y,-x
        u61_set_item_x(i,x)
        u61_set_item_y(i,y)
        i = i-1
    end
end

function rotation_right()
    local x
    local y
    local i 

    i = u61_get_nb_items()-1
    while i>=0 do
        x = u61_get_item_x(i) 
        y = u61_get_item_y(i) 
        x,y = -y,x
        u61_set_item_x(i,x)
        u61_set_item_y(i,y)
        i = i-1
    end
end

-- line pattern: any complete line of square is removed ----------------------

function line_delete(y_line)
    local x
    local y
    local width
    local color

    width=u61_get_width()
    x=0
    while x<width do
        u61_blow_up_square(x,y_line)
        x=x+1
    end
end

function line_match_pattern(match_count)
    local x
    local y
    local width
    local height
    local holes
    local lines
    
    width=u61_get_width()
    height=u61_get_height()

    lines=0
    y=0
    while y<height and lines==0 do
        holes=0
        x=0
        while x<width do
            if u61_get_square_color(x,y)<0 then
                holes=holes+1
            end
            if not (u61_is_square_exploding(x,y)==0) then
                holes=holes+1
            end
            x=x+1
        end
        if holes==0 then 
            line_delete(y)
            lines=lines+1
        end
        y=y+1
    end    

    if lines>0 then
        u61_add_score((match_count+1)*10000)    
        if (match_count>=3) then
            u61_add_antidote()
        end
    end

    return lines
end


-- ANTIDOTE curse: gives add antidote-------------------------------

ID_CURSE_ANTIDOTE=0

function antidote_do_curse()
    u61_add_antidote()
end


-- HOLEDLINE curse: adds a line with a hole in it ----------------------------

ID_CURSE_HOLEDLINE=1

function holedline_do_curse(sent)
    local x
    local y
    local width
    local height
    local color

    if sent==0 then
        u61_send_curse(ID_CURSE_HOLEDLINE)
    else
        utils_shift_map_up()

        width=u61_get_width()
        height=u61_get_height() 

        x=0
        while x<width do
            if (mod(x+u61_get_time(),width)==0) then
                color=-1
            else
               color=7
            end
            u61_set_square_color(x,height-1,color)
            x=x+1
        end
    end
end


-- CLEAR curse: clears the whole map -----------------------------------------

ID_CURSE_CLEAR=3

function clear_do_curse()
    utils_clear_map()
end


-- GOOFY curse: inverts the right & left keys --------------------------------

ID_CURSE_GOOFY=2

function goofy_do_curse(sent)
    if sent==0 then
        u61_send_curse(ID_CURSE_GOOFY)
    else
        u61_register_curse(ID_CURSE_GOOFY,120)
    end
end

function goofy_left()
    if (u61_get_curse_age(ID_CURSE_GOOFY)<0) then
        translation_x(-1)
    else
        translation_x(1)
    end    
end

function goofy_right()
    if (u61_get_curse_age(ID_CURSE_GOOFY)<0) then
        translation_x(1)
    else
        translation_x(-1)
    end    
end


-- SHUFFLE curse: shuffles the squares in the map ----------------------------

ID_CURSE_SHUFFLE=4

function shuffle_do_curse(sent)
    if sent==0 then
        u61_send_curse(ID_CURSE_SHUFFLE)
    else
        u61_register_curse(ID_CURSE_SHUFFLE,2)
    end
end

function shuffle_time_callback()
    local y
    local x
    local dy
    local dx
    local i
    local color
    local width
    local height

    if u61_get_curse_age(ID_CURSE_SHUFFLE)>=0 then
        width=u61_get_width()
        height=u61_get_height()

        i=u61_get_time()
        y=0
        while y<height do
            x=0
            while x<width do
                color=u61_get_square_color(x,y)
                if color>=0 then
                    dy=mod(floor(i/3),3)-1
                    dx=mod(i,3)-1
                    if x+dx>=0 and x+dx<width and (y+dy>=10 or dy>=0) and y+dy<height and u61_get_square_color(x+dx,y+dy)<0 then
                        u61_set_square_color(x,y,-1)
                        u61_set_square_color(x+dx,y+dy,color)
                    end
                    i=i+1
                end
                x=x+1
            end
            y=y+1
        end
    end
end


-- WIND curse: forces the block to move sideways -------------------------

ID_CURSE_WIND=5
ID_GLOBAL_WIND_COUNTER=0
ID_GLOBAL_WIND_BLOCK_X=1

function wind_do_curse(sent)
    if sent==0 then
        u61_send_curse(ID_CURSE_WIND)
    else
        u61_register_curse(ID_CURSE_WIND,300)
        wind_reset_globals()
    end
end

function wind_time_callback()
    if u61_get_curse_age(ID_CURSE_WIND)>=0 then
        if u61_get_global(ID_GLOBAL_WIND_BLOCK_X)==u61_get_block_x() then
            if u61_get_time()-u61_get_global(ID_GLOBAL_WIND_COUNTER)>=100 then
                u61_set_block_x(u61_get_block_x()-1)
                wind_reset_globals()
            end
        else
            wind_reset_globals()
        end
    end
end

function wind_reset_globals()
    u61_set_global(ID_GLOBAL_WIND_COUNTER,u61_get_time())
    u61_set_global(ID_GLOBAL_WIND_BLOCK_X,u61_get_block_x())
end



-- FIFTYTWO curse: gives only 5 and 2 like tetraminos ------------------------

ID_CURSE_FIFTYTWO=6

function fiftytwo_do_curse(sent)
    if sent==0 then
        u61_send_curse(ID_CURSE_FIFTYTWO)
    else
        u61_register_curse(ID_CURSE_FIFTYTWO,60)
    end
end

function fiftytwo_do_shape(num)
    if u61_get_curse_age(ID_CURSE_FIFTYTWO)>=0 then
        u61_reset_block()
        if mod(num,2)==0 then
            tetramino_s1()
        else
            tetramino_s2()
        end
    end
end


-- BIGX curse: replaces the current block with a big cross -------------------

ID_CURSE_BIGX=7

function bigx_do_curse(sent)
    if sent==0 then
        u61_send_curse(ID_CURSE_BIGX)
    else
        u61_reset_block()
        u61_add_item(0,0,7) 
        u61_add_item(-1,-1,7) 
        u61_add_item(-1,1,7) 
        u61_add_item(1,-1,7) 
        u61_add_item(1,1,7) 
        u61_add_item(-2,-2,7) 
        u61_add_item(-2,2,7) 
        u61_add_item(2,-2,7) 
        u61_add_item(2,2,7) 
    end
end


-- BOOST curse: makes the blocks fall very fast for a few seconds ------------

ID_CURSE_BOOST=10

function boost_do_curse(sent)
    if sent==0 then
        u61_send_curse(ID_CURSE_BOOST)
    else
        u61_register_curse(ID_CURSE_BOOST,5)
    end
end

function boost_time_callback()
    if u61_get_curse_age(ID_CURSE_BOOST)>=0 then
        translation_y(1)
    end
end


-- DROP curse: forces the block of the opponent to be dropped --- ------------

ID_CURSE_DROP=11

function drop_do_curse(sent)
    if sent==0 then
        u61_send_curse(ID_CURSE_DROP)
    else
        translation_y_check(u61_get_height())
    end
end


-- TOPDOWN curse: inverts the map, squares at the bottom go to the top -------

ID_CURSE_TOPDOWN=12

function topdown_do_curse(sent)
    local height
    local y
    local min_y

    if sent==0 then
        u61_send_curse(ID_CURSE_TOPDOWN)
    else
        min_y=utils_get_highest_square_y()
        height=u61_get_height()
        y=floor((height-min_y)/2)-1
        while y>=0 do
            utils_switch_lines(height-1-y,min_y+y)
            y=y-1
        end        
    end
end



-- TOPHOLEDLINE curse: puts 2 lines with a hole on top of the map ------------

ID_CURSE_TOPHOLEDLINE=13

function topholedline_do_curse(sent)
    local x
    local y
    local width
    local color1
    local color2

    if sent==0 then
        u61_send_curse(ID_CURSE_TOPHOLEDLINE)
    else
        width=u61_get_width()
        y=utils_get_highest_square_y()

        x=0
        while x<width do
            if (mod(x+u61_get_time(),width)==0) then
                color1=-1
            else
               color1=7
            end

            if (mod(x+u61_get_time(),width)==floor(width/2)) then
                color2=-1
            else
               color2=7
            end

            u61_set_square_color(x,y-1,color1)
            u61_set_square_color(x,y-2,color2)
            x=x+1
        end
    end
end



-- STAIRS curse, draws stairs on the map -------------------------------------

ID_CURSE_STAIRS=14

function stairs_do_curse(sent)
    if sent==0 then
        u61_send_curse(ID_CURSE_STAIRS)
    else
        if (mod(u61_get_time(),2)==0) then
            stairs_right()
        else
            stairs_left()
        end
    end
end

function stairs_right()
    local x
    local y
    local height

    height=u61_get_height()
    x=u61_get_width()-1
    while x>=0 do
        y=height-1-x
        u61_set_square_color(x-1,y,-1)
        u61_set_square_color(x,y,7)
        u61_set_square_color(x+1,y,-1)
        x=x-1
    end
end

function stairs_left()
    local x
    local y
    local height
    local width

    width=u61_get_width()
    height=u61_get_height()
    x=width
    while x>0 do
        y=height-x
        u61_set_square_color(width-x-1,y,-1)
        u61_set_square_color(width-x,y,7)
        u61_set_square_color(width-x+1,y,-1)
        x=x-1
    end
end

-- HAHA curse, writes "HA HA" on the map -------------------------------------

ID_CURSE_HAHA=15

function haha_do_curse(sent)
    if sent==0 then
        u61_send_curse(ID_CURSE_HAHA)
    else
        utils_clear_map()
        haha_draw_h(1,12)
        haha_draw_a(5,12)
        haha_draw_h(2,18)
        haha_draw_a(6,18)
    end
end

function haha_draw_h(x,y)
    u61_set_square_color(x+0,y+0,7)
    u61_set_square_color(x+0,y+1,7)
    u61_set_square_color(x+0,y+2,7)
    u61_set_square_color(x+0,y+3,7)
    u61_set_square_color(x+0,y+4,7)
    u61_set_square_color(x+1,y+2,7)
    u61_set_square_color(x+2,y+0,7)
    u61_set_square_color(x+2,y+1,7)
    u61_set_square_color(x+2,y+2,7)
    u61_set_square_color(x+2,y+3,7)
    u61_set_square_color(x+2,y+4,7)
end

function haha_draw_a(x,y)
    u61_set_square_color(x+0,y+1,7)
    u61_set_square_color(x+0,y+2,7)
    u61_set_square_color(x+0,y+3,7)
    u61_set_square_color(x+0,y+4,7)
    u61_set_square_color(x+1,y+0,7)
    u61_set_square_color(x+1,y+2,7)
    u61_set_square_color(x+2,y+1,7)
    u61_set_square_color(x+2,y+2,7)
    u61_set_square_color(x+2,y+3,7)
    u61_set_square_color(x+2,y+4,7)
end

