# OpenVerse Avatar Functions Module
# 
# This module includes all the functions related
# to avatars and avatar movement.
#
# Module Name		- Avatar Functions
# Sourced By		- InitMainWindow
#
# Copyright (C) 1999 David Gale <cruise@openverse.com>
# For more information visit http://www.openverse.com/
#
# 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.

# CRUISE - 11/08/2001 - Will only call itself if the avatar has multiple
#			frames and the animate option is set.
#
proc AnimateAvatar {} {
	global MV

	if {$MV(anim.current) == -1} {
		ChangeAvatar $MV(anim.0)
		set MV(anim.stop) 1
		set MV(anim.running) 0
		return
	}
	set delay 0
	if {$MV(anim.current) == 1 && !$MV(anim.new)} {
		set delay $MV(anim.final_delay)
	}
	if {$MV(anim.running) && $MV(anim.new)} {
		ChangeAvatar "$MV(anim.0)"
		set MV(anim.new) 0
		incr MV(anim.current)
		if {$MV(anim.current) > $MV(anim.frames)} {set MV(anim.current) 1}
		return
	}
	set MV(anim.new) 0
	if $MV(anim.stop) {
		ChangeAvatar "$MV(anim.0)"
		set MV(anim.running) 0
		return
	}
	ChangeAvatar "$MV(anim.[expr $MV(anim.current) -1])"
	set MV(anim.running) 1
	incr MV(anim.current)
	if {$MV(anim.current) > $MV(anim.frames)} {
		set MV(anim.current) 1
	}
	set do_delay [expr $MV(anim.delay) + $delay]
	if {$MV(anim.frames) > 1 && $MV(anim.animated)} {
		after $do_delay AnimateAvatar
	}
}

proc RaiseAvatar {who} {
	global MV errorInfo

	if {$who == $MV(nick)} {
		set image $MV(img)
	} else {
		if {[catch {set image $MV($who.icon)}]} {
			DebugIt "ERROR, Unable to raise $who (RaiseAvatar) Please report this error to cruise@openverse.com" other
			DebugIt "$errorInfo" other
			DebugIt "ERROR, Unable to raise $who (RaiseAvatar) Please report this error to cruise@openverse.com" other
			return
		}
	}
	.top.c raise $image
	if $MV(names) {
		KillName $who
		ShowName $who
	}
}

proc AnimateMe {what which} {
	global MV

	
	switch $which {
		1 {
			set file "$MV(avatar_files.$what)"
		}
		2 {
			set file "$MV(avatar_setup.$what)"
		}
		3 {
			if {![file exists "$MV(anims)/$what"]} {return}
			set file "$what"
		}
		default {
			set file "default.av"
		}
	}

	if {[winfo exists .setup.na.l.b.avatars.entry]} {
		.setup.na.l.b.avatars.entry delete 0 end
		.setup.na.l.b.avatars.entry insert end "$file"
	}
	catch {source "$MV(anims)/$file"}
	AnimateAvatar
}

proc ShowNames {} {
	global MV

	if $MV(names) {
		ShowName $MV(nick)
		# Process plugins
		foreach plugin $MV(plugin.traps.ShowNames) {
			if ![$MV(plugin.traps.ShowNames.$plugin) $MV(nick)] {
				return
			}
		}
		foreach who $MV(people) {
			ShowName $who
			# Process plugins
			foreach plugin $MV(plugin.traps.ShowNames) {
				if ![$MV(plugin.traps.ShowNames.$plugin) $who] {
					return
				}
			}
		}
	} else {
		KillName $MV(nick)
		# Process plugins
		foreach plugin $MV(plugin.traps.KillNames) {
			if ![$MV(plugin.traps.KillNames.$plugin) $MV(nick)] {
				return
			}
		}
		foreach who $MV(people) {
			KillName $who
			# Process plugins
			foreach plugin $MV(plugin.traps.KillNames) {
				if ![$MV(plugin.traps.KillNames.$plugin) $who] {
					return
				}
			}
		}
	}
}

