class MatterAbsorptionEffect(Effect): def __init__(self, duration, life_absorbed_percent, energy_absorbed_percent): Effect.__init__(self, duration) self.life_absorbed_percent = life_absorbed_percent self.energy_absorbed_percent = energy_absorbed_percent self.is_collidable = True self.unique_in_target = True self.collision_object = CollisionObject(getCollisionManager(), self) self.collision_object.InitializeCollisionClass("PowerUp") self.geometry = Circle(1.0) self.geometry.thisown = 0 self.collision_object.set_shape( self.geometry ) self.life_hud = None def OnSceneAdd(self, scene): self.radius = self.target.size.get_y() /2.0 self.size = Vector2D(self.radius*2, self.radius*2) texture_name = "images/shockwave.png" texture_obj = Engine_reference().resource_manager().texture_container().Load(texture_name, texture_name) self.shape = TexturedRectangle( texture_obj, self.size ) self.shape.set_hotspot(Drawable.CENTER) self.node.set_drawable(self.shape) color = self.node.modifier().color() color.set_a(0.5) self.node.modifier().set_color(color) self.target.invulnerable = True self.geometry = Circle(self.radius) self.collision_object.set_shape(self.geometry) self.collision_object.AddCollisionLogic("Entity", BasicColLogic(self) ) self.life_hud = BarUI(self, "lifetime", Color(0.85,0.0,0.85,1.0), -(self.radius+BAR_SIZE), True) self.hud_node.AddChild(self.life_hud.node) def Apply(self, dt): self.SetPos( self.target.GetPos() ) self.target.invulnerable = True if self.life_hud != None: self.life_hud.Update() def HandleCollision(self, coltarget): if hasattr(coltarget, "GetGroup") and coltarget.GetGroup() != self.target.GetGroup() and coltarget.GetGroup() != Group.NEUTRAL: if coltarget.CheckType("Asteroid"): self.target.Heal(coltarget.life * self.life_absorbed_percent) elif coltarget.CheckType("Projectile"): self.target.RestoreEnergy(coltarget.GetDamage(self.target.type) * self.energy_absorbed_percent) coltarget.TakeDamage(coltarget.life + 10) def GetDetailString(self): return "Absorbing Matter" def Delete(self): Effect.Delete(self) if self.target != None: self.target.invulnerable = False
class BasicEntity (EntityInterface): nextID = 1 def __init__(self, x, y, texture_name, radius, life, WtoHratio=1.0): EntityInterface.__init__(self, x, y, radius) self.size = Vector2D(self.radius*2, self.radius*2*WtoHratio) texture_obj = Engine_reference().resource_manager().texture_container().Load(texture_name, texture_name) self.shape = TexturedRectangle( texture_obj, self.size ) self.shape.set_hotspot(Drawable.CENTER) self.node.set_drawable(self.shape) #self.text = Engine_reference().text_manager().GetText( "#"+str(self.id) ) #self.text.set_hotspot(Drawable.CENTER) #self.textNode = Node(self.text) #self.textNode.modifier().set_offset( Vector2D(0.0, -self.radius ) ) #self.hud_node.AddChild(self.textNode) self.velocity = Vector2D(0.0, 0.0) self.max_velocity = 5000.0 #length of the maximum velocity - the entity can't achieve a velocity with length greater than this by whatever means self.last_velocity = None self.last_dt = 0.000001 self.life = life self.max_life = life self.hit_sounds = ["hit1.wav", "hit2.wav", "hit3.wav", "hit4.wav"] self.life_hud = BarUI(self, "life", Color(1.0,0.0,0.0,1.0), self.radius) self.hud_node.AddChild(self.life_hud.node) self.active_effects = {} self.group = Group.UNDETERMINED self.wraps_around_boundary = True self.invulnerable = False self.setupCollisionGeometry() self.setupCollisionObject() def setupCollisionGeometry(self): self.geometry = Circle(self.radius) def setupCollisionObject(self): self.collision_object = CollisionObject(getCollisionManager(), self) #initialize collision object, second arg is passed to collisionlogic to handle collisions self.collision_object.InitializeCollisionClass("Entity") # define the collision class self.collision_object.set_shape(self.geometry) # set our shape #finally add collision logics to whatever collision class we want self.collision_object.AddCollisionLogic("Entity", BasicColLogic(self) ) self.collision_object.thisown = 0 def ApplyEffect(self, effect): #since effects are entities too, we just do this AddNewObjectToScene(effect) if self.active_effects.has_key(effect.type): if effect.unique_in_target: for e in self.active_effects[effect.type]: e.Delete() self.active_effects[effect.type].append(effect) else: self.active_effects[effect.type] = [effect] def GetActiveEffectsDetailsList(self): aedl = [] for effectType, effects in self.active_effects.items(): countStr = "" count = len(effects) if count <= 0: continue if count > 1: countStr = "%sx " % count if effects[0].GetDetailString() != "": aedl.append( countStr+effects[0].GetDetailString() ) return aedl def GetActiveEffectsList(self): el = [] for effectType, effects in self.active_effects.items(): el = el + effects return el def CleanUpActiveEffects(self): for effectType, effects in self.active_effects.items(): for e in effects: if e.is_destroyed: self.active_effects[effectType].remove(e) def GetGroup(self): if self.group == Group.UNDETERMINED: if hasattr(self, "parent"): return self.parent.GetGroup() return Group.NEUTRAL return self.group def Update(self, dt): ### self.UpdatePosition(dt) self.CleanUpActiveEffects() self.life_hud.Update() if self.velocity.Length() > self.max_velocity: self.velocity = self.velocity * (self.max_velocity / self.velocity.Length()) def UpdatePosition(self, dt): pos = self.GetPos() pos = pos + (self.velocity * dt) self.last_velocity = self.velocity self.last_dt = dt if self.HandleMapBoundaries(pos) and not self.wraps_around_boundary: self.Delete() self.SetPos(pos) def GetDirection(self): if self.velocity.Length() == 0.0: return Vector2D(0.0, 1.0) return self.velocity.Normalize() def GetDamage(self, obj_type): # returns the amount of damage this object causes on collision with given obj_type print self.type, " GetDamage NOT IMPLEMENTED" def TakeDamage(self, damage): if damage < 0: return if self.invulnerable: return self.life -= damage if damage > 0: sound_name = self.hit_sounds[ randint(0, len(self.hit_sounds)-1) ] sound = Engine_reference().audio_manager().LoadSample(SOUND_PATH + sound_name) sound.Play() if self.life <= 0: self.Delete() #print self, "took %s damage, current life = %s [max life =%s]" % (damage, self.life, self.max_life) def Heal(self, amount): if amount < 0: return self.life += amount if self.life > self.max_life: self.life = self.max_life #print self, "has recovered %s life, current life = %s" % (amount, self.life) def ApplyVelocity(self, v): self.velocity = self.velocity + v def ApplyCollisionRollback(self): if self.is_destroyed: return pos = self.GetPos() v = self.last_velocity if not v: v = self.velocity pos = pos + (v * -self.last_dt) self.HandleMapBoundaries(pos) pos = pos + (self.velocity * self.last_dt) self.HandleMapBoundaries(pos) self.SetPos(pos) self.last_velocity = self.velocity
class ShieldEffect(Effect): def __init__(self, life): Effect.__init__(self, 10) self.max_life = life self.life = life self.is_collidable = True self.unique_in_target = True self.collision_object = CollisionObject(getCollisionManager(), self) self.collision_object.InitializeCollisionClass("PowerUp") self.geometry = Circle(1.0) self.geometry.thisown = 0 self.collision_object.set_shape( self.geometry ) self.life_hud = None def GetAttrDict(self): d = Effect.GetAttrDict(self) d["life"] = self.life d["max_life"] = self.max_life return d def OnSceneAdd(self, scene): self.radius = self.target.size.get_y()/2.0 self.size = Vector2D(self.radius*2, self.radius*2) texture_name = "images/shockwave.png" texture_obj = Engine_reference().resource_manager().texture_container().Load(texture_name, texture_name) self.shape = TexturedRectangle( texture_obj, self.size ) self.shape.set_hotspot(Drawable.CENTER) self.node.set_drawable(self.shape) color = self.node.modifier().color() color.set_a(0.5) self.node.modifier().set_color(color) self.target.invulnerable = True self.geometry = Circle(self.radius) self.collision_object.set_shape(self.geometry) self.collision_object.AddCollisionLogic("Entity", BasicColLogic(self) ) self.max_life += self.target.data.GetBonusLife() self.life += self.target.data.GetBonusLife() self.life_hud = BarUI(self, "life", Color(0.85,0.85,0.85,1.0), self.radius, True) self.hud_node.AddChild(self.life_hud.node) def Apply(self, dt): self.SetPos( self.target.GetPos() ) if self.life > 0 and not self.target.is_destroyed: self.lifetime = 10.0 self.target.invulnerable = True if self.life_hud != None: self.life_hud.Update() else: self.lifetime = 0.0 self.target.invulnerable = False def HandleCollision(self, coltarget): if coltarget.CheckType("Asteroid") or (coltarget.CheckType("Projectile") and coltarget.GetGroup() != self.target.GetGroup() ): self.life -= coltarget.GetDamage(self.target.type) coltarget.TakeDamage(coltarget.life + 10) #print "SHIELD COLLISION %s/%s" % (self.life, self.max_life) def GetDetailString(self): return "Shields On" def Delete(self): Effect.Delete(self) if self.target != None: self.target.invulnerable = False
class Shockwave (GravityWell): def __init__(self, x, y, lifetime, radius_range): self.max_lifetime = lifetime self.lifetime = 0.0 self.radius_range = radius_range GravityWell.__init__(self, x, y, radius_range[0]) self.radius = radius_range[0] self.geometry.set_radius(self.radius) self.is_antigrav = True self.size = Vector2D(self.radius*2, self.radius*2) texture_obj = Engine_reference().resource_manager().texture_container().Load("images/shockwave.png", "images/shockwave.png") self.shape = TexturedRectangle( texture_obj, self.size ) self.shape.set_hotspot(Drawable.CENTER) self.node.set_drawable(self.shape) color = self.node.modifier().color() color.set_a(0.5) self.node.modifier().set_color(color) self.scale_range = [1.0, radius_range[1]/radius_range[0]] self.affected_targets = [] self.shock_damage = 30.0 # done once when shockwave hits a target self.wave_damage = 6.0 # done continously while shockwave pushes a target self.shock_force_factor = 1.0 # multiplier factor to the shock force, which is the force that pushes/pulls entities from the wave def SetRadius(self, r): self.radius = r self.geometry.set_radius(r) self.mass = GetMassByRadius(r) scale = GetEquivalentValueInRange(r, self.radius_range, self.scale_range) self.node.modifier().set_scale( Vector2D(scale, scale) ) def Update(self, dt): GravityWell.Update(self, dt) self.lifetime += dt r = GetEquivalentValueInRange(self.lifetime, [0, self.max_lifetime], self.radius_range) self.SetRadius(r) self.collision_object.MoveTo(self.GetPos()) # to refresh to collision object if self.lifetime > self.max_lifetime: #gotta destroy this thing self.Delete() #print self, "is ending..." def HandleCollision(self, target): ignore_types = ["GravityWell", "Planet", "Shockwave", "Satellite"] if target.type in ignore_types or target.id in self.ignore_ids: return #print self, "is affecting", target v = self.GetPos() - target.GetPos() dist = v.Length() v = v.Normalize() if self.is_antigrav: v = v * -1 ####### ## shockwave now seems to push more like we wanted ## however its still not perfect, try to follow a straight ## line, do a wave, go around the map and shoot in the wave ## it should stop the projectiles, but they just go through ####### if target.id in self.affected_targets: # continuously affecting target... wave_speed = ( self.radius_range[1] - self.radius_range[0] ) / self.max_lifetime target.TakeDamage(self.wave_damage *self.delta_t) v = v * (wave_speed*self.delta_t) return else: # hitting target for the first time target.TakeDamage(self.shock_damage) self.affected_targets.append(target.id) current_r_range = [self.radius, self.radius_range[0]] current_shockforce_range = [GetGravForce(self.mass, r) for r in current_r_range] current_r_range.reverse() ShockForce = GetEquivalentValueInRange(dist, current_r_range, current_shockforce_range ) v_transpost = Vector2D( -v.get_y(), -v.get_x()) m = v_transpost * target.velocity target_velocity = target.velocity - (v_transpost*m) target.velocity = target_velocity wave_speed = ( self.radius_range[1] - self.radius_range[0] ) / self.max_lifetime v = v * (wave_speed/1.02) if target.CheckType("Projectile") and target.is_destroyed: target.CallOnHitEvents(self) v = v * self.shock_force_factor target.ApplyVelocity(v)