#!/usr/bin/env ruby


# This is a derivative work of an original copyrighted work;
# the original being distributed with Pygame, which is licensed
# under the GNU LGPL. If the original work was distributed under
# the GNU LGPL, then the following necessarily applies to this work:
# 
#	This program is free software; you can redistribute it and/or
#	modify it under the terms of the GNU Lesser General Public
#	License as published by the Free Software Foundation; either
#	version 2.1 of the License, or (at your option) any later version.
#
#	This library 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
#	Lesser General Public License for more details.
#
#	You should have received a copy of the GNU Lesser General Public
#	License along with this library; if not, write to the Free Software
#	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
# 
# If, however, the original was public domain, then the author of this
# derivative work places this work in the public domain as well.


# This is a shameless rip-off of an example application from
# pygame (http://www.pygame.org), translated to Rubygame.
# The original application had this to say:
# 
#   This simple example is used for the line-by-line tutorial
#   that comes with pygame. It is based on a 'popular' web banner.
#   Note there are comments here, but for the full explanation, 
#   follow along in the tutorial.
# 
# The original tutorial could be found at this location as of 2005-04-17:
# 
#   http://pygame.org/docs/tut/chimp/ChimpLineByLine.html
# 
# As much as possible, this is a straight port of the pygame example,
# without any real improvements in style. Significant deviations are
# noted in comments. As such, this might serve as something of a
# Rosetta Stone for a pygame user switching to Rubygame, but is not to
# be taken as recommended Rubygame program layout or style.

require "rubygame"

puts 'Warning, images disabled' unless ($image_ok = Rubygame::Image.usable?)
puts 'Warning, font disabled' unless ($font_ok = Rubygame::TTF.usable?)

#functions to create our resources
def load_image(name, colorkey=nil)
	image = Rubygame::Image.load(name)
	if colorkey != nil
		if colorkey == -1
			colorkey = image.get_at([0,0])
		end
		image.set_colorkey(colorkey)
	end
	return image, Rubygame::Rect.new(0,0,*image.size)
end

# load_sound would go here, but Rubygame can't do sound yet :(

#classes for our game objects

# The fist object, which follows the mouse and punches on mouseclick
class Fist
	# It's a sprite (an image with location data).
	include Rubygame::Sprites::Sprite

	# Create and set up a new Fist object
	def initialize
		super					# initialize sprite
		@image, @rect = load_image('fist.bmp', -1)
		@punching = false		# whether the fist is punching
		@mpos = [0,0]			# mouse curson position
	end

	# This is a small departure from the Pygame example. Instead
	# of polling the mouse for cursor position etc. (which Rubygame
	# doesn't do, as of October 2005), we receive notification
	# of mouse movements from a global event queue and store it
	# in @mpos for later use in Fist#update().
	def tell(ev)
		case ev
		when Rubygame::MouseMotionEvent
			# mouse cursor moved, remember its last location for #update()
			@mpos = ev.pos
		end
	end

	# Update the fist position
	def update
		# move the rect to the remembered position
		@rect.midtop = @mpos
		# apply offset (right and down) if we are punching
		if @punching
			@rect.move!(5,10)
		end
	end

	# Attempt to punch a target. Returns true if it hit or false if not.
	def punch(target)
		@punching = true
		# use a smaller rect to check if we collided with the target
		return @rect.inflate(-5, -5).collide_rect?(target.rect)
	end

	# Stop punching.
	def unpunch
		@punching = false
	end
end

# A chimpanzee which moves across the screen and spins when punched.
class Chimp
	# It's a sprite (an image with location data).
	include Rubygame::Sprites::Sprite

	# Create and set up a new Chimp object
	def initialize
		super					# initialize sprite
		@original, @rect = load_image('chimp.bmp', -1)
		@image = @original 		# store original image during rotation
		@rect.topleft = 10,10
		# @area is the area of the screen, which the chimp will walk across
		@area = Rubygame::Rect.new(0,0,
															 *Rubygame::Screen.get_surface().size())
		@xvel = 9 # called self.move in the pygame example

		# In python, the integer 0 signifies false, while in ruby it does not.
		# The pygame example used self.dizzy to mean the angle
		# in degrees the monkey has rotated, and also as a boolean.
		# 
		# Our example will do the same, but a conditional must be introduced
		# to #update() where in the pygame example, 0 was condition enough.
		@dizzy = 0
	end

	# Walk or spin, depending on the monkey's state
	def update
		# This   (!= 0) is the added conditional referred to above.
		if @dizzy != 0
			spin()
		else
			walk()
		end
	end

	# Move the chimp across the screen, and turn at the left and right edges.
	def walk
		newpos = @rect.move(@xvel,0) # calculate chimp position for next frame

		# If the chimp starts to walk off the screen
		if (@rect.left < @area.left) or (@rect.right > @area.right)
			@xvel = -@xvel		# reverse direction of movement
			newpos = @rect.move(@xvel,0) # recalculate with changed velocity
			@image = Rubygame::Transform.flip(@image, true, false) # flip x
		end
		@rect = newpos
	end

	# spin the monkey image
	def spin
		center = @rect.center
		@dizzy += 12			# increment angle
		if @dizzy >= 360		# if we have spun full-circle, stop spinning.
			@dizzy = 0
			@image = @original
		else					# otherwise, spin some more!
			# Note that we rotate with @original, not the current @image.
			# This reduces cumulative blurring from the rotation process,
			# and is just as efficient as incremental rotations.
			@image = Rubygame::Transform.rotozoom(@original,@dizzy,1,true)
		end
		@rect = Rubygame::Rect.new(0,0,*@image.size)
		@rect.center = center # re-center
	end

	# The pygame example used the mangled function names _walk and _spin
	# to indicate that they were privately used (as is python tradition).
	# We'll use a more explicit declaration (as is ruby tradition).
	private :walk, :spin

	# This will cause the chimp to start spinning
	def punched
		if (@dizzy == 0)
			@dizzy = 1
			@original = @image
		end
	end
