def special_fire(self, at): towards = helper.try_normalize(at.pos - self.pos) if self.get_stat("ship_take_damage_on_fire"): self.health -= self.get_stat("ship_take_damage_on_fire") b = Bullet(self.pos, at, self, mods=self.prepare_bullet_mods()) self.scene.game_group.add(b) sound.play(random.choice(['laser1', 'laser2', 'laser3'])) #self.velocity += -towards * 2 self.pos += -towards * 1 self.thrust_particle_time = THRUST_PARTICLE_RATE for i in range(10): pvel = helper.try_normalize(towards + V2(random.random() * 0.75, random.random() * 0.75) ) * 30 * (random.random() + 0.25) p = Particle([ PICO_WHITE, PICO_WHITE, PICO_BLUE, PICO_DARKBLUE, PICO_DARKBLUE ], 1, self.pos, 0.2 + random.random() * 0.15, pvel) self.scene.add_particle(p) self.bullets_chambered -= 1
def fire(self, at): towards = helper.try_normalize(at.pos - self.pos) if self.get_stat("ship_take_damage_on_fire"): self.health -= self.get_stat("ship_take_damage_on_fire") b = Bullet(V2(self.pos), at, self, mods=self.prepare_bullet_mods()) self.scene.game_group.add(b) #self.velocity += -towards * 2 self.pos += -towards * 1.25 self.thrust_particle_time = THRUST_PARTICLE_RATE sound.play(random.choice(['laser1', 'laser2', 'laser3'])) for i in range(10): pvel = helper.try_normalize(towards + V2( (random.random() - 0.5) * 1.5, (random.random() - 0.5) * 1.5)) * 30 * (random.random() + 0.25) p = Particle([ PICO_WHITE, PICO_WHITE, PICO_BLUE, PICO_DARKBLUE, PICO_DARKBLUE ], 1, V2(self.pos), 0.2 + random.random() * 0.15, pvel) self.scene.add_particle(p) self.need_attack_speed_particle = True self.attack_speed_particle_angle = towards.as_polar( )[1] * 3.14159 / 180 self.stealth = False
def state_siege(self, dt): if self.wants_to_dogfight() and not self.cinematic_no_combat: threats = self.get_threats() if threats: self.set_state(STATE_DOGFIGHT) return if not self.effective_target or self.effective_target.health <= 0 or self.effective_target.owning_civ == self.owning_civ: # If we just killed a planet, stay in waiting. if self.effective_target and isinstance(self.effective_target, planet.planet.Planet): self.set_state(STATE_WAITING) else: print("returning from siege") self.set_state(STATE_RETURNING) return tp = self.effective_target.pos + helper.try_normalize( self.pos - self.effective_target.pos) * self.effective_target.radius delta = tp - self.pos dsq_from_target = delta.length_squared( ) - self.effective_target.radius**2 def in_range(): return dsq_from_target <= self.get_weapon_range()**2 # Time to fire and in range? if self.fire_timer >= 1: if in_range(): self.fire_timer = 0 self.fire(self.effective_target) if random.random() < 0.33: self.combat_dodge_direction = random.randint(-1, 1) dir = V2(0, 0) if not in_range(): dir = helper.try_normalize(delta) self.target_heading = None elif self.fire_timer > 0.95: dir = helper.try_normalize(delta) self.target_heading = dir.as_polar()[1] * 3.14159 / 180 elif dsq_from_target < (self.get_weapon_range() * 0.66)**2: dir = -helper.try_normalize(delta) self.target_heading = None else: _, a = (-delta).as_polar() a *= 3.14159 / 180 a += self.combat_dodge_direction * 3.14159 / 2 dir = helper.from_angle(a) if self.combat_dodge_direction == 0: dir = V2(0, 0) self.target_heading = None self.target_velocity = dir * self.get_cruise_speed()
def state_dogfight(self, dt): def invalid_target(): return (not self.effective_target or not self.effective_target.is_alive() or (self.effective_target.pos - self.pos).length_squared() > self.THREAT_RANGE_DEFENSE**2 or self.effective_target.owning_civ == self.owning_civ) # If our target is dead or w/e, find a new one if invalid_target(): self.find_target() if invalid_target( ): # Still no target? Go back to whatever we were doing. self.set_state(self.post_dogfight_state) return # If we're defending a planet... if self.defending: # And our dogfight target is too far... if (self.effective_target.pos - self.defending.pos ).length_squared() > self.STOP_CHASING_RANGE**2: self.set_state("returning") # Fire if reloaded (and close enough) if self.fire_timer > 1: if (self.effective_target.pos - self.pos).length_squared() < self.get_weapon_range()**2: self.fire_timer = 0 self.fire(self.effective_target) self.target_heading = None # Need to get close to the enemy delta = self.effective_target.pos - self.pos if delta.length_squared() > self.get_weapon_range()**2: # Too far dir = helper.try_normalize(delta) elif delta.length_squared() < (self.get_weapon_range() / 2)**2: # Too close dir = -helper.try_normalize(delta) elif self.fire_timer > 0.65: # If we're close and about to fire dir = helper.try_normalize(delta) self.target_heading = dir.as_polar()[1] * 3.14159 / 180 else: _, a = (-delta).as_polar() a *= 3.14159 / 180 a += self.combat_dodge_direction * 3.14159 / 2 dir = helper.from_angle(a) self.target_velocity = dir * self.get_max_speed()
def emit_thrust_particles(self): pvel = V2(random.random() - 0.5, random.random() - 0.5) * 1 pvel += -self.velocity / 2 vn = helper.try_normalize(self.velocity) side = V2(vn.y, -vn.x) # Sideways vector from forward p1 = particle.Particle( [PICO_WHITE, PICO_WHITE, PICO_YELLOW], 1, self.pos + -helper.try_normalize(self.velocity) * self.radius + side * 1.5, 1, pvel) self.scene.add_particle(p1) p2 = particle.Particle( [PICO_WHITE, PICO_WHITE, PICO_YELLOW], 1, self.pos + -helper.try_normalize(self.velocity) * self.radius - side * 1.5, 1, pvel) self.scene.add_particle(p2)
def update(self, dt): if self.tethered: delta = self.tethered.pos - self.tether_end_pos if delta.length_squared() > 2**2: self.tether_end_pos += helper.try_normalize(delta) * dt * 15 else: self.tether_end_pos = self.tethered.pos self.tether_time += dt if self.tether_time > self.get_max_tether_time() / 2: self.tether_line.color = PICO_YELLOW self.tether_line.pt1 = self.pos self.tether_line.pt2 = self.tether_end_pos self.tether_line._generate_image() self.tether_line.pos = self.pos if self.tether_time > self.get_max_tether_time(): self.tethered.change_owner(self.owning_civ) self.tethered.set_state("returning") if self.tethered.owning_civ == self.owning_civ: self.tethered.tether_target = False self.tether_line.kill() self.tether_time = 0 self.tethered = None if self.tethered and not self.tethered.is_alive(): self.tether_line.kill() self.tether_time = 0 self.tethered = None return super().update(dt)
def _generate_image(self): delta = self.pos2 - self.pos1 w = abs(int(delta.x)) + 32 h = abs(int(delta.y)) + 32 self.image = pygame.Surface((w, h), pygame.SRCALPHA) direction = helper.try_normalize(delta) center = V2(w / 2, h / 2) distance = delta.length() steps = int((distance - 40) / 8) time_offset = (self.time * 1) % 1 extra = 2 if self.current else 1 color = PICO_ORANGE if self.travelled: color = PICO_GREEN if self.current: color = PICO_WHITE pygame.draw.line(self.image, color, (center - direction * (distance - 28) / 2), (center + direction * (distance - 28) / 2), 2) self._width = w self._height = h self._recalc_rect()
def apply(self, ship, planet): if ship.SHIP_BONUS_NAME == "fighter" and ( ship.chosen_target != planet or ship.effective_target != planet): ship.chosen_target = planet ship.effective_target = planet # Decoy sound effect delta = ship.pos - planet.pos dn = helper.try_normalize(delta) dist, ang = delta.as_polar() ang *= 3.14159 / 180 t = 0 p1 = planet.pos steps = 8 for i in range(steps): t += 0.25 if i == steps - 1: p2 = ship.pos else: p2 = p1 + helper.from_angle(ang + ((i % 2) - 0.5)) * dist / steps l = laserparticle.LaserParticle(p1, p2, PICO_BLUE, 0.25 + i / 8) planet.scene.add_particle(l) p1 = V2(p2) return super().apply(ship, planet)
def special_stat_update(self, dt): # Regenerate self.health += self.get_stat("ship_regenerate") * dt self.bonus_attack_speed_time -= dt speed_factor = self.get_max_speed() / self.MAX_SPEED if speed_factor > 1: if self._timers['bonus_speed_particle_time'] > 0.15 / speed_factor: #e = explosion.Explosion(self.pos + helper.random_angle(), [PICO_BLUE, PICO_BLUE, PICO_BLUE, PICO_WHITE, PICO_WHITE, PICO_BLUE], 0.25, 3, line_width=1) colors = [ PICO_WHITE, PICO_BLUE, PICO_GREEN, PICO_PINK, PICO_PURPLE ] n = int((speed_factor - 1) * 3) + 1 colors = colors[0:n] #ang = self.velocity.as_polar()[1] + 3.14159 + (random.random() - 0.5) * 3 ang = (self.velocity.as_polar()[1] * 3.14159 / 180 ) + 3.14159 + (random.random() - 0.5) * 0.45 + math.sin( self.time * 3 * speed_factor) if self.velocity.length_squared() == 0: veln = V2(0, 0) else: veln = helper.try_normalize(self.velocity) p = particle.Particle([random.choice(colors)], 1, self.pos + -veln * self.radius, 0.6, helper.from_angle(ang) * 8) self.scene.add_particle(p) self._timers['bonus_speed_particle_time'] = 0
def _generate_image(self): self.image = pygame.Surface(tuple(game.Game.inst.game_resolution), pygame.SRCALPHA) pygame.draw.circle(self.image, self.color, self.cursor_pos, 7, 1) pygame.draw.circle(self.image, PICO_WHITE, self.cursor_pos, 2, 0) if self.nearest_obj: center = self.nearest_obj.get_center() rect = (center.x - self.nearest_obj.radius - 4, center.y - self.nearest_obj.radius - 4, self.nearest_obj.radius * 2 + 8, self.nearest_obj.radius * 2 + 8) delta = (self.cursor_pos - center) dist, ang = V2(delta.x, -delta.y).as_polar() ang *= 3.14159 / 180 pygame.draw.arc(self.image, self.color, rect, ang - 1, ang + 1) if dist > 15: dn = helper.try_normalize(delta) p1 = self.cursor_pos - dn * 7 p2 = self.nearest_obj.get_center() + dn * ( self.nearest_obj.radius + 4) pygame.draw.line(self.image, self.color, p1, p2, 1) self._width, self._height = self.image.get_size()
def brake(self, dt): if self.velocity.length_squared() > 0: brake = -helper.try_normalize(self.velocity) * BRAKE * dt if self.velocity.length_squared() > brake.length_squared(): self.velocity += brake else: self.velocity = V2(0, 0)
def _generate_image(self): thickness = 6 ht = thickness / 2 color = self.color delta = self.pt2 - self.pt1 pt1 = V2(self.pt1) pt2 = V2(self.pt2) w, h = tuple(game.Game.inst.game_resolution) forward = helper.try_normalize(delta) side = V2(forward.y, -forward.x) points = [] points.append(pt1 + side * -ht) points.append(pt1 + side * ht) points.append(pt2 + side * ht + forward * -15) points.append(pt2 + side * 15 + forward * -15) points.append(pt2) points.append(pt2 + side * -15 + forward * -15) points.append(pt2 + side * -ht + forward * -15) points = [tuple(p) for p in points] self.image = pygame.Surface((w, h), pygame.SRCALPHA) pygame.draw.polygon(self.image, color, points, 0) self._width = w self._height = h self.pos = V2(0, 0) self._recalc_rect()
def bullet_hits(self, bullet): delta = helper.try_normalize(bullet.pos - self.pos) d, a = delta.as_polar() a *= 3.14159 / 180 print(a, self.sat.angle) if abs(helper.get_angle_delta(a, self.sat.angle)) < math.pi / 2: return True return False
def emit_thrust_particles(self): pvel = V2(random.random() - 0.5, random.random() - 0.5) * 5 pvel += -self.velocity / 2 p = particle.Particle( [PICO_WHITE, PICO_BLUE], 1, self.pos + -helper.try_normalize(self.velocity) * self.radius, 2, pvel) self.scene.add_particle(p)
def update_lines(self): delta = (self.tethered_to.pos - self.pos) nd = helper.try_normalize(delta) self.line2.visible = False self.line1.pt1 = self.pos + nd * 4 self.line1.pt2 = self.tethered_to.pos + -nd * (self.tethered_to.radius) self.line1.pos = self.line1.pt1 self.line1._generate_image()
def emit_thrust_particles(self): pvel = V2(random.random() - 0.5, random.random() - 0.5) * 5 pvel += -self.velocity / 2 p = particle.Particle( "assets/thrustparticle.png", 1, self.pos + -helper.try_normalize(self.velocity) * self.radius, 1, pvel) self.scene.add_particle(p)
def collide(self, other): if other.stationary: delta = other.pos - self.pos dist = delta.length() if dist > 0: overlap = (self.collision_radius + other.collision_radius) - dist push = helper.try_normalize(delta) * -overlap self.pos += push
def state_cruising(self, dt): if not self.chosen_target.is_alive(): self.set_state(STATE_RETURNING) return delta = self.effective_target.pos - self.pos use_path = True if not self.scene.flowfield.has_field( self.effective_target ) or delta.length_squared() < NO_PATH_RANGE**2: use_path = False if use_path: towards_flow = self.scene.flowfield.get_vector( self.pos, self.effective_target, 0) towards_center = towards_flow distance = 1 if self.fleet and len(self.fleet.path) > 2 and len( self.fleet.ships) > 1: distance = (self.fleet.path[2] - self.pos).length() towards_center = helper.try_normalize(self.fleet.path[2] - self.pos) ratio = 0.5 ratio = helper.clamp(20 / (distance + 1), 0, 1) self.debug_ratio = ratio self.target_velocity = (towards_flow * ratio + towards_center * (1 - ratio)) * self.get_cruise_speed() else: self.target_velocity = helper.try_normalize( delta) * self.get_cruise_speed() # Warp if self.get_stat("warp_drive"): if self._timers['warp_drive'] > 0: WARP_MIN_PLANET_DIST = 40 _, distsq = helper.get_nearest( self.pos, self.scene.get_planets_in_range(self.pos, WARP_MIN_PLANET_DIST)) if distsq > WARP_MIN_PLANET_DIST**2: self.warp(self.get_stat("warp_drive") * 10 + 20) self._timers['warp_drive'] = -20
def special_fire(self, at): towards = helper.try_normalize(at.pos - self.pos) b = Bullet(at.pos, at, self, mods=self.prepare_bullet_mods()) self.scene.game_group.add(b) l = laserparticle.LaserParticle(self.pos, at.pos, self.owning_civ.color, 0.2) self.scene.add_particle(l) self.bullets_chambered -= 1
def special_fire(self, at): towards = helper.try_normalize(at.pos - self.pos) fwd = helper.try_normalize(self.velocity) side = V2(fwd.y, -fwd.x) coef = (self.bullets_chambered % 2) * 2 - 1 b = Bullet(self.pos + side * coef * 2, at, self, mods=self.prepare_bullet_mods()) self.scene.game_group.add(b) sound.play(random.choice(['laser1', 'laser2', 'laser3'])) self.pos += -towards * 1 for i in range(7): pvel = helper.try_normalize(towards + V2(random.random() * 0.75, random.random() * 0.75)) * 30 * (random.random() + 0.25) p = Particle([PICO_WHITE, PICO_YELLOW, PICO_RED, PICO_PURPLE], 1, self.pos, 0.2 + random.random() * 0.15, pvel) self.scene.add_particle(p) self.bullets_chambered -= 1
def wander(self, dt): self.wander_time -= dt if self.wander_time < 0: self.wander_time = 5 self.wander_point = self.wander_center + helper.random_angle( ) * random.random() * 30 delta = self.wander_point - self.pos if delta.length_squared() < 10**2 or self.wander_time < 1: self.brake(dt) else: self.velocity += helper.try_normalize(delta) * ACCEL * dt
def set_target(self, target): super().set_target(target) if (target.pos - self.pos).length_squared() > 100 ** 2: self.is_warping = True delta = target.pos - self.pos dn = helper.try_normalize(delta) p = target.pos - dn * (target.radius + 15) self.warp_target = WarpWarning(self.scene, p, self) self.scene.game_group.add(self.warp_target) self.warp_line = WarpLine(self, self.warp_target) self.scene.game_group.add(self.warp_line)
def __init__(self, start, end, color): super().__init__(start, end, color) self.next_line = None self.time = -999999999 self.pt_start = V2(self.pt1) self.pt_final = V2(self.pt2) self.delta = helper.try_normalize(self.pt2 - self.pt1) self.len = (self.pt2 - self.pt1).length() self.pt2 = V2(self.pt1) self.visible = False self._generate_image()
def get_vector(self, pos, radius): out = V2(0,0) pos = pos - self.offset cx = int(clamp((pos.x) / GRIDSIZE, 0, self.gw-1)) cy = int(clamp((pos.y) / GRIDSIZE, 0, self.gh-1)) x1 = int(clamp((pos.x - radius) / GRIDSIZE, 0, self.gw-1)) x2 = int(clamp((pos.x + radius) / GRIDSIZE, 0, self.gw-1)) y1 = int(clamp((pos.y - radius) / GRIDSIZE, 0, self.gh-1)) y2 = int(clamp((pos.y + radius) / GRIDSIZE, 0, self.gh-1)) half = x2 - cx coefficient = 1 for x in range(x1, x2 + 1): for y in range(y1, y2 + 1): v = self.grid[y][x] if v: if half > 0: coefficient = 1 / max(((cx - x)) ** 2 + ((cy - y)) ** 2, 1) out += helper.try_normalize(v) * coefficient return helper.try_normalize(out)
def fire(self, at): if self.get_stat("battleship_laser"): self.fire_laser(at) return towards = helper.try_normalize(at.pos - self.pos) if self.get_stat("ship_take_damage_on_fire"): self.health -= self.get_stat("ship_take_damage_on_fire") b = Bullet(self.pos, at, self, mods=self.prepare_bullet_mods()) self.scene.game_group.add(b) for i in range(10): pvel = helper.try_normalize(towards + V2(random.random() * 0.75, random.random() * 0.75) ) * 30 * (random.random() + 0.25) p = Particle([ PICO_WHITE, PICO_WHITE, PICO_BLUE, PICO_DARKBLUE, PICO_DARKBLUE ], 1, self.pos, 0.2 + random.random() * 0.15, pvel) self.scene.add_particle(p)
def emit_thrust_particles(self): for i in range(2): pvel = V2(random.random() - 0.5, random.random() - 0.5) * 5 pvel += -self.velocity / 2 p = particle.Particle( [ PICO_YELLOW, PICO_RED, PICO_LIGHTGRAY, PICO_DARKGRAY, PICO_DARKGRAY ], 1, self.pos + -helper.try_normalize(self.velocity) * self.radius, 1, pvel) self.scene.add_particle(p)
def fire_bomb(self, at): towards = helper.try_normalize(at.pos - self.pos) self.last_shot_at = at if self.get_stat("ship_take_damage_on_fire"): self.health -= self.get_stat("ship_take_damage_on_fire") b = Bullet(self.pos, at, self, mods=self.prepare_bomb_mods()) self.scene.game_group.add(b) #self.velocity += -towards * 2 self.pos += -towards * 2 self.thrust_particle_time = THRUST_PARTICLE_RATE for i in range(10): pvel = helper.try_normalize(towards + pygame.math.Vector2( random.random() * 0.75, random.random() * 0.75)) * 30 * (random.random() + 0.25) p = Particle([ PICO_WHITE, PICO_WHITE, PICO_BLUE, PICO_DARKBLUE, PICO_DARKBLUE ], 1, self.pos, 0.2 + random.random() * 0.15, pvel) self.scene.game_group.add(p)
def collide(self, other): if self.can_land(other) and self.wants_to_land(): self.kill() other.add_ship(self.SHIP_NAME, notify=False) other.needs_panel_update = True else: if isinstance(other, bullet.Bullet): return if isinstance(other, ReflectorShieldObj) or isinstance( other, planet.building.ReflectorShieldCircleObj): return if not other.solid: return delta = helper.try_normalize(other.pos - self.pos) self.pos += -delta
def fire(self, at): if self.get_stat("ship_take_damage_on_fire"): self.health -= self.get_stat("ship_take_damage_on_fire") for j in range(3): towards = helper.try_normalize(self.effective_target.pos - self.pos) b = Bullet(self.pos, self.effective_target, self, vel=helper.random_angle() * 10, mods=self.prepare_bullet_mods()) self.scene.game_group.add(b) for i in range(3): pvel = helper.try_normalize(towards + V2(random.random() * 0.75, random.random() * 0.75)) * 30 * (random.random() + 0.25) p = Particle([PICO_WHITE, PICO_WHITE, PICO_BLUE, PICO_DARKBLUE, PICO_DARKBLUE], 1, self.pos, 0.2 + random.random() * 0.15, pvel) self.scene.add_particle(p) enemies = self.scene.get_enemy_objects(self.owning_civ) threat_range = self.THREAT_RANGE_DEFAULT if self.chosen_target.owning_civ == self.owning_civ: # Target is our own planet (defense) threat_range = self.THREAT_RANGE_DEFENSE threats = [ e for e in enemies if ((e.pos - self.pos).length_squared() < threat_range ** 2 and e.is_alive()) ] if threats: self.effective_target = random.choice(threats)
def develop_path(self, num_steps): if not self.target: return for i in range(num_steps): if (self.path[-1] - self.target.pos).length_squared() < (PATH_STEP_SIZE * 2) ** 2: self.path_done = True self.last_valid_path = self.path[::] return if self.scene.flowfield.has_field(self.target): step = PATH_STEP_SIZE * (random.random() + 0.5) new_pt = self.scene.flowfield.walk_field(self.path[-1], self.target, step) else: delta = self.target.pos - self.pos new_pt = self.path[-1] + helper.try_normalize(delta) * PATH_STEP_SIZE self.path.append(new_pt)