Commit ffc94bd8 authored by Markus Koschany's avatar Markus Koschany

Import Upstream version 1.5

parents
This diff is collapsed.
Copyright (c) 2006-2007 Olli Etuaho, Joona Karjalainen, Pekka Kujansuu
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
import pygame
from pygame.locals import *
def _pixelPerfectCollisionDetection(sp1,sp2):
"""
Internal method used for pixel perfect collision detection.
"""
rect1 = sp1.rect;
rect2 = sp2.rect;
rect = rect1.clip(rect2)
#hm1 = sp1.hitmask
#hm2 = sp2.hitmask
x1 = rect.x-rect1.x
y1 = rect.y-rect1.y
x2 = rect.x-rect2.x
y2 = rect.y-rect2.y
for r in xrange(0,rect.height):
for c in xrange(0,rect.width):
# I changed this for the 1.5 release of Funny Boat,
# because generating hitmasks is a bit problematic
# now that Numeric is outdated and surfarrays don't work.
# It's not an optimal solution, but is good enough for
# this game.
#if hm1[c+x1][r+y1] & hm2[c+x2][r+y2]:
if sp1.image.get_at((c+x1, r+y1))[3] & sp2.image.get_at((c+x2, r+y2))[3]:
return 1
return 0
def spritecollide_pp(sprite, group, dokill):
"""pygame.sprite.spritecollide_pp(sprite, group, dokill) -> list
pixel perfect collision detection between sprite and group
given a sprite and a group of sprites, this will
return a list of all the sprites that intersect
the given sprite.
all sprites must have a "hitmap" value, which is a 2d array
that contains a value larger than zero for all pixels that
can collide. the "hitmap" 2d array can be set by using
pygame.surfarray.array_colorkey() or pygame.surfarray.array_alpha().
all sprites must have a "rect" value, which is a
rectangle of the sprite area.if the dokill argument
is true, the sprites that do collide will be
automatically removed from all groups."""
crashed = []
spritecollide = sprite.rect.colliderect
ppcollide = _pixelPerfectCollisionDetection
if dokill:
for s in group.sprites():
if spritecollide(s.rect):
if ppcollide(sprite,s):
s.kill()
crashed.append(s)
else:
for s in group.sprites():
if spritecollide(s.rect):
if ppcollide(sprite,s):
crashed.append(s)
return crashed
def groupcollide_pp(groupa, groupb, dokilla, dokillb):
"""pygame.sprite.groupcollide_pp(groupa, groupb, dokilla, dokillb) -> dict
collision detection between group and group by using pixel perfect
collision detection
given two groups, this will find the intersections
between all sprites in each group. it returns a
dictionary of all sprites in the first group that
collide. the value for each item in the dictionary
is a list of the sprites in the second group it
collides with. the two dokill arguments control if
the sprites from either group will be automatically
removed from all groups."""
crashed = {}
SC = spritecollide_pp
if dokilla:
for s in groupa.sprites():
c = SC(s, groupb, dokillb)
if c:
crashed[s] = c
s.kill()
else:
for s in groupa.sprites():
c = SC(s, groupb, dokillb)
if c:
crashed[s] = c
return crashed
def spritecollideany_pp(sprite, group):
"""pygame.sprite.spritecollideany_pp(sprite, group) -> sprite
finds any sprites that collide by using pixel perfect
collision detection
given a sprite and a group of sprites, this will
return return any single sprite that collides with
with the given sprite. If there are no collisions
this returns None.
if you don't need all the features of the
spritecollide function, this function will be a
bit quicker.
all sprites must have a "hitmap" value, which is a 2d array
that contains a value larger than zero for all pixels that
can collide. the "hitmap" 2d array can be set by using
pygame.surfarray.array_colorkey() or pygame.surfarray.array_alpha().
all sprites must have a "rect" value, which is a
rectangle of the sprite area.
"""
spritecollide = sprite.rect.colliderect
ppcollide = _pixelPerfectCollisionDetection
for s in group.sprites():
if spritecollide(s.rect):
if ppcollide(sprite,s):
return s
return None
Trip on the Funny Boat
----------------------
This game was made for the second PyWeek competition during the week from
25.3.2006 to 2.4.2006. All source code and data was created from scratch by the
project team during this time, apart from the font and the collision detection
library used in the game (detailed below in "License").
You play the role of a steamboat captain on the wild seas populated by sharks,
pirates, minefields and the occasional seagull.
Game modes:
-----------
Story mode: In the story mode, you will go through five different phases of
play, and then face the final boss in the sixth phase. The story mode starts
easy, but you should find it quite challenging in the last phases.
Endless mode: Endless mode will put you up against waves after waves of enemies,
with twelve different phases. Endless mode is very challenging, but it's the
only way to get the big high scores. :-)
Power ups:
----------
There are little health power ups that give you one heart back if you have lost
them while battling enemies. You have a total of five hearts and if you lose all
of them, you will die, so be sure to take all the power ups that come your way.
Enemies:
--------
Shark: The sharks jump out of the water, so you'll have to time your shooting
carefully.
Mine: The mines won't try any tricks on you, but make sure that you're on a high
wave or jumping when it comes your way.
Pirate ship: These bastards shoot you with their cannons. You'll have to shoot
them back twice before they sink. Touching them doesn't hurt you so you might be
able to sail through them if you watch their cannon fire carefully.
License:
--------
The source code is provided under the GNU GPL licence version 2. (see
LICENSE-CODE.txt)
The graphics, sound effects and music are provided under the MIT License.
(see LICENSE-MEDIA.txt)
The Vera Sans font is made by Bitstream Inc. and it can't be sold by itself,
but can otherwise be used freely. See http://www.gnome.org/fonts/ for details.
The PixelPerfect collision detection library was created by John Eriksson in
2006 and is under public domain. It can be found on mr. Eriksson's website at
http://arainyday.se/projects/python/PixelPerfect/
System Requirements:
--------------------
Hardware:
Minimum of 500Mhz processor
Software:
Python 2.4 (http://www.python.org/)
PyGame 1.7 (http://www.pygame.org/)
Controls:
---------
Left cursor key / Joystick or gamepad left: Move left
Right cursor key / Joystick or gamepad right: Move right
Up cursor key / Joystick or gamepad button #1: Jump
Space bar / Joystick or gamepad button #2: Shoot with cannon
Hold for 3 seconds and then
release for a special shot!
S key / Joystick or gamepad button #6: Save screenshot as sshotXX.tga
P key / Joystick or gamepad button #9: Pause the game.
Original Credits:
-----------------
Pekka "pekuja" Kujansuu: Code, graphics and sound effects.
E-mail: "pekuja <at> iki <dot> fi"
Olli "Hectigo" Etuaho: Graphics and code.
E-mail: "admin <at> hectigo <dot> net"
Joona "JDruid" Karjalainen: Music
E-mail: "jhkarja2 <at> cc <dot> hut <dot> fi"
Additional Credits:
-------------------
Konstantin Yegupov: New features and bugfixes in version 1.3
import pygame
import math
from water import Water
from locals import *
import util
class Cannonball (pygame.sprite.Sprite):
image = None
spec_image = None
sound = None
def __init__(self, ship_rect, ship_angle, left = False, special = False):
pygame.sprite.Sprite.__init__(self)
if not Cannonball.image:
Cannonball.image = util.load_image("kuti")
if not Cannonball.spec_image:
Cannonball.spec_image = pygame.transform.flip(util.load_image("lokki2"),1,0)
if not Cannonball.sound:
Cannonball.sound = util.load_sound("pam")
screen = pygame.display.get_surface()
self.area = screen.get_rect()
if special:
self.image= Cannonball.spec_image
else:
self.image = Cannonball.image
self.special=special
self.underwater=0
#self.hitmask = pygame.surfarray.array_alpha(self.image)
if (Variables.sound):
Cannonball.sound.play()
#self.dy = -5
#self.dx = 10
# Shoot at an angle of 25 relative to the ship
self.angle=0
if not left:
if special:
velocity = 14.0
self.rect = pygame.Rect(ship_rect.right, ship_rect.top, self.image.get_width(), self.image.get_height())
self.vect = [math.cos((-ship_angle - 15.0) / 180.0 * math.pi) * velocity,
math.sin((-ship_angle - 15.0) / 180.0 * math.pi) * velocity]
else:
velocity = 11.0
self.rect = pygame.Rect(ship_rect.right, ship_rect.centery, self.image.get_width(), self.image.get_height())
self.vect = [math.cos((-ship_angle - 25.0) / 180.0 * math.pi) * velocity,
math.sin((-ship_angle - 25.0) / 180.0 * math.pi) * velocity]
else:
self.rect = pygame.Rect(ship_rect.left, ship_rect.centery, self.image.get_width(), self.image.get_height())
self.vect = [math.cos((-ship_angle + 180.0 + 25.0) / 180.0 * math.pi) * 11.0,
math.sin((-ship_angle + 180.0 + 25.0) / 180.0 * math.pi) * 11.0]
# Will have to think this through later
#self.vect = [10, -2] #vect
def update_angle(self, angle):
self.angle = angle
self.image = util.rotate(Cannonball.spec_image, angle)
self.rect.width = self.image.get_width()
self.rect.height = self.image.get_height()
#self.hitmask = pygame.surfarray.array_alpha(self.image)
def tail_point(self):
return self.rect.left, self.rect.centery-3+self.rect.width*math.sin(self.angle/180.0*math.pi)
def update(self):
self.rect.left += self.vect[0] #self.dx
self.rect.top += self.vect[1] #self.dy
self.vect[1] += 0.4
#self.dy += 1
if self.rect.bottom > Water.global_water.get_water_level(self.rect.centerx):
self.vect[0] *= 0.9
self.vect[1] *= 0.9
self.underwater=1
if 1 and self.special:
try:
self.update_angle(-180/math.pi*math.atan(self.vect[1]/self.vect[0]))
except ZeroDivisionError:
self.update_angle(-90)
import pygame
import math
import random
from locals import *
import util
def init():
Cloud.images = []
Cloud.images.append(util.load_image("cloud1"))
Cloud.images.append(util.load_image("cloud2"))
Cloud.images.append(util.load_image("cloud3"))
Cloud.images.append(util.load_image("cloud4"))
def update():
if Cloud.t % 150 == 0:
Cloud.global_clouds.append(Cloud())
Cloud.cloud_sprites.add(Cloud.global_clouds[-1])
for cloud in Cloud.global_clouds:
cloud.update()
if cloud.rect.right < 0:
Cloud.global_clouds.remove(cloud)
Cloud.cloud_sprites.remove(cloud)
Cloud.t += 1
def draw(screen):
Cloud.cloud_sprites.draw(screen)
class Cloud (pygame.sprite.Sprite):
images = None
global_clouds = []
cloud_sprites = pygame.sprite.Group()
t = 0
def __init__(self):
pygame.sprite.Sprite.__init__(self)
if not Cloud.images:
cloud.init()
screen = pygame.display.get_surface()
self.area = screen.get_rect()
self.cloudtype = int(random.random() * len(Cloud.images))
self.image = Cloud.images[self.cloudtype]
self.rect = pygame.Rect(SCREEN_WIDTH, random.random()*70, self.image.get_width(), self.image.get_height())
self.life = 0
self.dx, self.dy = -1, 0
def update(self):
self.rect.top = self.rect.top + self.dy
self.rect.left = self.rect.left + self.dx
File added
File added
File added
data/kuti.png

157 Bytes

data/miina.png

481 Bytes

File added
File added
data/sydan.png

368 Bytes

import pygame
import math
from water import Water
import util
from locals import *
class Enemy(pygame.sprite.Sprite):
def __init__(self, pos = [0.0, 0.0], health = 1):
pygame.sprite.Sprite.__init__(self)
self.pos = pos
self.velocity [0.0, 0.0]
self.health = health
#self.hitmask = pygame.surfarray.array_alpha(self.image)
self.angle = 0
self.targetangle = 0
self.dying = False
self.dead = False
self.t = 0
def damage(self):
self.health -= 1
if self.health == 0:
self.die()
def update(self):
self.t += 1
self.velocity[1] += 1.0 # Gravity
self.pos[0] += self.velocity[0]
self.pos[1] += self.velocity[1]
def die(self):
self.dying = True
main.py %1 %2
\ No newline at end of file
#!/bin/sh
env python main.py $1 $2
This diff is collapsed.
import pygame
from pygame.locals import *
from locals import *
import util
def init():
Health.heart = util.load_image("sydan")
Health.heart_empty = util.load_image("sydan-tyhja")
Health.heart_broken = util.load_image("sydan-rikki")
heart_broken = pygame.Surface((Health.heart_broken.get_rect().width, Health.heart_broken.get_rect().height))
heart_broken.fill((255,0,255))
heart_broken.set_colorkey((255,0,255))
heart_broken.blit(Health.heart_broken, heart_broken.get_rect())
Health.heart_broken = heart_broken
class Health (pygame.sprite.Sprite):
heart = None
heart_empty = None
heart_broken = None
def __init__(self):
pygame.sprite.Sprite.__init__(self)
if not Health.heart or not Health.heart_empty or not Health.heart_broken:
init()
self.rect = pygame.Rect(10, 0, Health.heart.get_width() * 5 + 4, Health.heart.get_height() * 2)
self.image = pygame.Surface((self.rect.width, self.rect.height))
self.image.set_colorkey((255,255,255))
self.hearts_left = 5
self.hearts_dying = 0
self.hearts_deathcounters = [0,0,0,0,0]
self.update()
def update(self):
# clear the surface
self.image.fill((255,255,255))
for i in xrange(5):
rect = pygame.Rect(i * (Health.heart.get_width() + 1), Health.heart.get_height(), Health.heart.get_width(), Health.heart.get_height())
if i < self.hearts_left:
self.image.blit(Health.heart, rect)
else:
self.image.blit(Health.heart_empty, rect)
if i < (self.hearts_left + self.hearts_dying):
rect.top -= self.hearts_deathcounters[i]
if Variables.alpha:
Health.heart_broken.set_alpha(255 - self.hearts_deathcounters[i]*10)
self.image.blit(Health.heart_broken, rect)
self.hearts_deathcounters[i] += 1
if self.hearts_deathcounters[i] == 25:
self.hearts_dying -= 1
def damage(self):
if self.hearts_left > 0:
self.hearts_left -= 1
self.hearts_dying += 1
self.update()
def add(self):
if self.hearts_left < 5:
self.hearts_left += 1
import pygame
import os
import sys
import codecs
import util
from locals import *
from water import Water
import cloud
class Highscores:
sky = None
def __init__(self, screen, new_score = -1, endless = False, online = False):
self.screen = screen
if not endless:
self.title = util.bigfont.render("Story Mode", True, (0,0,0))
elif not online:
self.title = util.bigfont.render("Endless Mode", True, (0,0,0))
else:
self.title = util.bigfont.render("Endless Online", True, (0,0,0))
if not Highscores.sky:
Highscores.sky = util.load_image("taivas")
Highscores.sky = pygame.transform.scale(Highscores.sky, (SCREEN_WIDTH, SCREEN_HEIGHT))
self.inputting = False
self.input_score = -1
self.scores = []
self.done = False
self.endless = endless
if online:
if not self.online_init():
self.done = True
print "Could not get online highscores!"
return
self.pathname = util.get_config_path()
if not endless:
self.filename = self.pathname + "/scores"
else:
self.filename = self.pathname + "/endless_scores"
try:
if not os.path.exists(self.pathname):
os.mkdir(self.pathname)
except:
print "Can't make directory " + self.pathname
self.done = True
return
if not os.path.exists(self.filename):
#print "Creating dummy high scores"
self.dummy_scores()
else:
try:
f = codecs.open(self.filename, "r", "utf_8")
i = 0
name, score = "", 0
for line in f:
if i % 2 == 0:
name = line.strip()
else:
try:
score = int(line)
except:
print "Corrupt high score file."
self.dummy_scores()
break
self.scores.append((name, score))
i += 1
except:
self.dummy_scores()
print "Can't open file " + self.filename + " or file corrupt"
if len(self.scores) < 10:
print "Corrupt high score file."
self.dummy_scores()
# The online highscore is always submitted
if endless and new_score != -1:
self.submit_score(Variables.name, new_score)
if new_score > self.scores[9][1]:
#print "It's a new high score!"
#self.inputting = True
for i in xrange(10):
if self.scores[i][1] < new_score:
self.input_score = i
for j in xrange(9 - i):
self.scores[9 - j] = self.scores[8 - j]
self.scores[i] = [Variables.name, new_score]
break
self.write_scores()
def online_init(self):
HIGHSCORE_URL = "http://funnyboat.sourceforge.net/cgi-bin/top10.py"
try:
import socket
socket.setdefaulttimeout(20)
import urllib2
f = urllib2.urlopen(HIGHSCORE_URL)
for line in f.readlines():
name,score = line.split("\t")
score = int(score)
name = unicode(name, "utf-8")
self.scores.append((name,score))
f.close()
except:
# Getting highscores failed
return False
# Success
return True
def submit_score(self, name, score):
SUBMIT_URL = "http://funnyboat.sourceforge.net/cgi-bin/submit.py"
try:
import socket
socket.setdefaulttimeout(20)
import urllib
import urllib2
#name,score = self.scores[self.input_score]
data = urllib.urlencode({'name' : name.encode('utf-8'), 'score' : score})
req = urllib2.Request(SUBMIT_URL, data)
f = urllib2.urlopen(req)
f.close()
except:
print "Failed to submit highscore"
def run(self):
water = Water.global_water
water.set_amplitude(SCREEN_HEIGHT / 8.0)
water_sprite = pygame.sprite.Group()
water_sprite.add(water)
while not self.done:
self.screen.blit(Highscores.sky, self.screen.get_rect())
water.update()
cloud.update()
cloud.draw(self.screen)
water_sprite.draw(self.screen)
rect = self.title.get_rect()
rect.centerx = self.screen.get_rect().centerx
rect.top = 10
self.screen.blit(self.title, rect)
for i in xrange(10):
color = (0,0,0)
#if self.inputting and self.input_score == i:
if self.input_score == i:
color = (220, 120, 20)
score = self.scores[i]
image = 0
try:
image = util.smallfont.render(str(i + 1) + ". " + score[0], True, color)
except:
image = util.smallfont.render(str(i + 1) + ". Error", True, color)
rect = image.get_rect()
rect.top = 50 + i * 1.5 * rect.height
rect.left = 10
self.screen.blit(image, rect)
image = util.smallfont.render(str(score[1]), True, color)
rect = image.get_rect()
rect.top = 50 + i * 1.5 * rect.height
rect.right = self.screen.get_rect().right - 10
self.screen.blit(image, rect)
pygame.display.flip()
nextframe = False
while not nextframe:
pygame.event.post(pygame.event.wait())
for event in pygame.event.get():
if event.type == NEXTFRAME: