# # GameObjectManager.py # # 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; version 2 of the License. # # 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. # # Copyright # Author: Nicholas F. Hoover # Contributors: Salvatore S. Gionfriddo # Created: 2007.06.20 # Last Modified: 2007.11.18 # import pygame, random import GameObject, Settings from Engine import Engine, SpriteList from Hero import Hero from Flame import Flame, Gas from PowerUp import PowerUp from Parachute import Parachute, Hole from Projectile import Projectile from Statistics import Statistics, EG_Stats class GameObjectManager(Engine): NUM_SPRITE_LISTS = 8 #NOTE: This is the update and draw order (POWERUPS, HOLES, KIDS, FLAMES, GASES, HERO, PROJECTILES, PKIDS) = range(NUM_SPRITE_LISTS) def __init__(self, drawSurface, resourceManager, hero = 'EvilGreg'): Engine.__init__(self, drawSurface) self.resourceManager = resourceManager self.setNumberSpriteLists(self.NUM_SPRITE_LISTS) self.addSpriteList(self.HOLES, SpriteList(GameObject.OrderedUpdatesDraw())) self.addSpriteList(self.HERO, SpriteList(GameObject.OrderedUpdatesDraw(), empty = False, reset = True, sorted = False)) self.addSpriteList(self.KIDS, SpriteList(GameObject.OrderedUpdatesDraw(), collidable = True, updateArgIndex = 0)) self.addSpriteList(self.FLAMES, SpriteList(GameObject.OrderedUpdatesDraw())) self.addSpriteList(self.GASES, SpriteList(GameObject.OrderedUpdatesDraw())) self.addSpriteList(self.POWERUPS, SpriteList(GameObject.OrderedUpdatesDraw())) self.addSpriteList(self.PROJECTILES, SpriteList(GameObject.OrderedUpdatesDraw())) self.addSpriteList(self.PKIDS, SpriteList(GameObject.OrderedUpdatesDraw(), updateArgIndex = 0)) self.hero_name = hero self.hero = Settings.HEROS[hero][1]() self.addSpriteToGroup(self.HERO, self.hero) self.egStats = EG_Stats() self.level = -1 #collision checks self.addCollisionFunctions( [self.checkHoles, self.checkAttack1, self.checkAttack2, self.checkSpecialAttack1, self.checkSpecialAttack2, self.checkKidAttack, self.checkEat, self.checkPickUp, self.checkParachutes, self.checkKidThrowing, self.checkProjectileHit, self.checkGroupers]) def reset(self): Engine.reset(self) self.run = True self.egStats.reset() self.level = -1 #update all the sprites, check for collisions and handle them, draw on the screen def update(self): self.createFlame() self.createGas() Engine.update(self, [self.hero.rect]) self.egStats.increment([Statistics.TIME, self.egStats.levelFlag(self.level)]) def checkAttack1(self): if self.hero.isActionActive(Hero.ATTACK1): attackSprite = self.hero.createAttack1Sprite() kills = self.hitKids(pygame.sprite.spritecollide(attackSprite,self.getSpriteGroup(self.KIDS),False), self.hero.ATTACK1_DAMAGE) for kidtype in kills: self.egStats.increment([Statistics.KILLS, Statistics.PUNCH, self.egStats.levelFlag(self.level), self.egStats.enemyFlag(kidtype)], kills[kidtype]) def checkAttack2(self): if self.hero.isActionActive(Hero.ATTACK2): attackSprite = self.hero.createAttack2Sprite() kills = self.hitKids(pygame.sprite.spritecollide(attackSprite,self.getSpriteGroup(self.KIDS),False), self.hero.ATTACK2_DAMAGE) for kidtype in kills: self.egStats.increment([Statistics.KILLS, Statistics.KICK, self.egStats.levelFlag(self.level), self.egStats.enemyFlag(kidtype)], kills[kidtype]) def checkSpecialAttack1(self): flameHitDict = pygame.sprite.groupcollide(self.getSpriteGroup(self.FLAMES),self.getSpriteGroup(self.KIDS), False, False) for flame in flameHitDict: if flame.isActionActive(Flame.FLAME): kills = self.hitKids(flameHitDict[flame],self.hero.SPECIAL1_DAMAGE) for kidtype in kills: self.egStats.increment([Statistics.KILLS, Statistics.FLAME, self.egStats.levelFlag(self.level), self.egStats.enemyFlag(kidtype)], kills[kidtype]) def checkSpecialAttack2(self): gasHitDict = pygame.sprite.groupcollide(self.getSpriteGroup(self.GASES), self.getSpriteGroup(self.KIDS), False, False) for gas in gasHitDict: if gas.isActionActive(Gas.GAS): kills = self.hitKids(gasHitDict[gas],self.hero.SPECIAL2_DAMAGE) for kidtype in kills: self.egStats.increment([Statistics.KILLS, Statistics.GAS, self.egStats.levelFlag(self.level), self.egStats.enemyFlag(kidtype)], kills[kidtype]) def hitKids(self, kidList, totalDamage): kills = {} for kid in kidList[:]: if totalDamage > 0: self.resourceManager.playSound('Kid_Crunch') if kid.health <= totalDamage: totalDamage -= kid.health kid.decHealth(kid.health) else: kid.decHealth(totalDamage) totalDamage = 0 if not kid.isAlive(): self.addDeadKid(kid) kidtype = kid.__class__.__name__ if kidtype in kills: kills[kidtype] += 1 else: kills.update([(kidtype, 1)]) kid.kill() self.resourceManager.playSound('Kid_Die') return kills def checkEat(self): if self.hero.isActionActive(Hero.EAT): eat = self.hero.createEatSprite() self.eatPowerUps(pygame.sprite.spritecollide(eat, self.getSpriteGroup(self.POWERUPS), False)) def eatPowerUps(self, puList): for powerUp in puList[:Hero.MAX_POWERUPS_EAT]: flags = [Statistics.EATEN, self.egStats.powerUpFlag(powerUp.currentAnimation - powerUp.facing), self.egStats.levelFlag(self.level)] if powerUp.isDrugs(): self.resourceManager.playSound(self.hero.HERO_NAME + '_Drugs') elif powerUp.isDeadKid(): self.resourceManager.playSound(self.hero.HERO_NAME + '_Eat') flags.append(Statistics.ENEMY) else: self.resourceManager.playSound(self.hero.HERO_NAME + '_Eat') flags.append(Statistics.POWERUP) for effect in powerUp.effects: self.hero.addEffect(effect) self.egStats.increment(flags) powerUp.kill() def checkPickUp(self): if self.hero.isActionActive(Hero.PICKUP): pickup = self.hero.createEatSprite() powerUps = pygame.sprite.spritecollide(pickup, self.getSpriteGroup(self.POWERUPS), False) for powerUp in powerUps[:Hero.MAX_POWERUPS_PICKUP]: self.hero.addItem(powerUp.currentAnimation-powerUp.facing) powerUp.kill() def checkKidAttack(self): kids = pygame.sprite.spritecollide(self.hero,self.getSpriteGroup(self.KIDS),False) for kid in kids: if kid.isActionActive(kid.ATTACK1): self.resourceManager.playSound('Kid_Bite') self.hero.decHealth(kid.ATTACK1_DAMAGE) def createFlame(self): if self.hero.isActionActive(self.hero.FLAME): self.addSpriteToGroup(self.FLAMES,self.hero.createFlameSprite()) self.resourceManager.playSound('Flame') def createGas(self): if self.hero.isActionActive(self.hero.GAS): self.addSpriteToGroup(self.GASES,self.hero.createGasSprite()) def checkParachutes(self): for kid in self.getSpriteGroup(self.PKIDS): if not kid.PARACHUTING: self.getSpriteGroup(self.PKIDS).remove(kid) self.addSpriteToGroup(self.KIDS,kid) def checkHoles(self): for hole in self.getSpriteGroup(self.HOLES): if hole.readyToPop and not hole.popped: hole.kid.setPosition((hole.rect.left+10, hole.rect.top-40)) self.addSpriteToGroup(self.KIDS, hole.kid) hole.popped = True def addDeadKid(self, kid): """Add a new DeadKid to the field basic on the killing of the given kid""" powerUpType = PowerUp.__dict__['DEAD_'+kid.__class__.__name__.upper()] if kid.facing == kid.LEFT: facing = PowerUp.LEFT else: facing = PowerUp.RIGHT newDeadKid = PowerUp(facing, powerUpType) newDeadKid.setPosition((kid.rect.left-10,kid.rect.top+20)) self.addSpriteToGroup(self.POWERUPS,newDeadKid) def checkKidThrowing(self): for kid in self.getSpriteGroup(self.KIDS): if kid.throwing: kid.throwing = False y = self.hero.rect.bottom - kid.rect.bottom x = self.hero.rect.left - kid.rect.left xdir = 5 ydir = 5 if x < 35 and x > -35: xdir = 0 if y < 35 and y > -35: ydir = 0 if x < 0: xdir = -xdir if y < 0: ydir = -ydir if not (x == 0 and y == 0): #don't throw if you are on top of him self.addSpriteToGroup(self.PROJECTILES, Projectile((kid.rect.left+5,kid.rect.top+10),(xdir,ydir))) def checkGroupers(self): for kid in self.getSpriteGroup(self.KIDS): if kid.GROUPER: gkids = pygame.sprite.spritecollide(kid,self.getSpriteGroup(self.KIDS),False) for gkid in gkids: if gkid.GROUPABLE: kid.addKid(gkid) def checkProjectileHit(self): projectileHitDict = pygame.sprite.groupcollide(self.getSpriteGroup(self.PROJECTILES), self.getSpriteGroup(self.HERO), False, False) for projectile in projectileHitDict: self.hero.decHealth(projectile.DAMAGE) projectile.kill() # SPAWN STUFFS def addSpawners(self): for enemy in Settings.ENEMIES: self.__dict__.update({'add'+enemy: self.createLambdaSpawner(self._addKid, Settings.ENEMIES[enemy][1])}) self.__dict__.update({'addPara'+enemy: self.createLambdaSpawner(self._addParaKid, Settings.ENEMIES[enemy][1])}) self.__dict__.update({'addHole'+enemy: self.createLambdaSpawner(self._addHole, Settings.ENEMIES[enemy][1])}) i = 0 for powerup in Settings.POWERUPS: self.__dict__.update({'add'+powerup: self.createLambdaSpawnerWithArg(self._addPowerUp, i)}) i += 1 def createLambdaSpawner(self, spawner, enemyConstructor): ecs = [enemyConstructor] return lambda: spawner(ecs[0]()) def createLambdaSpawnerWithArg(self, spawner, arg): args = [arg] return lambda: spawner(args[0]) def _addKid(self, newKid): newKid.setPosition(self.getRandomEdgeCoords()) self.addSpriteToGroup(self.KIDS,newKid) def _addParaKid(self, newKid): newKid.setPosition(self.getRandomParaCoords()) parachute = Parachute(newKid) newKid.attachGameObject(parachute) self.addSpriteToGroup(self.PKIDS,newKid) def getRandomParaCoords(self): x_min = 0 x_max = 800 y_min = -150 y_max = -120 x = random.randrange(x_min, x_max) y = random.randrange(y_min, y_max) return (x,y) def getRandomEdgeCoords(self): xy_min = 0 x_max = 800 y_max = 600 x = random.randrange(800) y = random.randrange(600) choices = [(x,xy_min), (x,y_max), (xy_min,y), (x_max,y)] (x,y) = random.choice(choices) return (x,y) def _addHole(self, newKid): hole = Hole(newKid) hole.setPosition(self.getRandomInternalCoords()) self.addSpriteToGroup(self.HOLES,hole) def getRandomInternalCoords(self): x = random.randrange(30,770) y = random.randrange(30,570) return (x,y) def _addPowerUp(self, powerUpType): newPowerUp = PowerUp(PowerUp.RIGHT, powerUpType) newPowerUp.setPosition(self.getRandomInternalCoords()) self.addSpriteToGroup(self.POWERUPS,newPowerUp) #this is a little bit HACKS def killEG(self, screen): deadEG = Settings.HEROS[self.hero_name][2]() if self.hero.facing == self.hero.LEFT: deadEG.setFacing(deadEG.LEFT) else: deadEG.setFacing(deadEG.RIGHT) deadEG.currentAnimation = deadEG.DEAD + deadEG.facing deadEG.setPosition((self.hero.rect.left, self.hero.rect.bottom - 60)) deadEG.update() self.getSpriteGroup(self.POWERUPS).draw(screen) self.getSpriteGroup(self.KIDS).draw(screen) self.getSpriteGroup(self.FLAMES).draw(screen) self.getSpriteGroup(self.GASES).draw(screen) screen.blit(deadEG.image, deadEG.rect) self.getSpriteGroup(self.PKIDS).draw(screen)