#!/usr/bin/tclsh
# OpenVerse Server Program
# Modified by Andy Goth <unununium@openverse.org>
# Now it runs a GothChess room!
# 
#
# Module Name		- Miscellaneous GothChess procs
# Current Maintainter 	- Andy Goth <unununium@openverse.org>
# Sourced By		- gothchess.tcl
#
# Copyright (C) 1999 David Gale <cruise@openverse.org>
# For more information visit http://OpenVerse.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.

global chess MVS

# push args
#
# Pushes args onto undo_stack
proc push {args} {
    global chess

    foreach item $args {
	set chess(undo_stack) [linsert $chess(undo_stack) 0 $item]
    }
}

# pop
#
# Returns the top of the undo_stack
proc pop {} {
    global chess

    if {[llength $chess(undo_stack)] > 0} {
	set return_value [lindex $chess(undo_stack) 0]
	set chess(undo_stack) [lreplace $chess(undo_stack) 0 0]

	return $return_value
    } else {
	log_it "(pop): Undo stack is empty (shouldn't happen)"
	return -1
    }
}

# clear_undo_stack
#
# Empties the undo_stack
proc clear_undo_stack {} {
    global chess

    set chess(undo_stack) {}
}

# is_num what
#
# Returns 0 if $what is a number or 1 if it is not
proc is_num {what} {
    global MVS

    set bad 0

    if {[string compare [string index $what 0] "-"] == 0} {
	set i 1
    } else {
	set i 0
    }

    for {set c $i} {$c < [string length $what] && !$bad} {incr c} {
	switch -exact -- [string index $what $c] {
	    1 {}
	    2 {}
	    3 {}
	    4 {}
	    5 {}
	    6 {}
	    7 {}
	    8 {}
	    9 {}
	    0 {}
	    default {set bad 1}
	}
    }

    unset c i what

    if $bad {
	unset bad
	return 1
    } else {
	unset bad
	return 0
    }
}

# name_of who
#
# Returns 1 if $who is player 1, 2 if $who is player 2, or 0 if $who is unknown
proc name_of {who} {
    global chess

    if {[string compare $chess(players.1.sock) $who] == 0} {
	unset who
	return 1
    } elseif {[string compare $chess(players.2.sock) $who] == 0} {
	unset who
	return 2
    } else {
	unset who
	return 0
    }
}

# push_to who x y
#
# Move $who to $x, $y
proc push_to {who x y} {
    global MVS

    send_to_user $who "PUSH $x $y 20"
    send_to_all_users "MOVE $MVS($who.name) $x $y 20"

    set $MVS($who.x) $x
    set $MVS($who.y) $y

    unset who x y
}

# check_for_players
#
# If no one is connected, kill the game
proc check_for_players {} {
    global MVS

    if {$MVS(users) == 0} {
	game_end "draw"
    }
}

# slide_object who name x1 y1 x2 y2 steps delay
#
# For $who, slide $name object from ($x1, $y1) to ($x2, $y2) in $steps steps with a $delay microsecond delay in between
proc slide_object {who name x1 y1 x2 y2 steps delay} {
    slide_object_callback $who $name [expr $x1 * 1.0] [expr $y1 * 1.0] $x1 $y1 [expr ($x2 - $x1) / ($steps * 1.0)] [expr ($y2 - $y1) / ($steps * 1.0)] $steps $delay

    unset who name x1 y1 x2 y2 steps delay
}

# slide_object_callback who name x_f y_f x_i y_i x_delta y_delta steps_remaining delay
#
# Workhorse for slide_object
proc slide_object_callback {who name x_f y_f x_i y_i x_delta y_delta steps_remaining delay} {
    # Increment the real locations
    set x_f [expr $x_f + $x_delta]
    set y_f [expr $y_f + $y_delta]

    # Derive the integral locations
    set x [expr round($x_f) * 1]
    set y [expr round($y_f) * 1]

    # Send the movement message (unless there is no change)
    if {($x != $x_i) || ($y != $y_i)} {
	if {[string compare $who "all"] == 0} {
	    send_to_all_users "MOVE_OBJ $name [expr $x - $x_i] [expr $y - $y_i] 0 0"
	} else {
	    send_to_user $who "MOVE_OBJ $name [expr $x - $x_i] [expr $y - $y_i] 0 0"
	}
    }

    incr steps_remaining -1
    if {$steps_remaining > 0} {
	# Do it again in a bit
	after $delay "slide_object_callback $who $name $x_f $y_f $x $y $x_delta $y_delta $steps_remaining $delay"
    }
    
    unset who name x_f y_f x_i y_i x_delta y_delta x y
}