proc KillName {who} {
	global MV

	catch {.top.c delete $MV($who.nameplate)}
}

# Display the nameplate.
proc ShowName {who} {
	global MV

	if {$who == $MV(nick)} {
		set MV($MV(nick).x) $MV(x)
		set MV($MV(nick).y) $MV(y)
		set MV($MV(nick).name_x_offset) $MV(anim.x_off)
		set MV($MV(nick).name_y_offset) $MV(anim.y_off)
	}

	if $MV($who.moving) {
		set x $MV($who.current_x)
		set y $MV($who.current_y)
	} else {
		set x $MV($who.x)
		set y $MV($who.y)
	}

	# Make this information available to plugins
	set MV($who.nameplate) "nameplate-[unique_id]"
	nameplate::create [expr $x + $MV($who.name_x_offset)] [expr $y +\
			$MV($who.name_y_offset)] .top.c $MV($who.nameplate)\
			-text [StripColorCodes [string_map {"_" " "} $who]]\
			-extra-tags "nameplate"
	set box [.top.c bbox "$MV($who.nameplate)-f"]
	set MV($who.name_tl_x) [lindex $box 0]
	set MV($who.name_tl_y) [lindex $box 1]
	set MV($who.name_br_x) [lindex $box 2]
	set MV($who.name_br_y) [lindex $box 3]

	# Process plugins
	foreach plugin $MV(plugin.traps.ShowName) {
		if ![$MV(plugin.traps.ShowName.$plugin) $who] return
	}
}

proc ChangeAvatar {what} {
	global MV

	if {![file exists "$MV(images)/$what"]} {
		image create photo OpenVerse_Image_pic -file "$MV(images)/default.gif"
		return
	}
	#
	# Do not allow image files with spaces in their names.
	# Cruise - 10/18/2001
	#
	if {[string first " " "$what"] != -1} {
		ThrowError "[Trns space_in_filename] (IMAGE NAME IS $what)"
		image create photo OpenVerse_Image_pic -file "$MV(images)/default.gif"
		return
	}
	image create photo OpenVerse_Image_pic -file "$MV(images)/$what"
	set MV(avatar) $what
	SendToServer "AVATAR $what $MV(anim.x_off) $MV(anim.y_off) [file size $MV(images)/$what] $MV(anim.baloon_x) $MV(anim.baloon_y)"
	if $MV(names) {
		KillName $MV(nick)
		ShowName $MV(nick)
	}

	# Process plugins
	foreach plugin $MV(plugin.traps.ChangeAvatar) {
 		if ![$MV(plugin.traps.ChangeAvatar.$plugin) $what] return
	}
}

proc DoAvatars {} {
	global MV

	set anims 0
	set depth 0
	set count 1

	destroy $MV(avatar_menu).m

	if $MV(use_windowmanager_colors) {
		menu $MV(avatar_menu).m -tearoff $MV(tearoff_menus)
	} else {
		menu $MV(avatar_menu).m -bg $MV(colors.av.bg)\
				-fg $MV(colors.av.fg)\
				-activeforeground $MV(colors.av.afg)\
				-activebackground $MV(colors.av.abg)\
				-tearoff $MV(tearoff_menus)
	}

	set MV(avatar_files.0) "default.av"
	foreach file [List_Avatars] {
		if !$depth {
			incr depth
			$MV(avatar_menu).m add cascade -menu \
				$MV(avatar_menu).m.m$depth -label "[Trns avatars] $depth"
			if $MV(use_windowmanager_colors) {
				menu $MV(avatar_menu).m.m$depth\
						-tearoff $MV(tearoff_menus)
			} else {
				menu $MV(avatar_menu).m.m$depth -bg $MV(colors.av.bg) \
					-fg $MV(colors.av.fg) -activeforeground $MV(colors.av.afg) \
					-activebackground $MV(colors.av.abg)\
						-tearoff $MV(tearoff_menus)
			}

		}
		set MV(avatar_files.$count) "[file tail $file]"
		if {[file tail $file] == "default.av"} {
			set MV(default_avatar_number) $count
		}
		$MV(avatar_menu).m.m$depth add command -label [file tail $file] \
			-command "AnimateMe $count 1"
		incr anims
		incr count
		if {$anims > 19} {
			incr depth
			$MV(avatar_menu).m add cascade -menu \
				$MV(avatar_menu).m.m$depth -label "[Trns avatars] $depth"
			if $MV(use_windowmanager_colors) {
				menu $MV(avatar_menu).m.m$depth\
						-tearoff $MV(tearoff_menus)
			} else {
				menu $MV(avatar_menu).m.m$depth -bg $MV(colors.av.bg) \
					-fg $MV(colors.av.fg) -activeforeground $MV(colors.av.afg) \
					-activebackground $MV(colors.av.abg)\
						-tearoff $MV(tearoff_menus)
			}
			set anims 0
		}
	}
}

