def wild_growth(actor, target, context): import mapgen terrain = main.current_map.tiles[target.x][target.y].tile_type if target.fighter and target.fighter.has_status('immobilized'): return 'cancelled' if terrain == 'grass floor': if target.fighter: if target is player.instance or fov.player_can_see( target.x, target.y): ui.message('The grass sprouts a tangle of grasping vines!', libtcod.lime) duration = main.roll_dice(context['root_duration']) immobilized = target.fighter.apply_status_effect( effects.immobilized(duration=duration), dc=context['save_dc']) if immobilized: target.fighter.apply_status_effect(effects.StatusEffect( 'wild growth', time_limit=duration, color=libtcod.lime, on_tick=wild_growth_tick, message='You are gripped by writhing vines!', description='This unit will take damage every turn', cleanseable=True), dc=None) else: if target is player.instance or fov.player_can_see(target.x, target.y): ui.message('Grass springs from the %s...' % terrain, libtcod.lime) grass = mapgen.create_terrain_patch((target.x, target.y), 'grass floor', min_patch=4, max_patch=12, overwrite=False) for tile in grass: main.changed_tiles.append(tile)
def dragonweed_pull(actor, target, context): if target.fighter.hp > 0: ui.message( "The dragonweed's stem lashes out at %s!" % syntax.name(target), libtcod.dark_green) result = combat.attack_ex(actor.fighter, target, 0, accuracy_modifier=1.5, damage_multiplier=0.75, verb=('pull', 'pulls')) if result == 'hit' and target.fighter is not None: if 'displacement' in target.fighter.immunities: if fov.player_can_see(target.x, target.y): ui.message( '%s %s.' % (syntax.name(target).capitalize(), syntax.conjugate(target is player.instance, ('resist', 'resists'))), libtcod.gray) return 'success' beam = main.beam(actor.x, actor.y, target.x, target.y) pull_to = beam[max(len(beam) - 3, 0)] target.set_position(pull_to[0], pull_to[1]) if main.roll_dice('1d10') <= 5: target.fighter.apply_status_effect( effects.immobilized(duration=2), context['save_dc'], actor)
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 bomb_beetle_corpse_tick(object=None, context=None): if object is None: return object.bomb_timer -= 1 if object.bomb_timer > 2: object.color = libtcod.black elif object.bomb_timer > 1: object.color = libtcod.darkest_red elif object.bomb_timer > 0: object.color = libtcod.red elif object.bomb_timer <= 0: ui.message('The bomb beetle corpse explodes!', libtcod.orange) ui.render_explosion(object.x, object.y, 1, libtcod.yellow, libtcod.flame) main.create_fire(object.x, object.y, 10) for tile in main.adjacent_tiles_diagonal(object.x, object.y): if libtcod.random_get_int(0, 0, 3) != 0: main.create_fire(tile[0], tile[1], 10) main.melt_ice(tile[0], tile[1]) monster = main.get_objects(tile[0], tile[1], lambda o: o.fighter is not None) if len(monster) > 0: monster[0].fighter.take_damage(main.roll_dice('22d3')) if monster[0].fighter is not None: monster[0].fighter.apply_status_effect(effects.burning()) object.destroy()
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 check_special_drop(): global elixir_life_ticker, elixir_stat_ticker, scroll_forge_ticker elixir_stat_ticker += 1 scroll_forge_ticker += 1 elixir_life_ticker += 1 if main.roll_dice('1d850') <= elixir_life_ticker: elixir_life_ticker = 0 return 'elixir_life' elif main.roll_dice('1d300') <= elixir_stat_ticker: elixir_stat_ticker = 0 return main.random_choice(table['elixirs_0']) elif main.roll_dice('1d200') <= scroll_forge_ticker: scroll_forge_ticker = 0 return 'scroll_forge' else: return None
def castigate(actor, target, context): origin = context['origin'] ui.render_explosion(origin[0], origin[1], 1, libtcod.violet, libtcod.light_yellow) dc = context['save_dc'] + actor.fighter.spell_power(elements=['radiance']) for f in target: f.fighter.apply_status_effect( effects.judgement(stacks=main.roll_dice('3d8')), dc, actor)
def magma_bolt(actor, target, context): for tile in target: main.create_temp_terrain('lava', [tile], main.roll_dice(context['lava_duration'])) for fighter in main.current_map.fighters: if fighter.x == tile[0] and fighter.y == tile[1]: combat.attack_magical(actor.fighter, fighter, 'ability_magma_bolt')
def smite(actor, target, context): import monsters dc = context['save_dc'] + actor.fighter.spell_power(elements=['radiance']) combat.attack_magical(actor.fighter, target, 'ability_smite') if target.fighter is not None: target.fighter.apply_status_effect( effects.judgement(main.roll_dice('2d8')), dc, actor) if target.fighter.has_flag(monsters.EVIL): target.fighter.apply_status_effect(effects.stunned()) return 'success'
def holy_water(actor, target, context): import monsters if not target.fighter.has_flag(monsters.EVIL): if actor is player.instance: ui.message('That target is not vulnerable to holy water.', libtcod.gray) return 'cancelled' ui.render_projectile((actor.x, actor.y), (target.x, target.y), color=spells.essence_colors['water'], character=libtcod.CHAR_BLOCK2) combat.attack_magical(actor.fighter, target, 'ability_holy_water') if target.fighter is not None: target.fighter.apply_status_effect( effects.stunned(duration=(3 + main.roll_dice('1d6')))) return 'success'
def heal_other(actor, target, context): if actor is player.instance: ui.message('Yo implement this', libtcod.red) return 'failure' ui.render_explosion(target.x, target.y, 0, libtcod.lightest_green, libtcod.green) amount = main.roll_dice('3d4') target.fighter.heal(amount) ui.message( '%s %s %s for %d damage.' % (syntax.name(actor).capitalize(), syntax.conjugate(actor is player.instance, ('heal', 'heals')), syntax.name(target, reflexive=actor), amount), libtcod.green) return 'success'
def flame_breath(actor, target, context): for tile in target: main.melt_ice(tile[0], tile[1]) t = main.current_map.tiles[tile[0]][tile[1]] if t.flammable or main.roll_dice('1d2') == 1: main.create_fire(tile[0], tile[1], 12) for obj in main.current_map.fighters: if obj.x == tile[0] and obj.y == tile[1]: combat.attack_magical(actor.fighter, obj, 'ability_flame_breath') if obj.fighter is not None: obj.fighter.apply_status_effect(effects.burning(), context['save_dc'], actor) return 'success'
def snowstorm_tick(actor, target, context): caster = context['caster'] dc = context['save_dc'] + caster.fighter.spell_power(elements=['radiance']) for t in target: if main.roll_dice('1d10') > 7: combat.attack_magical(caster.fighter, t, 'ability_snowstorm') if t.fighter is not None: t.fighter.apply_status_effect(effects.slowed(), dc, caster) t.fighter.apply_status_effect(effects.blinded(), dc, caster) fx = main.GameObject(t.x, t.y, '*', 'cloud of snow', libtcod.lightest_azure, summon_time=2) main.current_map.objects.append(fx)
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 item_from_table(branch, loot_table=None): if loot_table is None: loot_table = choose_loot_table(branch) if loot_table is None: return None # fall back to lower level table if higher level isn't available (TODO: Removeme) if not loot_table in table: split = loot_table.split('_') i = int(split[1]) - 1 while i >= 0: lower = split[0] + '_' + str(i) if lower in table: loot_table = lower break i -= 1 if loot_table not in table: return None loot_level = int(loot_table.split('_')[1]) category = loot_table.split('_')[0] while main.roll_dice('1d20') == 20: loot_level += 1 #oh lawdy tmp = category + '_' + str(loot_level) if not tmp in table.keys(): loot_level -= 1 break loot_table = category + '_' + str(loot_level) item_id = main.random_choice(table[loot_table]) if item_id in table.keys(): return item_from_table(branch, loot_table=item_id) material = None quality = '' if category == 'weapon': material = choose_weapon_material(loot_level) quality = choose_quality(loot_level) if category == 'armor': quality = choose_quality(loot_level) material = choose_armor_material(loot_level) return main.create_item(item_id, material, quality)
def bramble(actor, target, context): ui.message( 'Thorny brambles spring from %s fingertips!' % syntax.name(actor, possesive=True), spells.essence_colors['life']) for tile in target: _bramble = main.GameObject( tile[0], tile[1], 'x', 'bramble', libtcod.dark_lime, on_step=bramble_on_step, summon_time=context['duration_base'] + main.roll_dice(context['duration_variance'])) _bramble.summoner = actor _bramble.spell_power = actor.fighter.spell_power(['life']) main.current_map.add_object(_bramble) return 'success'
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()
def reeker_breath(actor, target, context): #TODO: Upgrade this to use auto targeting x = target.x y = target.y tiles = main.cone(actor.x, actor.y, x, y, max_range=context['range']) if tiles is None or len(tiles) == 0 or tiles[0] is None: return 'cancelled' if fov.player_can_see(target.x, target.y) or actor is player.instance: ui.message( '%s %s a cloud of acrid fumes!' % (syntax.name(actor).capitalize(), syntax.conjugate(actor is player.instance, ('breathe', 'breathes'))), libtcod.fuchsia) for tile in tiles: main.create_reeker_gas(tile[0], tile[1], duration=main.roll_dice('1d6') + 3) for obj in main.current_map.fighters: if obj.x == tile[0] and obj.y == tile[1]: combat.attack_magical(actor.fighter, obj, 'ability_reeker_breath')
def farmers_talisman_dig(actor, target, context): x, y = target[0], target[1] direction = x - player.instance.x, y - player.instance.y depth = context['min_depth'] + main.roll_dice(context['depth_variance']) return common.dig_line(player.instance.x, player.instance.y, direction[0], direction[1], depth)
def wild_growth_tick(effect, object): import abilities if object is not None and object.fighter is not None: spell = abilities.data['ability_wild_growth'] object.fighter.take_damage( main.roll_dice(spell['damage_per_tick'], normalize_size=4))
def read_line(line): # Variables inside curly braces are optional # Dirty but better than having "self" all over the damn code global logged_in, deposit, scores # PING messages don't start with ':' if line.startswith(':'): ### Parsing ### # Complete command (:name!username@host command {args} :args) full_command = line.split( ) # [:name!username@host, command{, args}, :args] if len(full_command) < 2: return # Sender info (:name!username@host) sender_info = full_command[0] sender_info = sender_info.lstrip(':').split( '!') # [name, username@host] sender = sender_info[0] # name # Message and parameters (command {args} :args) message = full_command[1:] command = message[0] # command ### Numeric replies ### # Initial connection if not logged_in and (command == '439' or 'NOTICE' in command): execute('NICK %s' % nickname) execute('USER %s %s %s :%s' % (nickname, nickname, nickname, nickname)) execute('NS IDENTIFY %s' % password) # execute('NS GHOST %s %s' % (nickname, password)) logged_in = True # Start of MOTD elif command == '375': for channel in channels: execute('JOIN %s' % channel) # NAMES list elif command == '353': # message = ['353', bot_nickname, '=', #chan, :nick1, nick2, nick3] channel = message[3] # #chan message[4] = message[4].lstrip(':') # nick1 names_list = message[4:] # [nick1, nick2, nick3] for name in names_list: add_user(channel, name) ### Handle common messages ### elif command == 'KICK': current_channel = full_command[2] user = full_command[3] # Autojoin if user == nickname: execute('JOIN %s' % current_channel) # User KICKs else: remove_user(user, current_channel) deposit += 10 # User JOINs elif command == 'JOIN' and sender != nickname: # message = ['JOIN', {':' + }#chan] current_channel = message[1].lstrip(':') add_user(current_channel, sender) # User PARTs elif command == 'PART': # message = ['PART', #chan, ':' + reason] current_channel = message[1] remove_user(current_channel, sender) # User QUITs elif command == 'QUIT': for channel in channels: remove_user(channel, sender) # User commands elif command == 'PRIVMSG': # message = ['PRIVMSG', #chan, ':' + word word word] message[2] = message[2].lstrip(':') current_channel = message[1] said = ' '.join(message[2:]) params = message[3:] # List of parameters (split by spaces) search_term = '+'.join(params) # Get title from web pages if 'http://' in said: url = extract_url(said) title = get_title(url) if title: say(current_channel, 'Title: %s' % title) # Get link to Wikipedia article if '[[' in said: article = extract_article(said) link = get_link(article) if link: say(current_channel, link) ## IRC commands ## # Commands with parameters if len(params) > 0: # Google if said.find('@g') == 0: say(current_channel, 'https://www.google.com/search?q=%s' % search_term) # Wolfram Alpha elif said.find('@wa') == 0: say( current_channel, 'http://www.wolframalpha.com/input/?i=%s' % search_term) # DuckDuckGo elif said.find('@ddg') == 0: say(current_channel, 'http://duckduckgo.com/?q=%s' % search_term) # DRAE elif said.find('@drae') == 0: say(current_channel, 'http://lema.rae.es/drae/?val=%s' % search_term) # DPD elif said.find('@dpd') == 0: say(current_channel, 'http://lema.rae.es/dpd/?key=%s' % search_term) # Jisho kanji lookup elif said.find('@kan') == 0: escaped_term = urllib2.quote(search_term) say(current_channel, 'http://jisho.org/kanji/details/%s' % escaped_term) # EN > JP elif said.find('@ei') == 0: say( current_channel, 'http://jisho.org/words?jap=&eng=%s&dict=edict' % search_term) # JP > EN elif said.find('@ni') == 0: escaped_term = urllib2.quote(search_term) say( current_channel, 'http://jisho.org/words?jap=%s&eng=&dict=edict' % escaped_term) # EN > ES elif said.find('@en') == 0: say( current_channel, 'http://www.wordreference.com/es/translation.asp?tranword=%s' % search_term) # ES > EN elif said.find('@es') == 0: say( current_channel, 'http://www.wordreference.com/es/en/translation.asp?spen=%s' % search_term) # Unit converter elif said.find('@conv') == 0: if 'to' not in params: return index = params.index('to') amount = params[0] unit_from = params[1:index] unit_from = urllib2.quote(' '.join(unit_from)) # 'to' == params[index] unit_to = params[index + 1:] unit_to = urllib2.quote(' '.join(unit_to)) conversion_url = 'http://www.google.com/ig/calculator?hl=en&q=' conversion = fetch_url(conversion_url + amount + unit_from + '=?' + unit_to).read() parsed_conversion = conversion.split('"') # Check for errors if len(parsed_conversion[5]) == 0: unit_result = urllib2.unquote(unit_to) say( current_channel, '%s %s' % (parsed_conversion[3].split()[0], unit_result)) # Linkrace module elif said.find('@link') == 0: linkcommand = params[0] # Get race links if linkcommand == 'get': url = 'http://es.wikipedia.org/wiki/%s' start, end = random_pair() starturl = url % urllib2.quote(start) endurl = url % urllib2.quote(end) say(current_channel, 'Start article is %s' % starturl) say(current_channel, 'Goal article is %s' % endurl) # Check if chain is valid if linkcommand == 'check': chain = ' '.join(params[1:]) broken_links = check_chain(chain) if not broken_links: say(current_channel, 'The chain is valid.') else: error_list = ' | '.join(broken_links) say(current_channel, error_list) say(current_channel, 'The chain is not valid.') # Calculator elif said.find('@calc') == 0: expression = ''.join(params) result = str(calculate(expression)) say(current_channel, result) # Wikipedia fetch elif said.find('@fetch') == 0: article_name = ' '.join(params) extract = fetch(article_name) say(current_channel, extract) # Bet elif said.find('@bet') == 0: wager = int(params[0]) if wager > deposit: say(current_channel, 'Deposit is %s, cannot bet %s' % (deposit, wager)) return # Cannot bet if last roll was 1 or 6 last = last_roll(sender) if last == 1 or last == 6: say(current_channel, 'Last roll was' % last) return roll = roll_dice(sender) # Won the bet if roll > last: wallet[sender] += wager deposit -= wager balance = wallet[sender] say( current_channel, '%s: roll: %s, +%sC, balance: %sC' % (sender, roll, wager, balance)) # Lost the bet else: # User doesn't have enough money to pay if wager > wallet[sender]: deposit += wallet[sender] # User has enough money to pay else: deposit += wager wallet[sender] -= wager balance = wallet[sender] say( current_channel, '%s: roll: %s, -%sC, balance: %sC' % (sender, roll, wager, balance)) # Kick if debt is greater than 10 if wallet[sender] < -10: bot_kick(current_channel, sender, 'Debt') # Commands without parameters else: # Roll if said.find('@roll') == 0: roll = roll_dice(sender) # Roll 1, give 1C to deposit (if available) if roll == 1 and wallet[sender] > 0: deposit += 1 wallet[sender] -= 1 balance = wallet[sender] say( current_channel, '%s: roll: %s, -1C, balance: %sC' % (sender, roll, balance)) # Roll 6, get 1C from deposit (if available) elif roll == 6 and deposit > 0: deposit -= 1 wallet[sender] += 1 balance = wallet[sender] say( current_channel, '%s: roll: %s, +1C, balance: %sC' % (sender, roll, balance)) else: say(current_channel, '%s: roll: %s' % (sender, roll)) # Check deposit elif said.find('@deposit') == 0: say(current_channel, 'Deposit: %s' % deposit) # Return last roll elif said.find('@last') == 0: say(current_channel, '%s: Last roll: %s' % (sender, last_roll(sender))) # List all wallets elif said.find('@wallets') == 0: say(current_channel, str(wallet)) # List own balance elif said.find('@balance') == 0: balance = wallet[sender] say(current_channel, '%s: balance: %sC' % (sender, balance)) ## Owner commands ## if sender == owner: # Disconnect if said == '.quit': end_bot() # Print userlist elif said.find('.users') == 0: say(current_channel, str(users)) # Bot joins elif said.find('.join') == 0: channel = said.split()[1] execute('JOIN %s' % channel) # Bot parts elif said.find('.part') == 0: execute('PART %s' % current_channel) del users[current_channel] # Bot kicks elif said.find('.kick') == 0: user = said.split()[1] bot_kick(current_channel, user) # PING messages don't start with ':' else: # Pong if 'PING' in line: execute('PONG %s' % line.split()[1])
def strangleweed_on_tick(effect, object): if object is not None and object.fighter is not None: spell = abilities.data['ability_strangleweeds'] object.fighter.take_damage( main.roll_dice(spell['tick_damage'], normalize_size=4))
def disarm_attack(actor, target, damage): if main.roll_dice('1d5') == 5: common.disarm(target)
def summon_lifeplant(actor, target, context): return common.summon_ally( 'monster_lifeplant', context['duration_base'] + main.roll_dice(context['duration_variance']))
def shatter_item(actor, target, context): x, y = 0, 0 dc = context['save_dc'] if actor is player.instance: # player is casting ui.message_flush('Left-click a target tile, or right-click to cancel.', libtcod.white) (x, y) = ui.target_tile() if x is None: return 'cancelled' choices = main.get_objects( x, y, lambda o: o.fighter and o.fighter.inventory and len( o.fighter.inventory) > 0) if len(choices) == 0: choices = main.get_objects(x, y, lambda o: o.item is not None) if len(choices) > 1: target = choices[ui.menu('Which target?', [i.name for i in choices], 24)] elif len(choices) > 0: target = choices[0] else: ui.message('No valid targets here', libtcod.gray) return 'cancelled' dc += 4 else: x, y = target.x, target.y if target is None: return 'cancelled' item = None inventory = None if target.fighter is not None: inventory = target.fighter.inventory if inventory is None or len(inventory) == 0: if actor == player.instance: ui.message('Target has no items', libtcod.light_blue) return 'cancelled' item = inventory[libtcod.random_get_int(0, 0, len(inventory) - 1)] dc += 5 elif target.item is not None: item = target if main.roll_dice('1d20') + main.roll_dice('1d{}'.format( actor.fighter.spell_power())) > dc: ui.render_explosion(x, y, 1, libtcod.yellow, libtcod.flame) ui.message("The {} shatters into pieces!".format(item.name), libtcod.flame) if inventory is not None: inventory.remove(item) item.destroy() damage_factor = 4 if item.equipment is not None: damage_factor = item.equipment.weight for obj in main.current_map.fighters: if obj.distance(x, y) <= context['burst']: combat.attack_magical_ex( actor, obj, base_damage_dice='2d{}'.format(damage_factor), spell_dice_number=context['dice'], spell_elements=context['element'], pierce=context['pierce'], shred=context['shred'], defense_types=context['defense_types'], damage_types=context['damage_types'], blockable=context['blockable'], attack_name=context['name']) return 'success' else: ui.message("Shatter failed to break the {}!".format(item.name), libtcod.yellow) return 'success'
def immobilize_attack(actor, target, damage): if target.fighter is not None and main.roll_dice('1d10') <= 5: target.fighter.apply_status_effect(effects.immobilized(duration=2))
def on_hit_self_corruption(attacker, target, damage): if attacker is player.instance: player.add_corruption(main.roll_dice('1d4'))
def on_hit_judgement(attacker, target, damage): if target.fighter is not None: target.fighter.apply_status_effect( effects.judgement(stacks=main.roll_dice('2d6')))
def poison_attack(actor, target, damage): if main.roll_dice('1d10') > target.fighter.armor: target.fighter.apply_status_effect(effects.poison())
def summon_arcane_construct(actor, target, context): common.summon_ally( 'monster_arcane_construct', duration=context['duration_base'] + main.roll_dice('1d%d' % actor.fighter.spell_power(context['element']), normalize_size=4))