def summon_ally(name, duration, x=None, y=None): adj = main.adjacent_tiles_diagonal(player.instance.x, player.instance.y) # Get viable summoning position. Return failure if no position is available if x is None or y is None: summon_positions = [] for tile in adj: if not main.is_blocked(tile[0], tile[1]): summon_positions.append(tile) if len(summon_positions) == 0: ui.message('There is no room to summon an ally here.') return summon_pos = summon_positions[libtcod.random_get_int( 0, 0, len(summon_positions) - 1)] else: summon_pos = (x, y) # Select monster type - default to goblin import monsters if name in monsters.proto.keys(): summon = main.spawn_monster(name, summon_pos[0], summon_pos[1], team='ally') if summon is not None: if summon.behavior is not None: summon.behavior.follow_target = player.instance # Set summon duration summon.summon_time = duration + libtcod.random_get_int( 0, 0, duration) return 'success' else: return 'didnt-take-turn'
def disarm(target): if target is None or target.fighter is None: return 'failure' weapon = main.get_equipped_in_slot(target.fighter.inventory, 'right hand') if weapon is None: return 'failure' weapon.dequip(no_message=True) possible_tiles = [] for x in range(target.x - 1, target.x + 2): for y in range(target.y - 1, target.y + 2): if not main.is_blocked( x, y, from_coord=(target.x, target.y), movement_type=1): possible_tiles.append((x, y)) if len(possible_tiles) == 0: selected_tile = main.find_closest_open_tile(target.x, target.y) else: selected_tile = possible_tiles[libtcod.random_get_int( 0, 0, len(possible_tiles) - 1)] weapon.owner.item.drop(no_message=True) weapon.owner.x = selected_tile[0] weapon.owner.y = selected_tile[1] ui.message( '%s %s disarmed!' % (syntax.name(target).capitalize(), syntax.conjugate(target is player.instance, ('are', 'is'))), libtcod.red) return 'success'
def spawn_vermin(actor, target, context): #Filthy hackery to add some state if not hasattr(actor, 'summons'): actor.summons = [] for s in actor.summons: # clear dead things from summoned list if not s.fighter: actor.summons.remove(s) if len(actor.summons) < context['max_summons']: summon_choice = main.random_choice_index( [e['weight'] for e in context['summons']]) summon_tiles = [] for y in range(5): for x in range(5): pos = actor.x - 2 + x, actor.y - 2 + y if main.in_bounds(pos[0], pos[1]) and not main.is_blocked( pos[0], pos[1]): summon_tiles.append(pos) for i in range(context['summons'][summon_choice]['count']): if len(summon_tiles) > 0: pos = summon_tiles[libtcod.random_get_int( 0, 0, len(summon_tiles) - 1)] spawn = main.spawn_monster( context['summons'][summon_choice]['monster'], pos[0], pos[1]) ui.message( 'A ' + spawn.name + " crawls from beneath the verman's cloak.", actor.color) spawn.fighter.loot_table = None actor.summons.append(spawn) summon_tiles.remove(pos)
def spawn_spiders(actor, target, context): #Filthy hackery to add some state if not hasattr(actor, 'summons'): actor.summons = [] for s in actor.summons: # clear dead things from summoned list if not s.fighter: actor.summons.remove(s) if len(actor.summons) < context['max_summons']: summon_tiles = [] for y in range(3): for x in range(3): pos = actor.x - 1 + x, actor.y - 1 + y if main.in_bounds(pos[0], pos[1]) and not main.is_blocked( pos[0], pos[1]): summon_tiles.append(pos) summon_count = main.roll_dice(context['summons_per_cast']) for i in range(summon_count): if len(summon_tiles) > 0 and len( actor.summons) < context['max_summons']: pos = summon_tiles[libtcod.random_get_int( 0, 0, len(summon_tiles) - 1)] spawn = main.spawn_monster('monster_tunnel_spider', pos[0], pos[1]) ui.message( 'A ' + spawn.name + " crawls from beneath %s cloak." % syntax.name(actor, possesive=True), actor.color) actor.summons.append(spawn) summon_tiles.remove(pos) return 'success' return 'cancelled'
def longstride(actor, target, context): if main.is_blocked(target[0], target[1], movement_type=actor.movement_type): if actor is player.instance: ui.message('Something is in the way.', libtcod.gray) return 'cancelled' actor.set_position(target[0], target[1])
def on_damaged_teleport(actor, attacker, damage): valid_teleports = [] for x in range(attacker.x - 5, attacker.x + 5): if x < 0 or x >= consts.MAP_WIDTH - 1: continue for y in range(attacker.y - 5, attacker.y + 5): if y < 0 or y >= consts.MAP_HEIGHT - 1: continue if fov.monster_can_see_tile(actor, x, y): if not main.is_blocked(x, y, movement_type=actor.movement_type, is_player=actor is player.instance): valid_teleports.append((x, y)) final_teleports = [] if attacker is not None: for vt in valid_teleports: if fov.monster_can_see_tile(attacker, vt[0], vt[1]): final_teleports.append(vt) else: final_teleports = list(valid_teleports) final_teleports.sort( key=lambda o: main.distance(o[0], o[1], actor.x, actor.y)) index = len(final_teleports) - main.roll_dice( '1d%d' % min(len(final_teleports), 5)) teleport_position = final_teleports[index] ui.render_explosion(actor.x, actor.y, 0, libtcod.fuchsia, libtcod.white) actor.set_position(teleport_position[0], teleport_position[1]) ui.render_explosion(actor.x, actor.y, 0, libtcod.fuchsia, libtcod.white)
def great_dive(actor, target, context): ui.message("{} {} into the ground!".format( syntax.name(actor).capitalize(), syntax.conjugate(actor is player.instance, ['slam', 'slams']))) for obj in main.current_map.fighters: if (obj.x, obj.y) in target: combat.attack_ex(actor.fighter, obj, 0) x, y = context['origin'] if not main.is_blocked(x, y): actor.set_position(x, y) else: for t in target: if not main.is_blocked(t[0], t[1]): actor.set_position(t[0], t[1]) break
def shimmering_swords(actor, target, context): import pathfinding sp = actor.fighter.spell_power(context['element']) adjacent = [] for tile in main.adjacent_tiles_diagonal(actor.x, actor.y): if not main.is_blocked( tile[0], tile[1], movement_type=pathfinding.FLYING): adjacent.append(tile) for i in range(context['sword_count']): if len(adjacent) < 1: break summon_pos = adjacent[libtcod.random_get_int(0, 0, len(adjacent) - 1)] common.summon_ally( 'monster_shimmering_sword', context['duration_base'] + main.roll_dice('1d%d' % sp), summon_pos[0], summon_pos[1]) adjacent.remove(summon_pos)
def summon_roaches(actor, attacker, damage): if not hasattr(actor, 'summon_limit') or not hasattr(actor, 'summons'): actor.summon_limit = 8 actor.summons = [] remove = [] for s in actor.summons: if s.fighter is None or not s in main.current_map.fighters: remove.append(s) for s in remove: actor.summons.remove(s) if len(actor.summons) >= actor.summon_limit: return if fov.player_can_see(actor.x, actor.y): ui.message( 'Cockroaches crawl from %s wounds!' % syntax.name(actor, possesive=True), libtcod.dark_magenta) for adj in main.adjacent_tiles_diagonal(actor.x, actor.y): if len(actor.summons) >= actor.summon_limit: break if not main.is_blocked( adj[0], adj[1]) and libtcod.random_get_int(0, 1, 10) <= 5: actor.summons.append( main.spawn_monster('monster_cockroach', adj[0], adj[1]))
def boomerang(actor, target, context): sprites = ['<', 'v', '>', '^'] ui.render_projectile((actor.x, actor.y), (target.x, target.y), libtcod.yellow, sprites) attack_result = actor.fighter.attack(target) if attack_result == 'failed': return 'didnt-take-turn' catch_skill = 30 if actor.player_stats: catch_skill = actor.player_stats.agi if main.roll_dice('1d' + str(catch_skill)) >= 10: #catch boomerang ui.render_projectile((target.x, target.y), (actor.x, actor.y), libtcod.yellow, sprites) if actor is player.instance: ui.message('You catch the boomerang as it returns to you', libtcod.gray) else: possible_tiles = [] for y in range(actor.y - 2, actor.y + 2): for x in range(actor.x - 2, actor.x + 2): if x >= 0 and y >= 0 and x < consts.MAP_WIDTH and y < consts.MAP_HEIGHT and not main.is_blocked( x, y): possible_tiles.append((x, y)) if len(possible_tiles) == 0: selected_tile = main.find_closest_open_tile(target.x, target.y) else: selected_tile = possible_tiles[libtcod.random_get_int( 0, 0, len(possible_tiles) - 1)] ui.render_projectile((target.x, target.y), (selected_tile[0], selected_tile[1]), libtcod.yellow, sprites) weapon = main.get_equipped_in_slot(actor.fighter.inventory, 'right hand') weapon.owner.item.drop(no_message=True) weapon.owner.x = selected_tile[0] weapon.owner.y = selected_tile[1] if actor is player.instance or fov.player_can_see(actor.x, actor.y): ui.message( '%s boomerang falls to the ground.' % syntax.name(target, possesive=True).capitalize(), libtcod.gray) libtcod.console_flush()