proc MoveTo {x y pushed} {
	global MV
	
	set ret 0
	if !$pushed {
		#
		# Process Plugins!
		#
		foreach plugin $MV(plugin.traps.MoveTo.Pre) {
			if {![$MV(plugin.traps.MoveTo.Pre.$plugin) $x $y]} {return}
		}
		foreach link $MV(server_links) {
			if {$x >= $MV(server_links.$link.x1) &&
				$x <= $MV(server_links.$link.x2) &&
				$y >= $MV(server_links.$link.y1) &&
				$y <= $MV(server_links.$link.y2)} {
				DebugIt "Openening URL $MV(server_links.$link.url)" other
				set MV(url.-1.-99.what) $MV(server_links.$link.url)
				URL_OpenWeb -1 -99
				set ret 1
			}
		}
		if !$ret {
			foreach tell $MV(server_tells) {
				if {$x >= $MV(server_tells.$tell.x1) &&
					$x <= $MV(server_tells.$tell.x2) &&
					$y >= $MV(server_tells.$tell.y1) &&
					$y <= $MV(server_tells.$tell.y2)} {
					DebugIt "Telling Server $tell" other
					SendToServer "TELL $tell"
					set ret 1
				}
			}
		}
		if !$ret {
			foreach link $MV(server_exits) {
				if {$x >= $MV(server_exits.$link.x1) &&
					$x <= $MV(server_exits.$link.x2) &&
					$y >= $MV(server_exits.$link.y1) &&
					$y <= $MV(server_exits.$link.y2)} {
					DebugIt "Clicked Exit $MV(server_exits.$link.host)" other
					ConnectToRoom $MV(server_exits.$link.host) $MV(server_exits.$link.port)
					set ret 1
					break
				}
			}
		}
	}

	if !$ret {
		SendToServer "MOVE $MV(nick) $x $y $MV(movespeed)"
		set str "$x $y $MV(x) $MV(y) $MV(movespeed) 1 0"
		set MV(x) $x
		set MV(y) $y
		update idletasks
		lappend MV($MV(nick).moves) $str
		MoveAvatars 0
	}
}

