def cast(self, context): from level import expandingCircle cx, cy = cxcy = context.player.tile.x, context.player.tile.y movers = [] from math import atan2, sqrt radius = 8 perimeter = [] for region in expandingCircle( cxcy, size = radius ): fx = {} for x, y in region: fx[x,y] = dict( ch = ' ', fg = 'white', bg = 'blue' ) dx, dy = x-cx, y-cy try: tile = context.player.tile.level.tiles[x,y] if tile.mobile and tile.mobile.flying and tile.mobile not in movers: movers.append( tile.mobile ) perimeter.append( (atan2(dy, dx), sqrt(dx*dx+dy*dy), tile ) ) except KeyError: pass context.game.showEffects( fx ) movers.reverse() for mover in movers: mover.logVisual( "You are caught in the blast!", "%s is caught in the blast!" ) mx, my = mover.tile.x, mover.tile.y from level import sign dx, dy = sign(mx-cx), sign(my-cy) dirs = [ (dx,dy) ] if dx and dy: dirs.append( (dx,0) ) dirs.append( (0,dy) ) elif dx: dirs.append( (dx,1) ) dirs.append( (dx,-1) ) elif dy: dirs.append( (1,dy) ) dirs.append( (-1,dy) ) ma = atan2( my - cy, mx - cx ) actuallyMoved = 0 for i in range( radius ): bestAdist = 2**30 step = None for dx, dy in dirs: tile = mover.tile.getRelative(dx,dy) if not tile: continue if tile.cannotEnterBecause( mover ): continue ta = atan2( tile.y - cy, tile.x - cx ) adist = abs( ma - ta ) if adist < bestAdist: bestAdist = adist step = tile if not step: break mover.moveto( step, neverfail = True ) actuallyMoved += 1 if actuallyMoved: duration = random.randint( actuallyMoved * 20, actuallyMoved * 40 ) mover.addBuff( self, duration )
def trigger(self, mob): # the rook is entirely stationary unless it spots a clear # straight line to the player. If it does, moves 8 (radius) # tiles pl = mob.context.player if not playerAccessibleForMelee( mob ): return if pl.invisible: return dx, dy = sign(pl.tile.x - mob.tile.x), sign(pl.tile.y - mob.tile.y) if dx != 0 and dy != 0: return # not a straight line, stationary lastTile = None tile = mob.tile.getRelative( dx, dy ) dist = 0 while not tile.mobile == pl: if not tile: return if tile.cannotEnterBecause( mob ): return dist += 1 lastTile = tile tile = tile.getRelative( dx, dy ) tile = lastTile # target acquired! if dist >= self.radius: tile = mob.tile.getRelative( dx * self.radius, dy * self.radius ) doAttack = False else: tile = pl.tile.getRelative( -dx, -dy ) doAttack = True if not pl.canBeMeleeAttackedBy( mob ): doAttack = False aniTarget = pl.tile if doAttack else tile # show an animation, a ray from mob.tile to aniTarget raylen = max( abs(aniTarget.x - mob.tile.x), abs(aniTarget.y - mob.tile.y) ) mob.context.game.showStraightRay( (mob.tile.x, mob.tile.y), (dx,dy), raylen, 'white', 'black' ) if not tile.cannotEnterBecause( mob ): # notably, can't move to its own square mob.moveto( tile ) if doAttack: mob.meleeAttack( pl )
def trigger(self, mob): p = mob.context.player dx,dy = sign( p.tile.x - mob.tile.x ), sign( p.tile.y - mob.tile.y ) tile = mob.tile.getRelative( dx, dy ) if not tile: return # omgwtf if tile.mobile: if tile.mobile != p: self.frustration += 1 if self.frustration > 5: mob.logVisualMon( "%s touches " + tile.mobile.name.definiteSingular() + "." ) if not tile.mobile.essential: tile.mobile.logVisualMon( "%s fades out of existence." ) tile.mobile.kill( noTriggerHooks = True ) else: mob.logVisualMon( "%s stares at " + tile.mobile.name.definiteSingular() + " in surprise." ) mob.logVisualMon( "%s fades out of existence." ) mob.kill() elif playerAccessibleForMelee( mob ): mob.meleeAttack( p ) # for spectres, an instakill else: mob.logVisualMon( "%s floats slowly but steadily towards you." ) mob.moveto( tile ) self.frustration = 0