# capture_anim x1 y1 x2 y2 owner index
#
# Shows a nifty capture animation for the piece at ($x1, $y1) and then moves $owner's $index piece to ($x2, $y2)
proc capture_anim {x1 y1 x2 y2 owner index} {
    global chess

    # Start the background animation
    capture_anim_callback $x1 $y1 $x2 $y2 $owner $index 0 $chess(anim_timer_count)

    # Find the next free animation timer
    incr chess(anim_timer_count)
    if {$chess(anim_timer_count) > 999} {
	set chess(anim_timer_count) 0
    }

    unset x1 y1 x2 y2 owner index
}

# capture_anim_callback x1 y1 x2 y2 owner frame
#
# Workhorse for capture_anim
proc capture_anim_callback {x1 y1 x2 y2 owner index frame number} {
    global chess MVS

    # Last frame?
    if {$frame == 15} {
	# Delete the animation image
	send_to_all_users "IMAGE capture_anim_$number [expr $x1 * 60 + 30] [expr $y1 * 60 + 30] blank.gif [file size "$MVS(images)/blank.gif"] 1"

	# Move the piece off the board
	set name "piece_$owner"
	append name "_$index"
	slide_object "all" $name [expr $x1 * 60 + 30] [expr 60 * $y1 + 30] [expr $x2 * 39 + 500] [expr $y2 * 39 + 19 + (2 - $owner) * 320] 30 10

	unset x1 y1 x2 y2 owner frame index number name
	return
    }

    # A light or dark square?
    if {[expr ($x1 & 1) ^ ($y1 & 1)] == 0} {
	set img "light"
    } else {
	set img "dark"
    }

    # Decide what to do based on the frame
    switch -exact -- $frame {
	0 {
	    append img "_anim_1.gif"
	}
	1 {
	    append img "_anim_2.gif"
	}
	2 {
	    append img "_anim_3.gif"
	}
	3 {
	    append img "_anim_4.gif"
	}
	4 {
	    append img "_anim_5.gif"
	}
	5 {
	    append img "_anim_6.gif"
	}
	6 {
	    append img "_anim_7.gif"
	}
	7 {
	    append img "_default.gif"
	    set name "piece_$owner"
	    append name "_$index"
	    send_to_all_users "IMAGE $name [expr $x1 * 60 + 30] [expr $y1 * 60 + 30] $chess(pieces.$owner.$index.img) [file size "$MVS(images)/$chess(pieces.$owner.$index.img)"] 0"
	    unset name
	}
	8 {
	    append img "_anim_7.gif"
	}
	9 {
	    append img "_anim_6.gif"
	}
	10 {
	    append img "_anim_5.gif"
	}
	11 {
	    append img "_anim_4.gif"
	}
	12 {
	    append img "_anim_3.gif"
	}
	13 {
	    append img "_anim_2.gif"
	}
	14 {
	    append img "_anim_1.gif"
	}
    }

    # Show the animation frame
    send_to_all_users "IMAGE capture_anim_$number [expr $x1 * 60 + 30] [expr $y1 * 60 + 30] $img [file size "$MVS(images)/$img"] 0"

    # Do it again in a bit
    after 20 "capture_anim_callback $x1 $y1 $x2 $y2 $owner $index [expr $frame + 1] $number"

    unset x1 y1 x2 y2 owner index frame number img
}

# capture_piece owner index
#
# Handles the capture of $owner's $index'th piece
proc capture_piece {owner index} {
    global MVS chess

    # Shrink its image
    set chess(pieces.$owner.$index.img) "mini_"
    if {$owner == 1} {
	append chess(pieces.$owner.$index.img) "white_"
    } else {
	append chess(pieces.$owner.$index.img) "black_"
    }
    switch -exact -- $chess(pieces.$owner.$index.type) {
	"rook" {
	    append chess(pieces.$owner.$index.img) "rook.gif"
	}
	"knight" {
	    append chess(pieces.$owner.$index.img) "knight.gif"
	}
	"bishop" {
	    append chess(pieces.$owner.$index.img) "bishop.gif"
	}
	"king" {
	    append chess(pieces.$owner.$index.img) "king.gif"
	}
	"queen" {
	    append chess(pieces.$owner.$index.img) "queen.gif"
	}
	"pawn" {
	    append chess(pieces.$owner.$index.img) "pawn.gif"
	}
	default {
	    # Bad piece type (use blank)
	    set chess(pieces.$owner.$index.img) "blank.gif"
	}
    }

    set x1 $chess(pieces.$owner.$index.x)
    set y1 $chess(pieces.$owner.$index.y)
    set x2 [expr $chess(players.[expr 3 - $owner].num_captured) % 4]
    set y2 [expr $chess(players.[expr 3 - $owner].num_captured) / 4]

    # Place it
    set chess(pieces.$owner.$index.x) $x2
    set chess(pieces.$owner.$index.y) $y2
    incr chess(players.[expr 3 - $owner].num_captured)

    # Show the goofy animation
    capture_anim $x1 $y1 $x2 $y2 $owner $index

    unset owner index x1 y1 x2 y2
}