proc DoTheMove {who} {
	global MV

	set length [llength $MV($who.moves)]
	if !$length return
	set info [split [lindex $MV($who.moves) 0] " "]
	set delete_flag [lindex $info 6]
	if $delete_flag return
	set x [lindex $info 0]
	set y [lindex $info 1]
	set xx [lindex $info 2]
	set yy [lindex $info 3]
	set speed [lindex $info 4]
	set nametag [lindex $info 5]
	if {$who == $MV(nick)} {
		set image $MV(img)
	} else {
		set image $MV($who.icon)
	}
	set MV($who.moving) 1
	set sspeed [expr $speed * 3]

	#puts "DoTheMove $x $y $xx $yy $speed $nametag $delete_flag"

	if {[expr $x - $xx] > 0} {set xdir 1} else {set xdir -1}
	if {[expr $y - $yy] > 0} {set ydir 1} else {set ydir -1}
	if {[expr $y - $yy] == 0} {set ydir 0}
	if {[expr $x - $xx] == 0} {set xdir 0}

	set xinc $xdir
	set yinc $ydir
	
	if {$xdir && $sspeed != 2} {
		set xinc [expr $xdir * 1]
		set xxx $xx
		while { $xxx != $x && $xinc != [expr $sspeed * $xdir]} {
			set xxx $xx
			incr xinc [expr $xdir * 1]
			incr xxx $xinc
		}
	}
	if {$ydir && $sspeed != 2} {
		set yinc [expr $ydir * 1]
		set yyy $yy
		while { $yyy != $y && $yinc != [expr $sspeed * $ydir]} {
			set yyy $yy
			incr yinc [expr $ydir * 1]
			incr yyy $yinc
		}
	}
	.top.c move $image $xinc $yinc
	set xx [expr $xx + $xinc]
	set yy [expr $yy + $yinc]

	set MV($who.current_x) $xx
	set MV($who.current_y) $yy

	if {$nametag && $MV(names)} {
		.top.c move $MV($who.nameplate) $xinc $yinc
		incr MV($who.name_tl_x) $xinc
		incr MV($who.name_tl_y) $yinc
		incr MV($who.name_br_x) $xinc
		incr MV($who.name_br_y) $yinc
	}

	if {$x != $xx || $y != $yy} {
		set newlist "$x $y $xx $yy $speed $nametag 0"
	} else {
		set newlist "$x $y $xx $yy $speed $nametag 1"
	}
	set MV($who.moves) [lreplace $MV($who.moves) 0 0 $newlist]
	
	# Process plugins
	foreach plugin $MV(plugin.traps.MoveTo.Post) {
		$MV(plugin.traps.MoveTo.Post.$plugin) $x $y
	}
}

proc MoveAvatars {loop_var} {
	global MV

	if {$MV(moving) && !$loop_var} {return}
	set MV(moving) 1

	# Info needed for movement.
	#
	# X position to move to.
	# Y position to move to.
	# XX Original X position
	# YY Original Y position
	# Speed at which we move.
	# Nametag replacement (should we move the nametag)
	# The image name to move.

	set anymove 0
	set moveusers {}
	if {[llength $MV($MV(nick).moves)]} {
		lappend moveusers $MV(nick)
	} else {
		set MV($MV(nick).moving) 0
	}
	foreach person $MV(people) {
		if {[llength $MV($person.moves)]} {
			lappend moveusers $person
		} else {
			set MV($person.moving) 0
		}
	}
	foreach user $moveusers {
		DoTheMove $user
		set info [split [lindex $MV($user.moves) 0] " "]
		set delete_flag [lindex $info 6]
		if $delete_flag {
			set MV($user.moves) [lreplace $MV($user.moves) 0 0]
		}
		if {[llength $MV($user.moves)]} {
			set anymove 1
		} else {
			set MV($user.moving) 0
		}
	}
	update idletasks
	if $anymove {
		#
		# NOTE: PERFORMANCE!
		#
		# What you see below is a great performance enhancer. It
		# causes this function to return now instead of later and
		# prevents unnescary nesting.
		#
		after 1 "MoveAvatars 1"
	} else {
		set MV(moving) 0
	}
	return
}