end

# This function is called when the program starts.It initializes
# everything it needs, then runs in a loop until the user closes
# the window or presses ESCAPE.
def main
	
	# Initialize Everything
	Rubygame.init()
	screen = Rubygame::Screen.set_mode([468, 60])
	screen.set_caption('Monkey Fever')
	# (can't make mouse invisible yet)
	# Rubygame makes an event Queue object, pygame just uses a function
	# It's a Singleton, so there's only one instance
	queue = Rubygame::Queue.instance()

	# Create The Background
	background = Rubygame::Surface.new(screen.size)
	background.fill([250,250,250])
	
	#Put Text On The Background, Centered
	# $font_ok was set at the very top. It tells us if it's ok to use TTF.
	if $font_ok
		# We have to setup the TTF class before we can make TTF objects
		Rubygame::TTF.setup()

		# Rubygame has no default font, so we must specify freesansbold.ttf
		# 
		# 25 is more or less the actual font size in the pygame example,
		# based on scaling factor (0.6875) pygame applies to its default font.
		font = Rubygame::TTF.new("freesansbold.ttf",25)
		text = font.render("Pummel The Chimp, And Win $$$", true, [10,10,10])
		textpos = Rubygame::Rect.new(0,0,*text.size)
		textpos.centerx = background.width/2
		# ATTENTION: Note that the "actor" is reversed from the pygame usage.
		# In pygame, a surface "pulls" another surface's data onto itself.
		# In Rubygame, a surface "pushes" its own data onto another surface.
		text.blit(background,textpos)
	end

	#Display The Background
	# Again, note the reversal of actors in the blit function
	background.blit(screen, [0,0])
	screen.update()
	
	#Prepare Game Objects

	# This also differs from pygame. Rather than pass the desired framerate
	# when you call clock.tick, you set the framerate for the clock, either
	# when you create it, or afterwards with the desired_fps accessors.
	# 
	# Please note that at the moment, framerate limiting is not very accurate.
	clock = Rubygame::Time::Clock.new(30)

	#whiff_sound = load_sound('whiff.wav')
	#punch_sound = load_sound('punch.wav')
	chimp = Chimp.new()
	fist = Fist.new()
	allsprites = Rubygame::Sprites::Group.new()
	allsprites.push(fist, chimp)
	
	#Main Loop
	loop do
		clock.tick()
		
		#Handle Input Events
		# Iterate through all the events the Queue has caught
		queue.get().each do |event|
			# Python doesn't have a case statement like Ruby does! :)
			# Here, we implicitly "switch" based on the event's class.
			# Unlike in pygame, each event is detected by class, not
			# by an integer type identifier.
			case(event)
			when Rubygame::QuitEvent
				return			# break out of the main function
			when Rubygame::KeyDownEvent
				case event.key 
				when Rubygame::K_ESCAPE
					return			# break out of the main function
				when Rubygame::K_SPACE
					sleep 1
				end
			when Rubygame::MouseMotionEvent
				fist.tell(event)
			when Rubygame::MouseDownEvent
				# can't play sound yet, we'll have to commentate
				if fist.punch(chimp)
					puts "Hit!"
					chimp.punched()
				else
					puts "Miss!"
				end
			when Rubygame::MouseUpEvent
				fist.unpunch()
			end
		end 					# end event handling

		allsprites.update()
		

    #Draw Everything
		background.blit(screen, [0, 0])
		allsprites.draw(screen)
		screen.update()

		screen.set_caption(clock.fps.to_s)
	end							# end loop

	#Game Over
end								# end main function


#this calls the 'main' function when this script is executed
if $0 == __FILE__
	main()
end