proc ChangeUserAvatar {who what x y size bx by} {
	global MV

	if ![lcontains $MV(people) $who] return
	if {[TestNum $x] || [TestNum $y] || [TestPosNum $size] || \
			[TestNum $bx] || [TestNum $by]} {
		DebugIt "ChangeUserAvatar: Invalid Parameters" other
		return
	}

	set MV($who.avatar) $what
	set MV($who.name_x_offset) $x
	set MV($who.name_y_offset) $y
	set MV($who.baloon_x) $bx
	set MV($who.baloon_y) $by
	if $MV(names) {
		KillName $who
		ShowName $who
	}
	if {$what == "default.gif"} {
		image create photo OpenVerse_User_Image_$who -file "$MV(images)/default.gif"
		return
	}
	if ![file exists "$MV(rem_images)/$what"] {
		if ![lcontains $MV(downloads) $what] {
			DebugIt "I do not have $what ([file exists \"$MV(rem_images)/$what\"])" other
			if $MV(download_avatars) {
				SendToServer "DCCSENDAV $what"
				set MV($who.downloading) 1
			}
		}
	} else {
		if {[file size "$MV(rem_images)/$what"] != $size} {
			if ![lcontains $MV(downloads) $what] {
				DebugIt "size mismatch for $what" other
				catch {file delete "$MV(rem_images)/$what"}
				if $MV(download_avatars) {
					SendToServer "DCCSENDAV $what"
					set MV($who.downloading) 1
				}
			}
		} else {
			if [catch {image create photo OpenVerse_User_Image_$who -file "$MV(rem_images)/$what"}] {
				image create photo OpenVerse_User_Image_$who -file "$MV(images)/default.gif"
			}
		}
	}

	# Process plugins
	foreach plugin $MV(plugin.traps.ChangeUserAvatar) {
		if ![$MV(plugin.traps.ChangeUserAvatar.$plugin) $who $what $x $y $size $bx $by] return
	}	
}

proc MoveUser {who x y speed} {
	global MV
	
	if {$who == $MV(nick)} return
	if ![lcontains $MV(people) $who] return
	if $MV($who.nomoremove) return
	if {[TestNum $x] || [TestNum $y] || [TestNum $speed]} {
		DebugIt "MoveUser: Invalid Parameters" other
		return
	}

	# Process plugins
	foreach plugin $MV(plugin.traps.MoveUser.Pre) {
		if ![$MV(plugin.traps.MoveUser.Pre.$plugin) $who $x $y $speed] {
			return
		}
	}	
	if {$speed == ""} {set speed 1}

	set str "$x $y $MV($who.x) $MV($who.y) $speed 1 0"
	set MV($who.x) $x
	set MV($who.y) $y
	update idletasks
	lappend MV($who.moves) $str
	MoveAvatars 0

	#
	# Process Plugins!
	#
	foreach plugin $MV(plugin.traps.MoveUser.Post) {
		if {![$MV(plugin.traps.MoveUser.Post.$plugin) $who $x $y $speed]} {return}
	}	
}

proc AvatarEffect {who what} {
	global MV

	if {$who == $MV(nick)} {
		set image $MV(img)
	} else {
		set image $MV($who.icon)
	}
	set x $MV($who.x)
	set y $MV($who.y)
	DebugIt "(Effect) - $who $what $x $y" other
	switch -- [string tolower $what] {
	"shiver" {
		set dir 0
		for {set c 0} {$c < 50} {incr c} {
			if $dir {
				set dir 0
				set xx [expr $x - 15]
			} else {
				set dir 1
				set xx [expr $x + 15]
			}
			lappend MV($who.moves) "$xx $y $x $y 12 0 0"
			lappend MV($who.moves) "$x $y $xx $y 12 0 0"
		}
		MoveAvatars 0
	} "jump" {
		set dir 0
		for {set c 0} {$c < 50} {incr c} {
			switch -- $dir {
			0 {
				set dir 1
				set yy [expr $y - 15]
			} 1 {
				set dir 2
				set yy [expr $y - 30]
			} 2 {
				set dir 3
				set yy [expr $y - 45]
			} 3 {
				set dir 4
				set yy [expr $y - 30]
			} 4 {
				set dir 5
				set yy [expr $y - 15]
			} 5 {
				set dir 0
				set yy $y
			}}
			lappend MV($who.moves) "$x $yy $x $y 3 0 0"
			lappend MV($who.moves) "$x $y $x $yy 3 0 0"
		}
		MoveAvatars 0
	}}
}

